diff --git a/assets/built-in/transformers/dockerfilegenerator/mappings/nodeversions.yaml b/assets/built-in/transformers/dockerfilegenerator/mappings/nodeversions.yaml new file mode 100644 index 000000000..c7c37e9a4 --- /dev/null +++ b/assets/built-in/transformers/dockerfilegenerator/mappings/nodeversions.yaml @@ -0,0 +1,10 @@ +apiVersion: move2kube.konveyor.io/v1alpha1 +kind: NodeVersionsMapping +metadata: + name: NodeVersionsMapping +spec: + nodeVersions: + - "v16.16.0" + - "v14.20.0" + - "v12.22.12" + - "v10.24.1" diff --git a/assets/built-in/transformers/dockerfilegenerator/nodejs/templates/Dockerfile b/assets/built-in/transformers/dockerfilegenerator/nodejs/templates/Dockerfile index fa24866e6..0199b9024 100644 --- a/assets/built-in/transformers/dockerfilegenerator/nodejs/templates/Dockerfile +++ b/assets/built-in/transformers/dockerfilegenerator/nodejs/templates/Dockerfile @@ -12,7 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM registry.access.redhat.com/ubi8/nodejs-{{ .NodeVersion }} +FROM registry.access.redhat.com/ubi8/ubi-minimal:latest +RUN microdnf update && microdnf install wget xz tar && microdnf clean all && \ + wget https://nodejs.org/dist/{{ .NodeVersion }}/node-{{ .NodeVersion }}-linux-x64.tar.xz && \ + tar -xJf node-{{ .NodeVersion }}-linux-x64.tar.xz && \ + mv node-{{ .NodeVersion }}-linux-x64 /node && \ + rm -f node-{{ .NodeVersion }}-linux-x64.tar.xz +ENV PATH="$PATH:/node/bin" COPY . . RUN npm install {{- if .Build }} diff --git a/assets/built-in/transformers/dockerfilegenerator/nodejs/transformer.yaml b/assets/built-in/transformers/dockerfilegenerator/nodejs/transformer.yaml index b8df95e62..b625c7b30 100644 --- a/assets/built-in/transformers/dockerfilegenerator/nodejs/transformer.yaml +++ b/assets/built-in/transformers/dockerfilegenerator/nodejs/transformer.yaml @@ -17,5 +17,5 @@ spec: disabled: false DockerfileForService: disabled: false - config: - defaultNodejsVersion: "14" + externalFiles: + "../mappings/nodeversions.yaml" : mappings/nodeversions.yaml diff --git a/assets/filepermissions.yaml b/assets/filepermissions.yaml index 8df2fe5f2..5547ca089 100644 --- a/assets/filepermissions.yaml +++ b/assets/filepermissions.yaml @@ -52,6 +52,7 @@ "built-in/transformers/dockerfilegenerator/java/waranalyser/transformer.yaml" : 0644 "built-in/transformers/dockerfilegenerator/java/warrouter/transformer.yaml" : 0644 "built-in/transformers/dockerfilegenerator/java/zuul/transformer.yaml" : 0644 +"built-in/transformers/dockerfilegenerator/mappings/nodeversions.yaml" : 0644 "built-in/transformers/dockerfilegenerator/nodejs/templates/Dockerfile" : 0644 "built-in/transformers/dockerfilegenerator/nodejs/transformer.yaml" : 0644 "built-in/transformers/dockerfilegenerator/php/templates/Dockerfile" : 0644 diff --git a/go.mod b/go.mod index f9b313ca7..f5278ecf2 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/go-git/go-git/v5 v5.4.2 github.com/google/go-cmp v0.5.7 github.com/gorilla/mux v1.8.0 + github.com/hashicorp/go-version v1.6.0 github.com/joho/godotenv v1.4.0 github.com/magiconair/properties v1.8.5 github.com/mikefarah/yq/v4 v4.16.2 diff --git a/go.sum b/go.sum index f0d88c74e..b232b4f51 100644 --- a/go.sum +++ b/go.sum @@ -1161,6 +1161,8 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= diff --git a/samples/nodejs/package.json b/samples/nodejs/package.json index 20471ca81..cf633ffb5 100644 --- a/samples/nodejs/package.json +++ b/samples/nodejs/package.json @@ -1,8 +1,11 @@ { - "name" : "main", + "name" : "nodejs-webapp", "version" : "0.1.0", "description": "This is a test web server", "keywords": ["test", "webserver"], + "engines": { + "node": "~>v14.10" + }, "scripts": { "start": "node main.js" } diff --git a/transformer/dockerfilegenerator/nodejsdockerfiletransformer.go b/transformer/dockerfilegenerator/nodejsdockerfiletransformer.go index 6f9c99e84..dca87a26d 100644 --- a/transformer/dockerfilegenerator/nodejsdockerfiletransformer.go +++ b/transformer/dockerfilegenerator/nodejsdockerfiletransformer.go @@ -19,31 +19,44 @@ package dockerfilegenerator import ( "fmt" "path/filepath" - "strings" "github.com/joho/godotenv" "github.com/konveyor/move2kube/common" "github.com/konveyor/move2kube/environment" + "github.com/konveyor/move2kube/types" irtypes "github.com/konveyor/move2kube/types/ir" "github.com/konveyor/move2kube/types/qaengine/commonqa" transformertypes "github.com/konveyor/move2kube/types/transformer" "github.com/konveyor/move2kube/types/transformer/artifacts" - "github.com/sirupsen/logrus" "github.com/spf13/cast" - "golang.org/x/mod/semver" ) const ( - defaultNodeVersion = "14" - packageJSONFile = "package.json" + packageJSONFile = "package.json" + versionMappingFilePath = "mappings/nodeversions.yaml" + // NodeVersionsMappingKind defines kind of NodeVersionMappingKind + NodeVersionsMappingKind types.Kind = "NodeVersionsMapping" ) +// NodeVersionsMapping stores the Node versions mapping +type NodeVersionsMapping struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec NodeVersionsMappingSpec `yaml:"spec,omitempty"` +} + +// NodeVersionsMappingSpec stores the Node version spec +type NodeVersionsMappingSpec struct { + NodeVersions []string `yaml:"nodeVersions"` +} + // NodejsDockerfileGenerator implements the Transformer interface type NodejsDockerfileGenerator struct { Config transformertypes.Transformer Env *environment.Environment NodejsConfig *NodejsDockerfileYamlConfig + NodeVersions []string } // NodejsTemplateConfig implements Nodejs config interface @@ -86,9 +99,22 @@ func (t *NodejsDockerfileGenerator) Init(tc transformertypes.Transformer, env *e logrus.Errorf("unable to load config for Transformer %+v into %T : %s", t.Config.Spec.Config, t.NodejsConfig, err) return err } + mappingFile := NodeVersionsMapping{} + mappingFilePath := filepath.Join(t.Env.GetEnvironmentContext(), versionMappingFilePath) + if err := common.ReadMove2KubeYaml(mappingFilePath, &mappingFile); err != nil { + return fmt.Errorf("failed to load the Node versions mapping file at path %s . Error: %q", mappingFilePath, err) + } + if len(mappingFile.Spec.NodeVersions) == 0 { + return fmt.Errorf("the mapping file at path %s is invalid", mappingFilePath) + } + t.NodeVersions = mappingFile.Spec.NodeVersions + if len(t.NodeVersions) == 0 { + return fmt.Errorf("atleast one node version should be specified in the nodeversions mappings file- %s", mappingFilePath) + } if t.NodejsConfig.DefaultNodejsVersion == "" { - t.NodejsConfig.DefaultNodejsVersion = defaultNodeVersion + t.NodejsConfig.DefaultNodejsVersion = t.NodeVersions[0] } + logrus.Debugf("Extracted node versions from nodeversion mappings file - %+v", t.NodeVersions) return nil } @@ -149,19 +175,18 @@ func (t *NodejsDockerfileGenerator) Transform(newArtifacts []transformertypes.Ar var nodeVersion string var packageJSON PackageJSON if err := common.ReadJSON(filepath.Join(a.Paths[artifacts.ServiceDirPathType][0], packageJSONFile), &packageJSON); err != nil { - logrus.Debugf("unable to read the package.json file: %s", err) - } else { - if _, ok := packageJSON.Scripts["build"]; ok { - build = true - } - if node, ok := packageJSON.Engines["node"]; ok { - if !strings.HasPrefix(node, "v") { - node = "v" + node - } - nodeVersion = strings.TrimPrefix(semver.Major(node), "v") - } + logrus.Errorf("unable to read the package.json file: %s", err) + continue + } + if _, ok := packageJSON.Scripts["build"]; ok { + build = true + } + if nodeVersionConstraint, ok := packageJSON.Engines["node"]; ok { + nodeVersion = getNodeVersion(nodeVersionConstraint, t.NodejsConfig.DefaultNodejsVersion, t.NodeVersions) + logrus.Debugf("Selected nodeVersion is - %s", nodeVersion) } if nodeVersion == "" { + logrus.Infof("No Node version specified in the package.json file. Selecting the default Node version- %s", t.NodejsConfig.DefaultNodejsVersion) nodeVersion = t.NodejsConfig.DefaultNodejsVersion } ports := ir.GetAllServicePorts() diff --git a/transformer/dockerfilegenerator/utils.go b/transformer/dockerfilegenerator/utils.go new file mode 100644 index 000000000..5ef71ec8e --- /dev/null +++ b/transformer/dockerfilegenerator/utils.go @@ -0,0 +1,46 @@ +/* + * Copyright IBM Corporation 2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dockerfilegenerator + +import ( + "github.com/hashicorp/go-version" + "github.com/sirupsen/logrus" +) + +// getNodeVersion returns the Node version to be used for the service +func getNodeVersion(versionConstraint, defaultNodejsVersion string, supportedVersions []string) string { + v1, err := version.NewVersion(versionConstraint) + if err == nil { + logrus.Debugf("the constraint is a Node version: %#v", v1) + return "v" + v1.String() + } + constraints, err := version.NewConstraint(versionConstraint) + if err != nil { + logrus.Errorf("failed to parse the Node version constraint string. Error: %q Actual: %s", err, versionConstraint) + return defaultNodejsVersion + } + logrus.Debugf("Node version constraints len = %d; constraints = %#v", constraints.Len(), constraints.String()) + for _, supportedVersion := range supportedVersions { + ver, _ := version.NewVersion(supportedVersion) + if constraints.Check(ver) { + logrus.Debugf("%#v satisfies constraints %#v\n", ver, constraints) + return supportedVersion + } + } + logrus.Infof("no supported Node version detected in package.json. Selecting default Node version- %s", defaultNodejsVersion) + return defaultNodejsVersion +}