diff --git a/go.mod b/go.mod index 85a2b8abc00..8010adfa91b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.17 require ( github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d - github.com/alessio/shellescape v1.4.1 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/aws/aws-sdk-go v1.34.28 github.com/buger/jsonparser v1.1.1 diff --git a/go.sum b/go.sum index d6e8126ce63..d844a5d318b 100644 --- a/go.sum +++ b/go.sum @@ -122,8 +122,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= -github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= diff --git a/internal/bminventory/inventory.go b/internal/bminventory/inventory.go index f30e5e74179..7f4e0338d0b 100644 --- a/internal/bminventory/inventory.go +++ b/internal/bminventory/inventory.go @@ -2877,7 +2877,7 @@ func (b *bareMetalInventory) getImageInfo(clusterId *strfmt.UUID) (*models.Image return &models.ImageInfo{}, nil } -func (b *bareMetalInventory) generateV2NextStepRunnerCommand(ctx context.Context, params *installer.V2RegisterHostParams) *models.HostRegistrationResponseAO1NextStepRunnerCommand { +func (b *bareMetalInventory) generateV2NextStepRunnerCommand(ctx context.Context, params *installer.V2RegisterHostParams) (*models.HostRegistrationResponseAO1NextStepRunnerCommand, error) { if params.NewHostParams.DiscoveryAgentVersion != b.AgentDockerImg { log := logutil.FromContext(ctx, b.log) @@ -2887,17 +2887,17 @@ func (b *bareMetalInventory) generateV2NextStepRunnerCommand(ctx context.Context config := hostcommands.NextStepRunnerConfig{ ServiceBaseURL: b.ServiceBaseURL, - InfraEnvID: params.InfraEnvID.String(), - HostID: params.NewHostParams.HostID.String(), + InfraEnvID: params.InfraEnvID, + HostID: *params.NewHostParams.HostID, UseCustomCACert: b.ServiceCACertPath != "", NextStepRunnerImage: b.AgentDockerImg, SkipCertVerification: b.SkipCertVerification, } - command, args := hostcommands.GetNextStepRunnerCommand(&config) + command, args, err := hostcommands.GetNextStepRunnerCommand(&config) return &models.HostRegistrationResponseAO1NextStepRunnerCommand{ Command: command, Args: *args, - } + }, err } func returnRegisterHostTransitionError( @@ -4655,9 +4655,15 @@ func (b *bareMetalInventory) V2RegisterHost(ctx context.Context, params installe eventgen.SendHostRegistrationSucceededEvent(ctx, b.eventsHandler, *params.NewHostParams.HostID, params.InfraEnvID, host.ClusterID, hostutil.GetHostnameForMsg(host)) + nextStepRunnerCommand, err := b.generateV2NextStepRunnerCommand(ctx, ¶ms) + if err != nil { + log.WithError(err).Errorf("Fail to create nextStepRunnerCommand") + return common.GenerateErrorResponder(err) + } + hostRegistration := models.HostRegistrationResponse{ Host: *host, - NextStepRunnerCommand: b.generateV2NextStepRunnerCommand(ctx, ¶ms), + NextStepRunnerCommand: nextStepRunnerCommand, } if err := tx.Commit().Error; err != nil { diff --git a/internal/bminventory/inventory_test.go b/internal/bminventory/inventory_test.go index 26772d13335..8ddd13c50f1 100644 --- a/internal/bminventory/inventory_test.go +++ b/internal/bminventory/inventory_test.go @@ -455,7 +455,7 @@ var _ = Describe("RegisterHost", func() { Expect(payload).ShouldNot(BeNil()) command := payload.NextStepRunnerCommand Expect(command).ShouldNot(BeNil()) - Expect(command.Command).ShouldNot(BeEmpty()) + Expect(command.Command).Should(BeEmpty()) Expect(command.Args).ShouldNot(BeEmpty()) }) } @@ -638,7 +638,7 @@ var _ = Describe("v2RegisterHost", func() { Expect(payload).ShouldNot(BeNil()) command := payload.NextStepRunnerCommand Expect(command).ShouldNot(BeNil()) - Expect(command.Command).ShouldNot(BeEmpty()) + Expect(command.Command).Should(BeEmpty()) Expect(command.Args).ShouldNot(BeEmpty()) }) } @@ -10900,7 +10900,8 @@ var _ = Describe("update image version", func() { agentImage := fmt.Sprintf("%s:%s", "quay.io/ocpmetal/agent", uuid.New().String()) bm.AgentDockerImg = agentImage params.NewHostParams.DiscoveryAgentVersion = agentImage - bm.generateV2NextStepRunnerCommand(ctx, params) + _, err := bm.generateV2NextStepRunnerCommand(ctx, params) + Expect(err).NotTo(HaveOccurred()) Expect(logHook.AllEntries()).To(BeEmpty()) }) @@ -10908,7 +10909,8 @@ var _ = Describe("update image version", func() { imageName := "quay.io/edge-infrastructure/assisted-installer-agent" bm.AgentDockerImg = fmt.Sprintf("%s:%s", imageName, uuid.New().String()) params.NewHostParams.DiscoveryAgentVersion = fmt.Sprintf("%s:%s", imageName, uuid.New().String()) - bm.generateV2NextStepRunnerCommand(ctx, params) + _, err := bm.generateV2NextStepRunnerCommand(ctx, params) + Expect(err).NotTo(HaveOccurred()) Expect(logHook.LastEntry().Message).To(ContainSubstring("uses an outdated agent image")) }) @@ -10916,7 +10918,8 @@ var _ = Describe("update image version", func() { imageTag := uuid.New().String() bm.AgentDockerImg = fmt.Sprintf("%s:%s", "quay.io/edge-infrastructure/assisted-installer-agent", imageTag) params.NewHostParams.DiscoveryAgentVersion = fmt.Sprintf("%s:%s", "quay.io/ocpmetal/agent", imageTag) - bm.generateV2NextStepRunnerCommand(ctx, params) + _, err := bm.generateV2NextStepRunnerCommand(ctx, params) + Expect(err).NotTo(HaveOccurred()) Expect(logHook.LastEntry().Message).To(ContainSubstring("uses an outdated agent image")) }) @@ -10925,7 +10928,8 @@ var _ = Describe("update image version", func() { imageName := "edge-infrastructure/assisted-installer-agent" bm.AgentDockerImg = fmt.Sprintf("%s/%s:%s", "quay.io", imageName, imageTag) params.NewHostParams.DiscoveryAgentVersion = fmt.Sprintf("%s/%s:%s", "docker.io", imageName, imageTag) - bm.generateV2NextStepRunnerCommand(ctx, params) + _, err := bm.generateV2NextStepRunnerCommand(ctx, params) + Expect(err).NotTo(HaveOccurred()) Expect(logHook.LastEntry().Message).To(ContainSubstring("uses an outdated agent image")) }) }) diff --git a/internal/host/hostcommands/install_cmd.go b/internal/host/hostcommands/install_cmd.go index 8dc755175e9..f2a63aed952 100644 --- a/internal/host/hostcommands/install_cmd.go +++ b/internal/host/hostcommands/install_cmd.go @@ -7,7 +7,6 @@ import ( "net" "strings" - "github.com/alessio/shellescape" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" "github.com/openshift/assisted-service/internal/common" @@ -35,16 +34,6 @@ type installCmd struct { versionsHandler versions.Handler } -var podmanBaseCmd = [...]string{ - "podman", "run", "--privileged", "--pid=host", "--net=host", "--name=assisted-installer", - "--volume", "/dev:/dev:rw", - "--volume", "/opt:/opt:rw", - "--volume", "/var/log:/var/log:rw", - "--volume", "/run/systemd/journal/socket:/run/systemd/journal/socket", - "--volume", "/etc/pki:/etc/pki", - "--env=PULL_SECRET_TOKEN", -} - func NewInstallCmd(log logrus.FieldLogger, db *gorm.DB, hwValidator hardware.Validator, ocRelease oc.Release, instructionConfig InstructionConfig, eventsHandler eventsapi.Handler, versionsHandler versions.Handler) *installCmd { return &installCmd{ @@ -61,7 +50,6 @@ func NewInstallCmd(log logrus.FieldLogger, db *gorm.DB, hwValidator hardware.Val func (i *installCmd) GetSteps(ctx context.Context, host *models.Host) ([]*models.Step, error) { step := &models.Step{} step.StepType = models.StepTypeInstall - step.Command = "bash" cluster, err := common.GetClusterFromDBWithHosts(i.db, *host.ClusterID) if err != nil { @@ -92,7 +80,7 @@ func (i *installCmd) GetSteps(ctx context.Context, host *models.Host) ([]*models return nil, err } - step.Args = []string{"-c", fullCmd} + step.Args = []string{fullCmd} if _, err := hostutil.UpdateHost(i.log, i.db, host.InfraEnvID, *host.ID, *host.Status, "installer_version", i.instructionConfig.InstallerImage); err != nil { @@ -113,17 +101,19 @@ func (i *installCmd) getFullInstallerCommand(cluster *common.Cluster, host *mode haMode = *cluster.HighAvailabilityMode } - podmanCmd := podmanBaseCmd[:] - installerCmdArgs := []string{ - "--role", string(role), - "--infra-env-id", host.InfraEnvID.String(), - "--cluster-id", host.ClusterID.String(), - "--host-id", string(*host.ID), - "--boot-device", bootdevice, - "--url", i.instructionConfig.ServiceBaseURL, - "--high-availability-mode", haMode, - "--controller-image", i.instructionConfig.ControllerImage, - "--agent-image", i.instructionConfig.AgentImage, + request := models.InstallCmdRequest{ + Role: &role, + BaseURL: swag.String(strings.TrimSpace(i.instructionConfig.ServiceBaseURL)), + ClusterID: host.ClusterID, + HostID: host.ID, + InfraEnvID: &host.InfraEnvID, + Insecure: swag.Bool(i.instructionConfig.SkipCertVerification), + Bootdevice: swag.String(bootdevice), + HighAvailabilityMode: &haMode, + ControllerImage: swag.String(i.instructionConfig.ControllerImage), + DisksToFormat: disksToFormat, + CheckCvo: swag.Bool(i.instructionConfig.CheckClusterVersion), + InstallerImage: swag.String(i.instructionConfig.InstallerImage), } // those flags are not used on day2 installation @@ -133,47 +123,26 @@ func (i *installCmd) getFullInstallerCommand(cluster *common.Cluster, host *mode return "", err } - mcoImage, err := i.ocRelease.GetMCOImage(i.log, *releaseImage.URL, i.instructionConfig.ReleaseImageMirror, cluster.PullSecret) + request.McoImage, err = i.ocRelease.GetMCOImage(i.log, *releaseImage.URL, i.instructionConfig.ReleaseImageMirror, cluster.PullSecret) if err != nil { return "", err } - i.log.Infof("Install command releaseImage: %s, mcoImage: %s", *releaseImage.URL, mcoImage) + i.log.Infof("Install command releaseImage: %s, mcoImage: %s", *releaseImage.URL, request.McoImage) mustGatherMap, err := i.versionsHandler.GetMustGatherImages(cluster.OpenshiftVersion, cluster.CPUArchitecture, cluster.PullSecret) if err != nil { return "", err } - mustGatherImages, err := i.getMustGatherArgument(mustGatherMap) + request.MustGatherImage, err = i.getMustGatherArgument(mustGatherMap) if err != nil { return "", err } - installerCmdArgs = append(installerCmdArgs, "--must-gather-image", mustGatherImages) - installerCmdArgs = append(installerCmdArgs, "--openshift-version", cluster.OpenshiftVersion) - installerCmdArgs = append(installerCmdArgs, "--mco-image", mcoImage) - } - - for _, diskToFormat := range disksToFormat { - installerCmdArgs = append(installerCmdArgs, "--format-disk") - installerCmdArgs = append(installerCmdArgs, diskToFormat) - } - - /* - boolean flag must be used either without value (flag present means True) or in the format of =True|False. - format is not supported by golang flag package and will cause the flags processing to finish - before processing the rest of the input flags - */ - if i.instructionConfig.SkipCertVerification { - installerCmdArgs = append(installerCmdArgs, "--insecure") - } - - if i.instructionConfig.CheckClusterVersion { - installerCmdArgs = append(installerCmdArgs, "--check-cluster-version") + request.OpenshiftVersion = cluster.OpenshiftVersion } if i.hasCACert() { - podmanCmd = append(podmanCmd, "--volume", fmt.Sprintf("%s:%s:rw", common.HostCACertPath, common.HostCACertPath)) - installerCmdArgs = append(installerCmdArgs, "--cacert", common.HostCACertPath) + request.CaCertPath = common.HostCACertPath } hostInstallerArgs, err := constructHostInstallerArgs(cluster, host, infraEnv, i.log) @@ -182,57 +151,42 @@ func (i *installCmd) getFullInstallerCommand(cluster *common.Cluster, host *mode } if hostInstallerArgs != "" { - installerCmdArgs = append(installerCmdArgs, "--installer-args", hostInstallerArgs) + request.InstallerArgs = hostInstallerArgs } - noProxyArgs := i.getProxyArguments(cluster.Name, cluster.BaseDNSDomain, cluster.HTTPProxy, cluster.HTTPSProxy, cluster.NoProxy) - if len(noProxyArgs) > 0 { - installerCmdArgs = append(installerCmdArgs, noProxyArgs...) - } + request.Proxy = i.getProxyArguments(cluster.Name, cluster.BaseDNSDomain, cluster.HTTPProxy, cluster.HTTPSProxy, cluster.NoProxy) if i.instructionConfig.ServiceIPs != "" { - installerCmdArgs = append(installerCmdArgs, "--service-ips", i.instructionConfig.ServiceIPs) - } - - return fmt.Sprintf("%s %s %s", shellescape.QuoteCommand(podmanCmd), i.instructionConfig.InstallerImage, - shellescape.QuoteCommand(installerCmdArgs)), nil -} - -func (i *installCmd) getMustGatherArgument(mustGatherMap versions.MustGatherVersion) (string, error) { - //for backward compatability, if must gather images map contains only the ocp must gather - //we shall send a single image. otherwise, we shall send a json structure holding all the - //relevant images - if len(mustGatherMap) == 1 && mustGatherMap["ocp"] != "" { - return mustGatherMap["ocp"], nil + request.ServiceIps = strings.Split(i.instructionConfig.ServiceIPs, ",") } - arg, err := json.Marshal(mustGatherMap) + b, err := json.Marshal(&request) if err != nil { - i.log.WithError(err).Errorf("can not encode must-gather image map") + i.log.WithError(err).Warn("Json marshal") return "", err } - return string(arg), nil + + return string(b), nil } -func (i *installCmd) getProxyArguments(clusterName, baseDNSDomain, httpProxy, httpsProxy, noProxy string) []string { - cmd := make([]string, 0) +func (i *installCmd) getProxyArguments(clusterName, baseDNSDomain, httpProxy, httpsProxy, noProxy string) *models.Proxy { + var proxy models.Proxy if httpProxy == "" && httpsProxy == "" { - return cmd + return nil } if httpProxy != "" { - cmd = append(cmd, "--http-proxy", httpProxy) + proxy.HTTPProxy = swag.String(httpProxy) } if httpsProxy != "" { - cmd = append(cmd, "--https-proxy", httpsProxy) + proxy.HTTPSProxy = swag.String(httpsProxy) } noProxyTrim := strings.TrimSpace(noProxy) if noProxyTrim == "*" { - cmd = append(cmd, "--no-proxy", noProxyTrim) + proxy.NoProxy = swag.String(noProxyTrim) } else { - noProxyUpdated := []string{} if noProxyTrim != "" { noProxyUpdated = append(noProxyUpdated, noProxyTrim) @@ -245,10 +199,26 @@ func (i *installCmd) getProxyArguments(clusterName, baseDNSDomain, httpProxy, ht ".svc", ".cluster.local", fmt.Sprintf("api-int.%s.%s", clusterName, baseDNSDomain)) - cmd = append(cmd, "--no-proxy", strings.Join(noProxyUpdated, ",")) + proxy.NoProxy = swag.String(strings.Join(noProxyUpdated, ",")) + } + + return &proxy +} + +func (i *installCmd) getMustGatherArgument(mustGatherMap versions.MustGatherVersion) (string, error) { + //for backward compatability, if must gather images map contains only the ocp must gather + //we shall send a single image. otherwise, we shall send a json structure holding all the + //relevant images + if len(mustGatherMap) == 1 && mustGatherMap["ocp"] != "" { + return mustGatherMap["ocp"], nil } - return cmd + arg, err := json.Marshal(mustGatherMap) + if err != nil { + i.log.WithError(err).Errorf("can not encode must-gather image map") + return "", err + } + return string(arg), nil } func (i *installCmd) hasCACert() bool { diff --git a/internal/host/hostcommands/install_cmd_test.go b/internal/host/hostcommands/install_cmd_test.go index 09b68171768..0892688b45e 100644 --- a/internal/host/hostcommands/install_cmd_test.go +++ b/internal/host/hostcommands/install_cmd_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "regexp" "strings" "github.com/go-openapi/strfmt" @@ -196,8 +195,8 @@ var _ = Describe("installcmd", func() { mockFormatEvent(disks[0], 0) prepareGetStep(sdb) stepReply, stepErr = installCmd.GetSteps(ctx, &host) - verifyDiskFormatCommand(stepReply[0].Args[1], disks[0].ID, false) - }) + verifyDiskFormatCommand(stepReply[0], disks[0].ID, false) + }) It("format_one_bootable", func() { disks := []*models.Disk{ @@ -213,9 +212,9 @@ var _ = Describe("installcmd", func() { validateInstallCommand(installCmd, stepReply[0], models.HostRoleMaster, infraEnvId, clusterId, *host.ID, sdb.ID, getBootableDiskNames(disks), models.ClusterHighAvailabilityModeFull) hostFromDb := hostutil.GetHostFromDB(*host.ID, infraEnvId, db) Expect(hostFromDb.InstallerVersion).Should(Equal(DefaultInstructionConfig.InstallerImage)) - verifyDiskFormatCommand(stepReply[0].Args[1], sda.ID, true) - verifyDiskFormatCommand(stepReply[0].Args[1], sdb.ID, false) - verifyDiskFormatCommand(stepReply[0].Args[1], sdh.ID, false) + verifyDiskFormatCommand(stepReply[0], sda.ID, true) + verifyDiskFormatCommand(stepReply[0], sdb.ID, false) + verifyDiskFormatCommand(stepReply[0], sdh.ID, false) }) It("format_multiple_bootable_skip", func() { @@ -248,11 +247,11 @@ var _ = Describe("installcmd", func() { validateInstallCommand(installCmd, stepReply[0], models.HostRoleMaster, infraEnvId, clusterId, *host.ID, sdb.ID, []string{sda.ID, sdc.ID}, models.ClusterHighAvailabilityModeFull) hostFromDb := hostutil.GetHostFromDB(*host.ID, infraEnvId, db) Expect(hostFromDb.InstallerVersion).Should(Equal(DefaultInstructionConfig.InstallerImage)) - verifyDiskFormatCommand(stepReply[0].Args[1], sda.ID, true) - verifyDiskFormatCommand(stepReply[0].Args[1], sdc.ID, true) - verifyDiskFormatCommand(stepReply[0].Args[1], sdi.ID, false) - verifyDiskFormatCommand(stepReply[0].Args[1], sdg.ID, false) - verifyDiskFormatCommand(stepReply[0].Args[1], sdj.ID, false) + verifyDiskFormatCommand(stepReply[0], sda.ID, true) + verifyDiskFormatCommand(stepReply[0], sdc.ID, true) + verifyDiskFormatCommand(stepReply[0], sdi.ID, false) + verifyDiskFormatCommand(stepReply[0], sdg.ID, false) + verifyDiskFormatCommand(stepReply[0], sdj.ID, false) }) }) @@ -315,7 +314,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--insecure")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.Insecure)).Should(BeFalse()) }) It("insecure_cert_is_set_to_false", func() { @@ -326,7 +326,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--insecure")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.Insecure)).Should(BeFalse()) }) It("insecure_cert_is_set_to_true", func() { @@ -337,7 +338,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--insecure")).Should(BeTrue()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.Insecure)).Should(BeTrue()) }) It("check_cluster_version_is_false_by_default", func() { @@ -346,7 +348,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--check-cluster-version")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.CheckCvo)).To(BeFalse()) }) It("check_cluster_version_is_set_to_false", func() { @@ -357,7 +360,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--check-cluster-version")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.CheckCvo)).To(BeFalse()) }) It("check_cluster_version_is_set_to_true", func() { @@ -368,7 +372,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--check-cluster-version")).Should(BeTrue()) + request := getRequest(stepReply[0]) + Expect(swag.BoolValue(request.CheckCvo)).To(BeTrue()) }) It("target_url_is_passed", func() { @@ -379,7 +384,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--url", config.ServiceBaseURL, 1) + request := getRequest(stepReply[0]) + Expect(swag.StringValue(request.BaseURL)).To(Equal(config.ServiceBaseURL)) }) It("verify high-availability-mode is None", func() { @@ -387,7 +393,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--high-availability-mode", models.ClusterHighAvailabilityModeNone, 1) + request := getRequest(stepReply[0]) + Expect(*request.HighAvailabilityMode).To(Equal(models.ClusterHighAvailabilityModeNone)) }) It("verify empty value", func() { @@ -399,29 +406,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--mco-image", "''", 1) - }) - - It("verify escaped whitespace value", func() { - value := "\nescaped_\n\t_value\n" - mockRelease = oc.NewMockRelease(ctrl) - mockRelease.EXPECT().GetMCOImage(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(value, nil).AnyTimes() - mockVersions.EXPECT().GetMustGatherImages(gomock.Any(), gomock.Any(), gomock.Any()).Return(defaultMustGatherVersion, nil).AnyTimes() - - installCmd := NewInstallCmd(common.GetTestLog(), db, validator, mockRelease, InstructionConfig{}, mockEvents, mockVersions) - stepReply, err := installCmd.GetSteps(ctx, &host) - Expect(err).NotTo(HaveOccurred()) - Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--mco-image", fmt.Sprintf("'%s'", value), 1) - }) - - It("validate that pki was mounted", func() { - config := &InstructionConfig{} - installCmd := NewInstallCmd(common.GetTestLog(), db, validator, mockRelease, *config, mockEvents, mockVersions) - stepReply, err := installCmd.GetSteps(ctx, &host) - Expect(err).NotTo(HaveOccurred()) - Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "/etc/pki:/etc/pki")).Should(BeTrue()) + request := getRequest(stepReply[0]) + Expect(request.McoImage).To(Equal("")) }) It("no must-gather , mco and openshift version in day2 installation", func() { @@ -430,23 +416,21 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--mco-image")).Should(BeFalse()) - Expect(strings.Contains(stepReply[0].Args[1], "--openshift-version")).Should(BeFalse()) - Expect(strings.Contains(stepReply[0].Args[1], "--must-gather-image")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(request.McoImage).To(BeEmpty()) + Expect(request.OpenshiftVersion).To(BeEmpty()) + Expect(request.MustGatherImage).To(BeEmpty()) }) Context("CA certificate", func() { - volumeMount := fmt.Sprintf("--volume %s:%s:rw", common.HostCACertPath, common.HostCACertPath) - cacertArgs := fmt.Sprintf("--cacert %s", common.HostCACertPath) - It("no CA certificate", func() { config := &InstructionConfig{} installCmd := NewInstallCmd(common.GetTestLog(), db, validator, mockRelease, *config, mockEvents, mockVersions) stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Join(stepReply[0].Args, " ")).NotTo(ContainSubstring(volumeMount)) - Expect(strings.Join(stepReply[0].Args, " ")).NotTo(ContainSubstring(cacertArgs)) + request := getRequest(stepReply[0]) + Expect(request.CaCertPath).To(BeEmpty()) }) It("with CA certificate", func() { @@ -455,8 +439,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Join(stepReply[0].Args, " ")).To(ContainSubstring(volumeMount)) - Expect(strings.Join(stepReply[0].Args, " ")).To(ContainSubstring(cacertArgs)) + request := getRequest(stepReply[0]) + Expect(request.CaCertPath).To(Equal(common.HostCACertPath)) }) }) }) @@ -477,14 +461,16 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--installer-args", fmt.Sprintf("'%s'", host.InstallerArgs), 1) + request := getRequest(stepReply[0]) + Expect(request.InstallerArgs).To(Equal(host.InstallerArgs)) }) It("empty installer args", func() { host.InstallerArgs = "" stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - Expect(strings.Contains(stepReply[0].Args[1], "--installer-args")).Should(BeFalse()) + request := getRequest(stepReply[0]) + Expect(request.InstallerArgs).To(BeEmpty()) }) It("empty installer args with static ip config", func() { @@ -493,7 +479,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--installer-args", fmt.Sprintf("'%s'", `["--copy-network"]`), 1) + request := getRequest(stepReply[0]) + Expect(request.InstallerArgs).To(Equal(`["--copy-network"]`)) }) It("non-empty installer args with static ip config", func() { @@ -502,7 +489,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--installer-args", fmt.Sprintf("'%s'", `["--append-karg","nameserver=8.8.8.8","-n","--copy-network"]`), 1) + request := getRequest(stepReply[0]) + Expect(request.InstallerArgs).To(Equal(`["--append-karg","nameserver=8.8.8.8","-n","--copy-network"]`)) }) It("non-empty installer args with copy network with static ip config", func() { @@ -511,7 +499,8 @@ var _ = Describe("installcmd arguments", func() { stepReply, err := installCmd.GetSteps(ctx, &host) Expect(err).NotTo(HaveOccurred()) Expect(stepReply).NotTo(BeNil()) - verifyArgInCommand(stepReply[0].Args[1], "--installer-args", fmt.Sprintf("'%s'", host.InstallerArgs), 1) + request := getRequest(stepReply[0]) + Expect(request.InstallerArgs).To(Equal(host.InstallerArgs)) }) }) @@ -559,45 +548,30 @@ var _ = Describe("installcmd arguments", func() { }) It("no-proxy without httpProxy", func() { args := installCmd.getProxyArguments("t-cluster", "proxy.org", "", "", "domain.com,192.168.1.0/24") - Expect(args).Should(Equal([]string{})) + Expect(args).Should(BeNil()) }) It("default no-proxy", func() { noProxy := installCmd.getProxyArguments("t-cluster", "proxy.org", "http://10.56.20.90:8080", "", "") - Expect(noProxy).Should(Equal([]string{ - "--http-proxy", - "http://10.56.20.90:8080", - "--no-proxy", - "127.0.0.1,localhost,.svc,.cluster.local,api-int.t-cluster.proxy.org", - })) + Expect(swag.StringValue(noProxy.HTTPProxy)).Should(Equal("http://10.56.20.90:8080")) + Expect(swag.StringValue(noProxy.NoProxy)).Should(Equal( + "127.0.0.1,localhost,.svc,.cluster.local,api-int.t-cluster.proxy.org")) }) It("updated no-proxy", func() { noProxy := installCmd.getProxyArguments("t-cluster", "proxy.org", "http://10.56.20.90:8080", "", "domain.org,127.0.0.2") - Expect(noProxy).Should(Equal([]string{ - "--http-proxy", - "http://10.56.20.90:8080", - "--no-proxy", - "domain.org,127.0.0.2,127.0.0.1,localhost,.svc,.cluster.local,api-int.t-cluster.proxy.org", - })) + Expect(swag.StringValue(noProxy.HTTPProxy)).Should(Equal("http://10.56.20.90:8080")) + Expect(swag.StringValue(noProxy.NoProxy)).Should(Equal( + "domain.org,127.0.0.2,127.0.0.1,localhost,.svc,.cluster.local,api-int.t-cluster.proxy.org")) }) It("all-excluded no-proxy", func() { noProxy := installCmd.getProxyArguments("t-cluster", "proxy.org", "http://10.56.20.90:8080", "", "*") - Expect(noProxy).Should(Equal([]string{ - "--http-proxy", - "http://10.56.20.90:8080", - "--no-proxy", - "*", - })) - + Expect(swag.StringValue(noProxy.HTTPProxy)).Should(Equal("http://10.56.20.90:8080")) + Expect(swag.StringValue(noProxy.NoProxy)).Should(Equal("*")) }) It("all-excluded no-proxy with spaces", func() { noProxy := installCmd.getProxyArguments("t-cluster", "proxy.org", "http://10.56.20.90:8080", "", " * ") - Expect(noProxy).Should(Equal([]string{ - "--http-proxy", - "http://10.56.20.90:8080", - "--no-proxy", - "*", - })) + Expect(swag.StringValue(noProxy.HTTPProxy)).Should(Equal("http://10.56.20.90:8080")) + Expect(swag.StringValue(noProxy.NoProxy)).Should(Equal("*")) }) }) }) @@ -1013,38 +987,17 @@ func getBootableDiskNames(disks []*models.Disk) []string { }).([]string) } -func verifyArgInCommand(command, key, value string, count int) { - r := regexp.MustCompile(fmt.Sprintf(`%s ([^ ]+)`, key)) - match := r.FindAllStringSubmatch(command, -1) - Expect(match).NotTo(BeNil()) - Expect(match).To(HaveLen(count)) - Expect(strings.TrimSpace(match[0][1])).To(Equal(quoteString(value))) +func getRequest(reply *models.Step) *models.InstallCmdRequest { + request := models.InstallCmdRequest{} + err := json.Unmarshal([]byte(reply.Args[0]), &request) + Expect(err).NotTo(HaveOccurred()) + return &request } -func verifyDiskFormatCommand(command string, value string, exists bool) { - r := regexp.MustCompile(`--format-disk ([^\s]+)`) - matches := r.FindAllStringSubmatch(command, -1) - matchValue := func() bool { - if matches == nil { - //empty format command - return false - } - for _, match := range matches { - if match[1] == value { - //found value in command - return true - } - } - return false - } - Expect(matchValue()).To(Equal(exists)) -} - -func quoteString(value string) string { - if strings.ContainsRune(value, '"') && !(strings.Index(value, "'") == 0) { - return fmt.Sprintf("'%s'", value) - } - return value +func verifyDiskFormatCommand(reply *models.Step, value string, exists bool) { + request := getRequest(reply) + contains := funk.ContainsString(request.DisksToFormat, value) + Expect(contains).To(Equal(exists)) } func createClusterInDb(db *gorm.DB, haMode string) common.Cluster { @@ -1097,7 +1050,7 @@ func postvalidation(isstepreplynil bool, issteperrnil bool, expectedstepreply *m ExpectWithOffset(1, expectedstepreply).Should(BeNil()) } else { ExpectWithOffset(1, expectedstepreply.StepType).To(Equal(models.StepTypeInstall)) - ExpectWithOffset(1, strings.Contains(expectedstepreply.Args[1], string(expectedrole))).To(Equal(true)) + ExpectWithOffset(1, strings.Contains(expectedstepreply.Args[0], string(expectedrole))).To(Equal(true)) } } @@ -1105,16 +1058,18 @@ func validateInstallCommand(installCmd *installCmd, reply *models.Step, role mod bootDevice string, bootableDisks []string, haMode string) { ExpectWithOffset(1, reply.StepType).To(Equal(models.StepTypeInstall)) mustGatherImage, _ := installCmd.getMustGatherArgument(defaultMustGatherVersion) - verifyArgInCommand(reply.Args[1], "--infra-env-id", string(infraEnvId), 1) - verifyArgInCommand(reply.Args[1], "--cluster-id", string(clusterId), 1) - verifyArgInCommand(reply.Args[1], "--host-id", string(hostId), 1) - verifyArgInCommand(reply.Args[1], "--high-availability-mode", haMode, 1) - verifyArgInCommand(reply.Args[1], "--openshift-version", common.TestDefaultConfig.OpenShiftVersion, 1) - verifyArgInCommand(reply.Args[1], "--role", string(role), 1) - verifyArgInCommand(reply.Args[1], "--boot-device", bootDevice, 1) - verifyArgInCommand(reply.Args[1], "--url", installCmd.instructionConfig.ServiceBaseURL, 1) - verifyArgInCommand(reply.Args[1], "--mco-image", defaultMCOImage, 1) - verifyArgInCommand(reply.Args[1], "--controller-image", installCmd.instructionConfig.ControllerImage, 1) - verifyArgInCommand(reply.Args[1], "--agent-image", installCmd.instructionConfig.AgentImage, 1) - verifyArgInCommand(reply.Args[1], "--must-gather-image", mustGatherImage, 1) + request := models.InstallCmdRequest{} + err := json.Unmarshal([]byte(reply.Args[0]), &request) + Expect(err).NotTo(HaveOccurred()) + Expect(request.InfraEnvID.String()).To(Equal(infraEnvId.String())) + Expect(request.ClusterID.String()).To(Equal(clusterId.String())) + Expect(request.HostID.String()).To(Equal(hostId.String())) + Expect(swag.StringValue(request.HighAvailabilityMode)).To(Equal(haMode)) + Expect(request.OpenshiftVersion).To(Equal(common.TestDefaultConfig.OpenShiftVersion)) + Expect(*request.Role).To(Equal(role)) + Expect(swag.StringValue(request.Bootdevice)).To(Equal(bootDevice)) + Expect(swag.StringValue(request.BaseURL)).To(Equal(installCmd.instructionConfig.ServiceBaseURL)) + Expect(request.McoImage).To(Equal(defaultMCOImage)) + Expect(swag.StringValue(request.ControllerImage)).To(Equal(installCmd.instructionConfig.ControllerImage)) + Expect(request.MustGatherImage).To(Equal(mustGatherImage)) } diff --git a/internal/host/hostcommands/instruction_manager_test.go b/internal/host/hostcommands/instruction_manager_test.go index ae64e9d7dc3..04fa71586d8 100644 --- a/internal/host/hostcommands/instruction_manager_test.go +++ b/internal/host/hostcommands/instruction_manager_test.go @@ -131,19 +131,19 @@ var _ = Describe("instruction_manager", func() { }) It("error", func() { checkStep(models.HostStatusError, []models.StepType{ - models.StepTypeExecute, models.StepTypeExecute, + models.StepTypeLogsGather, models.StepTypeStopInstallation, }) }) It("error with already uploades logs", func() { host.LogsCollectedAt = strfmt.DateTime(time.Now()) db.Save(&host) checkStep(models.HostStatusError, []models.StepType{ - models.StepTypeExecute, + models.StepTypeStopInstallation, }) }) It("cancelled", func() { checkStep(models.HostStatusCancelled, []models.StepType{ - models.StepTypeExecute, models.StepTypeExecute, + models.StepTypeLogsGather, models.StepTypeStopInstallation, }) }) It("installing", func() { @@ -224,12 +224,12 @@ var _ = Describe("instruction_manager", func() { }) It("error", func() { checkStep(models.HostStatusError, []models.StepType{ - models.StepTypeExecute, models.StepTypeExecute, + models.StepTypeLogsGather, models.StepTypeStopInstallation, }) }) It("cancelled", func() { checkStep(models.HostStatusCancelled, []models.StepType{ - models.StepTypeExecute, models.StepTypeExecute, + models.StepTypeLogsGather, models.StepTypeStopInstallation, }) }) It("installing", func() { @@ -344,7 +344,6 @@ var _ = Describe("instruction_manager", func() { }) It("Should filter out StepTypeDhcpLeaseAllocate when: HostState=installing DisabledSteps=execute,dhcp-lease-allocate.", func() { instMng = createInstMngWithDisabledSteps([]models.StepType{ - models.StepTypeExecute, models.StepTypeDhcpLeaseAllocate, }) checkStep(models.HostStatusInstalling, []models.StepType{ @@ -353,7 +352,8 @@ var _ = Describe("instruction_manager", func() { }) It("Should filter out StepTypeExecute (No steps) when: HostState=error DisabledSteps=execute.", func() { instMng = createInstMngWithDisabledSteps([]models.StepType{ - models.StepTypeExecute, + models.StepTypeLogsGather, + models.StepTypeStopInstallation, models.StepTypeDhcpLeaseAllocate, }) checkStep(models.HostStatusError, []models.StepType{}) diff --git a/internal/host/hostcommands/logs_cmd.go b/internal/host/hostcommands/logs_cmd.go index b81b8d826a2..2407b8f7c35 100644 --- a/internal/host/hostcommands/logs_cmd.go +++ b/internal/host/hostcommands/logs_cmd.go @@ -1,13 +1,10 @@ package hostcommands import ( - "bytes" "context" "encoding/json" "net" - "strconv" "strings" - "text/template" "time" "github.com/go-openapi/swag" @@ -32,87 +29,57 @@ func NewLogsCmd(log logrus.FieldLogger, db *gorm.DB, instructionConfig Instructi } } -func (i *logsCmd) GetSteps(ctx context.Context, host *models.Host) ([]*models.Step, error) { - // added to run upload logs if install command fails - if !time.Time(host.LogsCollectedAt).Equal(time.Time{}) { - return nil, nil - } - +func (i *logsCmd) prepareParam(ctx context.Context, host *models.Host) (string, error) { var mastersIPs []string var err error if host.Bootstrap { mastersIPs, err = i.getNonBootstrapMastersIPsInHostCluster(ctx, host) if err != nil { i.log.WithError(err).Errorf("Failed to get non-bootstrap masters IPs from cluster %s", host.ClusterID) - return nil, err + return "", err } } - logsCommand, err := i.createUploadLogsCmd(host, i.instructionConfig.ServiceBaseURL, - i.instructionConfig.AgentImage, strings.Join(mastersIPs, ","), - i.instructionConfig.SkipCertVerification, false, true) - if err != nil { - return nil, err - } - logsCommandAsArgs := strings.Fields(logsCommand) - step := &models.Step{ - StepType: models.StepTypeExecute, - Command: logsCommandAsArgs[0], - Args: logsCommandAsArgs[1:], - } - - return []*models.Step{step}, nil -} - -func (i *logsCmd) createUploadLogsCmd(host *models.Host, baseURL, agentImage, mastersIPs string, skipCertVerification, preservePreviousCommandReturnCode, - withInstallerGatherLogging bool) (string, error) { - - cmdArgsTmpl := "" - if preservePreviousCommandReturnCode { - cmdArgsTmpl = "( returnCode=$?; " + request := models.LogsGatherCmdRequest{ + BaseURL: swag.String(strings.TrimSpace(i.instructionConfig.ServiceBaseURL)), + ClusterID: host.ClusterID, + HostID: host.ID, + InfraEnvID: &host.InfraEnvID, + Insecure: swag.Bool(i.instructionConfig.SkipCertVerification), + Bootstrap: swag.Bool(host.Bootstrap), + InstallerGather: true, + MasterIps: mastersIPs, } - data := map[string]string{ - "BASE_URL": strings.TrimSpace(baseURL), - "CLUSTER_ID": host.ClusterID.String(), - "HOST_ID": host.ID.String(), - "INFRA_ENV_ID": host.InfraEnvID.String(), - "AGENT_IMAGE": strings.TrimSpace(agentImage), - "SKIP_CERT_VERIFICATION": strconv.FormatBool(skipCertVerification), - "BOOTSTRAP": strconv.FormatBool(host.Bootstrap), - "INSTALLER_GATHER": strconv.FormatBool(withInstallerGatherLogging), - "MASTERS_IPS": mastersIPs, + if i.instructionConfig.ServiceCACertPath != "" { + request.CaCertPath = common.HostCACertPath } - if i.instructionConfig.ServiceCACertPath != "" { - data["CACERTPATH"] = common.HostCACertPath + b, err := json.Marshal(&request) + if err != nil { + i.log.WithError(err).Warn("Json marshal") + return "", err } + return string(b), nil +} - cmdArgsTmpl += "timeout 1h podman run --rm --privileged --net=host " + - "-v /run/systemd/journal/socket:/run/systemd/journal/socket -v /var/log:/var/log -v /etc/pki:/etc/pki " + - "{{if .CACERTPATH}} -v {{.CACERTPATH}}:{{.CACERTPATH}} {{end}}" + - "{{if eq .BOOTSTRAP `true`}} -v /root/.ssh:/root/.ssh -v /tmp:/tmp {{end}}" + - "--env PULL_SECRET_TOKEN --name logs-sender --pid=host {{.AGENT_IMAGE}} logs_sender " + - "-url {{.BASE_URL}} -cluster-id {{.CLUSTER_ID}} -host-id {{.HOST_ID}} -infra-env-id {{.INFRA_ENV_ID}} " + - "--insecure={{.SKIP_CERT_VERIFICATION}} -bootstrap={{.BOOTSTRAP}} -with-installer-gather-logging={{.INSTALLER_GATHER}}" + - "{{if .MASTERS_IPS}} -masters-ips={{.MASTERS_IPS}} {{end}}" + - "{{if .CACERTPATH}} --cacert {{.CACERTPATH}} {{end}}" - - if preservePreviousCommandReturnCode { - cmdArgsTmpl = cmdArgsTmpl + "; exit $returnCode; )" +func (i *logsCmd) GetSteps(ctx context.Context, host *models.Host) ([]*models.Step, error) { + // added to run upload logs if install command fails + if !time.Time(host.LogsCollectedAt).Equal(time.Time{}) { + return nil, nil } - t, err := template.New("cmd").Parse(cmdArgsTmpl) + logsCommandAsArgs, err := i.prepareParam(ctx, host) if err != nil { - return "", err + return nil, err } - - buf := &bytes.Buffer{} - if err := t.Execute(buf, data); err != nil { - return "", err + step := &models.Step{ + StepType: models.StepTypeLogsGather, + Command: "", + Args: []string{logsCommandAsArgs}, } - return buf.String(), nil + return []*models.Step{step}, nil } func (i *logsCmd) getNonBootstrapMastersIPsInHostCluster(ctx context.Context, host *models.Host) ([]string, error) { diff --git a/internal/host/hostcommands/next_step_runner_cmd.go b/internal/host/hostcommands/next_step_runner_cmd.go index 8df2b1624e3..c360bce6b8b 100644 --- a/internal/host/hostcommands/next_step_runner_cmd.go +++ b/internal/host/hostcommands/next_step_runner_cmd.go @@ -1,48 +1,44 @@ package hostcommands import ( - "fmt" - "strconv" + "encoding/json" "strings" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" "github.com/openshift/assisted-service/internal/common" + "github.com/openshift/assisted-service/models" + log "github.com/sirupsen/logrus" ) type NextStepRunnerConfig struct { ServiceBaseURL string - InfraEnvID string - HostID string + InfraEnvID strfmt.UUID + HostID strfmt.UUID UseCustomCACert bool NextStepRunnerImage string SkipCertVerification bool } -func GetNextStepRunnerCommand(config *NextStepRunnerConfig) (string, *[]string) { - - arguments := []string{"run", "--rm", "-ti", "--privileged", "--pid=host", "--net=host", - "-v", "/dev:/dev:rw", "-v", "/opt:/opt:rw", - "-v", "/run/systemd/journal/socket:/run/systemd/journal/socket", - "-v", "/var/log:/var/log:rw", - "-v", "/run/media:/run/media:rw", - "-v", "/etc/pki:/etc/pki"} +func GetNextStepRunnerCommand(config *NextStepRunnerConfig) (string, *[]string, error) { + request := models.NextStepCmdRequest{ + InfraEnvID: &config.InfraEnvID, + HostID: &config.HostID, + Insecure: swag.Bool(config.SkipCertVerification), + BaseURL: swag.String(strings.TrimSpace(config.ServiceBaseURL)), + AgentVersion: swag.String(config.NextStepRunnerImage), + } if config.UseCustomCACert { - arguments = append(arguments, "-v", fmt.Sprintf("%s:%s", common.HostCACertPath, common.HostCACertPath)) + request.CaCertPath = common.HostCACertPath } - arguments = append(arguments, - "--env", "PULL_SECRET_TOKEN", - "--env", "CONTAINERS_CONF", - "--env", "CONTAINERS_STORAGE_CONF", - "--env", "HTTP_PROXY", "--env", "HTTPS_PROXY", "--env", "NO_PROXY", - "--env", "http_proxy", "--env", "https_proxy", "--env", "no_proxy", - "--name", "next-step-runner", config.NextStepRunnerImage, "next_step_runner", - "--url", strings.TrimSpace(config.ServiceBaseURL), "--infra-env-id", config.InfraEnvID, "--host-id", config.HostID, - "--agent-version", config.NextStepRunnerImage, fmt.Sprintf("--insecure=%s", strconv.FormatBool(config.SkipCertVerification))) - - if config.UseCustomCACert { - arguments = append(arguments, "--cacert", common.HostCACertPath) + b, err := json.Marshal(&request) + if err != nil { + log.WithError(err).Warn("Json marshal") + return "", nil, err } + arguments := []string{string(b)} - return "podman", &arguments + return "", &arguments, nil } diff --git a/internal/host/hostcommands/next_step_runner_cmd_test.go b/internal/host/hostcommands/next_step_runner_cmd_test.go index 70877403537..af95fb9289a 100644 --- a/internal/host/hostcommands/next_step_runner_cmd_test.go +++ b/internal/host/hostcommands/next_step_runner_cmd_test.go @@ -1,23 +1,33 @@ package hostcommands import ( + "encoding/json" "fmt" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" "github.com/google/uuid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/openshift/assisted-service/internal/common" + "github.com/openshift/assisted-service/models" ) +func getNextStepRequest(args []string) *models.NextStepCmdRequest { + request := models.NextStepCmdRequest{} + err := json.Unmarshal([]byte(args[0]), &request) + Expect(err).NotTo(HaveOccurred()) + return &request +} + var _ = Describe("Format command for starting next step agent", func() { var config NextStepRunnerConfig - infraEnvId := uuid.New().String() - hostID := uuid.New().String() + infraEnvId := strfmt.UUID(uuid.New().String()) + hostID := strfmt.UUID(uuid.New().String()) serviceURL := uuid.New().String() image := uuid.New().String() - certVolume := fmt.Sprintf("%s:%s", common.HostCACertPath, common.HostCACertPath) BeforeEach(func() { config = NextStepRunnerConfig{ @@ -29,70 +39,56 @@ var _ = Describe("Format command for starting next step agent", func() { It("standard formatting", func() { config.ServiceBaseURL = serviceURL - command, args := GetNextStepRunnerCommand(&config) - Expect(command).Should(Equal("podman")) - assertValue("--infra-env-id", infraEnvId, *args) - assertValue("--host-id", hostID, *args) - assertValue("--url", serviceURL, *args) - assertValue("--agent-version", image, *args) - Expect(*args).ShouldNot(ContainElement("--cacert")) - Expect(*args).ShouldNot(ContainElement(certVolume)) - Expect(*args).Should(ContainElement("/etc/pki:/etc/pki")) - Expect(*args).Should(ContainElement("--insecure=false")) - Expect(*args).ShouldNot(ContainElement("--insecure=true")) + command, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + Expect(command).Should(Equal("")) + request := getNextStepRequest(*args) + Expect(swag.BoolValue(request.Insecure)).Should(BeFalse()) + Expect(request.HostID.String()).Should(Equal(hostID.String())) + Expect(request.InfraEnvID.String()).Should(Equal(infraEnvId.String())) + Expect(swag.StringValue(request.BaseURL)).Should(Equal(serviceURL)) + Expect(request.CaCertPath).Should(BeEmpty()) + Expect(swag.StringValue(request.AgentVersion)).Should(Equal(image)) }) It("trim service URL", func() { config.ServiceBaseURL = fmt.Sprintf(" %s ", serviceURL) Expect(config.ServiceBaseURL).ShouldNot(Equal(serviceURL)) - _, args := GetNextStepRunnerCommand(&config) - assertValue("--url", serviceURL, *args) + _, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + request := getNextStepRequest(*args) + Expect(swag.StringValue(request.BaseURL)).Should(Equal(serviceURL)) }) It("without custom CA certificate", func() { config.UseCustomCACert = false - _, args := GetNextStepRunnerCommand(&config) - - Expect(*args).ShouldNot(ContainElement("--cacert")) - Expect(*args).ShouldNot(ContainElement(certVolume)) + _, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + request := getNextStepRequest(*args) + Expect(request.CaCertPath).Should(BeEmpty()) }) It("with custom CA certificate", func() { config.UseCustomCACert = true - _, args := GetNextStepRunnerCommand(&config) - assertValue("--cacert", common.HostCACertPath, *args) - Expect(*args).Should(ContainElement(certVolume)) + _, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + request := getNextStepRequest(*args) + Expect(request.CaCertPath).Should(Equal(common.HostCACertPath)) }) It("certificate verification on", func() { config.SkipCertVerification = false - _, args := GetNextStepRunnerCommand(&config) - Expect(*args).Should(ContainElement("--insecure=false")) - Expect(*args).ShouldNot(ContainElement("--insecure=true")) + _, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + request := getNextStepRequest(*args) + Expect(swag.BoolValue(request.Insecure)).Should(BeFalse()) }) It("certificate verification off", func() { config.SkipCertVerification = true - _, args := GetNextStepRunnerCommand(&config) - Expect(*args).Should(ContainElement("--insecure=true")) - Expect(*args).ShouldNot(ContainElement("--insecure=false")) + _, args, err := GetNextStepRunnerCommand(&config) + Expect(err).ToNot(HaveOccurred()) + request := getNextStepRequest(*args) + Expect(swag.BoolValue(request.Insecure)).Should(BeTrue()) }) }) - -func assertValue(key string, value string, args []string) { - i := search(key, args) - Expect(i).Should(BeNumerically(">", -1)) - Expect(i).Should(BeNumerically("<", len(args)-1)) - Expect(args[i+1]).Should(Equal(value)) -} - -func search(term string, s []string) int { - - for i, v := range s { - if v == term { - return i - } - } - - return -1 -} diff --git a/internal/host/hostcommands/stop_installation_cmd.go b/internal/host/hostcommands/stop_installation_cmd.go index 5c31cc08dce..bd316794b7a 100644 --- a/internal/host/hostcommands/stop_installation_cmd.go +++ b/internal/host/hostcommands/stop_installation_cmd.go @@ -18,14 +18,10 @@ func NewStopInstallationCmd(log logrus.FieldLogger) *stopInstallationCmd { } func (h *stopInstallationCmd) GetSteps(ctx context.Context, host *models.Host) ([]*models.Step, error) { - command := "/usr/bin/podman" - step := &models.Step{ - StepType: models.StepTypeExecute, - Command: command, - Args: []string{ - "stop", "-i", "-t", "5", "assisted-installer", - }, + StepType: models.StepTypeStopInstallation, + Command: "", + Args: []string{}, } return []*models.Step{step}, nil diff --git a/internal/host/hostcommands/stop_installation_cmd_test.go b/internal/host/hostcommands/stop_installation_cmd_test.go index d23c5982780..72debbd578a 100644 --- a/internal/host/hostcommands/stop_installation_cmd_test.go +++ b/internal/host/hostcommands/stop_installation_cmd_test.go @@ -36,7 +36,7 @@ var _ = Describe("stop-podman", func() { It("get_step", func() { stepReply, stepErr = stopCmd.GetSteps(ctx, &host) - Expect(stepReply[0].StepType).To(Equal(models.StepTypeExecute)) + Expect(stepReply[0].StepType).To(Equal(models.StepTypeStopInstallation)) Expect(stepErr).ShouldNot(HaveOccurred()) }) diff --git a/models/install_cmd_request.go b/models/install_cmd_request.go new file mode 100644 index 00000000000..4bd13b9c6f2 --- /dev/null +++ b/models/install_cmd_request.go @@ -0,0 +1,408 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// InstallCmdRequest install cmd request +// +// swagger:model install_cmd_request +type InstallCmdRequest struct { + + // Service base url to send logs to + // Required: true + BaseURL *string `json:"base_url"` + + // Boot device to write image on + // Required: true + Bootdevice *string `json:"bootdevice"` + + // Path to certificate on the nodes + CaCertPath string `json:"ca_cert_path,omitempty"` + + // Check CVO status if needed + CheckCvo *bool `json:"check_cvo,omitempty"` + + // Cluster id + // Required: true + // Format: uuid + ClusterID *strfmt.UUID `json:"cluster_id"` + + // Assisted installer controller image + // Required: true + ControllerImage *string `json:"controller_image"` + + // List of disks to format + DisksToFormat []string `json:"disks_to_format"` + + // Guaranteed availability of the installed cluster. 'Full' installs a Highly-Available cluster + // over multiple master nodes whereas 'None' installs a full cluster over one node. + // + // Required: true + // Enum: [Full None] + HighAvailabilityMode *string `json:"high_availability_mode"` + + // Host id + // Required: true + // Format: uuid + HostID *strfmt.UUID `json:"host_id"` + + // Infra env id + // Required: true + // Format: uuid + InfraEnvID *strfmt.UUID `json:"infra_env_id"` + + // Skip ceritifacate verification + // Required: true + Insecure *bool `json:"insecure"` + + // Core-os installer addtional args + InstallerArgs string `json:"installer_args,omitempty"` + + // Assisted installer image + // Required: true + InstallerImage *string `json:"installer_image"` + + // Machine config operator image + McoImage string `json:"mco_image,omitempty"` + + // Must-gather images to use + MustGatherImage string `json:"must_gather_image,omitempty"` + + // Version of the OpenShift cluster. + OpenshiftVersion string `json:"openshift_version,omitempty"` + + // proxy + Proxy *Proxy `json:"proxy,omitempty" gorm:"embedded;embeddedPrefix:proxy_"` + + // role + // Required: true + Role *HostRole `json:"role"` + + // List of service ips + ServiceIps []string `json:"service_ips"` +} + +// Validate validates this install cmd request +func (m *InstallCmdRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateBaseURL(formats); err != nil { + res = append(res, err) + } + + if err := m.validateBootdevice(formats); err != nil { + res = append(res, err) + } + + if err := m.validateClusterID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateControllerImage(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHighAvailabilityMode(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHostID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInfraEnvID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInsecure(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInstallerImage(formats); err != nil { + res = append(res, err) + } + + if err := m.validateProxy(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRole(formats); err != nil { + res = append(res, err) + } + + if err := m.validateServiceIps(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InstallCmdRequest) validateBaseURL(formats strfmt.Registry) error { + + if err := validate.Required("base_url", "body", m.BaseURL); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateBootdevice(formats strfmt.Registry) error { + + if err := validate.Required("bootdevice", "body", m.Bootdevice); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateClusterID(formats strfmt.Registry) error { + + if err := validate.Required("cluster_id", "body", m.ClusterID); err != nil { + return err + } + + if err := validate.FormatOf("cluster_id", "body", "uuid", m.ClusterID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateControllerImage(formats strfmt.Registry) error { + + if err := validate.Required("controller_image", "body", m.ControllerImage); err != nil { + return err + } + + return nil +} + +var installCmdRequestTypeHighAvailabilityModePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["Full","None"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + installCmdRequestTypeHighAvailabilityModePropEnum = append(installCmdRequestTypeHighAvailabilityModePropEnum, v) + } +} + +const ( + + // InstallCmdRequestHighAvailabilityModeFull captures enum value "Full" + InstallCmdRequestHighAvailabilityModeFull string = "Full" + + // InstallCmdRequestHighAvailabilityModeNone captures enum value "None" + InstallCmdRequestHighAvailabilityModeNone string = "None" +) + +// prop value enum +func (m *InstallCmdRequest) validateHighAvailabilityModeEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, installCmdRequestTypeHighAvailabilityModePropEnum, true); err != nil { + return err + } + return nil +} + +func (m *InstallCmdRequest) validateHighAvailabilityMode(formats strfmt.Registry) error { + + if err := validate.Required("high_availability_mode", "body", m.HighAvailabilityMode); err != nil { + return err + } + + // value enum + if err := m.validateHighAvailabilityModeEnum("high_availability_mode", "body", *m.HighAvailabilityMode); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateHostID(formats strfmt.Registry) error { + + if err := validate.Required("host_id", "body", m.HostID); err != nil { + return err + } + + if err := validate.FormatOf("host_id", "body", "uuid", m.HostID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateInfraEnvID(formats strfmt.Registry) error { + + if err := validate.Required("infra_env_id", "body", m.InfraEnvID); err != nil { + return err + } + + if err := validate.FormatOf("infra_env_id", "body", "uuid", m.InfraEnvID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateInsecure(formats strfmt.Registry) error { + + if err := validate.Required("insecure", "body", m.Insecure); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateInstallerImage(formats strfmt.Registry) error { + + if err := validate.Required("installer_image", "body", m.InstallerImage); err != nil { + return err + } + + return nil +} + +func (m *InstallCmdRequest) validateProxy(formats strfmt.Registry) error { + if swag.IsZero(m.Proxy) { // not required + return nil + } + + if m.Proxy != nil { + if err := m.Proxy.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("proxy") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("proxy") + } + return err + } + } + + return nil +} + +func (m *InstallCmdRequest) validateRole(formats strfmt.Registry) error { + + if err := validate.Required("role", "body", m.Role); err != nil { + return err + } + + if err := validate.Required("role", "body", m.Role); err != nil { + return err + } + + if m.Role != nil { + if err := m.Role.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("role") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("role") + } + return err + } + } + + return nil +} + +func (m *InstallCmdRequest) validateServiceIps(formats strfmt.Registry) error { + if swag.IsZero(m.ServiceIps) { // not required + return nil + } + + for i := 0; i < len(m.ServiceIps); i++ { + + if err := validate.Pattern("service_ips"+"."+strconv.Itoa(i), "body", m.ServiceIps[i], `^(?:(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$`); err != nil { + return err + } + + } + + return nil +} + +// ContextValidate validate this install cmd request based on the context it is used +func (m *InstallCmdRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateProxy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRole(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *InstallCmdRequest) contextValidateProxy(ctx context.Context, formats strfmt.Registry) error { + + if m.Proxy != nil { + if err := m.Proxy.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("proxy") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("proxy") + } + return err + } + } + + return nil +} + +func (m *InstallCmdRequest) contextValidateRole(ctx context.Context, formats strfmt.Registry) error { + + if m.Role != nil { + if err := m.Role.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("role") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("role") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *InstallCmdRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *InstallCmdRequest) UnmarshalBinary(b []byte) error { + var res InstallCmdRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/logs_gather_cmd_request.go b/models/logs_gather_cmd_request.go new file mode 100644 index 00000000000..538b3817d36 --- /dev/null +++ b/models/logs_gather_cmd_request.go @@ -0,0 +1,215 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// LogsGatherCmdRequest logs gather cmd request +// +// swagger:model logs_gather_cmd_request +type LogsGatherCmdRequest struct { + + // Service base url to send logs to + // Required: true + BaseURL *string `json:"base_url"` + + // Host is bootstrap or not + // Required: true + Bootstrap *bool `json:"bootstrap"` + + // Path to certificate on the nodes + CaCertPath string `json:"ca_cert_path,omitempty"` + + // Cluster id + // Required: true + // Format: uuid + ClusterID *strfmt.UUID `json:"cluster_id"` + + // Host id + // Required: true + // Format: uuid + HostID *strfmt.UUID `json:"host_id"` + + // Infra env id + // Required: true + // Format: uuid + InfraEnvID *strfmt.UUID `json:"infra_env_id"` + + // Skip ceritifacate verification + // Required: true + Insecure *bool `json:"insecure"` + + // Run installer gather logs + // Required: true + InstallerGather bool `json:"installer_gather"` + + // List of master ips + MasterIps []string `json:"master_ips"` +} + +// Validate validates this logs gather cmd request +func (m *LogsGatherCmdRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateBaseURL(formats); err != nil { + res = append(res, err) + } + + if err := m.validateBootstrap(formats); err != nil { + res = append(res, err) + } + + if err := m.validateClusterID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHostID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInfraEnvID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInsecure(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInstallerGather(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMasterIps(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *LogsGatherCmdRequest) validateBaseURL(formats strfmt.Registry) error { + + if err := validate.Required("base_url", "body", m.BaseURL); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateBootstrap(formats strfmt.Registry) error { + + if err := validate.Required("bootstrap", "body", m.Bootstrap); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateClusterID(formats strfmt.Registry) error { + + if err := validate.Required("cluster_id", "body", m.ClusterID); err != nil { + return err + } + + if err := validate.FormatOf("cluster_id", "body", "uuid", m.ClusterID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateHostID(formats strfmt.Registry) error { + + if err := validate.Required("host_id", "body", m.HostID); err != nil { + return err + } + + if err := validate.FormatOf("host_id", "body", "uuid", m.HostID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateInfraEnvID(formats strfmt.Registry) error { + + if err := validate.Required("infra_env_id", "body", m.InfraEnvID); err != nil { + return err + } + + if err := validate.FormatOf("infra_env_id", "body", "uuid", m.InfraEnvID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateInsecure(formats strfmt.Registry) error { + + if err := validate.Required("insecure", "body", m.Insecure); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateInstallerGather(formats strfmt.Registry) error { + + if err := validate.Required("installer_gather", "body", bool(m.InstallerGather)); err != nil { + return err + } + + return nil +} + +func (m *LogsGatherCmdRequest) validateMasterIps(formats strfmt.Registry) error { + if swag.IsZero(m.MasterIps) { // not required + return nil + } + + for i := 0; i < len(m.MasterIps); i++ { + + if err := validate.Pattern("master_ips"+"."+strconv.Itoa(i), "body", m.MasterIps[i], `^(?:(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$`); err != nil { + return err + } + + } + + return nil +} + +// ContextValidate validates this logs gather cmd request based on context it is used +func (m *LogsGatherCmdRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *LogsGatherCmdRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *LogsGatherCmdRequest) UnmarshalBinary(b []byte) error { + var res LogsGatherCmdRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/next_step_cmd_request.go b/models/next_step_cmd_request.go new file mode 100644 index 00000000000..edf1fe88cc8 --- /dev/null +++ b/models/next_step_cmd_request.go @@ -0,0 +1,152 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// NextStepCmdRequest next step cmd request +// +// swagger:model next_step_cmd_request +type NextStepCmdRequest struct { + + // Agent image version + // Required: true + AgentVersion *string `json:"agent_version"` + + // Service base url to connect + // Required: true + BaseURL *string `json:"base_url"` + + // Path to certificate on the nodes + CaCertPath string `json:"ca_cert_path,omitempty"` + + // Host id + // Required: true + // Format: uuid + HostID *strfmt.UUID `json:"host_id"` + + // Infra env id + // Required: true + // Format: uuid + InfraEnvID *strfmt.UUID `json:"infra_env_id"` + + // Skip ceritifacate verification + // Required: true + Insecure *bool `json:"insecure"` +} + +// Validate validates this next step cmd request +func (m *NextStepCmdRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAgentVersion(formats); err != nil { + res = append(res, err) + } + + if err := m.validateBaseURL(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHostID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInfraEnvID(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInsecure(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *NextStepCmdRequest) validateAgentVersion(formats strfmt.Registry) error { + + if err := validate.Required("agent_version", "body", m.AgentVersion); err != nil { + return err + } + + return nil +} + +func (m *NextStepCmdRequest) validateBaseURL(formats strfmt.Registry) error { + + if err := validate.Required("base_url", "body", m.BaseURL); err != nil { + return err + } + + return nil +} + +func (m *NextStepCmdRequest) validateHostID(formats strfmt.Registry) error { + + if err := validate.Required("host_id", "body", m.HostID); err != nil { + return err + } + + if err := validate.FormatOf("host_id", "body", "uuid", m.HostID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *NextStepCmdRequest) validateInfraEnvID(formats strfmt.Registry) error { + + if err := validate.Required("infra_env_id", "body", m.InfraEnvID); err != nil { + return err + } + + if err := validate.FormatOf("infra_env_id", "body", "uuid", m.InfraEnvID.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *NextStepCmdRequest) validateInsecure(formats strfmt.Registry) error { + + if err := validate.Required("insecure", "body", m.Insecure); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this next step cmd request based on context it is used +func (m *NextStepCmdRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *NextStepCmdRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *NextStepCmdRequest) UnmarshalBinary(b []byte) error { + var res NextStepCmdRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/step_type.go b/models/step_type.go index f332e90cfd5..dd76dbcf6e0 100644 --- a/models/step_type.go +++ b/models/step_type.go @@ -61,6 +61,15 @@ const ( // StepTypeDomainResolution captures enum value "domain-resolution" StepTypeDomainResolution StepType = "domain-resolution" + + // StepTypeStopInstallation captures enum value "stop-installation" + StepTypeStopInstallation StepType = "stop-installation" + + // StepTypeLogsGather captures enum value "logs-gather" + StepTypeLogsGather StepType = "logs-gather" + + // StepTypeNextStepRunner captures enum value "next-step-runner" + StepTypeNextStepRunner StepType = "next-step-runner" ) // for schema @@ -68,7 +77,7 @@ var stepTypeEnum []interface{} func init() { var res []StepType - if err := json.Unmarshal([]byte(`["connectivity-check","execute","inventory","install","free-network-addresses","reset-installation","dhcp-lease-allocate","api-vip-connectivity-check","ntp-synchronizer","installation-disk-speed-check","container-image-availability","domain-resolution"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["connectivity-check","execute","inventory","install","free-network-addresses","reset-installation","dhcp-lease-allocate","api-vip-connectivity-check","ntp-synchronizer","installation-disk-speed-check","container-image-availability","domain-resolution","stop-installation","logs-gather","next-step-runner"]`), &res); err != nil { panic(err) } for _, v := range res { diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index 6161760b514..70560c40a65 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -7477,6 +7477,115 @@ func init() { "ingress-cert-params": { "type": "string" }, + "install_cmd_request": { + "type": "object", + "required": [ + "cluster_id", + "infra_env_id", + "host_id", + "insecure", + "base_url", + "role", + "bootdevice", + "controller_image", + "installer_image", + "high_availability_mode" + ], + "properties": { + "base_url": { + "description": "Service base url to send logs to", + "type": "string" + }, + "bootdevice": { + "description": "Boot device to write image on", + "type": "string" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "check_cvo": { + "description": "Check CVO status if needed", + "type": "boolean", + "default": true + }, + "cluster_id": { + "description": "Cluster id", + "type": "string", + "format": "uuid" + }, + "controller_image": { + "description": "Assisted installer controller image", + "type": "string" + }, + "disks_to_format": { + "description": "List of disks to format", + "type": "array", + "items": { + "description": "Disk to format", + "type": "string" + } + }, + "high_availability_mode": { + "description": "Guaranteed availability of the installed cluster. 'Full' installs a Highly-Available cluster\nover multiple master nodes whereas 'None' installs a full cluster over one node.\n", + "type": "string", + "default": "Full", + "enum": [ + "Full", + "None" + ] + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + }, + "installer_args": { + "description": "Core-os installer addtional args", + "type": "string" + }, + "installer_image": { + "description": "Assisted installer image", + "type": "string" + }, + "mco_image": { + "description": "Machine config operator image", + "type": "string" + }, + "must_gather_image": { + "description": "Must-gather images to use", + "type": "string" + }, + "openshift_version": { + "description": "Version of the OpenShift cluster.", + "type": "string" + }, + "proxy": { + "$ref": "#/definitions/proxy" + }, + "role": { + "$ref": "#/definitions/host-role" + }, + "service_ips": { + "description": "List of service ips", + "type": "array", + "items": { + "description": "Service ip.", + "type": "string", + "pattern": "^(?:(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$" + } + } + } + }, "installer-args-params": { "type": "object", "properties": { @@ -7696,6 +7805,65 @@ func init() { } } }, + "logs_gather_cmd_request": { + "type": "object", + "required": [ + "cluster_id", + "infra_env_id", + "host_id", + "insecure", + "base_url", + "bootstrap", + "installer_gather" + ], + "properties": { + "base_url": { + "description": "Service base url to send logs to", + "type": "string" + }, + "bootstrap": { + "description": "Host is bootstrap or not", + "type": "boolean" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "cluster_id": { + "description": "Cluster id", + "type": "string", + "format": "uuid" + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + }, + "installer_gather": { + "description": "Run installer gather logs", + "type": "boolean", + "default": true + }, + "master_ips": { + "description": "List of master ips", + "type": "array", + "items": { + "description": "Master ip.", + "type": "string", + "pattern": "^(?:(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$" + } + } + } + }, "logs_state": { "type": "string", "enum": [ @@ -7858,6 +8026,44 @@ func init() { "$ref": "#/definitions/monitored-operator" } }, + "next_step_cmd_request": { + "type": "object", + "required": [ + "infra_env_id", + "host_id", + "insecure", + "base_url", + "agent_version" + ], + "properties": { + "agent_version": { + "description": "Agent image version", + "type": "string" + }, + "base_url": { + "description": "Service base url to connect", + "type": "string" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + } + } + }, "ntp_source": { "type": "object", "properties": { @@ -8386,7 +8592,10 @@ func init() { "ntp-synchronizer", "installation-disk-speed-check", "container-image-availability", - "domain-resolution" + "domain-resolution", + "stop-installation", + "logs-gather", + "next-step-runner" ] }, "steps": { @@ -16251,6 +16460,115 @@ func init() { "ingress-cert-params": { "type": "string" }, + "install_cmd_request": { + "type": "object", + "required": [ + "cluster_id", + "infra_env_id", + "host_id", + "insecure", + "base_url", + "role", + "bootdevice", + "controller_image", + "installer_image", + "high_availability_mode" + ], + "properties": { + "base_url": { + "description": "Service base url to send logs to", + "type": "string" + }, + "bootdevice": { + "description": "Boot device to write image on", + "type": "string" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "check_cvo": { + "description": "Check CVO status if needed", + "type": "boolean", + "default": true + }, + "cluster_id": { + "description": "Cluster id", + "type": "string", + "format": "uuid" + }, + "controller_image": { + "description": "Assisted installer controller image", + "type": "string" + }, + "disks_to_format": { + "description": "List of disks to format", + "type": "array", + "items": { + "description": "Disk to format", + "type": "string" + } + }, + "high_availability_mode": { + "description": "Guaranteed availability of the installed cluster. 'Full' installs a Highly-Available cluster\nover multiple master nodes whereas 'None' installs a full cluster over one node.\n", + "type": "string", + "default": "Full", + "enum": [ + "Full", + "None" + ] + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + }, + "installer_args": { + "description": "Core-os installer addtional args", + "type": "string" + }, + "installer_image": { + "description": "Assisted installer image", + "type": "string" + }, + "mco_image": { + "description": "Machine config operator image", + "type": "string" + }, + "must_gather_image": { + "description": "Must-gather images to use", + "type": "string" + }, + "openshift_version": { + "description": "Version of the OpenShift cluster.", + "type": "string" + }, + "proxy": { + "$ref": "#/definitions/proxy" + }, + "role": { + "$ref": "#/definitions/host-role" + }, + "service_ips": { + "description": "List of service ips", + "type": "array", + "items": { + "description": "Service ip.", + "type": "string", + "pattern": "^(?:(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$" + } + } + } + }, "installer-args-params": { "type": "object", "properties": { @@ -16470,6 +16788,65 @@ func init() { } } }, + "logs_gather_cmd_request": { + "type": "object", + "required": [ + "cluster_id", + "infra_env_id", + "host_id", + "insecure", + "base_url", + "bootstrap", + "installer_gather" + ], + "properties": { + "base_url": { + "description": "Service base url to send logs to", + "type": "string" + }, + "bootstrap": { + "description": "Host is bootstrap or not", + "type": "boolean" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "cluster_id": { + "description": "Cluster id", + "type": "string", + "format": "uuid" + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + }, + "installer_gather": { + "description": "Run installer gather logs", + "type": "boolean", + "default": true + }, + "master_ips": { + "description": "List of master ips", + "type": "array", + "items": { + "description": "Master ip.", + "type": "string", + "pattern": "^(?:(?:(?:[0-9]{1,3}\\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$" + } + } + } + }, "logs_state": { "type": "string", "enum": [ @@ -16621,6 +16998,44 @@ func init() { "$ref": "#/definitions/monitored-operator" } }, + "next_step_cmd_request": { + "type": "object", + "required": [ + "infra_env_id", + "host_id", + "insecure", + "base_url", + "agent_version" + ], + "properties": { + "agent_version": { + "description": "Agent image version", + "type": "string" + }, + "base_url": { + "description": "Service base url to connect", + "type": "string" + }, + "ca_cert_path": { + "description": "Path to certificate on the nodes", + "type": "string" + }, + "host_id": { + "description": "Host id", + "type": "string", + "format": "uuid" + }, + "infra_env_id": { + "description": "Infra env id", + "type": "string", + "format": "uuid" + }, + "insecure": { + "description": "Skip ceritifacate verification", + "type": "boolean" + } + } + }, "ntp_source": { "type": "object", "properties": { @@ -17149,7 +17564,10 @@ func init() { "ntp-synchronizer", "installation-disk-speed-check", "container-image-availability", - "domain-resolution" + "domain-resolution", + "stop-installation", + "logs-gather", + "next-step-runner" ] }, "steps": { diff --git a/swagger.yaml b/swagger.yaml index 404d04916e9..aa103f17eae 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -4012,6 +4012,9 @@ definitions: - installation-disk-speed-check - container-image-availability - domain-resolution + - stop-installation + - logs-gather + - next-step-runner step: type: object @@ -5526,6 +5529,170 @@ definitions: type: string description: Contents of last acquired lease for Ingress virtual IP. + next_step_cmd_request: + type: object + required: + - infra_env_id + - host_id + - insecure + - base_url + - agent_version + properties: + infra_env_id: + type: string + format: uuid + description: Infra env id + host_id: + type: string + format: uuid + description: Host id + insecure: + type: boolean + description: Skip ceritifacate verification + base_url: + type: string + description: Service base url to connect + ca_cert_path: + type: string + description: Path to certificate on the nodes + agent_version: + type: string + description: Agent image version + + logs_gather_cmd_request: + type: object + required: + - cluster_id + - infra_env_id + - host_id + - insecure + - base_url + - bootstrap + - installer_gather + properties: + cluster_id: + type: string + format: uuid + description: Cluster id + infra_env_id: + type: string + format: uuid + description: Infra env id + host_id: + type: string + format: uuid + description: Host id + base_url: + type: string + description: Service base url to send logs to + insecure: + type: boolean + description: Skip ceritifacate verification + bootstrap: + type: boolean + description: Host is bootstrap or not + installer_gather: + type: boolean + description: Run installer gather logs + default: true + ca_cert_path: + type: string + description: Path to certificate on the nodes + master_ips: + type: array + description: List of master ips + items: + type: string + description: Master ip. + pattern: '^(?:(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$' + + + install_cmd_request: + type: object + required: + - cluster_id + - infra_env_id + - host_id + - insecure + - base_url + - role + - bootdevice + - controller_image + - installer_image + - high_availability_mode + properties: + cluster_id: + type: string + format: uuid + description: Cluster id + infra_env_id: + type: string + format: uuid + description: Infra env id + host_id: + type: string + format: uuid + description: Host id + base_url: + type: string + description: Service base url to send logs to + insecure: + type: boolean + description: Skip ceritifacate verification + role: + $ref: '#/definitions/host-role' + bootdevice: + type: string + description: Boot device to write image on + controller_image: + type: string + description: Assisted installer controller image + installer_image: + type: string + description: Assisted installer image + high_availability_mode: + type: string + enum: ['Full', 'None'] + default: 'Full' + description: | + Guaranteed availability of the installed cluster. 'Full' installs a Highly-Available cluster + over multiple master nodes whereas 'None' installs a full cluster over one node. + proxy: + $ref: "#/definitions/proxy" + check_cvo: + type: boolean + description: Check CVO status if needed + default: true + disks_to_format: + type: array + description: List of disks to format + items: + type: string + description: Disk to format + must_gather_image: + type: string + description: Must-gather images to use + mco_image: + type: string + description: Machine config operator image + openshift_version: + type: string + description: Version of the OpenShift cluster. + ca_cert_path: + type: string + description: Path to certificate on the nodes + service_ips: + type: array + description: List of service ips + items: + type: string + description: Service ip. + pattern: '^(?:(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})|(?:(?:[0-9a-fA-F]*:[0-9a-fA-F]*){2,}))$' + installer_args: + type: string + description: Core-os installer addtional args + + ntp_synchronization_request: type: object required: