mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-02-19 19:44:27 +02:00
Fix helm execute command (#3701)
* Add small fix * fix unit-tests * Add deploymentName and packageVersion as flags * small fix * Change getting version of helm chart * small fix Co-authored-by: “Vitalii <“vitalii.sidorov@sap.com”> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
parent
d519966fe5
commit
63cdfc0e68
@ -6,6 +6,7 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/kubernetes"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||
)
|
||||
|
||||
func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData) {
|
||||
@ -28,17 +29,27 @@ func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData)
|
||||
TargetRepositoryPassword: config.TargetRepositoryPassword,
|
||||
HelmCommand: config.HelmCommand,
|
||||
CustomTLSCertificateLinks: config.CustomTLSCertificateLinks,
|
||||
// ArtifactVersion: config.Version,
|
||||
Version: config.Version,
|
||||
}
|
||||
|
||||
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)
|
||||
artifactOpts := versioning.Options{
|
||||
VersioningScheme: "library",
|
||||
}
|
||||
|
||||
artifact, err := versioning.GetArtifact("helm", "", &artifactOpts, utils)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatalf("getting artifact information failed: %v", err)
|
||||
}
|
||||
artifactInfo, err := artifact.GetCoordinates()
|
||||
|
||||
helmConfig.DeploymentName = artifactInfo.ArtifactID
|
||||
|
||||
if len(config.Version) == 0 {
|
||||
helmConfig.Version = artifactInfo.Version
|
||||
}
|
||||
helmConfig.DeploymentName = nameChart
|
||||
helmConfig.PackageVersion = packageVersion
|
||||
|
||||
helmExecutor := kubernetes.NewHelmExecutor(helmConfig, utils, GeneralConfig.Verbose, log.Writer())
|
||||
|
||||
|
@ -19,7 +19,7 @@ type helmExecuteOptions struct {
|
||||
AdditionalParameters []string `json:"additionalParameters,omitempty"`
|
||||
ChartPath string `json:"chartPath,omitempty"`
|
||||
TargetRepositoryURL string `json:"targetRepositoryURL,omitempty"`
|
||||
TargetRepositoryName string `json:"targetRepositoryName,omitempty" validate:"required_if=HelmCommand install"`
|
||||
TargetRepositoryName string `json:"targetRepositoryName,omitempty"`
|
||||
TargetRepositoryUser string `json:"targetRepositoryUser,omitempty"`
|
||||
TargetRepositoryPassword string `json:"targetRepositoryPassword,omitempty"`
|
||||
HelmDeployWaitSeconds int `json:"helmDeployWaitSeconds,omitempty"`
|
||||
@ -38,6 +38,7 @@ type helmExecuteOptions struct {
|
||||
FilterTest string `json:"filterTest,omitempty"`
|
||||
CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"`
|
||||
Publish bool `json:"publish,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// HelmExecuteCommand Executes helm3 functionality as the package manager for Kubernetes.
|
||||
@ -155,9 +156,9 @@ 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.ChartPath, "chartPath", os.Getenv("PIPER_chartPath"), "Defines the chart path for helm. chartPath is mandatory for install/upgrade/publish commands.")
|
||||
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.TargetRepositoryName, "targetRepositoryName", os.Getenv("PIPER_targetRepositoryName"), "set the chart repository. The value is required for install/upgrade/uninstall commands.")
|
||||
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.")
|
||||
@ -176,8 +177,8 @@ func addHelmExecuteFlags(cmd *cobra.Command, stepConfig *helmExecuteOptions) {
|
||||
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().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.Flags().StringVar(&stepConfig.Version, "version", os.Getenv("PIPER_version"), "Defines the artifact version to use from helm package/publish commands.")
|
||||
|
||||
cmd.MarkFlagRequired("chartPath")
|
||||
cmd.MarkFlagRequired("image")
|
||||
}
|
||||
|
||||
@ -213,7 +214,7 @@ func helmExecuteMetadata() config.StepData {
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "helmChartPath"}},
|
||||
Default: os.Getenv("PIPER_chartPath"),
|
||||
},
|
||||
@ -454,6 +455,20 @@ func helmExecuteMetadata() config.StepData {
|
||||
Aliases: []config.Alias{},
|
||||
Default: false,
|
||||
},
|
||||
{
|
||||
Name: "version",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "artifactVersion",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: os.Getenv("PIPER_version"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
|
@ -43,7 +43,7 @@ type HelmExecuteOptions struct {
|
||||
KubeContext string `json:"kubeContext,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
DockerConfigJSON string `json:"dockerConfigJSON,omitempty"`
|
||||
PackageVersion string `json:"packageVersion,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
AppVersion string `json:"appVersion,omitempty"`
|
||||
Dependency string `json:"dependency,omitempty" validate:"possible-values=build list update"`
|
||||
PackageDependencyUpdate bool `json:"packageDependencyUpdate,omitempty"`
|
||||
@ -110,11 +110,19 @@ func (h *HelmExecute) runHelmAdd() error {
|
||||
|
||||
// RunHelmUpgrade is used to upgrade a release
|
||||
func (h *HelmExecute) RunHelmUpgrade() error {
|
||||
if len(h.config.ChartPath) == 0 {
|
||||
return fmt.Errorf("there is no ChartPath value. The chartPath value is mandatory")
|
||||
}
|
||||
|
||||
err := h.runHelmInit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
}
|
||||
|
||||
if err := h.runHelmAdd(); err != nil {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
}
|
||||
|
||||
helmParams := []string{
|
||||
"upgrade",
|
||||
h.config.DeploymentName,
|
||||
@ -184,6 +192,10 @@ func (h *HelmExecute) RunHelmLint() error {
|
||||
|
||||
// RunHelmInstall is used to install a chart
|
||||
func (h *HelmExecute) RunHelmInstall() error {
|
||||
if len(h.config.ChartPath) == 0 {
|
||||
return fmt.Errorf("there is no ChartPath value. The chartPath value is mandatory")
|
||||
}
|
||||
|
||||
if err := h.runHelmInit(); err != nil {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
}
|
||||
@ -235,6 +247,10 @@ func (h *HelmExecute) RunHelmUninstall() error {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
}
|
||||
|
||||
if err := h.runHelmAdd(); err != nil {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
}
|
||||
|
||||
helmParams := []string{
|
||||
"uninstall",
|
||||
h.config.DeploymentName,
|
||||
@ -267,6 +283,10 @@ func (h *HelmExecute) RunHelmUninstall() error {
|
||||
|
||||
// RunHelmPackage is used to package a chart directory into a chart archive
|
||||
func (h *HelmExecute) runHelmPackage() error {
|
||||
if len(h.config.ChartPath) == 0 {
|
||||
return fmt.Errorf("there is no ChartPath value. The chartPath value is mandatory")
|
||||
}
|
||||
|
||||
err := h.runHelmInit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute deployments: %v", err)
|
||||
@ -276,8 +296,8 @@ func (h *HelmExecute) runHelmPackage() error {
|
||||
"package",
|
||||
h.config.ChartPath,
|
||||
}
|
||||
if len(h.config.PackageVersion) > 0 {
|
||||
helmParams = append(helmParams, "--version", h.config.PackageVersion)
|
||||
if len(h.config.Version) > 0 {
|
||||
helmParams = append(helmParams, "--version", h.config.Version)
|
||||
}
|
||||
if h.config.PackageDependencyUpdate {
|
||||
helmParams = append(helmParams, "--dependency-update")
|
||||
@ -373,7 +393,7 @@ func (h *HelmExecute) RunHelmPublish() error {
|
||||
|
||||
h.utils.SetOptions(repoClientOptions)
|
||||
|
||||
binary := fmt.Sprintf("%v", h.config.DeploymentName+"-"+h.config.PackageVersion+".tgz")
|
||||
binary := fmt.Sprintf("%v", h.config.DeploymentName+"-"+h.config.Version+".tgz")
|
||||
|
||||
targetPath := fmt.Sprintf("%v/%s", h.config.DeploymentName, binary)
|
||||
|
||||
|
@ -71,8 +71,10 @@ func TestRunHelm(t *testing.T) {
|
||||
utils := newHelmMockUtilsBundle()
|
||||
|
||||
testTable := []struct {
|
||||
config HelmExecuteOptions
|
||||
expectedConfig []string
|
||||
config HelmExecuteOptions
|
||||
generalVerbose bool
|
||||
expectedAddConfig []string
|
||||
expectedUpgradeConfig []string
|
||||
}{
|
||||
{
|
||||
config: HelmExecuteOptions{
|
||||
@ -83,21 +85,26 @@ func TestRunHelm(t *testing.T) {
|
||||
HelmDeployWaitSeconds: 3456,
|
||||
AdditionalParameters: []string{"additional parameter"},
|
||||
Image: "dtzar/helm-kubectl:3.4.1",
|
||||
TargetRepositoryName: "test",
|
||||
TargetRepositoryURL: "https://charts.helm.sh/stable",
|
||||
},
|
||||
expectedConfig: []string{"upgrade", "test_deployment", ".", "--install", "--namespace", "test_namespace", "--force", "--wait", "--timeout", "3456s", "--atomic", "additional parameter"},
|
||||
generalVerbose: true,
|
||||
expectedAddConfig: []string{"repo", "add", "test", "https://charts.helm.sh/stable", "--debug"},
|
||||
expectedUpgradeConfig: []string{"upgrade", "test_deployment", ".", "--debug", "--install", "--namespace", "test_namespace", "--force", "--wait", "--timeout", "3456s", "--atomic", "additional parameter"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testTable {
|
||||
for _, testCase := range testTable {
|
||||
helmExecute := HelmExecute{
|
||||
utils: utils,
|
||||
config: testCase.config,
|
||||
verbose: false,
|
||||
verbose: testCase.generalVerbose,
|
||||
stdout: log.Writer(),
|
||||
}
|
||||
err := helmExecute.RunHelmUpgrade()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[i])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedAddConfig}, utils.Calls[0])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedUpgradeConfig}, utils.Calls[1])
|
||||
}
|
||||
})
|
||||
|
||||
@ -185,7 +192,6 @@ func TestRunHelm(t *testing.T) {
|
||||
|
||||
t.Run("Helm uninstal command", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
utils := newHelmMockUtilsBundle()
|
||||
|
||||
testTable := []struct {
|
||||
config HelmExecuteOptions
|
||||
@ -194,9 +200,10 @@ func TestRunHelm(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
config: HelmExecuteOptions{
|
||||
ChartPath: ".",
|
||||
DeploymentName: "testPackage",
|
||||
Namespace: "test-namespace",
|
||||
ChartPath: ".",
|
||||
DeploymentName: "testPackage",
|
||||
Namespace: "test-namespace",
|
||||
TargetRepositoryName: "test",
|
||||
},
|
||||
expectedConfig: []string{"uninstall", "testPackage", "--namespace", "test-namespace"},
|
||||
},
|
||||
@ -206,13 +213,15 @@ func TestRunHelm(t *testing.T) {
|
||||
DeploymentName: "testPackage",
|
||||
Namespace: "test-namespace",
|
||||
HelmDeployWaitSeconds: 524,
|
||||
TargetRepositoryName: "test",
|
||||
},
|
||||
generalVerbose: true,
|
||||
expectedConfig: []string{"uninstall", "testPackage", "--namespace", "test-namespace", "--wait", "--timeout", "524s", "--debug", "--dry-run"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testTable {
|
||||
for _, testCase := range testTable {
|
||||
utils := newHelmMockUtilsBundle()
|
||||
helmExecute := HelmExecute{
|
||||
utils: utils,
|
||||
config: testCase.config,
|
||||
@ -221,7 +230,7 @@ func TestRunHelm(t *testing.T) {
|
||||
}
|
||||
err := helmExecute.RunHelmUninstall()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[i])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[1])
|
||||
}
|
||||
})
|
||||
|
||||
@ -243,7 +252,7 @@ func TestRunHelm(t *testing.T) {
|
||||
config: HelmExecuteOptions{
|
||||
ChartPath: ".",
|
||||
DeploymentName: "testPackage",
|
||||
PackageVersion: "1.2.3",
|
||||
Version: "1.2.3",
|
||||
PackageDependencyUpdate: true,
|
||||
AppVersion: "9.8.7",
|
||||
},
|
||||
@ -316,6 +325,14 @@ func TestRunHelm(t *testing.T) {
|
||||
ChartPath: ".",
|
||||
DeploymentName: "testPackage",
|
||||
},
|
||||
expectedError: errors.New("failed to execute deployments: there is no TargetRepositoryName value. 'helm repo add' command requires 2 arguments"),
|
||||
},
|
||||
{
|
||||
config: HelmExecuteOptions{
|
||||
ChartPath: ".",
|
||||
DeploymentName: "testPackage",
|
||||
TargetRepositoryName: "test",
|
||||
},
|
||||
expectedError: errors.New("namespace has not been set, please configure namespace parameter"),
|
||||
},
|
||||
}
|
||||
@ -424,8 +441,9 @@ func TestRunHelm(t *testing.T) {
|
||||
TargetRepositoryURL: "https://my.target.repository.local/",
|
||||
TargetRepositoryUser: "testUser",
|
||||
TargetRepositoryPassword: "testPWD",
|
||||
PackageVersion: "1.2.3",
|
||||
Version: "1.2.3",
|
||||
DeploymentName: "test_helm_chart",
|
||||
ChartPath: ".",
|
||||
}
|
||||
utils.ReturnFileUploadStatus = 200
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
@ -19,6 +20,7 @@ type DeployUtils interface {
|
||||
Stdout(out io.Writer)
|
||||
Stderr(err io.Writer)
|
||||
RunExecutable(e string, p ...string) error
|
||||
DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
|
||||
|
||||
piperutils.FileUtils
|
||||
piperhttp.Uploader
|
||||
@ -95,3 +97,7 @@ func GetChartInfo(chartYamlFile string, utils DeployUtils) (string, string, erro
|
||||
|
||||
return name, version, nil
|
||||
}
|
||||
|
||||
func (d *deployUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
@ -49,3 +49,8 @@ func (utils *HttpClientMock) UploadRequest(method, url, file, fieldName string,
|
||||
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)
|
||||
}
|
||||
|
||||
// DownloadFile mock
|
||||
func (utils *HttpClientMock) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
@ -28,6 +28,20 @@ func TestSendRequest(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("DownloadFile", func(t *testing.T) {
|
||||
utils := HttpClientMock{}
|
||||
url := "https://localhost"
|
||||
filename := "testFile"
|
||||
var header http.Header
|
||||
var cookies []*http.Cookie
|
||||
err := utils.DownloadFile(url, filename, header, cookies)
|
||||
assert.Error(t, err)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetOption(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("SetOption", func(t *testing.T) {
|
||||
|
@ -49,8 +49,7 @@ spec:
|
||||
aliases:
|
||||
- name: helmChartPath
|
||||
type: string
|
||||
mandatory: true
|
||||
description: Defines the chart path for helm.
|
||||
description: Defines the chart path for helm. chartPath is mandatory for install/upgrade/publish commands.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
@ -69,10 +68,7 @@ spec:
|
||||
param: custom/repositoryUrl
|
||||
- name: targetRepositoryName
|
||||
type: string
|
||||
description: set the chart repository
|
||||
mandatoryIf:
|
||||
- name: helmCommand
|
||||
value: install
|
||||
description: set the chart repository. The value is required for install/upgrade/uninstall commands.
|
||||
scope:
|
||||
- GENERAL
|
||||
- PARAMETERS
|
||||
@ -264,6 +260,17 @@ spec:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
- name: version
|
||||
type: string
|
||||
description: Defines the artifact version to use from helm package/publish commands.
|
||||
scope:
|
||||
- GENERAL
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: artifactVersion
|
||||
containers:
|
||||
- image: dtzar/helm-kubectl:3.8.0
|
||||
workingDir: /config
|
||||
|
Loading…
x
Reference in New Issue
Block a user