You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	feat(helmExecute): run complete lint, build, publish cycle (#3546)
* Add runHelmCommand * Add dryRun for debug * Add default case in helmExecute * Fix unit-tests * small fix * Fix RunHelmAdd and change RunHelmPublish methods * Fix RunHelmPublish * Fix unit-tests * Fix unit-test * small fix * small fix * small fix * Add LintFlag PackageFlag PublishFlag flags * Add tests for httpClient.go * test * test * smal fix * small fix * Add getting name and version from Chart.yaml * Add test * Fix * small fix * Fix according to comments * small fix Co-authored-by: “Vitalii <“vitalii.sidorov@sap.com”> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Co-authored-by: Vitalii Sidorov <vitalii_sidorov@sap.com>
This commit is contained in:
		| @@ -9,41 +9,46 @@ import ( | ||||
| ) | ||||
|  | ||||
| func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData) { | ||||
| 	utils := kubernetes.NewDeployUtilsBundle() | ||||
|  | ||||
| 	helmConfig := kubernetes.HelmExecuteOptions{ | ||||
| 		ChartPath:             config.ChartPath, | ||||
| 		DeploymentName:        config.DeploymentName, | ||||
| 		ContainerRegistryURL:  config.ContainerRegistryURL, | ||||
| 		Image:                 config.Image, | ||||
| 		ContainerImageName:    config.ContainerImageName, | ||||
| 		ContainerImageTag:     config.ContainerImageTag, | ||||
| 		Namespace:             config.Namespace, | ||||
| 		KubeContext:           config.KubeContext, | ||||
| 		KubeConfig:            config.KubeConfig, | ||||
| 		HelmDeployWaitSeconds: config.HelmDeployWaitSeconds, | ||||
| 		DryRun:                config.DryRun, | ||||
| 		PackageVersion:        config.PackageVersion, | ||||
| 		AppVersion:            config.AppVersion, | ||||
| 		DependencyUpdate:      config.DependencyUpdate, | ||||
| 		HelmValues:            config.HelmValues, | ||||
| 		FilterTest:            config.FilterTest, | ||||
| 		DumpLogs:              config.DumpLogs, | ||||
| 		ChartRepo:             config.ChartRepo, | ||||
| 		HelmRegistryUser:      config.HelmRegistryUser, | ||||
| 		HelmChartServer:       config.HelmChartServer, | ||||
| 		ChartPath:                 config.ChartPath, | ||||
| 		Image:                     config.Image, | ||||
| 		Namespace:                 config.Namespace, | ||||
| 		KubeContext:               config.KubeContext, | ||||
| 		KubeConfig:                config.KubeConfig, | ||||
| 		HelmDeployWaitSeconds:     config.HelmDeployWaitSeconds, | ||||
| 		AppVersion:                config.AppVersion, | ||||
| 		DependencyUpdate:          config.DependencyUpdate, | ||||
| 		HelmValues:                config.HelmValues, | ||||
| 		FilterTest:                config.FilterTest, | ||||
| 		DumpLogs:                  config.DumpLogs, | ||||
| 		TargetRepositoryURL:       config.TargetRepositoryURL, | ||||
| 		TargetRepositoryName:      config.TargetRepositoryName, | ||||
| 		TargetRepositoryUser:      config.TargetRepositoryUser, | ||||
| 		TargetRepositoryPassword:  config.TargetRepositoryPassword, | ||||
| 		HelmCommand:               config.HelmCommand, | ||||
| 		CustomTLSCertificateLinks: config.CustomTLSCertificateLinks, | ||||
| 	} | ||||
|  | ||||
| 	utils := kubernetes.NewDeployUtilsBundle(helmConfig.CustomTLSCertificateLinks) | ||||
|  | ||||
| 	helmChart := config.ChartPath + "Chart.yaml" | ||||
| 	nameChart, packageVersion, err := kubernetes.GetChartInfo(helmChart, utils) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatalf("failed to get version in Chart.yaml: %v", err) | ||||
| 	} | ||||
| 	helmConfig.DeploymentName = nameChart | ||||
| 	helmConfig.PackageVersion = packageVersion | ||||
|  | ||||
| 	helmExecutor := kubernetes.NewHelmExecutor(helmConfig, utils, GeneralConfig.Verbose, log.Writer()) | ||||
|  | ||||
| 	// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	if err := runHelmExecute(config.HelmCommand, helmExecutor); err != nil { | ||||
| 	if err := runHelmExecute(config, helmExecutor); err != nil { | ||||
| 		log.Entry().WithError(err).Fatalf("step execution failed: %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func runHelmExecute(helmCommand string, helmExecutor kubernetes.HelmExecutor) error { | ||||
| 	switch helmCommand { | ||||
| func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor) error { | ||||
| 	switch config.HelmCommand { | ||||
| 	case "upgrade": | ||||
| 		if err := helmExecutor.RunHelmUpgrade(); err != nil { | ||||
| 			return fmt.Errorf("failed to execute upgrade: %v", err) | ||||
| @@ -68,9 +73,31 @@ func runHelmExecute(helmCommand string, helmExecutor kubernetes.HelmExecutor) er | ||||
| 		if err := helmExecutor.RunHelmPackage(); err != nil { | ||||
| 			return fmt.Errorf("failed to execute helm package: %v", err) | ||||
| 		} | ||||
| 	case "push": | ||||
| 		if err := helmExecutor.RunHelmPush(); err != nil { | ||||
| 			return fmt.Errorf("failed to execute helm push: %v", err) | ||||
| 	case "publish": | ||||
| 		if err := helmExecutor.RunHelmPublish(); err != nil { | ||||
| 			return fmt.Errorf("failed to execute helm publish: %v", err) | ||||
| 		} | ||||
| 	default: | ||||
| 		if err := runHelmExecuteDefault(config, helmExecutor); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func runHelmExecuteDefault(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor) error { | ||||
| 	if err := helmExecutor.RunHelmLint(); err != nil { | ||||
| 		return fmt.Errorf("failed to execute helm lint: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := helmExecutor.RunHelmPackage(); err != nil { | ||||
| 		return fmt.Errorf("failed to execute helm package: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if config.Publish { | ||||
| 		if err := helmExecutor.RunHelmPublish(); err != nil { | ||||
| 			return fmt.Errorf("failed to execute helm publish: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -18,13 +18,10 @@ import ( | ||||
| type helmExecuteOptions struct { | ||||
| 	AdditionalParameters      []string `json:"additionalParameters,omitempty"` | ||||
| 	ChartPath                 string   `json:"chartPath,omitempty"` | ||||
| 	ContainerRegistryPassword string   `json:"containerRegistryPassword,omitempty"` | ||||
| 	ContainerImageName        string   `json:"containerImageName,omitempty"` | ||||
| 	ContainerImageTag         string   `json:"containerImageTag,omitempty"` | ||||
| 	ContainerRegistryURL      string   `json:"containerRegistryUrl,omitempty"` | ||||
| 	ContainerRegistryUser     string   `json:"containerRegistryUser,omitempty"` | ||||
| 	ContainerRegistrySecret   string   `json:"containerRegistrySecret,omitempty"` | ||||
| 	DeploymentName            string   `json:"deploymentName,omitempty"` | ||||
| 	TargetRepositoryURL       string   `json:"targetRepositoryURL,omitempty"` | ||||
| 	TargetRepositoryName      string   `json:"targetRepositoryName,omitempty" validate:"required_if=HelmCommand install"` | ||||
| 	TargetRepositoryUser      string   `json:"targetRepositoryUser,omitempty"` | ||||
| 	TargetRepositoryPassword  string   `json:"targetRepositoryPassword,omitempty"` | ||||
| 	HelmDeployWaitSeconds     int      `json:"helmDeployWaitSeconds,omitempty"` | ||||
| 	HelmValues                []string `json:"helmValues,omitempty"` | ||||
| 	Image                     string   `json:"image,omitempty"` | ||||
| @@ -33,16 +30,13 @@ type helmExecuteOptions struct { | ||||
| 	KubeContext               string   `json:"kubeContext,omitempty"` | ||||
| 	Namespace                 string   `json:"namespace,omitempty"` | ||||
| 	DockerConfigJSON          string   `json:"dockerConfigJSON,omitempty"` | ||||
| 	HelmCommand               string   `json:"helmCommand,omitempty" validate:"possible-values=upgrade install lint test uninstall package push"` | ||||
| 	DryRun                    bool     `json:"dryRun,omitempty"` | ||||
| 	PackageVersion            string   `json:"packageVersion,omitempty"` | ||||
| 	HelmCommand               string   `json:"helmCommand,omitempty" validate:"possible-values=upgrade install lint test uninstall package publish"` | ||||
| 	AppVersion                string   `json:"appVersion,omitempty"` | ||||
| 	DependencyUpdate          bool     `json:"dependencyUpdate,omitempty"` | ||||
| 	DumpLogs                  bool     `json:"dumpLogs,omitempty"` | ||||
| 	FilterTest                string   `json:"filterTest,omitempty"` | ||||
| 	ChartRepo                 string   `json:"chartRepo,omitempty"` | ||||
| 	HelmRegistryUser          string   `json:"helmRegistryUser,omitempty"` | ||||
| 	HelmChartServer           string   `json:"helmChartServer,omitempty"` | ||||
| 	CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"` | ||||
| 	Publish                   bool     `json:"publish,omitempty"` | ||||
| } | ||||
|  | ||||
| // HelmExecuteCommand Executes helm3 functionality as the package manager for Kubernetes. | ||||
| @@ -78,7 +72,6 @@ Available Commands: | ||||
|   verify      verify that a chart at the given path has been signed and is valid | ||||
|   push        upload a chart to a registry | ||||
|  | ||||
|   also piper Execute step supports direct execution helm command via one flag. | ||||
| ` + "`" + `` + "`" + `` + "`" + ` | ||||
|  | ||||
| Note: piper supports only helm3 version, since helm2 is deprecated.`, | ||||
| @@ -98,8 +91,8 @@ Note: piper supports only helm3 version, since helm2 is deprecated.`, | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
| 			log.RegisterSecret(stepConfig.ContainerRegistryPassword) | ||||
| 			log.RegisterSecret(stepConfig.ContainerRegistryUser) | ||||
| 			log.RegisterSecret(stepConfig.TargetRepositoryUser) | ||||
| 			log.RegisterSecret(stepConfig.TargetRepositoryPassword) | ||||
| 			log.RegisterSecret(stepConfig.KubeConfig) | ||||
| 			log.RegisterSecret(stepConfig.DockerConfigJSON) | ||||
|  | ||||
| @@ -162,13 +155,10 @@ Note: piper supports only helm3 version, since helm2 is deprecated.`, | ||||
| func addHelmExecuteFlags(cmd *cobra.Command, stepConfig *helmExecuteOptions) { | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.AdditionalParameters, "additionalParameters", []string{}, "Defines additional parameters for Helm like  \"helm install [NAME] [CHART] [flags]\".") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ChartPath, "chartPath", os.Getenv("PIPER_chartPath"), "Defines the chart path for helm.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistryPassword, "containerRegistryPassword", os.Getenv("PIPER_containerRegistryPassword"), "Password for container registry access - typically provided by the CI/CD environment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageName, "containerImageName", os.Getenv("PIPER_containerImageName"), "Name of the container which will be built - will be used together with `containerImageTag` instead of parameter `containerImage`") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageTag, "containerImageTag", os.Getenv("PIPER_containerImageTag"), "Tag of the container which will be built - will be used together with `containerImageName` instead of parameter `containerImage`") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "http(s) url of the Container registry where the image to deploy is located.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistryUser, "containerRegistryUser", os.Getenv("PIPER_containerRegistryUser"), "Username for container registry access - typically provided by the CI/CD environment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistrySecret, "containerRegistrySecret", `regsecret`, "Name of the container registry secret used for pulling containers from the registry.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.DeploymentName, "deploymentName", os.Getenv("PIPER_deploymentName"), "Defines the name of the deployment. It is a mandatory parameter when deploying with helm.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TargetRepositoryURL, "targetRepositoryURL", os.Getenv("PIPER_targetRepositoryURL"), "URL of the target repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TargetRepositoryName, "targetRepositoryName", os.Getenv("PIPER_targetRepositoryName"), "set the chart repository") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TargetRepositoryUser, "targetRepositoryUser", os.Getenv("PIPER_targetRepositoryUser"), "Username for the char repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TargetRepositoryPassword, "targetRepositoryPassword", os.Getenv("PIPER_targetRepositoryPassword"), "Password for the target repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment.") | ||||
| 	cmd.Flags().IntVar(&stepConfig.HelmDeployWaitSeconds, "helmDeployWaitSeconds", 300, "Number of seconds before helm deploy returns.") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.HelmValues, "helmValues", []string{}, "List of helm values as YAML file reference or URL (as per helm parameter description for `-f` / `--values`)") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Image, "image", os.Getenv("PIPER_image"), "Full name of the image to be deployed.") | ||||
| @@ -178,20 +168,15 @@ func addHelmExecuteFlags(cmd *cobra.Command, stepConfig *helmExecuteOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.Namespace, "namespace", `default`, "Defines the target Kubernetes namespace for the deployment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.DockerConfigJSON, "dockerConfigJSON", os.Getenv("PIPER_dockerConfigJSON"), "Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).") | ||||
| 	cmd.Flags().StringVar(&stepConfig.HelmCommand, "helmCommand", os.Getenv("PIPER_helmCommand"), "Helm: defines the command `install`, `lint`, `package`, `test`, `upgrade` and etc.") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.DryRun, "dryRun", false, "simulate execute command, like simulate an install") | ||||
| 	cmd.Flags().StringVar(&stepConfig.PackageVersion, "packageVersion", os.Getenv("PIPER_packageVersion"), "set the version on the chart to this semver version") | ||||
| 	cmd.Flags().StringVar(&stepConfig.AppVersion, "appVersion", os.Getenv("PIPER_appVersion"), "set the appVersion on the chart to this version") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.DependencyUpdate, "dependencyUpdate", false, "set the appVersion on the chart to this version") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.DumpLogs, "dumpLogs", false, "dump the logs from test pods (this runs after all tests are complete, but before any cleanup)") | ||||
| 	cmd.Flags().StringVar(&stepConfig.FilterTest, "filterTest", os.Getenv("PIPER_filterTest"), "specify tests by attribute (currently `name`) using attribute=value syntax or `!attribute=value` to exclude a test (can specify multiple or separate values with commas `name=test1,name=test2`)") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ChartRepo, "chartRepo", `https://charts.helm.sh/stable`, "set the chart repository") | ||||
| 	cmd.Flags().StringVar(&stepConfig.HelmRegistryUser, "helmRegistryUser", os.Getenv("PIPER_helmRegistryUser"), "set the user for login to helm registry") | ||||
| 	cmd.Flags().StringVar(&stepConfig.HelmChartServer, "helmChartServer", `localhost:5000`, "set chart server for pushing chart") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List of download links to custom TLS certificates. This is required to ensure trusted connections to instances with repositories (like nexus) when publish flag is set to true.") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.Publish, "publish", false, "Configures helm to run the deploy command to publish artifacts to a repository.") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("chartPath") | ||||
| 	cmd.MarkFlagRequired("containerRegistryUrl") | ||||
| 	cmd.MarkFlagRequired("image") | ||||
| 	cmd.MarkFlagRequired("helmCommand") | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| @@ -231,81 +216,31 @@ func helmExecuteMetadata() config.StepData { | ||||
| 						Default:     os.Getenv("PIPER_chartPath"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "containerRegistryPassword", | ||||
| 						Name: "targetRepositoryURL", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "dockerCredentialsId", | ||||
| 								Param: "password", | ||||
| 								Type:  "secret", | ||||
| 							}, | ||||
|  | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "container/repositoryPassword", | ||||
| 							}, | ||||
|  | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "custom/repositoryPassword", | ||||
| 								Param: "custom/repositoryUrl", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_containerRegistryPassword"), | ||||
| 						Default:   os.Getenv("PIPER_targetRepositoryURL"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "containerImageName", | ||||
| 						Name:        "targetRepositoryName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "dockerImageName"}}, | ||||
| 						Default:     os.Getenv("PIPER_containerImageName"), | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_targetRepositoryName"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "containerImageTag", | ||||
| 						Name: "targetRepositoryUser", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "artifactVersion", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{{Name: "artifactVersion"}}, | ||||
| 						Default:   os.Getenv("PIPER_containerImageTag"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "containerRegistryUrl", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "container/registryUrl", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: true, | ||||
| 						Aliases:   []config.Alias{{Name: "dockerRegistryUrl"}}, | ||||
| 						Default:   os.Getenv("PIPER_containerRegistryUrl"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "containerRegistryUser", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "dockerCredentialsId", | ||||
| 								Param: "username", | ||||
| 								Type:  "secret", | ||||
| 							}, | ||||
|  | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "container/repositoryUsername", | ||||
| 							}, | ||||
|  | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "custom/repositoryUsername", | ||||
| @@ -315,25 +250,21 @@ func helmExecuteMetadata() config.StepData { | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_containerRegistryUser"), | ||||
| 						Default:   os.Getenv("PIPER_targetRepositoryUser"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "containerRegistrySecret", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `regsecret`, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "deploymentName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "helmDeploymentName"}}, | ||||
| 						Default:     os.Getenv("PIPER_deploymentName"), | ||||
| 						Name: "targetRepositoryPassword", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "commonPipelineEnvironment", | ||||
| 								Param: "custom/repositoryPassword", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_targetRepositoryPassword"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "helmDeployWaitSeconds", | ||||
| @@ -439,28 +370,10 @@ func helmExecuteMetadata() config.StepData { | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_helmCommand"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "dryRun", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "packageVersion", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_packageVersion"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "appVersion", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| @@ -498,36 +411,27 @@ func helmExecuteMetadata() config.StepData { | ||||
| 						Default:     os.Getenv("PIPER_filterTest"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "chartRepo", | ||||
| 						Name:        "customTlsCertificateLinks", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Type:        "[]string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `https://charts.helm.sh/stable`, | ||||
| 						Default:     []string{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "helmRegistryUser", | ||||
| 						Name:        "publish", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_helmRegistryUser"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "helmChartServer", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `localhost:5000`, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
| 				{Image: "dtzar/helm-kubectl:3.4.1", WorkingDir: "/config", Options: []config.Option{{Name: "-u", Value: "0"}}}, | ||||
| 				{Image: "dtzar/helm-kubectl:3.8.0", WorkingDir: "/config", Options: []config.Option{{Name: "-u", Value: "0"}}}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|   | ||||
| @@ -37,7 +37,7 @@ func TestRunHelmUpgrade(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmUpgrade").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -75,7 +75,7 @@ func TestRunHelmLint(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmLint").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -113,7 +113,7 @@ func TestRunHelmInstall(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmInstall").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -150,7 +150,7 @@ func TestRunHelmTest(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmTest").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -187,7 +187,7 @@ func TestRunHelmUninstall(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmUninstall").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -224,7 +224,7 @@ func TestRunHelmPackage(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmPackage").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -243,25 +243,25 @@ func TestRunHelmPush(t *testing.T) { | ||||
| 	}{ | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "push", | ||||
| 				HelmCommand: "publish", | ||||
| 			}, | ||||
| 			methodError: nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "push", | ||||
| 				HelmCommand: "publish", | ||||
| 			}, | ||||
| 			methodError:    errors.New("some error"), | ||||
| 			expectedErrStr: "failed to execute helm push: some error", | ||||
| 			expectedErrStr: "failed to execute helm publish: some error", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, testCase := range testTable { | ||||
| 		t.Run(fmt.Sprint("case ", i), func(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmPush").Return(testCase.methodError) | ||||
| 			helmExecute.On("RunHelmPublish").Return(testCase.methodError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config.HelmCommand, helmExecute) | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
| @@ -269,3 +269,61 @@ func TestRunHelmPush(t *testing.T) { | ||||
|  | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestRunHelmDefaultCommand(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	testTable := []struct { | ||||
| 		config             helmExecuteOptions | ||||
| 		methodLintError    error | ||||
| 		methodPackageError error | ||||
| 		methodPublishError error | ||||
| 		expectedErrStr     string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "", | ||||
| 			}, | ||||
| 			methodLintError:    nil, | ||||
| 			methodPackageError: nil, | ||||
| 			methodPublishError: nil, | ||||
| 		}, | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "", | ||||
| 			}, | ||||
| 			methodLintError: errors.New("some error"), | ||||
| 			expectedErrStr:  "failed to execute helm lint: some error", | ||||
| 		}, | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "", | ||||
| 			}, | ||||
| 			methodPackageError: errors.New("some error"), | ||||
| 			expectedErrStr:     "failed to execute helm package: some error", | ||||
| 		}, | ||||
| 		{ | ||||
| 			config: helmExecuteOptions{ | ||||
| 				HelmCommand: "", | ||||
| 			}, | ||||
| 			methodPublishError: errors.New("some error"), | ||||
| 			expectedErrStr:     "failed to execute helm publish: some error", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, testCase := range testTable { | ||||
| 		t.Run(fmt.Sprint("case ", i), func(t *testing.T) { | ||||
| 			helmExecute := &mocks.HelmExecutor{} | ||||
| 			helmExecute.On("RunHelmLint").Return(testCase.methodLintError) | ||||
| 			helmExecute.On("RunHelmPackage").Return(testCase.methodPackageError) | ||||
| 			helmExecute.On("RunHelmPublish").Return(testCase.methodPublishError) | ||||
|  | ||||
| 			err := runHelmExecute(testCase.config, helmExecute) | ||||
| 			if err != nil { | ||||
| 				assert.Equal(t, testCase.expectedErrStr, err.Error()) | ||||
| 			} | ||||
|  | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -23,7 +23,8 @@ import ( | ||||
| ) | ||||
|  | ||||
| func kubernetesDeploy(config kubernetesDeployOptions, telemetryData *telemetry.CustomData) { | ||||
| 	utils := kubernetes.NewDeployUtilsBundle() | ||||
| 	customTLSCertificateLinks := []string{} | ||||
| 	utils := kubernetes.NewDeployUtilsBundle(customTLSCertificateLinks) | ||||
|  | ||||
| 	// error situations stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	err := runKubernetesDeploy(config, telemetryData, utils, log.Writer()) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ type kubernetesDeployMockUtils struct { | ||||
| 	requestedFiles []string | ||||
| 	*mock.FilesMock | ||||
| 	*mock.ExecMockRunner | ||||
| 	*mock.HttpClientMock | ||||
| } | ||||
|  | ||||
| func newKubernetesDeployMockUtils() kubernetesDeployMockUtils { | ||||
|   | ||||
| @@ -3,22 +3,22 @@ package kubernetes | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
|  | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| // HelmExecutor is used for mock | ||||
| type HelmExecutor interface { | ||||
| 	RunHelmAdd() error | ||||
| 	RunHelmUpgrade() error | ||||
| 	RunHelmLint() error | ||||
| 	RunHelmInstall() error | ||||
| 	RunHelmUninstall() error | ||||
| 	RunHelmPackage() error | ||||
| 	RunHelmTest() error | ||||
| 	RunHelmRegistryLogin() error | ||||
| 	RunHelmRegistryLogout() error | ||||
| 	RunHelmPush() error | ||||
| 	RunHelmPublish() error | ||||
| } | ||||
|  | ||||
| // HelmExecute struct | ||||
| @@ -33,12 +33,6 @@ type HelmExecute struct { | ||||
| type HelmExecuteOptions struct { | ||||
| 	AdditionalParameters      []string `json:"additionalParameters,omitempty"` | ||||
| 	ChartPath                 string   `json:"chartPath,omitempty"` | ||||
| 	ContainerRegistryPassword string   `json:"containerRegistryPassword,omitempty"` | ||||
| 	ContainerImageName        string   `json:"containerImageName,omitempty"` | ||||
| 	ContainerImageTag         string   `json:"containerImageTag,omitempty"` | ||||
| 	ContainerRegistryURL      string   `json:"containerRegistryUrl,omitempty"` | ||||
| 	ContainerRegistryUser     string   `json:"containerRegistryUser,omitempty"` | ||||
| 	ContainerRegistrySecret   string   `json:"containerRegistrySecret,omitempty"` | ||||
| 	DeploymentName            string   `json:"deploymentName,omitempty"` | ||||
| 	ForceUpdates              bool     `json:"forceUpdates,omitempty"` | ||||
| 	HelmDeployWaitSeconds     int      `json:"helmDeployWaitSeconds,omitempty"` | ||||
| @@ -49,15 +43,17 @@ type HelmExecuteOptions struct { | ||||
| 	KubeContext               string   `json:"kubeContext,omitempty"` | ||||
| 	Namespace                 string   `json:"namespace,omitempty"` | ||||
| 	DockerConfigJSON          string   `json:"dockerConfigJSON,omitempty"` | ||||
| 	DryRun                    bool     `json:"dryRun,omitempty"` | ||||
| 	PackageVersion            string   `json:"packageVersion,omitempty"` | ||||
| 	AppVersion                string   `json:"appVersion,omitempty"` | ||||
| 	DependencyUpdate          bool     `json:"dependencyUpdate,omitempty"` | ||||
| 	DumpLogs                  bool     `json:"dumpLogs,omitempty"` | ||||
| 	FilterTest                string   `json:"filterTest,omitempty"` | ||||
| 	ChartRepo                 string   `json:"chartRepo,omitempty"` | ||||
| 	HelmRegistryUser          string   `json:"helmRegistryUser,omitempty"` | ||||
| 	HelmChartServer           string   `json:"helmChartServer,omitempty"` | ||||
| 	TargetRepositoryURL       string   `json:"targetRepositoryURL,omitempty"` | ||||
| 	TargetRepositoryName      string   `json:"targetRepositoryName,omitempty"` | ||||
| 	TargetRepositoryUser      string   `json:"targetRepositoryUser,omitempty"` | ||||
| 	TargetRepositoryPassword  string   `json:"targetRepositoryPassword,omitempty"` | ||||
| 	HelmCommand               string   `json:"helmCommand,omitempty"` | ||||
| 	CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"` | ||||
| } | ||||
|  | ||||
| // NewHelmExecutor creates HelmExecute instance | ||||
| @@ -89,23 +85,22 @@ func (h *HelmExecute) runHelmInit() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RunHelmAdd is used to add a chart repository | ||||
| func (h *HelmExecute) RunHelmAdd() error { | ||||
| // runHelmAdd is used to add a chart repository | ||||
| func (h *HelmExecute) runHelmAdd() error { | ||||
| 	helmParams := []string{ | ||||
| 		"repo", | ||||
| 		"add", | ||||
| 		"stable", | ||||
| 	} | ||||
|  | ||||
| 	helmParams = append(helmParams, h.config.ChartRepo) | ||||
| 	if len(h.config.TargetRepositoryName) == 0 { | ||||
| 		return fmt.Errorf("there is no TargetRepositoryName value. 'helm repo add' command requires 2 arguments") | ||||
| 	} | ||||
| 	helmParams = append(helmParams, h.config.TargetRepositoryName) | ||||
| 	helmParams = append(helmParams, h.config.TargetRepositoryURL) | ||||
| 	if h.verbose { | ||||
| 		helmParams = append(helmParams, "--debug") | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm add ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm add call failed") | ||||
| 	} | ||||
|  | ||||
| @@ -119,14 +114,6 @@ func (h *HelmExecute) RunHelmUpgrade() error { | ||||
| 		return fmt.Errorf("failed to execute deployments: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var containerInfo map[string]string | ||||
| 	if h.config.Image != "" && h.config.ContainerRegistryURL != "" { | ||||
| 		containerInfo, err = getContainerInfo(h.config) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to execute deployments") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	helmParams := []string{ | ||||
| 		"upgrade", | ||||
| 		h.config.DeploymentName, | ||||
| @@ -147,11 +134,6 @@ func (h *HelmExecute) RunHelmUpgrade() error { | ||||
| 		"--namespace", h.config.Namespace, | ||||
| 	) | ||||
|  | ||||
| 	if h.config.Image != "" && h.config.ContainerRegistryURL != "" { | ||||
| 		helmParams = append(helmParams, "--set", fmt.Sprintf("image.repository=%v/%v,image.tag=%v", | ||||
| 			containerInfo["containerRegistry"], containerInfo["containerImageName"], containerInfo["containerImageTag"])) | ||||
| 	} | ||||
|  | ||||
| 	if h.config.ForceUpdates { | ||||
| 		helmParams = append(helmParams, "--force") | ||||
| 	} | ||||
| @@ -166,10 +148,7 @@ func (h *HelmExecute) RunHelmUpgrade() error { | ||||
| 		helmParams = append(helmParams, h.config.AdditionalParameters...) | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm upgrade ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm upgrade call failed") | ||||
| 	} | ||||
|  | ||||
| @@ -208,7 +187,7 @@ func (h *HelmExecute) RunHelmInstall() error { | ||||
| 		return fmt.Errorf("failed to execute deployments: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := h.RunHelmAdd(); err != nil { | ||||
| 	if err := h.runHelmAdd(); err != nil { | ||||
| 		return fmt.Errorf("failed to execute deployments: %v", err) | ||||
| 	} | ||||
|  | ||||
| @@ -222,9 +201,6 @@ func (h *HelmExecute) RunHelmInstall() error { | ||||
| 	if !h.config.KeepFailedDeployments { | ||||
| 		helmParams = append(helmParams, "--atomic") | ||||
| 	} | ||||
| 	if h.config.DryRun { | ||||
| 		helmParams = append(helmParams, "--dry-run") | ||||
| 	} | ||||
| 	helmParams = append(helmParams, "--wait", "--timeout", fmt.Sprintf("%vs", h.config.HelmDeployWaitSeconds)) | ||||
| 	for _, v := range h.config.HelmValues { | ||||
| 		helmParams = append(helmParams, "--values", v) | ||||
| @@ -236,10 +212,15 @@ func (h *HelmExecute) RunHelmInstall() error { | ||||
| 		helmParams = append(helmParams, "--debug") | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm install ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if h.verbose { | ||||
| 		helmParamsDryRun := helmParams | ||||
| 		helmParamsDryRun = append(helmParamsDryRun, "--dry-run") | ||||
| 		if err := h.runHelmCommand(helmParamsDryRun); err != nil { | ||||
| 			log.Entry().WithError(err).Error("Helm install --dry-run call failed") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm install call failed") | ||||
| 	} | ||||
|  | ||||
| @@ -264,17 +245,19 @@ func (h *HelmExecute) RunHelmUninstall() error { | ||||
| 	if h.config.HelmDeployWaitSeconds > 0 { | ||||
| 		helmParams = append(helmParams, "--wait", "--timeout", fmt.Sprintf("%vs", h.config.HelmDeployWaitSeconds)) | ||||
| 	} | ||||
| 	if h.config.DryRun { | ||||
| 		helmParams = append(helmParams, "--dry-run") | ||||
| 	} | ||||
| 	if h.verbose { | ||||
| 		helmParams = append(helmParams, "--debug") | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm uninstall ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if h.verbose { | ||||
| 		helmParamsDryRun := helmParams | ||||
| 		helmParamsDryRun = append(helmParamsDryRun, "--dry-run") | ||||
| 		if err := h.runHelmCommand(helmParamsDryRun); err != nil { | ||||
| 			log.Entry().WithError(err).Error("Helm uninstall --dry-run call failed") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm uninstall call failed") | ||||
| 	} | ||||
|  | ||||
| @@ -305,10 +288,7 @@ func (h *HelmExecute) RunHelmPackage() error { | ||||
| 		helmParams = append(helmParams, "--debug") | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm package ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm package call failed") | ||||
| 	} | ||||
|  | ||||
| @@ -336,77 +316,66 @@ func (h *HelmExecute) RunHelmTest() error { | ||||
| 		helmParams = append(helmParams, "--debug") | ||||
| 	} | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm test ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 	if err := h.runHelmCommand(helmParams); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm test call failed") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RunHelmRegistryLogin is used to login private registry | ||||
| func (h *HelmExecute) RunHelmRegistryLogin() error { | ||||
| 	helmParams := []string{ | ||||
| 		"registry login", | ||||
| 	} | ||||
| 	helmParams = append(helmParams, "-u", h.config.HelmRegistryUser) | ||||
| 	helmParams = append(helmParams, h.config.HelmChartServer) | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm login ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm push login failed") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // RunHelmRegistryLogout is logout to login private registry | ||||
| func (h *HelmExecute) RunHelmRegistryLogout() error { | ||||
| 	helmParams := []string{ | ||||
| 		"registry logout", | ||||
| 	} | ||||
| 	helmParams = append(helmParams, h.config.HelmChartServer) | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm logout ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm push logout failed") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| //RunHelmPush is used to upload a chart to a registry | ||||
| func (h *HelmExecute) RunHelmPush() error { | ||||
| //RunHelmPublish is used to upload a chart to a registry | ||||
| func (h *HelmExecute) RunHelmPublish() error { | ||||
| 	err := h.runHelmInit() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to execute deployments: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if err := h.RunHelmRegistryLogin(); err != nil { | ||||
| 		return fmt.Errorf("failed to execute registry login: %v", err) | ||||
| 	if len(h.config.TargetRepositoryURL) == 0 { | ||||
| 		return fmt.Errorf("there's no target repository for helm chart publishing configured") | ||||
| 	} | ||||
|  | ||||
| 	helmParams := []string{ | ||||
| 		"push", | ||||
| 	} | ||||
| 	helmParams = append(helmParams, fmt.Sprintf("%v", h.config.DeploymentName+h.config.PackageVersion+".tgz")) | ||||
| 	helmParams = append(helmParams, fmt.Sprintf("%v", "oci://"+h.config.HelmChartServer+"/helm-charts")) | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Info("Calling helm push ...") | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Helm push call failed") | ||||
| 	repoClientOptions := piperhttp.ClientOptions{ | ||||
| 		Username:     h.config.TargetRepositoryUser, | ||||
| 		Password:     h.config.TargetRepositoryPassword, | ||||
| 		TrustedCerts: h.config.CustomTLSCertificateLinks, | ||||
| 	} | ||||
|  | ||||
| 	if err := h.RunHelmRegistryLogout(); err != nil { | ||||
| 		return fmt.Errorf("failed to execute registry logout: %v", err) | ||||
| 	h.utils.SetOptions(repoClientOptions) | ||||
|  | ||||
| 	binary := fmt.Sprintf("%v", h.config.DeploymentName+"-"+h.config.PackageVersion+".tgz") | ||||
|  | ||||
| 	targetPath := fmt.Sprintf("%v/%s", h.config.DeploymentName, binary) | ||||
|  | ||||
| 	separator := "/" | ||||
|  | ||||
| 	if strings.HasSuffix(h.config.TargetRepositoryURL, "/") { | ||||
| 		separator = "" | ||||
| 	} | ||||
|  | ||||
| 	targetURL := fmt.Sprintf("%s%s%s", h.config.TargetRepositoryURL, separator, targetPath) | ||||
|  | ||||
| 	log.Entry().Infof("publishing artifact: %s", targetURL) | ||||
|  | ||||
| 	response, err := h.utils.UploadRequest(http.MethodPut, targetURL, binary, "", nil, nil, "binary") | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("couldn't upload artifact: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	if !(response.StatusCode == 200 || response.StatusCode == 201) { | ||||
| 		return fmt.Errorf("couldn't upload artifact, received status code %d", response.StatusCode) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (h *HelmExecute) runHelmCommand(helmParams []string) error { | ||||
|  | ||||
| 	h.utils.Stdout(h.stdout) | ||||
| 	log.Entry().Infof("Calling helm %v ...", h.config.HelmCommand) | ||||
| 	log.Entry().Debugf("Helm parameters: %v", helmParams) | ||||
| 	if err := h.utils.RunExecutable("helm", helmParams...); err != nil { | ||||
| 		log.Entry().WithError(err).Fatalf("Helm %v call failed", h.config.HelmCommand) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
|   | ||||
| @@ -10,12 +10,19 @@ import ( | ||||
| ) | ||||
|  | ||||
| type helmMockUtilsBundle struct { | ||||
| 	*mock.FilesMock | ||||
| 	*mock.ExecMockRunner | ||||
| 	*mock.FilesMock | ||||
| 	*mock.HttpClientMock | ||||
| } | ||||
|  | ||||
| func newHelmMockUtilsBundle() helmMockUtilsBundle { | ||||
| 	utils := helmMockUtilsBundle{ExecMockRunner: &mock.ExecMockRunner{}} | ||||
| 	utils := helmMockUtilsBundle{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 		FilesMock:      &mock.FilesMock{}, | ||||
| 		HttpClientMock: &mock.HttpClientMock{ | ||||
| 			FileUploads: map[string]string{}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return utils | ||||
| } | ||||
|  | ||||
| @@ -27,12 +34,23 @@ func TestRunHelm(t *testing.T) { | ||||
| 		testTable := []struct { | ||||
| 			config         HelmExecuteOptions | ||||
| 			expectedConfig []string | ||||
| 			generalVerbose bool | ||||
| 		}{ | ||||
| 			{ | ||||
| 				config: HelmExecuteOptions{ | ||||
| 					ChartRepo: "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryURL:  "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryName: "stable", | ||||
| 				}, | ||||
| 				expectedConfig: []string{"repo", "add", "stable", "https://charts.helm.sh/stable"}, | ||||
| 				generalVerbose: false, | ||||
| 			}, | ||||
| 			{ | ||||
| 				config: HelmExecuteOptions{ | ||||
| 					TargetRepositoryURL:  "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryName: "test", | ||||
| 				}, | ||||
| 				expectedConfig: []string{"repo", "add", "test", "https://charts.helm.sh/stable", "--debug"}, | ||||
| 				generalVerbose: true, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| @@ -40,10 +58,10 @@ func TestRunHelm(t *testing.T) { | ||||
| 			helmExecute := HelmExecute{ | ||||
| 				utils:   utils, | ||||
| 				config:  testCase.config, | ||||
| 				verbose: false, | ||||
| 				verbose: testCase.generalVerbose, | ||||
| 				stdout:  log.Writer(), | ||||
| 			} | ||||
| 			err := helmExecute.RunHelmAdd() | ||||
| 			err := helmExecute.runHelmAdd() | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[i]) | ||||
| 		} | ||||
| @@ -64,10 +82,9 @@ func TestRunHelm(t *testing.T) { | ||||
| 					ForceUpdates:          true, | ||||
| 					HelmDeployWaitSeconds: 3456, | ||||
| 					AdditionalParameters:  []string{"additional parameter"}, | ||||
| 					ContainerRegistryURL:  "https://hub.docker.com/", | ||||
| 					Image:                 "dtzar/helm-kubectl:3.4.1", | ||||
| 				}, | ||||
| 				expectedConfig: []string{"upgrade", "test_deployment", ".", "--install", "--namespace", "test_namespace", "--set", "image.repository=hub.docker.com/dtzar/helm-kubectl,image.tag=3.4.1", "--force", "--wait", "--timeout", "3456s", "--atomic", "additional parameter"}, | ||||
| 				expectedConfig: []string{"upgrade", "test_deployment", ".", "--install", "--namespace", "test_namespace", "--force", "--wait", "--timeout", "3456s", "--atomic", "additional parameter"}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| @@ -117,6 +134,7 @@ func TestRunHelm(t *testing.T) { | ||||
|  | ||||
| 		testTable := []struct { | ||||
| 			config                HelmExecuteOptions | ||||
| 			generalVerbose        bool | ||||
| 			expectedConfigInstall []string | ||||
| 			expectedConfigAdd     []string | ||||
| 		}{ | ||||
| @@ -126,9 +144,11 @@ func TestRunHelm(t *testing.T) { | ||||
| 					DeploymentName:        "testPackage", | ||||
| 					Namespace:             "test-namespace", | ||||
| 					HelmDeployWaitSeconds: 525, | ||||
| 					ChartRepo:             "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryURL:   "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryName:  "test", | ||||
| 				}, | ||||
| 				expectedConfigAdd:     []string{"repo", "add", "stable", "https://charts.helm.sh/stable"}, | ||||
| 				generalVerbose:        false, | ||||
| 				expectedConfigAdd:     []string{"repo", "add", "test", "https://charts.helm.sh/stable"}, | ||||
| 				expectedConfigInstall: []string{"install", "testPackage", ".", "--namespace", "test-namespace", "--create-namespace", "--atomic", "--wait", "--timeout", "525s"}, | ||||
| 			}, | ||||
| 			{ | ||||
| @@ -138,12 +158,13 @@ func TestRunHelm(t *testing.T) { | ||||
| 					Namespace:             "test-namespace", | ||||
| 					HelmDeployWaitSeconds: 525, | ||||
| 					KeepFailedDeployments: false, | ||||
| 					DryRun:                true, | ||||
| 					AdditionalParameters:  []string{"--set-file my_script=dothings.sh"}, | ||||
| 					ChartRepo:             "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryURL:   "https://charts.helm.sh/stable", | ||||
| 					TargetRepositoryName:  "test", | ||||
| 				}, | ||||
| 				expectedConfigAdd:     []string{"repo", "add", "stable", "https://charts.helm.sh/stable"}, | ||||
| 				expectedConfigInstall: []string{"install", "testPackage", ".", "--namespace", "test-namespace", "--create-namespace", "--atomic", "--dry-run", "--wait", "--timeout", "525s", "--set-file my_script=dothings.sh"}, | ||||
| 				generalVerbose:        true, | ||||
| 				expectedConfigAdd:     []string{"repo", "add", "test", "https://charts.helm.sh/stable", "--debug"}, | ||||
| 				expectedConfigInstall: []string{"install", "testPackage", ".", "--namespace", "test-namespace", "--create-namespace", "--atomic", "--wait", "--timeout", "525s", "--set-file my_script=dothings.sh", "--debug", "--dry-run"}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| @@ -152,7 +173,7 @@ func TestRunHelm(t *testing.T) { | ||||
| 			helmExecute := HelmExecute{ | ||||
| 				utils:   utils, | ||||
| 				config:  testCase.config, | ||||
| 				verbose: false, | ||||
| 				verbose: testCase.generalVerbose, | ||||
| 				stdout:  log.Writer(), | ||||
| 			} | ||||
| 			err := helmExecute.RunHelmInstall() | ||||
| @@ -168,6 +189,7 @@ func TestRunHelm(t *testing.T) { | ||||
|  | ||||
| 		testTable := []struct { | ||||
| 			config         HelmExecuteOptions | ||||
| 			generalVerbose bool | ||||
| 			expectedConfig []string | ||||
| 		}{ | ||||
| 			{ | ||||
| @@ -184,9 +206,9 @@ func TestRunHelm(t *testing.T) { | ||||
| 					DeploymentName:        "testPackage", | ||||
| 					Namespace:             "test-namespace", | ||||
| 					HelmDeployWaitSeconds: 524, | ||||
| 					DryRun:                true, | ||||
| 				}, | ||||
| 				expectedConfig: []string{"uninstall", "testPackage", "--namespace", "test-namespace", "--wait", "--timeout", "524s", "--dry-run"}, | ||||
| 				generalVerbose: true, | ||||
| 				expectedConfig: []string{"uninstall", "testPackage", "--namespace", "test-namespace", "--wait", "--timeout", "524s", "--debug", "--dry-run"}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| @@ -194,7 +216,7 @@ func TestRunHelm(t *testing.T) { | ||||
| 			helmExecute := HelmExecute{ | ||||
| 				utils:   utils, | ||||
| 				config:  testCase.config, | ||||
| 				verbose: false, | ||||
| 				verbose: testCase.generalVerbose, | ||||
| 				stdout:  log.Writer(), | ||||
| 			} | ||||
| 			err := helmExecute.RunHelmUninstall() | ||||
| @@ -351,49 +373,46 @@ func TestRunHelm(t *testing.T) { | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Helm registry login command", func(t *testing.T) { | ||||
| 	t.Run("Helm publish command", func(t *testing.T) { | ||||
| 		utils := newHelmMockUtilsBundle() | ||||
|  | ||||
| 		testTable := []struct { | ||||
| 			config         HelmExecuteOptions | ||||
| 			expectedConfig []string | ||||
| 		}{ | ||||
| 			{ | ||||
| 				config: HelmExecuteOptions{ | ||||
| 					HelmRegistryUser: "helmRegistryUser", | ||||
| 					HelmChartServer:  "localhost:5000", | ||||
| 				}, | ||||
| 				expectedConfig: []string{"registry login", "-u", "helmRegistryUser", "localhost:5000"}, | ||||
| 			}, | ||||
| 		config := HelmExecuteOptions{ | ||||
| 			TargetRepositoryURL:      "https://my.target.repository.local/", | ||||
| 			TargetRepositoryUser:     "testUser", | ||||
| 			TargetRepositoryPassword: "testPWD", | ||||
| 			PackageVersion:           "1.2.3", | ||||
| 			DeploymentName:           "test_helm_chart", | ||||
| 		} | ||||
| 		utils.ReturnFileUploadStatus = 200 | ||||
|  | ||||
| 		helmExecute := HelmExecute{ | ||||
| 			utils:   utils, | ||||
| 			config:  config, | ||||
| 			verbose: false, | ||||
| 			stdout:  log.Writer(), | ||||
| 		} | ||||
|  | ||||
| 		for i, testCase := range testTable { | ||||
| 			helmExecute := HelmExecute{ | ||||
| 				utils:   utils, | ||||
| 				config:  testCase.config, | ||||
| 				verbose: false, | ||||
| 				stdout:  log.Writer(), | ||||
| 			} | ||||
| 			err := helmExecute.RunHelmRegistryLogin() | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[i]) | ||||
| 		err := helmExecute.RunHelmPublish() | ||||
| 		if assert.NoError(t, err) { | ||||
| 			assert.Equal(t, 1, len(utils.FileUploads)) | ||||
| 			assert.Equal(t, "https://my.target.repository.local/test_helm_chart/test_helm_chart-1.2.3.tgz", utils.FileUploads["test_helm_chart-1.2.3.tgz"]) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Helm registry login command", func(t *testing.T) { | ||||
| 	t.Run("Helm run command", func(t *testing.T) { | ||||
| 		utils := newHelmMockUtilsBundle() | ||||
|  | ||||
| 		testTable := []struct { | ||||
| 			helmParams     []string | ||||
| 			config         HelmExecuteOptions | ||||
| 			expectedConfig []string | ||||
| 		}{ | ||||
| 			{ | ||||
| 				helmParams: []string{"lint, package, publish"}, | ||||
| 				config: HelmExecuteOptions{ | ||||
| 					DeploymentName:  "nginx", | ||||
| 					PackageVersion:  "2.3.4", | ||||
| 					HelmChartServer: "localhost:5000", | ||||
| 					HelmCommand: "lint_package_publish", | ||||
| 				}, | ||||
| 				expectedConfig: []string{"push", "nginx2.3.4.tgz", "oci://localhost:5000/helm-charts"}, | ||||
| 				expectedConfig: []string{"lint, package, publish"}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| @@ -404,10 +423,11 @@ func TestRunHelm(t *testing.T) { | ||||
| 				verbose: false, | ||||
| 				stdout:  log.Writer(), | ||||
| 			} | ||||
| 			err := helmExecute.RunHelmPush() | ||||
| 			err := helmExecute.runHelmCommand(testCase.helmParams) | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[1]) | ||||
| 			assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[0]) | ||||
| 		} | ||||
|  | ||||
| 	}) | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -65,36 +65,8 @@ func (_m *HelmExecutor) RunHelmPackage() error { | ||||
| 	return r0 | ||||
| } | ||||
|  | ||||
| // RunHelmPush provides a mock function with given fields: | ||||
| func (_m *HelmExecutor) RunHelmPush() error { | ||||
| 	ret := _m.Called() | ||||
|  | ||||
| 	var r0 error | ||||
| 	if rf, ok := ret.Get(0).(func() error); ok { | ||||
| 		r0 = rf() | ||||
| 	} else { | ||||
| 		r0 = ret.Error(0) | ||||
| 	} | ||||
|  | ||||
| 	return r0 | ||||
| } | ||||
|  | ||||
| // RunHelmRegistryLogin provides a mock function with given fields: | ||||
| func (_m *HelmExecutor) RunHelmRegistryLogin() error { | ||||
| 	ret := _m.Called() | ||||
|  | ||||
| 	var r0 error | ||||
| 	if rf, ok := ret.Get(0).(func() error); ok { | ||||
| 		r0 = rf() | ||||
| 	} else { | ||||
| 		r0 = ret.Error(0) | ||||
| 	} | ||||
|  | ||||
| 	return r0 | ||||
| } | ||||
|  | ||||
| // RunHelmRegistryLogout provides a mock function with given fields: | ||||
| func (_m *HelmExecutor) RunHelmRegistryLogout() error { | ||||
| // RunHelmPublish provides a mock function with given fields: | ||||
| func (_m *HelmExecutor) RunHelmPublish() error { | ||||
| 	ret := _m.Called() | ||||
|  | ||||
| 	var r0 error | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/docker" | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| 	"gopkg.in/yaml.v2" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
| @@ -20,16 +21,28 @@ type DeployUtils interface { | ||||
| 	RunExecutable(e string, p ...string) error | ||||
|  | ||||
| 	piperutils.FileUtils | ||||
| 	piperhttp.Uploader | ||||
| } | ||||
|  | ||||
| // deployUtilsBundle struct  for utils | ||||
| type deployUtilsBundle struct { | ||||
| 	*command.Command | ||||
| 	*piperutils.Files | ||||
| 	piperhttp.Uploader | ||||
| } | ||||
|  | ||||
| // NewDeployUtilsBundle initialize using deployUtilsBundle struct | ||||
| func NewDeployUtilsBundle() DeployUtils { | ||||
| func NewDeployUtilsBundle(customTLSCertificateLinks []string) DeployUtils { | ||||
| 	httpClientOptions := piperhttp.ClientOptions{} | ||||
|  | ||||
| 	if len(customTLSCertificateLinks) > 0 { | ||||
| 		httpClientOptions.TransportSkipVerification = false | ||||
| 		httpClientOptions.TrustedCerts = customTLSCertificateLinks | ||||
| 	} | ||||
|  | ||||
| 	httpClient := piperhttp.Client{} | ||||
| 	httpClient.SetOptions(httpClientOptions) | ||||
|  | ||||
| 	utils := deployUtilsBundle{ | ||||
| 		Command: &command.Command{ | ||||
| 			ErrorCategoryMapping: map[string][]string{ | ||||
| @@ -49,41 +62,36 @@ func NewDeployUtilsBundle() DeployUtils { | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Files: &piperutils.Files{}, | ||||
| 		Files:    &piperutils.Files{}, | ||||
| 		Uploader: &httpClient, | ||||
| 	} | ||||
| 	// reroute stderr output to logging framework, stdout will be used for command interactions | ||||
| 	utils.Stderr(log.Writer()) | ||||
| 	return &utils | ||||
| } | ||||
|  | ||||
| func getContainerInfo(config HelmExecuteOptions) (map[string]string, error) { | ||||
| 	var err error | ||||
| 	containerRegistry, err := docker.ContainerRegistryFromURL(config.ContainerRegistryURL) | ||||
| // GetChartInfo is used to get name and version of helm chart | ||||
| func GetChartInfo(chartYamlFile string, utils DeployUtils) (string, string, error) { | ||||
|  | ||||
| 	var result map[string]interface{} | ||||
| 	p, err := utils.FileRead(chartYamlFile) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatalf("Container registry url '%v' incorrect", config.ContainerRegistryURL) | ||||
| 		return "", "", fmt.Errorf("file couldn't read: %w", err) | ||||
| 	} | ||||
| 	err = yaml.Unmarshal(p, &result) | ||||
| 	if err != nil { | ||||
| 		return "", "", fmt.Errorf("failed unmarshal: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	//support either image or containerImageName and containerImageTag | ||||
| 	containerInfo := map[string]string{ | ||||
| 		"containerImageName": "", | ||||
| 		"containerImageTag":  "", | ||||
| 		"containerRegistry":  containerRegistry, | ||||
| 	name, ok := result["name"].(string) | ||||
| 	if !ok || len(name) == 0 { | ||||
| 		return "", "", errors.New("name not found in chart yaml file (or wrong type)") | ||||
| 	} | ||||
|  | ||||
| 	if len(config.Image) > 0 { | ||||
| 		ref, err := docker.ContainerImageNameTagFromImage(config.Image) | ||||
| 		if err != nil { | ||||
| 			log.Entry().WithError(err).Fatalf("Container image '%v' incorrect", config.Image) | ||||
| 		} | ||||
| 		parts := strings.Split(ref, ":") | ||||
| 		containerInfo["containerImageName"] = parts[0] | ||||
| 		containerInfo["containerImageTag"] = parts[1] | ||||
| 	} else if len(config.ContainerImageName) > 0 && len(config.ContainerImageTag) > 0 { | ||||
| 		containerInfo["containerImageName"] = config.ContainerImageName | ||||
| 		containerInfo["containerImageTag"] = config.ContainerImageTag | ||||
| 	} else { | ||||
| 		return nil, fmt.Errorf("image information not given - please either set image or containerImageName and containerImageTag") | ||||
| 	version, ok := result["version"].(string) | ||||
| 	if !ok || len(name) == 0 { | ||||
| 		return "", "", errors.New("version not found in chart yaml file (or wrong type)") | ||||
| 	} | ||||
|  | ||||
| 	return containerInfo, nil | ||||
| 	return name, version, nil | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -9,30 +10,70 @@ import ( | ||||
| func TestRunUtils(t *testing.T) { | ||||
| 	t.Run("Get container info", func(t *testing.T) { | ||||
| 		testTable := []struct { | ||||
| 			config                HelmExecuteOptions | ||||
| 			expectedContainerInfo map[string]string | ||||
| 			expectedError         error | ||||
| 			chartYamlFile          string | ||||
| 			dataChartYaml          string | ||||
| 			expectedChartName      string | ||||
| 			expectedPackageVersion string | ||||
| 			expectedError          error | ||||
| 			setFileReadError       bool | ||||
| 		}{ | ||||
| 			{ | ||||
| 				config: HelmExecuteOptions{ | ||||
| 					Image:                "dtzar/helm-kubectl:3.4.1", | ||||
| 					ContainerImageName:   "", | ||||
| 					ContainerImageTag:    "", | ||||
| 					ContainerRegistryURL: "https://hub.docker.com/", | ||||
| 				}, | ||||
| 				expectedContainerInfo: map[string]string{ | ||||
| 					"containerImageName": "dtzar/helm-kubectl", | ||||
| 					"containerImageTag":  "3.4.1", | ||||
| 				}, | ||||
| 				expectedError: nil, | ||||
| 				chartYamlFile:          "path/to/Chart.yaml", | ||||
| 				dataChartYaml:          "name: nginx-testChart\nversion: 1.3.5", | ||||
| 				expectedChartName:      "nginx-testChart", | ||||
| 				expectedPackageVersion: "1.3.5", | ||||
| 				expectedError:          nil, | ||||
| 				setFileReadError:       false, | ||||
| 			}, | ||||
| 			{ | ||||
| 				chartYamlFile:          "path/to/Chart.yaml", | ||||
| 				dataChartYaml:          "name: nginx-testChart\nversion: 1.3.5", | ||||
| 				expectedChartName:      "nginx-testChart", | ||||
| 				expectedPackageVersion: "1.3.5", | ||||
| 				expectedError:          errors.New("file couldn't read"), | ||||
| 				setFileReadError:       true, | ||||
| 			}, | ||||
| 			{ | ||||
| 				chartYamlFile:          "path/to/Chart.yaml", | ||||
| 				dataChartYaml:          "version: 1.3.5", | ||||
| 				expectedChartName:      "nginx-testChart", | ||||
| 				expectedPackageVersion: "1.3.5", | ||||
| 				expectedError:          errors.New("name not found in chart yaml file (or wrong type)"), | ||||
| 				setFileReadError:       false, | ||||
| 			}, | ||||
| 			{ | ||||
| 				chartYamlFile:          "path/to/Chart.yaml", | ||||
| 				dataChartYaml:          "name: nginx-testChart", | ||||
| 				expectedChartName:      "nginx-testChart", | ||||
| 				expectedPackageVersion: "1.3.5", | ||||
| 				expectedError:          errors.New("version not found in chart yaml file (or wrong type)"), | ||||
| 				setFileReadError:       false, | ||||
| 			}, | ||||
| 			{ | ||||
| 				chartYamlFile:          "path/to/Chart.yaml", | ||||
| 				dataChartYaml:          "name=nginx-testChart", | ||||
| 				expectedChartName:      "nginx-testChart", | ||||
| 				expectedPackageVersion: "1.3.5", | ||||
| 				expectedError:          errors.New("failed unmarshal"), | ||||
| 				setFileReadError:       false, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		for _, testCase := range testTable { | ||||
| 			containerInfo, err := getContainerInfo(testCase.config) | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, testCase.expectedContainerInfo["containerImageName"], containerInfo["containerImageName"]) | ||||
| 			assert.Equal(t, testCase.expectedContainerInfo["containerImageTag"], containerInfo["containerImageTag"]) | ||||
| 			utils := newHelmMockUtilsBundle() | ||||
| 			utils.AddFile(testCase.chartYamlFile, []byte(testCase.dataChartYaml)) | ||||
| 			if testCase.setFileReadError { | ||||
| 				utils.FileReadErrors = map[string]error{testCase.chartYamlFile: testCase.expectedError} | ||||
| 			} | ||||
| 			nameChart, packageVersion, err := GetChartInfo(testCase.chartYamlFile, utils) | ||||
| 			if testCase.expectedError != nil { | ||||
| 				assert.Error(t, err) | ||||
| 				assert.Contains(t, err.Error(), testCase.expectedError.Error()) | ||||
| 			} else { | ||||
| 				assert.NoError(t, err) | ||||
| 				assert.Equal(t, testCase.expectedChartName, nameChart) | ||||
| 				assert.Equal(t, testCase.expectedPackageVersion, packageVersion) | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	}) | ||||
|   | ||||
							
								
								
									
										51
									
								
								pkg/mock/httpClient.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								pkg/mock/httpClient.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| //go:build !release | ||||
| // +build !release | ||||
|  | ||||
| package mock | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
|  | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| ) | ||||
|  | ||||
| // HttpClientMock mock struct | ||||
| type HttpClientMock struct { | ||||
| 	ClientOptions          []piperhttp.ClientOptions // set by mock | ||||
| 	FileUploads            map[string]string         // set by mock | ||||
| 	ReturnFileUploadStatus int                       // expected to be set upfront | ||||
| 	ReturnFileUploadError  error                     // expected to be set upfront | ||||
| } | ||||
|  | ||||
| // SendRequest mock | ||||
| func (utils *HttpClientMock) SendRequest(method string, url string, r io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) { | ||||
| 	return nil, fmt.Errorf("not implemented") | ||||
| } | ||||
|  | ||||
| // SetOptions mock | ||||
| func (utils *HttpClientMock) SetOptions(options piperhttp.ClientOptions) { | ||||
| 	utils.ClientOptions = append(utils.ClientOptions, options) | ||||
| } | ||||
|  | ||||
| // Upload mock | ||||
| func (utils *HttpClientMock) Upload(data piperhttp.UploadRequestData) (*http.Response, error) { | ||||
| 	return nil, fmt.Errorf("not implemented") | ||||
| } | ||||
|  | ||||
| // UploadRequest mock | ||||
| func (utils *HttpClientMock) UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) { | ||||
| 	utils.FileUploads[file] = url | ||||
|  | ||||
| 	response := http.Response{ | ||||
| 		StatusCode: utils.ReturnFileUploadStatus, | ||||
| 	} | ||||
|  | ||||
| 	return &response, utils.ReturnFileUploadError | ||||
| } | ||||
|  | ||||
| // UploadFile mock | ||||
| func (utils *HttpClientMock) UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) { | ||||
| 	return utils.UploadRequest(http.MethodPut, url, file, fieldName, header, cookies, uploadType) | ||||
| } | ||||
							
								
								
									
										112
									
								
								pkg/mock/httpClient_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								pkg/mock/httpClient_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| //go:build !release | ||||
| // +build !release | ||||
|  | ||||
| package mock | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"testing" | ||||
|  | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestSendRequest(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("SendRequest", func(t *testing.T) { | ||||
| 		utils := HttpClientMock{} | ||||
| 		method := "PUT" | ||||
| 		url := "https://localhost" | ||||
| 		var header http.Header | ||||
| 		var r io.Reader | ||||
| 		var cookies []*http.Cookie | ||||
|  | ||||
| 		_, err := utils.SendRequest(method, url, r, header, cookies) | ||||
| 		assert.Error(t, err) | ||||
|  | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestSetOption(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("SetOption", func(t *testing.T) { | ||||
| 		utils := HttpClientMock{} | ||||
| 		options := []piperhttp.ClientOptions{ | ||||
| 			{ | ||||
| 				Username: "user", | ||||
| 				Password: "pwd", | ||||
| 			}, | ||||
| 			{ | ||||
| 				Username: "user2", | ||||
| 				Password: "pwd2", | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		for _, option := range options { | ||||
| 			utils.SetOptions(option) | ||||
| 		} | ||||
| 		assert.Equal(t, options, utils.ClientOptions) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUpload(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("Upload", func(t *testing.T) { | ||||
| 		utils := HttpClientMock{} | ||||
| 		data := piperhttp.UploadRequestData{} | ||||
|  | ||||
| 		_, err := utils.Upload(data) | ||||
| 		assert.Error(t, err) | ||||
|  | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUploadRequest(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("UploadRequest", func(t *testing.T) { | ||||
| 		utils := HttpClientMock{ | ||||
| 			ReturnFileUploadStatus: 200, | ||||
| 			FileUploads: map[string]string{ | ||||
| 				"key": "value", | ||||
| 			}, | ||||
| 		} | ||||
| 		method := "PUT" | ||||
| 		url := "https://localhost" | ||||
| 		file := "test-7.8.9.tgz" | ||||
| 		fieldName := "" | ||||
| 		uploadType := "" | ||||
| 		var header http.Header | ||||
| 		var cookies []*http.Cookie | ||||
| 		returnFileUploadStatus := 200 | ||||
|  | ||||
| 		response, err := utils.UploadRequest(method, url, file, fieldName, header, cookies, uploadType) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, returnFileUploadStatus, response.StatusCode) | ||||
|  | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestUploadFile(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("UploadFile", func(t *testing.T) { | ||||
| 		utils := HttpClientMock{ | ||||
| 			ReturnFileUploadStatus: 200, | ||||
| 			FileUploads: map[string]string{ | ||||
| 				"key": "value", | ||||
| 			}, | ||||
| 		} | ||||
| 		url := "https://localhost" | ||||
| 		file := "test-7.8.9.tgz" | ||||
| 		fieldName := "" | ||||
| 		uploadType := "" | ||||
| 		var header http.Header | ||||
| 		var cookies []*http.Cookie | ||||
| 		returnFileUploadStatus := 200 | ||||
|  | ||||
| 		response, err := utils.UploadFile(url, file, fieldName, header, cookies, uploadType) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, returnFileUploadStatus, response.StatusCode) | ||||
|  | ||||
| 	}) | ||||
| } | ||||
| @@ -21,7 +21,6 @@ metadata: | ||||
|       verify      verify that a chart at the given path has been signed and is valid | ||||
|       push        upload a chart to a registry | ||||
|  | ||||
|       also piper Execute step supports direct execution helm command via one flag. | ||||
|     ``` | ||||
|  | ||||
|     Note: piper supports only helm3 version, since helm2 is deprecated. | ||||
| @@ -56,8 +55,29 @@ spec: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: containerRegistryPassword | ||||
|         description: Password for container registry access - typically provided by the CI/CD environment. | ||||
|       - name: targetRepositoryURL | ||||
|         description: "URL of the target repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment." | ||||
|         type: string | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: custom/repositoryUrl | ||||
|       - name: targetRepositoryName | ||||
|         type: string | ||||
|         description: set the chart repository | ||||
|         mandatoryIf: | ||||
|           - name: helmCommand | ||||
|             value: install | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: targetRepositoryUser | ||||
|         description: "Username for the char repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment." | ||||
|         type: string | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
| @@ -65,89 +85,19 @@ spec: | ||||
|           - STEPS | ||||
|         secret: true | ||||
|         resourceRef: | ||||
|           - name: dockerCredentialsId | ||||
|             type: secret | ||||
|             param: password | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: container/repositoryPassword | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: custom/repositoryPassword | ||||
|       - name: containerImageName | ||||
|         aliases: | ||||
|           - name: dockerImageName | ||||
|         type: string | ||||
|         description: Name of the container which will be built - will be used together with `containerImageTag` instead of parameter `containerImage` | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: containerImageTag | ||||
|         aliases: | ||||
|           - name: artifactVersion | ||||
|         type: string | ||||
|         description: Tag of the container which will be built - will be used together with `containerImageName` instead of parameter `containerImage` | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: artifactVersion | ||||
|       - name: containerRegistryUrl | ||||
|         aliases: | ||||
|           - name: dockerRegistryUrl | ||||
|         type: string | ||||
|         description: http(s) url of the Container registry where the image to deploy is located. | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: container/registryUrl | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|       - name: containerRegistryUser | ||||
|         description: Username for container registry access - typically provided by the CI/CD environment. | ||||
|         type: string | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         secret: true | ||||
|         resourceRef: | ||||
|           - name: dockerCredentialsId | ||||
|             type: secret | ||||
|             param: username | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: container/repositoryUsername | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: custom/repositoryUsername | ||||
|       - name: containerRegistrySecret | ||||
|         description: Name of the container registry secret used for pulling containers from the registry. | ||||
|         longDescription: |- | ||||
|           Name of the container registry secret used for pulling containers from the registry. | ||||
|  | ||||
|           If `containerRegistryUser` and `containerRegistryPassword` are provided, a secret is created on the fly and the information is passed to the helm template.<br /> | ||||
|  | ||||
|           If neither `containerRegistryUser` nor `containerRegistryPassword` are provided, it is expected that a secret with the configured name exists in the target Kubernetes cluster.<br /> | ||||
|       - name: targetRepositoryPassword | ||||
|         description: "Password for the target repository where the compiled helm .tgz archive shall be uploaded - typically provided by the CI/CD environment." | ||||
|         type: string | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         default: regsecret | ||||
|       - name: deploymentName | ||||
|         aliases: | ||||
|           - name: helmDeploymentName | ||||
|         type: string | ||||
|         description: Defines the name of the deployment. It is a mandatory parameter when deploying with helm. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         secret: true | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: custom/repositoryPassword | ||||
|       - name: helmDeployWaitSeconds | ||||
|         type: int | ||||
|         description: Number of seconds before helm deploy returns. | ||||
| @@ -238,7 +188,6 @@ spec: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|         possibleValues: | ||||
|           - upgrade | ||||
|           - install | ||||
| @@ -246,24 +195,7 @@ spec: | ||||
|           - test | ||||
|           - uninstall | ||||
|           - package | ||||
|           - push | ||||
|       - name: dryRun | ||||
|         type: bool | ||||
|         description: simulate execute command, like simulate an install | ||||
|         default: false | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: packageVersion | ||||
|         type: string | ||||
|         description: set the version on the chart to this semver version | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - publish | ||||
|       - name: appVersion | ||||
|         type: string | ||||
|         description: set the appVersion on the chart to this version | ||||
| @@ -298,34 +230,25 @@ spec: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: chartRepo | ||||
|         type: string | ||||
|         description: set the chart repository | ||||
|         default: "https://charts.helm.sh/stable" | ||||
|       - name: customTlsCertificateLinks | ||||
|         type: "[]string" | ||||
|         description: "List of download links to custom TLS certificates. This is required to ensure trusted connections to instances with repositories (like nexus) when publish flag is set to true." | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: helmRegistryUser | ||||
|         type: string | ||||
|         description: set the user for login to helm registry | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: helmChartServer | ||||
|         type: string | ||||
|         description: set chart server for pushing chart | ||||
|         default: "localhost:5000" | ||||
|       - name: publish | ||||
|         type: bool | ||||
|         description: Configures helm to run the deploy command to publish artifacts to a repository. | ||||
|         default: false | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|   containers: | ||||
|     - image: dtzar/helm-kubectl:3.4.1 | ||||
|     - image: dtzar/helm-kubectl:3.8.0 | ||||
|       workingDir: /config | ||||
|       options: | ||||
|         - name: -u | ||||
|   | ||||
		Reference in New Issue
	
	Block a user