From e86cbfe46e4b5b210fdfb0851e26223d0797049f Mon Sep 17 00:00:00 2001 From: Akash-Nayak Date: Sun, 15 Jan 2023 09:45:06 +0530 Subject: [PATCH] feat: Update the Golang Dockerfilegenerator transformer to support multi-arch build (#943) Signed-off-by: Akash Nayak --- .../golang/mappings/golangversions.yaml | 20 +++++ .../golang/templates/Dockerfile | 14 +-- .../golang/transformer.yaml | 2 + assets/filepermissions.yaml | 1 + .../golangdockerfiletransformer.go | 87 +++++++++++++++++-- 5 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 assets/built-in/transformers/dockerfilegenerator/golang/mappings/golangversions.yaml diff --git a/assets/built-in/transformers/dockerfilegenerator/golang/mappings/golangversions.yaml b/assets/built-in/transformers/dockerfilegenerator/golang/mappings/golangversions.yaml new file mode 100644 index 000000000..09d37bb7c --- /dev/null +++ b/assets/built-in/transformers/dockerfilegenerator/golang/mappings/golangversions.yaml @@ -0,0 +1,20 @@ +apiVersion: move2kube.konveyor.io/v1alpha1 +kind: GolangVersionsMapping +metadata: + name: GolangVersionsMapping +spec: + golangVersions: + - version: "1.18" + imageTag: "1.18" + - version: "1.17" + imageTag: "1.17" + - version: "1.16" + imageTag: "1.16.12" + - version: "1.15" + imageTag: "1.15.14" + - version: "1.14" + imageTag: "1.14.12" + - version: "1.13" + imageTag: "1.13.15" + - version: "1.12" + imageTag: "1.12.8" diff --git a/assets/built-in/transformers/dockerfilegenerator/golang/templates/Dockerfile b/assets/built-in/transformers/dockerfilegenerator/golang/templates/Dockerfile index 4e44aaa28..b5740c707 100644 --- a/assets/built-in/transformers/dockerfilegenerator/golang/templates/Dockerfile +++ b/assets/built-in/transformers/dockerfilegenerator/golang/templates/Dockerfile @@ -13,22 +13,14 @@ # limitations under the License. # Build App -FROM registry.access.redhat.com/ubi8/ubi:latest AS builder -WORKDIR /temp -ENV GOPATH=/go -ENV PATH=$GOPATH/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -RUN curl -o go.tar.gz https://dl.google.com/go/go{{ .GoVersion }}.linux-amd64.tar.gz -RUN tar -xzf go.tar.gz && mv go /usr/local/ -RUN yum install git make -y -RUN mkdir -p $GOPATH/src $GOPATH/bin && chmod -R 777 $GOPATH +FROM registry.access.redhat.com/ubi8/go-toolset:{{ .GolangImageTag }} AS builder WORKDIR /{{ .AppName }} COPY . . -RUN go build -o {{ .AppName }} -RUN cp ./{{ .AppName }} /bin/{{ .AppName }} +RUN go build -o ./bin/{{ .AppName }} # Run App FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3-201 -COPY --from=builder /bin/{{ .AppName }} /bin/{{ .AppName }} +COPY --from=builder /{{ .AppName }}/bin/{{ .AppName }} /bin/{{ .AppName }} {{- range $port := .Ports }} EXPOSE {{ $port }} {{- end }} diff --git a/assets/built-in/transformers/dockerfilegenerator/golang/transformer.yaml b/assets/built-in/transformers/dockerfilegenerator/golang/transformer.yaml index 7eb0533e4..e6de062b1 100644 --- a/assets/built-in/transformers/dockerfilegenerator/golang/transformer.yaml +++ b/assets/built-in/transformers/dockerfilegenerator/golang/transformer.yaml @@ -19,3 +19,5 @@ spec: disabled: false config: defaultGoVersion: "1.18" + externalFiles: + "./mappings/golangversions.yaml" : mappings/golangversions.yaml diff --git a/assets/filepermissions.yaml b/assets/filepermissions.yaml index 7ac12773d..5d2dcd4e1 100644 --- a/assets/filepermissions.yaml +++ b/assets/filepermissions.yaml @@ -34,6 +34,7 @@ "built-in/transformers/dockerfilegenerator/common/Dockerfile.license" : 0644 "built-in/transformers/dockerfilegenerator/dotnetcore/templates/Dockerfile" : 0644 "built-in/transformers/dockerfilegenerator/dotnetcore/transformer.yaml" : 0644 +"built-in/transformers/dockerfilegenerator/golang/mappings/golangversions.yaml" : 0644 "built-in/transformers/dockerfilegenerator/golang/templates/Dockerfile" : 0644 "built-in/transformers/dockerfilegenerator/golang/transformer.yaml" : 0644 "built-in/transformers/dockerfilegenerator/java/earanalyser/transformer.yaml" : 0644 diff --git a/transformer/dockerfilegenerator/golangdockerfiletransformer.go b/transformer/dockerfilegenerator/golangdockerfiletransformer.go index f36a01ed4..38982abf3 100644 --- a/transformer/dockerfilegenerator/golangdockerfiletransformer.go +++ b/transformer/dockerfilegenerator/golangdockerfiletransformer.go @@ -20,9 +20,11 @@ import ( "fmt" "os" "path/filepath" + "sort" "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" @@ -30,26 +32,43 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/mod/modfile" "golang.org/x/mod/module" + "golang.org/x/mod/semver" ) const ( - defaultGoVersion = "1.18" + golangVersionMappingFilePath = "mappings/golangversions.yaml" // GolangModFilePathType points to the go.mod file path GolangModFilePathType transformertypes.PathType = "GoModFilePath" + // GolangVersionsMappingKind defines kind of GolangVersionMappingKind + GolangVersionsMappingKind types.Kind = "GolangVersionsMapping" ) +// GolangVersionsMapping stores the Go versions mapping +type GolangVersionsMapping struct { + types.TypeMeta `yaml:",inline"` + types.ObjectMeta `yaml:"metadata,omitempty"` + Spec GolangVersionsMappingSpec `yaml:"spec,omitempty"` +} + +// GolangVersionsMappingSpec stores the Go version spec +type GolangVersionsMappingSpec struct { + DisableSort bool `yaml:"disableSort"` + GolangVersions []map[string]string `yaml:"golangVersions"` +} + // GolangDockerfileGenerator implements the Transformer interface type GolangDockerfileGenerator struct { Config transformertypes.Transformer Env *environment.Environment GolangConfig *GolangDockerfileYamlConfig + Spec GolangVersionsMappingSpec } // GolangTemplateConfig implements Golang config interface type GolangTemplateConfig struct { - Ports []int32 - AppName string - GoVersion string + Ports []int32 + AppName string + GolangImageTag string } // GolangDockerfileYamlConfig represents the configuration of the Golang dockerfile @@ -67,9 +86,21 @@ func (t *GolangDockerfileGenerator) Init(tc transformertypes.Transformer, env *e logrus.Errorf("unable to load config for Transformer %+v into %T : %s", t.Config.Spec.Config, t.GolangConfig, err) return err } + // load the version mapping file + mappingFilePath := filepath.Join(t.Env.GetEnvironmentContext(), golangVersionMappingFilePath) + spec, err := LoadGolangVersionMappingsFile(mappingFilePath) + if err != nil { + return fmt.Errorf("failed to load the Golang version mappings file at path %s . Error: %q", golangVersionMappingFilePath, err) + } + t.Spec = spec if t.GolangConfig.DefaultGoVersion == "" { - t.GolangConfig.DefaultGoVersion = defaultGoVersion + if len(t.Spec.GolangVersions) != 0 { + if _, ok := t.Spec.GolangVersions[0][versionKey]; ok { + t.GolangConfig.DefaultGoVersion = t.Spec.GolangVersions[0][versionKey] + } + } } + logrus.Debugf("Extracted Golang versions from Go version mappings file - %+v", t.Spec) return nil } @@ -152,15 +183,31 @@ func (t *GolangDockerfileGenerator) Transform(newArtifacts []transformertypes.Ar logrus.Debugf("Didn't find the Go version in the go.mod file at path %s, selecting Go version %s", a.Paths[GolangModFilePathType][0], t.GolangConfig.DefaultGoVersion) modFile.Go.Version = t.GolangConfig.DefaultGoVersion } + golangVersionToImageTagMapping := make(map[string]string) + for _, golangVersion := range t.Spec.GolangVersions { + if imageTag, ok := golangVersion[imageTagKey]; ok { + golangVersionToImageTagMapping[golangVersion[versionKey]] = imageTag + } + } + logrus.Debugf("Extracted Golang version-image tag mappings are %+v", golangVersionToImageTagMapping) + var golangImageTag string + imageTag, ok := golangVersionToImageTagMapping[modFile.Go.Version] + if ok { + golangImageTag = imageTag + logrus.Debugf("Selected Golang image tag is - %s", golangImageTag) + } else { + golangImageTag = golangVersionToImageTagMapping[t.GolangConfig.DefaultGoVersion] + logrus.Warnf("Could not find a matching Golang version in the mapping. Selecting image tag %s corresponding to the default Golang version %s", golangImageTag, t.GolangConfig.DefaultGoVersion) + } detectedPorts := ir.GetAllServicePorts() if len(detectedPorts) == 0 { detectedPorts = append(detectedPorts, common.DefaultServicePort) } detectedPorts = commonqa.GetPortsForService(detectedPorts, `"`+a.Name+`"`) golangConfig := GolangTemplateConfig{ - AppName: a.Name, - Ports: detectedPorts, - GoVersion: modFile.Go.Version, + AppName: a.Name, + Ports: detectedPorts, + GolangImageTag: golangImageTag, } pathMappings = append(pathMappings, transformertypes.PathMapping{ @@ -199,3 +246,27 @@ func (t *GolangDockerfileGenerator) Transform(newArtifacts []transformertypes.Ar } return pathMappings, artifactsCreated, nil } + +// LoadGolangVersionMappingsFile loads the Golang version mappings file +func LoadGolangVersionMappingsFile(mappingFilePath string) (GolangVersionsMappingSpec, error) { + mappingFile := GolangVersionsMapping{} + if err := common.ReadMove2KubeYaml(mappingFilePath, &mappingFile); err != nil { + return mappingFile.Spec, fmt.Errorf("failed to load the Golang versions mapping file at path %s . Error: %q", mappingFilePath, err) + } + // validate the file + if len(mappingFile.Spec.GolangVersions) == 0 { + return mappingFile.Spec, fmt.Errorf("the Golang version mappings file at path %s is invalid. Atleast one Go version should be specified", mappingFilePath) + } + for i, v := range mappingFile.Spec.GolangVersions { + if _, ok := v[versionKey]; !ok { + return mappingFile.Spec, fmt.Errorf("the Golang version is missing from the object %#v at the %dth index in the array", mappingFile.Spec.GolangVersions[i], i) + } + } + // sort the list using semantic version comparison + if !mappingFile.Spec.DisableSort { + sort.SliceStable(mappingFile.Spec.GolangVersions, func(i, j int) bool { + return semver.Compare(mappingFile.Spec.GolangVersions[i][versionKey], mappingFile.Spec.GolangVersions[j][versionKey]) == 1 + }) + } + return mappingFile.Spec, nil +}