From b56671f3ef129be5f4ca7ddfece65d24f138d4fa Mon Sep 17 00:00:00 2001 From: Dawid Rusnak Date: Fri, 15 Nov 2024 09:39:02 +0100 Subject: [PATCH 1/4] fix: merge general-use steps properly (#6031) --- .../action/containerize.go | 6 +- .../action/containerize_test.go | 61 ++++++++++++++++++ .../presets/processor_test.go | 64 +++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 pkg/testworkflows/testworkflowprocessor/action/containerize_test.go diff --git a/pkg/testworkflows/testworkflowprocessor/action/containerize.go b/pkg/testworkflows/testworkflowprocessor/action/containerize.go index fd04d8bfe4..b0d631b64d 100644 --- a/pkg/testworkflows/testworkflowprocessor/action/containerize.go +++ b/pkg/testworkflows/testworkflowprocessor/action/containerize.go @@ -39,11 +39,15 @@ func CreateContainer(groupId int, defaultContainer stage2.Container, actions []a // Find the highest priority container configuration var bestContainerConfig *actiontypes.Action var bestIsToolkit = false + var bestIsDefaultImage = true for i := range containerConfigs { if executable[containerConfigs[i].Container.Ref] { - if bestContainerConfig == nil || bestIsToolkit { + image := containerConfigs[i].Container.Config.Image + isDefaultImage := image == "" || image == constants.DefaultInitImage || image == constants.DefaultToolkitImage + if bestContainerConfig == nil || bestIsToolkit || (bestIsDefaultImage && !isDefaultImage) { bestContainerConfig = containerConfigs[i] bestIsToolkit = toolkit[bestContainerConfig.Container.Ref] + bestIsDefaultImage = isDefaultImage } } } diff --git a/pkg/testworkflows/testworkflowprocessor/action/containerize_test.go b/pkg/testworkflows/testworkflowprocessor/action/containerize_test.go new file mode 100644 index 0000000000..90e37219d5 --- /dev/null +++ b/pkg/testworkflows/testworkflowprocessor/action/containerize_test.go @@ -0,0 +1,61 @@ +package action + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + testworkflowsv1 "github.com/kubeshop/testkube-operator/api/testworkflows/v1" + "github.com/kubeshop/testkube/internal/common" + "github.com/kubeshop/testkube/pkg/testworkflows/testworkflowprocessor/action/actiontypes" + "github.com/kubeshop/testkube/pkg/testworkflows/testworkflowprocessor/constants" + "github.com/kubeshop/testkube/pkg/testworkflows/testworkflowprocessor/stage" +) + +func TestCreateContainer_MergingDefaultStepBefore(t *testing.T) { + input := actiontypes.NewActionList(). + MutateContainer("ref1", testworkflowsv1.ContainerConfig{ + Command: common.Ptr([]string{"sleep"}), + }). + Start("ref1"). + Execute("ref1", false, true). + End("ref1"). + CurrentStatus("ref1"). + MutateContainer("ref2", testworkflowsv1.ContainerConfig{ + Image: "custom-image:1.2.3", + Command: common.Ptr([]string{"my-test"}), + }). + Start("ref2"). + Execute("ref2", false, false). + End("ref2"). + End(constants.RootOperationName). + End("") + result, _, err := CreateContainer(1, stage.NewContainer(), input, false) + + assert.NoError(t, err) + assert.Equal(t, result.Image, "custom-image:1.2.3") +} + +func TestCreateContainer_MergingDefaultStepAfter(t *testing.T) { + input := actiontypes.NewActionList(). + MutateContainer("ref1", testworkflowsv1.ContainerConfig{ + Image: "custom-image:1.2.3", + Command: common.Ptr([]string{"my-test"}), + }). + Start("ref1"). + Execute("ref1", false, false). + End("ref1"). + CurrentStatus("ref1"). + MutateContainer("ref2", testworkflowsv1.ContainerConfig{ + Command: common.Ptr([]string{"sleep"}), + }). + Start("ref2"). + Execute("ref2", false, true). + End("ref2"). + End(constants.RootOperationName). + End("") + result, _, err := CreateContainer(1, stage.NewContainer(), input, false) + + assert.NoError(t, err) + assert.Equal(t, result.Image, "custom-image:1.2.3") +} diff --git a/pkg/testworkflows/testworkflowprocessor/presets/processor_test.go b/pkg/testworkflows/testworkflowprocessor/presets/processor_test.go index b7f842085d..18b503e3e7 100644 --- a/pkg/testworkflows/testworkflowprocessor/presets/processor_test.go +++ b/pkg/testworkflows/testworkflowprocessor/presets/processor_test.go @@ -1334,3 +1334,67 @@ func TestProcess_PureShellAtTheEnd(t *testing.T) { assert.NoError(t, err) assert.Equal(t, want, res.LiteActions()) } + +func TestProcess_MergingActions(t *testing.T) { + wf := &testworkflowsv1.TestWorkflow{ + Spec: testworkflowsv1.TestWorkflowSpec{ + Steps: []testworkflowsv1.Step{ + { + StepOperations: testworkflowsv1.StepOperations{Delay: "1s"}, + }, + { + StepDefaults: testworkflowsv1.StepDefaults{Container: &testworkflowsv1.ContainerConfig{ + Image: "custom-image:1.2.3", + }}, + StepOperations: testworkflowsv1.StepOperations{Shell: "test-command"}, + }, + }, + }, + } + + res, err := proc.Bundle(context.Background(), wf, testworkflowprocessor.BundleOptions{Config: testConfig}) + sig := res.Signature + + wantActions := lite.NewLiteActionGroups(). + Append(func(list lite.LiteActionList) lite.LiteActionList { + return list. + // configure + Setup(true, false, true). + Declare(constants.RootOperationName, "true"). + Declare(sig[0].Ref(), "true", constants.RootOperationName). + Declare(sig[1].Ref(), sig[0].Ref(), constants.RootOperationName). + Result(constants.RootOperationName, and(sig[0].Ref(), sig[1].Ref())). + Result("", constants.RootOperationName). + + // initialize + Start(""). + CurrentStatus("true"). + Start(constants.RootOperationName). + CurrentStatus(constants.RootOperationName) + }). + Append(func(list lite.LiteActionList) lite.LiteActionList { + return list. + // start first container + MutateContainer(lite.LiteContainerConfig{ + Command: cmd("sleep"), + Args: cmd("1"), + }). + Start(sig[0].Ref()). + Execute(sig[0].Ref(), false, true). + End(sig[0].Ref()). + CurrentStatus(and(sig[0].Ref(), constants.RootOperationName)). + MutateContainer(lite.LiteContainerConfig{ + Command: cmd("/.tktw/bin/sh"), + Args: cmdShell("test-command"), + }). + Start(sig[1].Ref()). + Execute(sig[1].Ref(), false, false). + End(sig[1].Ref()). + End(constants.RootOperationName). + End("") + }) + + assert.NoError(t, err) + assert.Equal(t, wantActions, res.LiteActions()) + assert.Equal(t, res.Job.Spec.Template.Spec.Containers[0].Image, "custom-image:1.2.3") +} From 59c91b3a7c63b4ecc1b64f90f76b3a980b12732b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:32:22 +0300 Subject: [PATCH 2/4] build(deps): bump anchore/sbom-action from 0.17.6 to 0.17.7 (#6010) Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.17.6 to 0.17.7. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md) - [Commits](https://github.com/anchore/sbom-action/compare/v0.17.6...v0.17.7) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../docker-build-api-executors-tag.yaml | 22 +++++++++---------- .github/workflows/release-dev.yaml | 2 +- .github/workflows/release.yaml | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/docker-build-api-executors-tag.yaml b/.github/workflows/docker-build-api-executors-tag.yaml index fef18588e3..c416842072 100644 --- a/.github/workflows/docker-build-api-executors-tag.yaml +++ b/.github/workflows/docker-build-api-executors-tag.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up Docker Buildx id: buildx @@ -94,7 +94,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up Docker Buildx id: buildx @@ -178,7 +178,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -249,7 +249,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -317,7 +317,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -442,7 +442,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -510,7 +510,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -669,7 +669,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -741,7 +741,7 @@ jobs: uses: docker/setup-qemu-action@v3 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up Docker Buildx id: buildx @@ -790,7 +790,7 @@ jobs: uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -863,7 +863,7 @@ jobs: fetch-depth: 0 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.github/workflows/release-dev.yaml b/.github/workflows/release-dev.yaml index 8688fbbc3c..f7070c56f5 100644 --- a/.github/workflows/release-dev.yaml +++ b/.github/workflows/release-dev.yaml @@ -185,7 +185,7 @@ jobs: with: fetch-depth: 0 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Download Artifacts for Linux uses: actions/download-artifact@master with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e50e15a883..f2a8ff1388 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -177,7 +177,7 @@ jobs: with: fetch-depth: 0 - uses: sigstore/cosign-installer@v3.7.0 - - uses: anchore/sbom-action/download-syft@v0.17.6 + - uses: anchore/sbom-action/download-syft@v0.17.7 - name: Download Artifacts for Linux uses: actions/download-artifact@master with: From b806dd3b7d3de1329c99fba9da8f83517c3f5b78 Mon Sep 17 00:00:00 2001 From: Vladislav Sukhin Date: Mon, 18 Nov 2024 13:39:08 +0300 Subject: [PATCH 3/4] fix: [TKC-2713] helm and kubectl init info (#6002) * fix: helm and kubectl debug info Signed-off-by: Vladislav Sukhin * fix: debug for dashboard Signed-off-by: Vladislav Sukhin * fix: pass set helm options Signed-off-by: Vladislav Sukhin * fix: mode debug info Signed-off-by: Vladislav Sukhin * fix: executed command Signed-off-by: Vladislav Sukhin * fix: add/modify sets Signed-off-by: Vladislav Sukhin * fix: add command context Signed-off-by: Vladislav Sukhin * fix: helm arg options Signed-off-by: Vladislav Sukhin * fix: ignore empty value Signed-off-by: Vladislav Sukhin * fix: adjust error message Signed-off-by: Vladislav Sukhin * fix: spinner Signed-off-by: Vladislav Sukhin --------- Signed-off-by: Vladislav Sukhin --- .../commands/common/errors.go | 33 ++++- .../commands/common/helper.go | 137 ++++++++++++------ cmd/kubectl-testkube/commands/dashboard.go | 7 +- cmd/kubectl-testkube/commands/init.go | 25 +++- cmd/kubectl-testkube/commands/pro/init.go | 14 +- pkg/ui/printers.go | 7 + pkg/ui/ui.go | 1 + 7 files changed, 167 insertions(+), 57 deletions(-) diff --git a/cmd/kubectl-testkube/commands/common/errors.go b/cmd/kubectl-testkube/commands/common/errors.go index 8279f2f49a..e48d0147b6 100644 --- a/cmd/kubectl-testkube/commands/common/errors.go +++ b/cmd/kubectl-testkube/commands/common/errors.go @@ -3,6 +3,7 @@ package common import ( "fmt" "os" + "strings" "github.com/spf13/cobra" @@ -52,13 +53,14 @@ const ( const helpUrl = "https://testkubeworkspace.slack.com" type CLIError struct { - Code ErrorCode - Title string - Description string - ActualError error - StackTrace string - MoreInfo string - Telemetry *ErrorTelemetry + Code ErrorCode + Title string + Description string + ActualError error + StackTrace string + MoreInfo string + ExecutedCommand string + Telemetry *ErrorTelemetry } type ErrorTelemetry struct { @@ -86,6 +88,15 @@ func (e *CLIError) Print() { pterm.DefaultSection.Println("Error Details") + cmd := "" + if e.ExecutedCommand != "" { + pterm.FgDarkGray.Printfln("Executed command: %s", e.ExecutedCommand) + params := strings.Split(e.ExecutedCommand, " ") + if len(params) > 0 { + cmd = params[0] + } + } + items := []pterm.BulletListItem{ {Level: 0, Text: pterm.Sprintf("[%s]: %s", e.Code, e.Title), TextStyle: pterm.NewStyle(pterm.FgRed)}, {Level: 0, Text: pterm.Sprintf("%s", e.Description), TextStyle: pterm.NewStyle(pterm.FgLightWhite)}, @@ -94,6 +105,9 @@ func (e *CLIError) Print() { items = append(items, pterm.BulletListItem{Level: 0, Text: pterm.Sprintf("%s", e.MoreInfo), TextStyle: pterm.NewStyle(pterm.FgGray)}) } pterm.DefaultBulletList.WithItems(items).Render() + if cmd != "" { + pterm.DefaultBox.Printfln("Error description is provided in context of binary execution %s", cmd) + } pterm.Println() pterm.Println("Let us help you!") @@ -111,6 +125,11 @@ func NewCLIError(code ErrorCode, title, moreInfoURL string, err error) *CLIError } } +func (err *CLIError) WithExecutedCommand(executedCommand string) *CLIError { + err.ExecutedCommand = executedCommand + return err +} + // HandleCLIError checks does the error exist, and if it does, prints the error and exits the program. func HandleCLIError(err *CLIError) { if err != nil { diff --git a/cmd/kubectl-testkube/commands/common/helper.go b/cmd/kubectl-testkube/commands/common/helper.go index 4e9e8e58f7..778ba132ac 100644 --- a/cmd/kubectl-testkube/commands/common/helper.go +++ b/cmd/kubectl-testkube/commands/common/helper.go @@ -28,6 +28,7 @@ type HelmOptions struct { Name, Namespace, Chart, Values string NoMinio, NoMongo, NoConfirm bool MinioReplicas, MongoReplicas int + SetOptions, ArgOptions map[string]string // On-prem LicenseKey string @@ -101,16 +102,11 @@ func HelmUpgradeOrInstallTestkubeAgent(options HelmOptions, cfg config.Data, isM } args := prepareTestkubeProHelmArgs(options, isMigration) - output, err := runHelmCommand(helmPath, args, options.DryRun) + _, err := runHelmCommand(helmPath, args, options.DryRun) if err != nil { return err } - ui.Debug("Helm command output:") - ui.Debug(helmPath, args...) - - ui.Debug("Helm install testkube output", output) - return nil } @@ -147,7 +143,7 @@ func lookupHelmPath() (string, *CLIError) { return helmPath, nil } -func updateHelmRepo(helmPath string, dryRun bool, isOnPrem bool) *CLIError { +func updateHelmRepo(helmPath string, dryRun, isOnPrem bool) *CLIError { registryURL := "https://kubeshop.github.io/helm-charts" registryName := "kubeshop" if isOnPrem { @@ -176,16 +172,18 @@ func CleanExistingCompletedMigrationJobs(namespace string) (cliErr *CLIError) { } // Clean the job only when it's found and it's state is successful - ignore pending migrations. - succeeded, _ := runKubectlCommand(kubectlPath, []string{"get", "job", "testkube-enterprise-api-migrations", "-n", namespace, "-o", "jsonpath={.status.succeeded}"}) + cmd := []string{"get", "job", "testkube-enterprise-api-migrations", "-n", namespace, "-o", "jsonpath={.status.succeeded}"} + succeeded, _ := runKubectlCommand(kubectlPath, cmd) if succeeded == "1" { - _, err := runKubectlCommand(kubectlPath, []string{"delete", "job", "testkube-enterprise-api-migrations", "--namespace", namespace}) + cmd = []string{"delete", "job", "testkube-enterprise-api-migrations", "--namespace", namespace} + _, err := runKubectlCommand(kubectlPath, cmd) if err != nil { return NewCLIError( TKErrCleanOldMigrationJobFailed, "Can't clean old migrations job", "Migration job can't be deleted from some reason, check for errors in installation namespace, check execution. As a workaround try to delete job manually and retry installation/upgrade process", err, - ) + ).WithExecutedCommand(strings.Join(cmd, " ")) } } @@ -193,82 +191,120 @@ func CleanExistingCompletedMigrationJobs(namespace string) (cliErr *CLIError) { } func runHelmCommand(helmPath string, args []string, dryRun bool) (commandOutput string, cliErr *CLIError) { + cmd := strings.Join(append([]string{helmPath}, args...), " ") + ui.DebugNL() + ui.Debug("Helm command:") + ui.Debug(cmd) + output, err := process.ExecuteWithOptions(process.Options{Command: helmPath, Args: args, DryRun: dryRun}) + ui.DebugNL() + ui.Debug("Helm output:") + ui.Debug(string(output)) if err != nil { return "", NewCLIError( TKErrHelmCommandFailed, "Helm command failed", - "Retry the command with a bigger timeout by setting --timeout 30m, if the error still persists, reach out to Testkube support", + "Retry the command with a bigger timeout by setting --helm-arg timeout=30m, if the error still persists, reach out to Testkube support", err, - ) + ).WithExecutedCommand(cmd) } return string(output), nil } +func appendHelmArgs(args []string, options HelmOptions, settings map[string]string) []string { + for key, value := range settings { + if _, ok := options.SetOptions[key]; !ok { + args = append(args, "--set", fmt.Sprintf("%s=%s", key, value)) + } + } + + for key, value := range options.SetOptions { + args = append(args, "--set", fmt.Sprintf("%s=%s", key, value)) + } + + for key, value := range options.ArgOptions { + args = append(args, fmt.Sprintf("--%s", key)) + if value != "" { + args = append(args, value) + } + } + + return args +} + func prepareTestkubeOnPremDemoArgs(options HelmOptions) []string { - return []string{ + args := []string{ "upgrade", "--install", "--create-namespace", "--namespace", options.Namespace, - "--set", "global.enterpriseLicenseKey=" + options.LicenseKey, - "--values", options.DemoValuesURL, + } + + settings := map[string]string{ + "global.enterpriseLicenseKey": options.LicenseKey, + } + + args = append(appendHelmArgs(args, options, settings), "--values", options.DemoValuesURL, "--wait", - "testkube", "testkubeenterprise/testkube-enterprise"} + "testkube", "testkubeenterprise/testkube-enterprise") + + return args } // prepareTestkubeProHelmArgs prepares Helm arguments for Testkube Pro installation. func prepareTestkubeProHelmArgs(options HelmOptions, isMigration bool) []string { - args := prepareCommonHelmArgs(options) + args, settings := prepareCommonHelmArgs(options) - args = append(args, - "--set", "testkube-api.cloud.url="+options.Master.URIs.Agent, - "--set", "testkube-api.cloud.key="+options.Master.AgentToken, - "--set", "testkube-api.cloud.uiURL="+options.Master.URIs.Ui, - "--set", "testkube-logs.pro.url="+options.Master.URIs.Logs, - "--set", "testkube-logs.pro.key="+options.Master.AgentToken, - ) + settings["testkube-api.cloud.url"] = options.Master.URIs.Agent + settings["testkube-api.cloud.key"] = options.Master.AgentToken + settings["testkube-api.cloud.uiURL"] = options.Master.URIs.Ui + settings["testkube-logs.pro.url"] = options.Master.URIs.Logs + settings["testkube-logs.pro.key"] = options.Master.AgentToken if isMigration { - args = append(args, "--set", "testkube-api.cloud.migrate=true") + settings["testkube-api.cloud.migrate"] = "true" } if options.Master.EnvId != "" { - args = append(args, "--set", fmt.Sprintf("testkube-api.cloud.envId=%s", options.Master.EnvId)) - args = append(args, "--set", fmt.Sprintf("testkube-logs.pro.envId=%s", options.Master.EnvId)) + settings["testkube-api.cloud.envId"] = options.Master.EnvId + settings["testkube-logs.pro.envId"] = options.Master.EnvId } if options.Master.OrgId != "" { - args = append(args, "--set", fmt.Sprintf("testkube-api.cloud.orgId=%s", options.Master.OrgId)) - args = append(args, "--set", fmt.Sprintf("testkube-logs.pro.orgId=%s", options.Master.OrgId)) + settings["testkube-api.cloud.orgId"] = options.Master.OrgId + settings["testkube-logs.pro.orgId"] = options.Master.OrgId } - return args + return appendHelmArgs(args, options, settings) } // prepareTestkubeHelmArgs prepares Helm arguments for Testkube OS installation. func prepareTestkubeHelmArgs(options HelmOptions) []string { - args := prepareCommonHelmArgs(options) + args, settings := prepareCommonHelmArgs(options) if options.NoMinio { - args = append(args, "--set", "testkube-api.logs.storage=mongo") + settings["testkube-api.logs.storage"] = "mongo" } else { - args = append(args, "--set", "testkube-api.logs.storage=minio") + settings["testkube-api.logs.storage"] = "minio" } - return args + return appendHelmArgs(args, options, settings) } // prepareCommonHelmArgs prepares common Helm arguments for both OS and Pro installation. -func prepareCommonHelmArgs(options HelmOptions) []string { +func prepareCommonHelmArgs(options HelmOptions) ([]string, map[string]string) { args := []string{ "upgrade", "--install", "--create-namespace", "--namespace", options.Namespace, - "--set", fmt.Sprintf("global.features.logsV2=%v", options.Master.Features.LogsV2), - "--set", fmt.Sprintf("testkube-api.multinamespace.enabled=%t", options.MultiNamespace), - "--set", fmt.Sprintf("testkube-api.minio.enabled=%t", !options.NoMinio), - "--set", fmt.Sprintf("testkube-api.minio.replicas=%d", options.MinioReplicas), "--set", fmt.Sprintf("testkube-operator.enabled=%t", !options.NoOperator), - "--set", fmt.Sprintf("mongodb.enabled=%t", !options.NoMongo), - "--set", fmt.Sprintf("mongodb.replicas=%d", options.MongoReplicas), + } + + settings := map[string]string{ + "global.features.logsV2": fmt.Sprintf("%v", options.Master.Features.LogsV2), + "testkube-api.multinamespace.enabled": fmt.Sprintf("%t", options.MultiNamespace), + "testkube-api.minio.enabled": fmt.Sprintf("%t", !options.NoMinio), + "testkube-api.minio.replicas": fmt.Sprintf("%d", options.MinioReplicas), + "testkube-operator.enabled": fmt.Sprintf("%t", !options.NoOperator), + "mongodb.enabled": fmt.Sprintf("%t", !options.NoMongo), + "mongodb.replicas": fmt.Sprintf("%d", options.MongoReplicas), } if options.Values != "" { @@ -277,12 +313,12 @@ func prepareCommonHelmArgs(options HelmOptions) []string { // if embedded nats is enabled disable nats chart if options.EmbeddedNATS { - args = append(args, "--set", "testkube-api.nats.enabled=false") - args = append(args, "--set", "testkube-api.nats.embedded=true") + settings["testkube-api.nats.enabled"] = "false" + settings["testkube-api.nats.embedded"] = "true" } args = append(args, options.Name, options.Chart) - return args + return args, settings } func PopulateHelmFlags(cmd *cobra.Command, options *HelmOptions) { @@ -463,6 +499,7 @@ func LoginUser(authUri string, customConnector bool) (string, string, error) { connectorID = ui.Select("Choose your login method", []string{github, gitlab}) } + ui.Debug("Logging into cloud with parameters", authUri, connectorID) authUrl, tokenChan, err := cloudlogin.CloudLogin(context.Background(), authUri, strings.ToLower(connectorID)) if err != nil { return "", "", fmt.Errorf("cloud login: %w", err) @@ -477,6 +514,7 @@ func LoginUser(authUri string, customConnector bool) (string, string, error) { return "", "", fmt.Errorf("login cancelled") } + ui.Debug("Opening login page in browser to get a token", authUrl) // open browser with login page and redirect to localhost open.Run(authUrl) @@ -732,14 +770,21 @@ func lookupKubectlPath() (string, *CLIError) { } func runKubectlCommand(kubectlPath string, args []string) (output string, cliErr *CLIError) { + cmd := strings.Join(append([]string{kubectlPath}, args...), " ") + ui.DebugNL() + ui.Debug("Kubectl command:") + ui.Debug(cmd) out, err := process.Execute(kubectlPath, args...) + ui.DebugNL() + ui.Debug("Kubectl output:") + ui.Debug(string(out)) if err != nil { return "", NewCLIError( TKErrKubectlCommandFailed, "Kubectl command failed", "Check does the kubeconfig file (~/.kube/config) exist and has correct permissions and is the Kubernetes cluster reachable and has Ready nodes by running 'kubectl get nodes' ", err, - ) + ).WithExecutedCommand(cmd) } return string(out), nil } @@ -766,7 +811,7 @@ func RunDockerCommand(args []string) (output string, cliErr *CLIError) { "Docker command failed", "Check is the Docker service installed and running on your computer by executing 'docker info' ", err, - ) + ).WithExecutedCommand(strings.Join(append([]string{"docker"}, args...), " ")) } return string(out), nil } diff --git a/cmd/kubectl-testkube/commands/dashboard.go b/cmd/kubectl-testkube/commands/dashboard.go index 3aec322e43..b54bc8f556 100644 --- a/cmd/kubectl-testkube/commands/dashboard.go +++ b/cmd/kubectl-testkube/commands/dashboard.go @@ -71,22 +71,26 @@ func openOnPremDashboard(cmd *cobra.Command, cfg config.Data, verbose, skipBrows uri := fmt.Sprintf("http://localhost:%d", uiLocalPort) ctx, cancel := context.WithCancel(context.Background()) + + ui.Debug("Port forwarding for api", config.EnterpriseApiName) err = k8sclient.PortForward(ctx, cfg.Namespace, config.EnterpriseApiName, config.EnterpriseApiPort, config.EnterpriseApiForwardingPort, verbose) if err != nil { sendErrTelemetry(cmd, cfg, "port_forward", license, "port forwarding api", err) } ui.ExitOnError("port forwarding api", err) + ui.Debug("Port forwarding for ui", config.EnterpriseUiName) err = k8sclient.PortForward(ctx, cfg.Namespace, config.EnterpriseUiName, config.EnterpriseUiPort, uiLocalPort, verbose) if err != nil { sendErrTelemetry(cmd, cfg, "port_forward", license, "port forwarding ui", err) } ui.ExitOnError("port forwarding ui", err) + ui.Debug("Port forwarding for dex", config.EnterpriseDexName) err = k8sclient.PortForward(ctx, cfg.Namespace, config.EnterpriseDexName, config.EnterpriseDexPort, config.EnterpriseDexForwardingPort, verbose) if err != nil { sendErrTelemetry(cmd, cfg, "port_forward", license, "port forwarding dex", err) } ui.ExitOnError("port forwarding dex", err) - + ui.Debug("Port forwarding for minio", config.EnterpriseMinioName) err = k8sclient.PortForward(ctx, cfg.Namespace, config.EnterpriseMinioName, config.EnterpriseMinioPort, config.EnterpriseMinioPortFrwardingPort, verbose) if err != nil { sendTelemetry(cmd, cfg, license, "port forwarding minio") @@ -94,6 +98,7 @@ func openOnPremDashboard(cmd *cobra.Command, cfg config.Data, verbose, skipBrows ui.ExitOnError("port forwarding minio", err) if !skipBrowser { + ui.Debug("Opening dashboard in browser", uri) err = open.Run(uri) if err != nil { sendErrTelemetry(cmd, cfg, "open_dashboard", license, "opening dashboard", err) diff --git a/cmd/kubectl-testkube/commands/init.go b/cmd/kubectl-testkube/commands/init.go index aa434d03be..4fe0ff53ee 100644 --- a/cmd/kubectl-testkube/commands/init.go +++ b/cmd/kubectl-testkube/commands/init.go @@ -61,6 +61,7 @@ func NewInitCmd() *cobra.Command { func NewInitCmdStandalone() *cobra.Command { var export bool var options common.HelmOptions + var setOptions, argOptions map[string]string cmd := &cobra.Command{ Use: standaloneAgentProfile, @@ -81,7 +82,11 @@ func NewInitCmdStandalone() *cobra.Command { } common.ProcessMasterFlags(cmd, &options, nil) - + options.SetOptions = setOptions + options.ArgOptions = argOptions + ui.NL() + ui.H2("Running Helm command...") + ui.NL() common.HandleCLIError(common.HelmUpgradeOrInstallTestkube(options)) ui.Info(`To help improve the quality of Testkube, we collect anonymous basic telemetry data. Head out to https://docs.testkube.io/articles/telemetry to read our policy or feel free to:`) @@ -97,6 +102,8 @@ func NewInitCmdStandalone() *cobra.Command { } cmd.Flags().BoolVarP(&export, "export", "", false, "Export the values.yaml") + cmd.Flags().StringToStringVarP(&setOptions, "helm-set", "", nil, "helm set option in form of key=value") + cmd.Flags().StringToStringVarP(&argOptions, "helm-arg", "", nil, "helm arg option in form of key=value") common.PopulateHelmFlags(cmd, &options) common.PopulateMasterFlags(cmd, &options, false) @@ -106,6 +113,7 @@ func NewInitCmdStandalone() *cobra.Command { func NewInitCmdDemo() *cobra.Command { var noConfirm, dryRun, export bool var license, namespace string + var setOptions, argOptions map[string]string cmd := &cobra.Command{ Use: demoProfile, @@ -132,6 +140,9 @@ func NewInitCmdDemo() *cobra.Command { sendTelemetry(cmd, cfg, license, "installation launched") + ui.NL() + ui.H2("Running Kubectl command...") + ui.NL() kubecontext, cliErr := common.GetCurrentKubernetesContext() if cliErr != nil { if cfg.TelemetryEnabled { @@ -206,7 +217,7 @@ func NewInitCmdDemo() *cobra.Command { } } - spinner := ui.NewSpinner("Installing Testkube On-Prem Demo...") + spinner := ui.NewSpinner("Running Kubectl command...") sendTelemetry(cmd, cfg, license, "installing started") options := common.HelmOptions{ Namespace: namespace, @@ -225,6 +236,10 @@ func NewInitCmdDemo() *cobra.Command { common.HandleCLIError(cliErr) } + spinner.Success() + spinner = ui.NewSpinner("Running Helm command...") + options.SetOptions = setOptions + options.ArgOptions = argOptions cliErr = common.HelmUpgradeOrInstallTestkubeOnPremDemo(options) if cliErr != nil { spinner.Fail("Failed to install Testkube On-Prem Demo") @@ -264,6 +279,10 @@ func NewInitCmdDemo() *cobra.Command { sendTelemetry(cmd, cfg, license, "opening dashboard") cfg, err = config.Load() ui.ExitOnError("Cannot open dashboard", err) + + ui.NL() + ui.H2("Launching web browser...") + ui.NL() openOnPremDashboard(cmd, cfg, false, false, license) }, } @@ -273,6 +292,8 @@ func NewInitCmdDemo() *cobra.Command { cmd.Flags().StringVarP(&license, "license", "l", "", "License key") cmd.Flags().BoolVarP(&dryRun, "dry-run", "", false, "Dry run") cmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace to install "+demoInstallationName) + cmd.Flags().StringToStringVarP(&setOptions, "helm-set", "", nil, "helm set option in form of key=value") + cmd.Flags().StringToStringVarP(&argOptions, "helm-arg", "", nil, "helm arg option in form of key=value") return cmd } diff --git a/cmd/kubectl-testkube/commands/pro/init.go b/cmd/kubectl-testkube/commands/pro/init.go index 7f54702a57..3270480f60 100644 --- a/cmd/kubectl-testkube/commands/pro/init.go +++ b/cmd/kubectl-testkube/commands/pro/init.go @@ -16,6 +16,8 @@ import ( func NewInitCmd() *cobra.Command { var export bool var noLogin bool // ignore ask for login + var setOptions, argOptions map[string]string + options := common.HelmOptions{ NoMinio: true, NoMongo: true, @@ -56,6 +58,9 @@ func NewInitCmd() *cobra.Command { ui.Warn("Please be sure you're on valid kubectl context before continuing!") ui.NL() + ui.NL() + ui.H2("Running Kubectl command...") + ui.NL() currentContext, cliErr := common.GetCurrentKubernetesContext() if cliErr != nil { sendErrTelemetry(cmd, cfg, "k8s_context", err) @@ -72,7 +77,9 @@ func NewInitCmd() *cobra.Command { } } - spinner := ui.NewSpinner("Installing Testkube") + spinner := ui.NewSpinner("Running Helm command...") + options.SetOptions = setOptions + options.ArgOptions = argOptions if cliErr := common.HelmUpgradeOrInstallTestkubeAgent(options, cfg, false); cliErr != nil { spinner.Fail() sendErrTelemetry(cmd, cfg, "helm_install", cliErr) @@ -98,6 +105,9 @@ func NewInitCmd() *cobra.Command { ui.H2("Saving Testkube CLI Pro context") var token, refreshToken string if !common.IsUserLoggedIn(cfg, options) { + ui.NL() + ui.H2("Launching web browser...") + ui.NL() token, refreshToken, err = common.LoginUser(options.Master.URIs.Auth, options.Master.CustomAuth) sendErrTelemetry(cmd, cfg, "login", err) ui.ExitOnError("user login", err) @@ -119,6 +129,8 @@ func NewInitCmd() *cobra.Command { cmd.Flags().BoolVarP(&export, "export", "", false, "Export the values.yaml") cmd.Flags().BoolVar(&options.MultiNamespace, "multi-namespace", false, "multi namespace mode") cmd.Flags().BoolVar(&options.NoOperator, "no-operator", false, "should operator be installed (for more instances in multi namespace mode it should be set to true)") + cmd.Flags().StringToStringVarP(&setOptions, "helm-set", "", nil, "helm set option in form of key=value") + cmd.Flags().StringToStringVarP(&argOptions, "helm-arg", "", nil, "helm arg option in form of key=value") return cmd } diff --git a/pkg/ui/printers.go b/pkg/ui/printers.go index 0d567cb05e..362c2a80c2 100644 --- a/pkg/ui/printers.go +++ b/pkg/ui/printers.go @@ -37,6 +37,13 @@ func (ui *UI) NL(amount ...int) { fmt.Fprintln(ui.Writer) } +func (ui *UI) DebugNL(amount ...int) { + if !ui.Verbose { + return + } + ui.NL(amount...) +} + // Success shows success in terminal func (ui *UI) Success(message string, subMessages ...string) { fmt.Fprintf(ui.Writer, "%s", LightYellow(message)) diff --git a/pkg/ui/ui.go b/pkg/ui/ui.go index 82563b7c39..3425926fa9 100644 --- a/pkg/ui/ui.go +++ b/pkg/ui/ui.go @@ -61,6 +61,7 @@ func WarnOnErrorAndOutputPretty(item string, outputPretty bool, errors ...error) func Logo() { ui.Logo() } func LogoNoColor() { ui.LogoNoColor() } func NL(amount ...int) { ui.NL(amount...) } +func DebugNL(amount ...int) { ui.DebugNL(amount...) } func H1(message string) { ui.H1(message) } func H2(message string) { ui.H2(message) } func Paragraph(message string) { ui.Paragraph(message) } From 481c968ef081545bc32191828a1f471c86313f97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:58:16 +0300 Subject: [PATCH 4/4] build(deps): bump codecov/codecov-action from 4 to 5 (#6033) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 437aa02fbd..472a1e9ebb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -53,7 +53,7 @@ jobs: - name: Send coverage report to Codecov if: always() - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: file: ./coverage.out flags: unittests @@ -181,7 +181,7 @@ jobs: - name: Send coverage report to Codecov if: always() - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: file: ./coverage.out flags: integrationtests