From 9acd8b6c5411a6bd571386c37932f2b160a1650d Mon Sep 17 00:00:00 2001 From: Pushkar Acharya Date: Tue, 5 Jul 2022 21:58:15 -0700 Subject: [PATCH 1/7] Add option to skip node auth in prep-node (#315) * Add option to skip node auth in prep-node --- cmd/prepNode.go | 4 +++- pkg/pmk/node.go | 7 ++++++- pkg/util/constants.go | 7 +++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/prepNode.go b/cmd/prepNode.go index 701c9fa5..92ca937c 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -58,10 +58,12 @@ func init() { prepNodeCmd.Flags().StringSliceVarP(&nodeConfig.IPs, "ip", "i", []string{}, "IP address of host to be prepared") prepNodeCmd.Flags().BoolVarP(&skipChecks, "skip-checks", "c", false, "Will skip optional checks if true") prepNodeCmd.Flags().BoolVarP(&disableSwapOff, "disable-swapoff", "d", false, "Will skip swapoff") - prepNodeCmd.Flags().StringVar(&nodeConfig.MFA, "mfa", "", "MFA token") prepNodeCmd.Flags().MarkHidden("disable-swapoff") + prepNodeCmd.Flags().StringVar(&nodeConfig.MFA, "mfa", "", "MFA token") prepNodeCmd.Flags().StringVarP(&nodeConfig.SudoPassword, "sudo-pass", "e", "", "sudo password for user on remote host") prepNodeCmd.Flags().BoolVarP(&nodeConfig.RemoveExistingPkgs, "remove-existing-pkgs", "r", false, "Will remove previous installation if found (default false)") + prepNodeCmd.Flags().BoolVar(&util.SkipKube, "skip-kube", false, "Skip installing pf9-kube/nodelet on this host") + prepNodeCmd.Flags().MarkHidden("skip-kube") rootCmd.AddCommand(prepNodeCmd) } diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index d4ea0d64..20321457 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -145,13 +145,18 @@ func PrepNode(ctx objects.Config, allClients client.Client, auth keystone.Keysto s.Stop() fmt.Println(color.Green("✓ ") + "Initialised host successfully") zap.S().Debug("Initialised host successfully") + if util.SkipKube { + zap.S().Debug("Skip authorizing host as --skip-kube flag is true") + sendSegmentEvent(allClients, "Successful", auth, false) + return nil + } + s.Restart() s.Suffix = " Authorising host" zap.S().Debug("Authorising host") hostID := strings.TrimSuffix(output, "\n") time.Sleep(ctx.WaitPeriod * time.Second) - sendSegmentEvent(allClients, "Authorising host - 4", auth, false) if err := allClients.Resmgr.AuthorizeHost(hostID, auth.Token); err != nil { errStr := "Error: Unable to authorise host. " + err.Error() sendSegmentEvent(allClients, errStr, auth, true) diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 94947e05..9bf8a5ed 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -10,9 +10,12 @@ var Files []string var Pf9Packages []string var RequiredPorts []string var PortErr string -var ProcessesList []string //Kubernetes clusters processes list -var SwapOffDisabled bool //If this is true the swapOff functionality will be disabled. +var ProcessesList []string // Kubernetes clusters processes list +var SwapOffDisabled bool // If this is true the swapOff functionality will be disabled. var SkipPrepNode bool + +// SkipKube skips authorizing kube role during prep-node. Not applicable to bootstrap command +var SkipKube bool var HostDown bool var EBSPermissions []string var Route53Permissions []string From b6507f862be572ab71edef7a8eb265d278ad8ff4 Mon Sep 17 00:00:00 2001 From: Devidas Khedkar <76941923+devidask27@users.noreply.github.com> Date: Wed, 13 Jul 2022 10:58:19 +0530 Subject: [PATCH 2/7] updated version (#317) --- README.md | 2 +- pkg/util/constants.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6677aaec..00a92b6e 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Use "pf9ctl [command] --help" for more information about a command. ```sh #pf9ctl version -pf9ctl version: v1.15 +pf9ctl version: v1.16 ``` - **Upgrading** diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 9bf8a5ed..a657698a 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -300,7 +300,7 @@ func init() { //These are the constants needed for everything version related const ( - Version string = "pf9ctl version: v1.15" + Version string = "pf9ctl version: v1.16" AWSBucketName string = "pmkft-assets" AWSBucketKey string = "pf9ctl" AWSBucketRegion string = "us-west-1" From 4a4eac9225bcfe12185eceb9bd0a1979556f8061 Mon Sep 17 00:00:00 2001 From: devidask27 Date: Mon, 25 Jul 2022 16:09:40 +0530 Subject: [PATCH 3/7] onboarding N nodes & some code refactoring --- cmd/attachNode.go | 12 +-- cmd/authoriseNode.go | 12 +-- cmd/bootstrap.go | 23 +++--- cmd/checkNode.go | 20 ++--- cmd/cloudProviders.go | 7 +- cmd/clusterListCmd.go | 6 +- cmd/config.go | 5 +- cmd/deauthoriseNode.go | 12 +-- cmd/decomissionNode.go | 19 ++--- cmd/deleteCluster.go | 12 +-- cmd/detachNode.go | 12 +-- cmd/prepNode.go | 146 +++++++++++++++++++++---------------- cmd/supportBundle.go | 20 ++--- pkg/cmdexec/executor.go | 10 +-- pkg/config/config.go | 42 +++++------ pkg/pmk/decomissionNode.go | 67 ++++++++++++----- pkg/pmk/node.go | 15 ++-- pkg/util/constants.go | 3 + 18 files changed, 251 insertions(+), 192 deletions(-) diff --git a/cmd/attachNode.go b/cmd/attachNode.go index 48300b66..7ce22567 100644 --- a/cmd/attachNode.go +++ b/cmd/attachNode.go @@ -58,17 +58,17 @@ func attachNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -76,7 +76,7 @@ func attachNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/authoriseNode.go b/cmd/authoriseNode.go index 3e8a9b14..de7bef9c 100644 --- a/cmd/authoriseNode.go +++ b/cmd/authoriseNode.go @@ -38,17 +38,17 @@ func authNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -56,7 +56,7 @@ func authNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 56955c97..6ab13481 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -14,7 +14,6 @@ import ( "github.com/platform9/pf9ctl/pkg/color" "github.com/platform9/pf9ctl/pkg/config" "github.com/platform9/pf9ctl/pkg/log" - "github.com/platform9/pf9ctl/pkg/objects" "github.com/platform9/pf9ctl/pkg/pmk" "github.com/platform9/pf9ctl/pkg/qbert" "github.com/platform9/pf9ctl/pkg/supportBundle" @@ -100,8 +99,8 @@ var bootstrapCmd = &cobra.Command{ }, PreRun: func(cmd *cobra.Command, args []string) { - if node.Hostname != "" { - nc.Spec.Nodes = append(nc.Spec.Nodes, node) + if util.Node.Hostname != "" { + nc.Spec.Nodes = append(nc.Spec.Nodes, util.Node) } }, @@ -109,7 +108,7 @@ var bootstrapCmd = &cobra.Command{ Run: bootstrapCmdRun, } -var node objects.Node +//var node objects.Node func init() { bootstrapCmd.Flags().IntVar(&networkStack, "network-stack", 0, "0 for ipv4 and 1 for ipv6") @@ -142,10 +141,10 @@ func init() { bootstrapCmd.Flags().BoolVar(&privileged, "privileged", true, "Enable privileged mode for K8s API, use either --privileged or --privileged=false to change") bootstrapCmd.Flags().BoolVar(&allowWorkloadsOnMaster, "allow-workloads-on-master", true, "Taint master nodes ( to enable workloads ), use either --allow-workloads-on-master or --allow-workloads-on-master=false to change") bootstrapCmd.Flags().StringVar(&networkPlugin, "network-plugin", "calico", "Specify network plugin ( Possible values: flannel or calico )") - bootstrapCmd.Flags().StringVarP(&node.Hostname, "user", "u", "", "Ssh username for the node") + bootstrapCmd.Flags().StringVarP(&util.Node.Hostname, "user", "u", "", "Ssh username for the node") bootstrapCmd.Flags().StringVarP(&nc.Password, "password", "p", "", "Ssh password for the node (use 'single quotes' to pass password)") bootstrapCmd.Flags().StringVarP(&nc.SshKey, "ssh-key", "s", "", "Ssh key file for connecting to the node") - bootstrapCmd.Flags().StringVarP(&node.Ip, "ip", "i", "", "IP address of the host to be prepared") + bootstrapCmd.Flags().StringVarP(&util.Node.Ip, "ip", "i", "", "IP address of the host to be prepared") bootstrapCmd.Flags().StringVar(&util.MFA, "mfa", "", "MFA token") bootstrapCmd.Flags().StringVarP(&util.SudoPassword, "sudo-pass", "e", "", "Sudo password for user on remote host") bootstrapCmd.Flags().BoolVarP(&util.RemoveExistingPkgs, "remove-existing-pkgs", "r", false, "Will remove previous installation if found (default false)") @@ -207,7 +206,7 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { } detachedMode := cmd.Flags().Changed("no-prompt") - isRemote := cmdexec.CheckRemote(nc) + isRemote := cmdexec.CheckRemote(util.Node) isEtcdBackupDisabled := cmd.Flags().Changed("etcd-backup") qbert.IsMonitoringDisabled = cmd.Flags().Changed("monitoring") @@ -229,16 +228,16 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { } if isRemote { - if !config.ValidateNodeConfig(nc, !detachedMode) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -247,7 +246,7 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/checkNode.go b/cmd/checkNode.go index 1d1395f0..23c9b5e8 100644 --- a/cmd/checkNode.go +++ b/cmd/checkNode.go @@ -26,18 +26,18 @@ var ( at https://platform9.com/blog/support/managed-container-cloud-requirements-checklist/`, Run: checkNodeRun, PreRun: func(cmd *cobra.Command, args []string) { - if node.Hostname != "" { - nc.Spec.Nodes = append(nc.Spec.Nodes, node) + if util.Node.Hostname != "" { + nc.Spec.Nodes = append(nc.Spec.Nodes, util.Node) } }, } ) func init() { - checkNodeCmd.Flags().StringVarP(&node.Hostname, "user", "u", "", "ssh username for the nodes") + checkNodeCmd.Flags().StringVarP(&util.Node.Hostname, "user", "u", "", "ssh username for the nodes") checkNodeCmd.Flags().StringVarP(&nc.Password, "password", "p", "", "ssh password for the nodes (use 'single quotes' to pass password)") checkNodeCmd.Flags().StringVarP(&nc.SshKey, "ssh-key", "s", "", "ssh key file for connecting to the nodes") - checkNodeCmd.Flags().StringVarP(&node.Ip, "ip", "i", "", "IP address of host to be prepared") + checkNodeCmd.Flags().StringVarP(&util.Node.Ip, "ip", "i", "", "IP address of host to be prepared") checkNodeCmd.Flags().StringVar(&util.MFA, "mfa", "", "MFA token") checkNodeCmd.Flags().StringVarP(&util.SudoPassword, "sudo-pass", "e", "", "sudo password for user on remote host") checkNodeCmd.Flags().BoolVarP(&util.RemoveExistingPkgs, "remove-existing-pkgs", "r", false, "Will remove previous installation if found (default false)") @@ -61,20 +61,20 @@ func checkNodeRun(cmd *cobra.Command, args []string) { } detachedMode := cmd.Flags().Changed("no-prompt") - isRemote := cmdexec.CheckRemote(nc) + isRemote := cmdexec.CheckRemote(util.Node) if isRemote { - if !config.ValidateNodeConfig(nc, !detachedMode) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { util.RemoveExistingPkgs = true - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -83,7 +83,7 @@ func checkNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/cloudProviders.go b/cmd/cloudProviders.go index 28153647..9a299302 100644 --- a/cmd/cloudProviders.go +++ b/cmd/cloudProviders.go @@ -7,7 +7,6 @@ import ( "github.com/platform9/pf9ctl/pkg/color" "github.com/platform9/pf9ctl/pkg/config" - "github.com/platform9/pf9ctl/pkg/objects" "github.com/platform9/pf9ctl/pkg/pmk" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -68,7 +67,7 @@ func checkGoogleProviderRun(cmd *cobra.Command, args []string) { os.Exit(1) } } else { - err = config.GetConfigRecursive("google.json", cfg, &objects.NodeConfig{}) + err = config.GetConfigRecursive("google.json", cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -89,7 +88,7 @@ func checkAmazonProviderRun(cmd *cobra.Command, args []string) { os.Exit(1) } } else { - err = config.GetConfigRecursive("amazon.json", cfg, &objects.NodeConfig{}) + err = config.GetConfigRecursive("amazon.json", cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -109,7 +108,7 @@ func checkAzureProviderRun(cmd *cobra.Command, args []string) { os.Exit(1) } } else { - err = config.GetConfigRecursive("azure.json", cfg, &objects.NodeConfig{}) + err = config.GetConfigRecursive("azure.json", cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n") diff --git a/cmd/clusterListCmd.go b/cmd/clusterListCmd.go index 489c6e59..86cceef5 100644 --- a/cmd/clusterListCmd.go +++ b/cmd/clusterListCmd.go @@ -29,9 +29,9 @@ func listClusterCmdRun(cmd *cobra.Command, args []string) { var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -39,7 +39,7 @@ func listClusterCmdRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/config.go b/cmd/config.go index 4894e36a..4022f5ad 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -75,6 +75,7 @@ var ( } nc = &objects.NodeConfig{} + //host = objects.Node{} ) func init() { @@ -100,7 +101,7 @@ func configCmdCreateRun(cmd *cobra.Command, args []string) { } if cmd.Flags().Changed("no-prompt") { - if err = config.ValidateUserCredentials(cfg, &objects.NodeConfig{}); err != nil { + if err = config.ValidateUserCredentials(cfg); err != nil { zap.S().Fatal(color.Red("x "), err) } @@ -109,7 +110,7 @@ func configCmdCreateRun(cmd *cobra.Command, args []string) { } } else { - if err = config.GetConfigRecursive(util.Pf9DBLoc, cfg, &objects.NodeConfig{}); err != nil { + if err = config.GetConfigRecursive(util.Pf9DBLoc, cfg); err != nil { zap.S().Fatal(color.Red("x "), err) } } diff --git a/cmd/deauthoriseNode.go b/cmd/deauthoriseNode.go index 81c028bc..dc38aa78 100644 --- a/cmd/deauthoriseNode.go +++ b/cmd/deauthoriseNode.go @@ -37,17 +37,17 @@ func deauthNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -55,7 +55,7 @@ func deauthNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/decomissionNode.go b/cmd/decomissionNode.go index 8ef3edcc..17e8faad 100644 --- a/cmd/decomissionNode.go +++ b/cmd/decomissionNode.go @@ -25,18 +25,18 @@ var decommissionNodeCmd = &cobra.Command{ }, Run: decommissionNodeRun, PreRun: func(cmd *cobra.Command, args []string) { - if node.Hostname != "" { - nc.Spec.Nodes = append(nc.Spec.Nodes, node) + if util.Node.Hostname != "" { + nc.Spec.Nodes = append(nc.Spec.Nodes, util.Node) } }, } func init() { decommissionNodeCmd.Flags().StringVar(&util.MFA, "mfa", "", "MFA token") - decommissionNodeCmd.Flags().StringVarP(&node.Hostname, "user", "u", "", "ssh username for the nodes") + decommissionNodeCmd.Flags().StringVarP(&util.Node.Hostname, "user", "u", "", "ssh username for the nodes") decommissionNodeCmd.Flags().StringVarP(&nc.Password, "password", "p", "", "ssh password for the nodes (use 'single quotes' to pass password)") decommissionNodeCmd.Flags().StringVarP(&nc.SshKey, "ssh-key", "s", "", "ssh key file for connecting to the nodes") - decommissionNodeCmd.Flags().StringVarP(&node.Ip, "ip", "i", "", "IP address of host to be decommissioned") + decommissionNodeCmd.Flags().StringVarP(&util.Node.Ip, "ip", "i", "", "IP address of host to be decommissioned") decommissionNodeCmd.Flags().StringVar(&ConfigPath, "user-config", "", "Path of user-config file") decommissionNodeCmd.Flags().StringVar(&NodeConfigPath, "node-config", "", "Path of node-config file") nodeCmd.AddCommand(decommissionNodeCmd) @@ -50,21 +50,22 @@ func decommissionNodeRun(cmd *cobra.Command, args []string) { if cmd.Flags().Changed("node-config") { config.LoadNodeConfig(nc, NodeConfigPath) + util.Node = nc.Spec.Nodes[0] } detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) diff --git a/cmd/deleteCluster.go b/cmd/deleteCluster.go index 0df0e303..e3dbaf4c 100644 --- a/cmd/deleteCluster.go +++ b/cmd/deleteCluster.go @@ -47,17 +47,17 @@ func deleteClusterRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -65,7 +65,7 @@ func deleteClusterRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/detachNode.go b/cmd/detachNode.go index 91eb3e9a..d48dcc2a 100644 --- a/cmd/detachNode.go +++ b/cmd/detachNode.go @@ -42,17 +42,17 @@ func detachNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(nc) { - if !config.ValidateNodeConfig(nc, !detachedMode) { + if cmdexec.CheckRemote(util.Node) { + /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -60,7 +60,7 @@ func detachNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/prepNode.go b/cmd/prepNode.go index 350db8c8..5a2ea5ed 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -8,12 +8,14 @@ import ( "fmt" "os" "strings" + "sync" "github.com/platform9/pf9ctl/pkg/client" "github.com/platform9/pf9ctl/pkg/cmdexec" "github.com/platform9/pf9ctl/pkg/color" "github.com/platform9/pf9ctl/pkg/config" "github.com/platform9/pf9ctl/pkg/log" + "github.com/platform9/pf9ctl/pkg/objects" "github.com/platform9/pf9ctl/pkg/pmk" "github.com/platform9/pf9ctl/pkg/ssh" "github.com/platform9/pf9ctl/pkg/supportBundle" @@ -37,8 +39,8 @@ var prepNodeCmd = &cobra.Command{ return nil }, PreRun: func(cmd *cobra.Command, args []string) { - if node.Hostname != "" { - nc.Spec.Nodes = append(nc.Spec.Nodes, node) + if util.Node.Hostname != "" { + nc.Spec.Nodes = append(nc.Spec.Nodes, util.Node) } }, } @@ -52,13 +54,16 @@ var ( skipChecks bool disableSwapOff bool NodeConfigPath string + wg sync.WaitGroup + isRemote bool + detachedMode bool ) func init() { - prepNodeCmd.Flags().StringVarP(&node.Hostname, "user", "u", "", "ssh username for the nodes") + prepNodeCmd.Flags().StringVarP(&util.Node.Hostname, "user", "u", "", "ssh username for the nodes") prepNodeCmd.Flags().StringVarP(&nc.Password, "password", "p", "", "ssh password for the nodes (use 'single quotes' to pass password)") prepNodeCmd.Flags().StringVarP(&nc.SshKey, "ssh-key", "s", "", "ssh key file for connecting to the nodes") - prepNodeCmd.Flags().StringVarP(&node.Ip, "ip", "i", "", "IP address of host to be prepared") + prepNodeCmd.Flags().StringVarP(&util.Node.Ip, "ip", "i", "", "IP address of host to be prepared") prepNodeCmd.Flags().BoolVarP(&skipChecks, "skip-checks", "c", false, "Will skip optional checks if true") prepNodeCmd.Flags().BoolVarP(&disableSwapOff, "disable-swapoff", "d", false, "Will skip swapoff") prepNodeCmd.Flags().StringVar(&util.MFA, "mfa", "", "MFA token") @@ -80,27 +85,22 @@ func prepNodeRun(cmd *cobra.Command, args []string) { if cmd.Flags().Changed("node-config") { config.LoadNodeConfig(nc, NodeConfigPath) + skipChecks = true + util.RemoveExistingPkgs = true } if skipChecks { pmk.WarningOptionalChecks = true } - detachedMode := cmd.Flags().Changed("no-prompt") - isRemote := cmdexec.CheckRemote(nc) - - if isRemote { - if !config.ValidateNodeConfig(nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } - } + detachedMode = cmd.Flags().Changed("no-prompt") var err error if detachedMode { util.RemoveExistingPkgs = true - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { @@ -109,8 +109,67 @@ func prepNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") + + wg.Add(len(nc.Spec.Nodes)) + for _, util.Node = range nc.Spec.Nodes { + go onboardNodes(util.Node) + } + wg.Wait() + + zap.S().Debug("==========Finished running prep-node==========") +} + +// To check if Remote Host needs Password to access Sudo and prompt for Sudo Password if exists. +func SudoPasswordCheck(exec cmdexec.Executor, detached bool, sudoPass string) error { + + ssh.SudoPassword = sudoPass + + _, err := exec.RunWithStdout("-l | grep '(ALL) PASSWD: ALL'") + if err == nil { + if detached { + if sudoPass == "" { + return errors.New("sudo password is required for the user on remote host, use --sudo-pass(-e) flag to pass") + } else if validateSudoPassword(exec) == util.Invalid { + return errors.New("Invalid password for user on remote host") + } + } + + // To bail out if Sudo Password entered is invalid multiple times. + loopcounter := 1 + for true { + if loopcounter >= 4 { + zap.S().Fatalf("\n" + color.Red("x ") + "Invalid Sudo Password entered multiple times") + } + // Validate Sudo Password entered. + if ssh.SudoPassword == "" || validateSudoPassword(exec) == util.Invalid { + loopcounter += 1 + fmt.Printf("\n" + color.Red("x ") + "Invalid Sudo Password provided of Remote Host\n") + fmt.Printf("Enter Sudo password for Remote Host: ") + sudopassword, _ := terminal.ReadPassword(0) + ssh.SudoPassword = string(sudopassword) + } else { + return nil + } + } + } + return nil +} + +func validateSudoPassword(exec cmdexec.Executor) string { + + _ = pmk.CheckSudo(exec) + // Validate Sudo Password entered for Remote Host from stderr. + if strings.Contains(cmdexec.StdErrSudoPassword, util.InvalidPassword) { + return util.Invalid + } + return util.Valid +} + +func onboardNodes(node objects.Node) { + defer wg.Done() var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + var err error + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } @@ -138,6 +197,15 @@ func prepNodeRun(cmd *cobra.Command, args []string) { } zap.S().Fatalf("Unable to obtain keystone credentials: %s", err.Error()) } + + isRemote = cmdexec.CheckRemote(node) + + if isRemote { + /*if !config.ValidateNodeConfig(node, nc, !detachedMode) { + zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") + }*/ + } + if isRemote { if err := SudoPasswordCheck(executor, detachedMode, util.SudoPassword); err != nil { zap.S().Fatal("Failed executing commands on remote machine with sudo: ", err.Error()) @@ -190,52 +258,4 @@ func prepNodeRun(cmd *cobra.Command, args []string) { zap.S().Debugf("Unable to prep node: %s\n", err.Error()) zap.S().Fatalf("\nFailed to prepare node. See %s or use --verbose for logs\n", log.GetLogLocation(util.Pf9Log)) } - - zap.S().Debug("==========Finished running prep-node==========") -} - -// To check if Remote Host needs Password to access Sudo and prompt for Sudo Password if exists. -func SudoPasswordCheck(exec cmdexec.Executor, detached bool, sudoPass string) error { - - ssh.SudoPassword = sudoPass - - _, err := exec.RunWithStdout("-l | grep '(ALL) PASSWD: ALL'") - if err == nil { - if detached { - if sudoPass == "" { - return errors.New("sudo password is required for the user on remote host, use --sudo-pass(-e) flag to pass") - } else if validateSudoPassword(exec) == util.Invalid { - return errors.New("Invalid password for user on remote host") - } - } - - // To bail out if Sudo Password entered is invalid multiple times. - loopcounter := 1 - for true { - if loopcounter >= 4 { - zap.S().Fatalf("\n" + color.Red("x ") + "Invalid Sudo Password entered multiple times") - } - // Validate Sudo Password entered. - if ssh.SudoPassword == "" || validateSudoPassword(exec) == util.Invalid { - loopcounter += 1 - fmt.Printf("\n" + color.Red("x ") + "Invalid Sudo Password provided of Remote Host\n") - fmt.Printf("Enter Sudo password for Remote Host: ") - sudopassword, _ := terminal.ReadPassword(0) - ssh.SudoPassword = string(sudopassword) - } else { - return nil - } - } - } - return nil -} - -func validateSudoPassword(exec cmdexec.Executor) string { - - _ = pmk.CheckSudo(exec) - // Validate Sudo Password entered for Remote Host from stderr. - if strings.Contains(cmdexec.StdErrSudoPassword, util.InvalidPassword) { - return util.Invalid - } - return util.Valid } diff --git a/cmd/supportBundle.go b/cmd/supportBundle.go index 2c507a7a..a16b3c87 100644 --- a/cmd/supportBundle.go +++ b/cmd/supportBundle.go @@ -23,8 +23,8 @@ var ( Long: `Gathers support bundle that includes logs for pf9 services and pf9ctl, uploads to S3 `, Run: supportBundleUpload, PreRun: func(cmd *cobra.Command, args []string) { - if node.Hostname != "" { - nc.Spec.Nodes = append(nc.Spec.Nodes, node) + if util.Node.Hostname != "" { + nc.Spec.Nodes = append(nc.Spec.Nodes, util.Node) } }, } @@ -32,10 +32,10 @@ var ( //This initialization is using create commands which is not in use for now. func init() { - supportBundleCmd.Flags().StringVarP(&node.Hostname, "user", "u", "", "ssh username for the nodes") + supportBundleCmd.Flags().StringVarP(&util.Node.Hostname, "user", "u", "", "ssh username for the nodes") supportBundleCmd.Flags().StringVarP(&nc.Password, "password", "p", "", "ssh password for the nodes (use 'single quotes' to pass password)") supportBundleCmd.Flags().StringVarP(&nc.SshKey, "ssh-key", "s", "", "ssh key file for connecting to the nodes") - supportBundleCmd.Flags().StringVarP(&node.Ip, "ip", "i", "", "IP address of host to be prepared") + supportBundleCmd.Flags().StringVarP(&util.Node.Ip, "ip", "i", "", "IP address of host to be prepared") supportBundleCmd.Flags().StringVar(&util.MFA, "mfa", "", "MFA token") supportBundleCmd.Flags().StringVarP(&util.SudoPassword, "sudo-pass", "e", "", "sudo password for user on remote host") supportBundleCmd.Flags().StringVar(&ConfigPath, "user-config", "", "Path of user-config file") @@ -55,19 +55,19 @@ func supportBundleUpload(cmd *cobra.Command, args []string) { } detachedMode := cmd.Flags().Changed("no-prompt") - isRemote := cmdexec.CheckRemote(nc) + isRemote := cmdexec.CheckRemote(util.Node) if isRemote { - if !config.ValidateNodeConfig(nc, !detachedMode) { + /*f !config.ValidateNodeConfig(host, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - } + }*/ } var err error if detachedMode { - err = config.LoadConfig(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfig(util.Pf9DBLoc, cfg) } else { - err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg, nc) + err = config.LoadConfigInteractive(util.Pf9DBLoc, cfg) } if err != nil { zap.S().Fatalf("Unable to load the context: %s\n", err.Error()) @@ -75,7 +75,7 @@ func supportBundleUpload(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") zap.S().Debug("Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/pkg/cmdexec/executor.go b/pkg/cmdexec/executor.go index d1752aaa..a7c756d9 100644 --- a/pkg/cmdexec/executor.go +++ b/pkg/cmdexec/executor.go @@ -163,8 +163,8 @@ func ConfidentialInfoRemover(cmd string) string { return cmd } -func GetExecutor(proxyURL string, nc *objects.NodeConfig) (Executor, error) { - if CheckRemote(nc) { +func GetExecutor(proxyURL string, node objects.Node, nc *objects.NodeConfig) (Executor, error) { + if CheckRemote(node) { var pKey []byte var err error if nc.SshKey != "" { @@ -173,14 +173,14 @@ func GetExecutor(proxyURL string, nc *objects.NodeConfig) (Executor, error) { zap.S().Fatalf("Unable to read the sshKey %s, %s", nc.SshKey, err.Error()) } } - return NewRemoteExecutor(nc.Spec.Nodes[0].Ip, 22, nc.Spec.Nodes[0].Hostname, pKey, nc.Password, proxyURL) + return NewRemoteExecutor(node.Ip, 22, node.Hostname, pKey, nc.Password, proxyURL) } zap.S().Debug("Using local executor") return LocalExecutor{ProxyUrl: proxyURL}, nil } -func CheckRemote(nc *objects.NodeConfig) bool { - for _, node := range nc.Spec.Nodes { +func CheckRemote(node objects.Node) bool { + if node.Ip != "" { if node.Ip != "localhost" && node.Ip != "127.0.0.1" && node.Ip != "::1" { return true } diff --git a/pkg/config/config.go b/pkg/config/config.go index 018ba8ee..ff61e8af 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -11,8 +11,6 @@ import ( "reflect" "strings" - "github.com/platform9/pf9ctl/pkg/client" - "github.com/platform9/pf9ctl/pkg/cmdexec" "github.com/platform9/pf9ctl/pkg/color" "github.com/platform9/pf9ctl/pkg/keystone" "github.com/platform9/pf9ctl/pkg/objects" @@ -59,7 +57,7 @@ func StoreConfig(cfg *objects.Config, loc string) error { } // LoadConfig returns the information for communication with PF9 controller. -func LoadConfig(loc string, cfg *objects.Config, nc *objects.NodeConfig) error { +func LoadConfig(loc string, cfg *objects.Config) error { zap.S().Debug("Loading configuration details. pf9ctl version: ", util.Version) @@ -99,12 +97,12 @@ func LoadConfig(loc string, cfg *objects.Config, nc *objects.NodeConfig) error { return err } - return ValidateUserCredentials(cfg, nc) + return ValidateUserCredentials(cfg) } -func LoadConfigInteractive(loc string, cfg *objects.Config, nc *objects.NodeConfig) error { +func LoadConfigInteractive(loc string, cfg *objects.Config) error { - err := LoadConfig(loc, cfg, nc) + err := LoadConfig(loc, cfg) if err == nil { return nil } @@ -118,11 +116,11 @@ func LoadConfigInteractive(loc string, cfg *objects.Config, nc *objects.NodeConf } clearContext(cfg) - return GetConfigRecursive(loc, cfg, nc) + return GetConfigRecursive(loc, cfg) } -func GetConfigRecursive(loc string, cfg *objects.Config, nc *objects.NodeConfig) error { +func GetConfigRecursive(loc string, cfg *objects.Config) error { maxLoopNoConfig := 3 InvalidExistingConfig := false count := 0 @@ -153,7 +151,7 @@ func GetConfigRecursive(loc string, cfg *objects.Config, nc *objects.NodeConfig) continue } - if err = ValidateUserCredentials(cfg, nc); err != nil { + if err = ValidateUserCredentials(cfg); err != nil { clearContext(cfg) InvalidExistingConfig = true count++ @@ -169,19 +167,20 @@ func GetConfigRecursive(loc string, cfg *objects.Config, nc *objects.NodeConfig) return err } -func ValidateUserCredentials(cfg *objects.Config, nc *objects.NodeConfig) error { +func ValidateUserCredentials(cfg *objects.Config) error { if err := validateConfigFields(cfg); err != nil { return err } - c, err := createClient(cfg, nc) + /*c, err := createClient(cfg, nc) defer c.Segment.Close() if err != nil { return fmt.Errorf("Error validating credentials %w", err) - } + }*/ - auth, err := c.Keystone.GetAuth( + k := keystone.NewKeystone(cfg.Spec.AccountUrl) + auth, err := k.GetAuth( cfg.Spec.Username, cfg.Spec.Password, cfg.Spec.Tenant, @@ -366,8 +365,9 @@ func ConfigCmdCreateRun(cfg *objects.Config) error { return SetProxy(cfg.Spec.ProxyURL) } -func createClient(cfg *objects.Config, nc *objects.NodeConfig) (client.Client, error) { - executor, err := cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc) +/*func createClient(cfg *objects.Config, nc *objects.NodeConfig) (client.Client, error) { + var host objects.Node + executor, err := cmdexec.GetExecutor(cfg.Spec.ProxyURL, host, nc) if err != nil { //debug first since Fatalf calls os.Exit zap.S().Debug("Error connecting to host %s", err.Error()) @@ -375,7 +375,7 @@ func createClient(cfg *objects.Config, nc *objects.NodeConfig) (client.Client, e } return client.NewClient(cfg.Spec.AccountUrl, executor, cfg.Spec.OtherData.AllowInsecure, false) -} +}*/ //This function clears the context if it is invalid. Before storing it. func clearContext(v interface{}) { @@ -383,18 +383,18 @@ func clearContext(v interface{}) { p.Set(reflect.Zero(p.Type())) } -func ValidateNodeConfig(nc *objects.NodeConfig, interactive bool) bool { +func ValidateNodeConfig(node objects.Node, nc *objects.NodeConfig, interactive bool) bool { - if nc.Spec.Nodes[0].Hostname == "" || (nc.SshKey == "" && nc.Password == "") { + if node.Hostname == "" || (nc.SshKey == "" && nc.Password == "") { if !interactive { return false } - if nc.Spec.Nodes[0].Hostname == "" { + if node.Hostname == "" { fmt.Printf("Enter username for remote host: ") reader := bufio.NewReader(os.Stdin) - nc.Spec.Nodes[0].Hostname, _ = reader.ReadString('\n') - nc.Spec.Nodes[0].Hostname = strings.TrimSpace(nc.Spec.Nodes[0].Hostname) + node.Hostname, _ = reader.ReadString('\n') + node.Hostname = strings.TrimSpace(node.Hostname) } if nc.SshKey == "" && nc.Password == "" { var choice int diff --git a/pkg/pmk/decomissionNode.go b/pkg/pmk/decomissionNode.go index 12d0e32c..7c3c688f 100644 --- a/pkg/pmk/decomissionNode.go +++ b/pkg/pmk/decomissionNode.go @@ -5,8 +5,10 @@ import ( "strings" "time" + "github.com/briandowns/spinner" "github.com/platform9/pf9ctl/pkg/client" "github.com/platform9/pf9ctl/pkg/cmdexec" + "github.com/platform9/pf9ctl/pkg/color" "github.com/platform9/pf9ctl/pkg/objects" "github.com/platform9/pf9ctl/pkg/qbert" "github.com/platform9/pf9ctl/pkg/util" @@ -14,20 +16,16 @@ import ( ) func removePf9Installation(c client.Client) { - fmt.Println("Removing /etc/pf9 logs") cmd := fmt.Sprintf("rm -rf %s", util.EtcDir) c.Executor.RunCommandWait(cmd) - fmt.Println("Removing /var/opt/pf9 logs") cmd = fmt.Sprintf("rm -rf %s", util.OptDir) c.Executor.RunCommandWait(cmd) - fmt.Println("Removing pf9 HOME dir") cmd = fmt.Sprintf("rm -rf $HOME/pf9") c.Executor.RunCommandWait(cmd) } func removeHostagent(c client.Client, hostOS string) { - fmt.Println("Removing pf9-hostagent (this might take a few minutes...)") var services = []string{"pf9-hostagent", "pf9-nodeletd", "pf9-kubelet"} //stop hostagent for _, service := range services { @@ -45,11 +43,8 @@ func removeHostagent(c client.Client, hostOS string) { _, err = c.Executor.RunWithStdout("bash", "-c", "sudo yum remove pf9-hostagent -y") } if err != nil { - zap.S().Debugf("Could not execute command %v", err) - } else { - fmt.Println("Removed hostagent") + zap.S().Fatalf("Could not execute command %v", err) } - fmt.Println("Removing logs...") for _, file := range util.Files { cmd := fmt.Sprintf("rm -rf %s", file) c.Executor.RunCommandWait(cmd) @@ -66,9 +61,13 @@ func DecommissionNode(cfg *objects.Config, nc *objects.NodeConfig, removePf9 boo //purge pf9-hostagent //clean up logs + s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) + s.Color("red") + var executor cmdexec.Executor var err error - if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, nc); err != nil { + + if executor, err = cmdexec.GetExecutor(cfg.Spec.ProxyURL, util.Node, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } var c client.Client @@ -110,52 +109,84 @@ func DecommissionNode(cfg *objects.Config, nc *objects.NodeConfig, removePf9 boo } if nodeInfo.ClusterName == "" { - fmt.Println("Node is not connected to any cluster") + fmt.Println(color.Green("✓ ") + "Node is not connected to any cluster") if nodeConnectedToDU { + fmt.Println("Deauthorizing node:", hostID[0]) err = c.Qbert.DeauthoriseNode(hostID[0], auth.Token) if err != nil { zap.S().Fatalf("Failed to deauthorize node") } else { - fmt.Println("Deauthorized node from UI") + fmt.Println(color.Green("✓ ") + "Deauthorized node from UI") } + s.Start() + s.Suffix = " Removing pf9-hostagent (this might take a few minutes...)" + //s.FinalMSG = color.Green("✓ ") + "pf9-hostagent removed successfully" removeHostagent(c, hostOS) + s.Stop() + fmt.Println(color.Green("✓ ") + "pf9-hostagent removed successfully") + } else { //case where node is not connected to DU but hostagent is installed partially + s.Start() + s.Suffix = " Removing pf9-hostagent (this might take a few minutes...)" + //s.FinalMSG = color.Green("✓ ") + "pf9-hostagent removed successfully" removeHostagent(c, hostOS) + s.Stop() + fmt.Println(color.Green("✓ ") + "pf9-hostagent removed successfully") } //remove pf9 dir if removePf9 { removePf9Installation(c) } - fmt.Println("Node decommissioning started....This may take a few minutes....Check the latest status in UI") + //fmt.Println("Node decommissioning started....This may take a few minutes....Check the latest status in UI") + s.Restart() + s.Suffix = " Node decommissioning started....This may take a few minutes....Check the latest status in UI" + //s.FinalMSG = color.Green("✓ ") + "Node decommission completed" time.Sleep(50 * time.Second) + s.Stop() + fmt.Println(color.Green("✓ ") + "Node decommission completed") } else { //detach node from cluster - fmt.Printf("Node is connected to %s cluster\n", nodeInfo.ClusterName) - fmt.Println("Detaching node from cluster...") + fmt.Printf(color.Green("✓ ")+"Node is connected to %s cluster\n", nodeInfo.ClusterName) + //fmt.Println("Detaching node from cluster...") + s.Start() + s.Suffix = " Detaching node from cluster..." err = c.Qbert.DetachNode(nodeInfo.ClusterUuid, auth.ProjectID, auth.Token, hostID[0]) if err != nil { + s.Stop() zap.S().Fatalf("Failed to detach host from cluster") } else { - fmt.Println("Detached node from cluster") + s.Stop() + fmt.Println(color.Green("✓ ") + "Detached node from cluster") } //deauthorize host from UI - fmt.Println("Deauthorizing node from UI...") + //fmt.Println("Deauthorizing node from UI...") + s.Restart() + s.Suffix = " Deauthorizing node from UI..." err = c.Qbert.DeauthoriseNode(hostID[0], auth.Token) if err != nil { + s.Stop() zap.S().Fatalf("Failed to deauthorize node") } else { - fmt.Println("Deauthorized node from UI") + s.Stop() + fmt.Println(color.Green("✓ ") + "Deauthorized node from UI") } //stop host agent and remove it + s.Restart() + s.Suffix = " Removing pf9-hostagent (this might take a few minutes...)" removeHostagent(c, hostOS) + s.Stop() + fmt.Println(color.Green("✓ ") + "pf9-hostagent removed successfully") //remove pf9 dir if removePf9 { removePf9Installation(c) } - fmt.Println("Node decommissioning started....This may take a few minutes....Check the latest status in UI") + s.Restart() + s.Suffix = " Node decommissioning started....This may take a few minutes....Check the latest status in UI" time.Sleep(50 * time.Second) + s.Stop() + fmt.Println(color.Green("✓ ") + "Node decommission completed") } } else { fmt.Println("Host is not connected to Platform9 Management Plane") diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 9a07a489..a0ec6b70 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -116,16 +116,21 @@ func PrepNode(ctx objects.Config, allClients client.Client, auth keystone.Keysto return fmt.Errorf(errStr) } + hostName, err := allClients.Executor.RunWithStdout("bash", "-c", "hostname") + if err != nil { + zap.S().Debugf("error getting host name") + } + hostName = strings.TrimSpace(hostName) s.Suffix = " Platform9 packages installed successfully" if HostAgent == HostAgentCertless { s.Suffix = " Platform9 packages installed successfully" s.Stop() - fmt.Println(color.Green("✓ ") + "Platform9 packages installed successfully") + fmt.Println(color.Green("✓ ") + "Platform9 packages installed successfully" + " on host " + hostName) } else if HostAgent == HostAgentLegacy { s.Suffix = " Hostagent installed successfully" s.Stop() - fmt.Println(color.Green("✓ ") + "Hostagent installed successfully") + fmt.Println(color.Green("✓ ") + "Hostagent installed successfully" + " on host " + hostName) } s.Restart() @@ -143,8 +148,8 @@ func PrepNode(ctx objects.Config, allClients client.Client, auth keystone.Keysto } s.Stop() - fmt.Println(color.Green("✓ ") + "Initialised host successfully") - zap.S().Debug("Initialised host successfully") + fmt.Println(color.Green("✓ ") + "Initialised host " + hostName + " successfully") + zap.S().Debug("Initialised host " + hostName + " successfully") s.Restart() s.Suffix = " Authorising host" zap.S().Debug("Authorising host") @@ -163,7 +168,7 @@ func PrepNode(ctx objects.Config, allClients client.Client, auth keystone.Keysto sendSegmentEvent(allClients, "Successful", auth, false) s.Stop() - fmt.Println(color.Green("✓ ") + "Host successfully attached to the Platform9 control-plane") + fmt.Println(color.Green("✓ ") + "Host " + hostName + " successfully attached to the Platform9 control-plane") return nil } diff --git a/pkg/util/constants.go b/pkg/util/constants.go index ca6dde46..f6cb298f 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -4,6 +4,8 @@ import ( "os" "path/filepath" "time" + + "github.com/platform9/pf9ctl/pkg/objects" ) var Files []string @@ -29,6 +31,7 @@ var SudoPassword string var RemoveExistingPkgs bool var InstallerErrors = make(map[int]string) var LogFileNamePath string +var Node objects.Node const ( From bdb770c10870b835e09d4c429b30064d7d5382b0 Mon Sep 17 00:00:00 2001 From: Devidas Khedkar <76941923+devidask27@users.noreply.github.com> Date: Thu, 28 Jul 2022 11:45:52 +0530 Subject: [PATCH 4/7] support added for rhel 8.5 and 8.6 (#319) * support added for rhel 8.5 and 8.6 * excluded centos 8.5 and 8.6 --- pkg/platform/centos/centos.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pkg/platform/centos/centos.go b/pkg/platform/centos/centos.go index a2a8a934..f0b2feac 100644 --- a/pkg/platform/centos/centos.go +++ b/pkg/platform/centos/centos.go @@ -282,14 +282,27 @@ func (c *CentOS) Version() (string, error) { //using cat command content of os-release file is printed on terminal //using grep command os name and version are searched. e.g (CentOS Linux release 7.6.1810 (Core)) //using cut command required field (7.6.1810) is selected. - out, err := c.exec.RunWithStdout( - "bash", - "-c", - "cat /etc/*release | grep 'Red Hat Enterprise Linux Server release' -m 1 | cut -f7 -d ' ' && cat /etc/*release | grep 'CentOS Linux release' -m 1 | cut -f4 -d ' '") + var cmd string + var centos bool + _, err := c.exec.RunWithStdout("bash", "-c", "grep -i 'centos' /etc/*release") + if err != nil { + cmd = fmt.Sprintf("grep -oP '(?<=^VERSION_ID=).+' /etc/os-release") + } else { + centos = true + cmd = fmt.Sprintf("cat /etc/*release | grep 'CentOS Linux release' -m 1 | cut -f4 -d ' '") + } + + out, err := c.exec.RunWithStdout("bash", "-c", cmd) if err != nil { return "", fmt.Errorf("Couldn't read the OS configuration file os-release: %s", err.Error()) } - if match, _ := regexp.MatchString(`.*7\.[3-9]\.*`, string(out)); match { + if centos { + //comparing because we are not supporting centos 8.5 and 8.6 + if match, _ := regexp.MatchString(`.*7\.[3-9]\.*`, string(out)); match { + return "redhat", nil + } + } + if match, _ := regexp.MatchString(`.*7\.[3-9]\.*|.*8\.[5-6]\.*`, string(out)); match { return "redhat", nil } return "", fmt.Errorf("Unable to determine OS type: %s", string(out)) From df6a79eafc53097467094ce89961a73f22726650 Mon Sep 17 00:00:00 2001 From: Devidas Khedkar <76941923+devidask27@users.noreply.github.com> Date: Fri, 29 Jul 2022 09:25:08 +0530 Subject: [PATCH 5/7] droped ubuntu 16 support (#321) * droped ubuntu 16 support * updated msg of supported os --- pkg/platform/debian/debian.go | 36 +++++++++-------------------------- pkg/pmk/checkNode.go | 2 +- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/pkg/platform/debian/debian.go b/pkg/platform/debian/debian.go index b81c24ce..bb068f4a 100644 --- a/pkg/platform/debian/debian.go +++ b/pkg/platform/debian/debian.go @@ -297,9 +297,7 @@ func (d *Debian) Version() (string, error) { return "", fmt.Errorf("Couldn't read the OS configuration file os-release: %s", err.Error()) } var isVersionMatch bool - if strings.Contains(string(majorVersion), "16") && strings.Contains(string(minorVersion), "04") { - isVersionMatch = true - } else if strings.Contains(string(majorVersion), "18") && strings.Contains(string(minorVersion), "04") { + if strings.Contains(string(majorVersion), "18") && strings.Contains(string(minorVersion), "04") { isVersionMatch = true } else if strings.Contains(string(majorVersion), "20") && strings.Contains(string(minorVersion), "04") { isVersionMatch = true @@ -469,31 +467,15 @@ func split(version, delimiter string) (string, string, string) { func (d *Debian) IsPresent(service string) error { zap.S().Debugf("checking if %s is present", service) - var cmd string - majorVersion, minorVersion, _, err1 := d.getVersion() - if err1 != nil { - zap.S().Debugf("Couldn't read the OS configuration file os-release: %s", err1.Error()) - } - if strings.Contains(string(majorVersion), "16") && strings.Contains(string(minorVersion), "04") { - cmd = fmt.Sprintf(`systemctl status %s | grep 'not-found'`, service) - _, err := d.exec.RunWithStdout("bash", "-c", cmd) - if err != nil { - zap.S().Debugf("%s is present", service) - return nil - } else { - zap.S().Debugf("%s is not present", service) - return fmt.Errorf("%s is not present", service) - } + + cmd := fmt.Sprintf(`systemctl list-unit-files %s | grep '%s'`, service, service) + _, err := d.exec.RunWithStdout("bash", "-c", cmd) + if err != nil { + zap.S().Debugf("%s is not present", service) + return err } else { - cmd = fmt.Sprintf(`systemctl list-unit-files %s | grep '%s'`, service, service) - _, err := d.exec.RunWithStdout("bash", "-c", cmd) - if err != nil { - zap.S().Debugf("%s is not present", service) - return err - } else { - zap.S().Debugf("%s is present", service) - return nil - } + zap.S().Debugf("%s is present", service) + return nil } } diff --git a/pkg/pmk/checkNode.go b/pkg/pmk/checkNode.go index 2e37eb10..e1918bfc 100644 --- a/pkg/pmk/checkNode.go +++ b/pkg/pmk/checkNode.go @@ -61,7 +61,7 @@ func CheckNode(ctx objects.Config, allClients client.Client, auth keystone.Keyst case "redhat": platform = centos.NewCentOS(allClients.Executor) default: - return RequiredFail, fmt.Errorf("This OS is not supported. Supported operating systems are: Ubuntu (16.04, 18.04, 20.04), CentOS 7.x & RHEL 7.x") + return RequiredFail, fmt.Errorf("This OS is not supported. Supported operating systems are: Ubuntu (18.04, 20.04), CentOS 7.[3-9], RHEL 7.[3-9] & RHEL 8.[5-6]") } if err = allClients.Segment.SendEvent("Starting CheckNode", auth, checkPass, ""); err != nil { From f1eb3a354e0161a02628f4a87642655b0667b0fc Mon Sep 17 00:00:00 2001 From: devidask27 Date: Fri, 29 Jul 2022 10:40:15 +0530 Subject: [PATCH 6/7] refactored/removed unnecessary code from some files --- cmd/attachNode.go | 6 ------ cmd/authoriseNode.go | 6 ------ cmd/bootstrap.go | 4 ++-- cmd/checkNode.go | 4 ++-- cmd/deauthoriseNode.go | 6 ------ cmd/decomissionNode.go | 4 ++-- cmd/deleteCluster.go | 6 ------ cmd/detachNode.go | 6 ------ cmd/prepNode.go | 4 ++-- cmd/supportBundle.go | 4 ++-- pkg/cmdexec/executor_test.go | 3 ++- pkg/config/config.go | 18 ------------------ 12 files changed, 12 insertions(+), 59 deletions(-) diff --git a/cmd/attachNode.go b/cmd/attachNode.go index 7ce22567..e1834a3a 100644 --- a/cmd/attachNode.go +++ b/cmd/attachNode.go @@ -58,12 +58,6 @@ func attachNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ - } - var err error if detachedMode { err = config.LoadConfig(util.Pf9DBLoc, cfg) diff --git a/cmd/authoriseNode.go b/cmd/authoriseNode.go index de7bef9c..f3070619 100644 --- a/cmd/authoriseNode.go +++ b/cmd/authoriseNode.go @@ -38,12 +38,6 @@ func authNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ - } - var err error if detachedMode { err = config.LoadConfig(util.Pf9DBLoc, cfg) diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 6ab13481..9c2c57ed 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -228,9 +228,9 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { } if isRemote { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { + if !config.ValidateNodeConfig(util.Node, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ + } } var err error diff --git a/cmd/checkNode.go b/cmd/checkNode.go index 23c9b5e8..4458de2c 100644 --- a/cmd/checkNode.go +++ b/cmd/checkNode.go @@ -64,9 +64,9 @@ func checkNodeRun(cmd *cobra.Command, args []string) { isRemote := cmdexec.CheckRemote(util.Node) if isRemote { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { + if !config.ValidateNodeConfig(util.Node, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ + } } var err error diff --git a/cmd/deauthoriseNode.go b/cmd/deauthoriseNode.go index dc38aa78..06ab3fa0 100644 --- a/cmd/deauthoriseNode.go +++ b/cmd/deauthoriseNode.go @@ -37,12 +37,6 @@ func deauthNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ - } - var err error if detachedMode { err = config.LoadConfig(util.Pf9DBLoc, cfg) diff --git a/cmd/decomissionNode.go b/cmd/decomissionNode.go index 17e8faad..6b934191 100644 --- a/cmd/decomissionNode.go +++ b/cmd/decomissionNode.go @@ -56,9 +56,9 @@ func decommissionNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { + if !config.ValidateNodeConfig(util.Node, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ + } } var err error diff --git a/cmd/deleteCluster.go b/cmd/deleteCluster.go index e3dbaf4c..55460274 100644 --- a/cmd/deleteCluster.go +++ b/cmd/deleteCluster.go @@ -47,12 +47,6 @@ func deleteClusterRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ - } - var err error if detachedMode { err = config.LoadConfig(util.Pf9DBLoc, cfg) diff --git a/cmd/detachNode.go b/cmd/detachNode.go index d48dcc2a..ae656b4d 100644 --- a/cmd/detachNode.go +++ b/cmd/detachNode.go @@ -42,12 +42,6 @@ func detachNodeRun(cmd *cobra.Command, args []string) { detachedMode := cmd.Flags().Changed("no-prompt") - if cmdexec.CheckRemote(util.Node) { - /*if !config.ValidateNodeConfig(host, nc, !detachedMode) { - zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ - } - var err error if detachedMode { err = config.LoadConfig(util.Pf9DBLoc, cfg) diff --git a/cmd/prepNode.go b/cmd/prepNode.go index 8ffa0874..8d1ae5c8 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -202,9 +202,9 @@ func onboardNodes(node objects.Node) { isRemote = cmdexec.CheckRemote(node) if isRemote { - /*if !config.ValidateNodeConfig(node, nc, !detachedMode) { + if !config.ValidateNodeConfig(node, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ + } } if isRemote { diff --git a/cmd/supportBundle.go b/cmd/supportBundle.go index a16b3c87..cfc0f255 100644 --- a/cmd/supportBundle.go +++ b/cmd/supportBundle.go @@ -58,9 +58,9 @@ func supportBundleUpload(cmd *cobra.Command, args []string) { isRemote := cmdexec.CheckRemote(util.Node) if isRemote { - /*f !config.ValidateNodeConfig(host, nc, !detachedMode) { + if !config.ValidateNodeConfig(util.Node, nc, !detachedMode) { zap.S().Fatal("Invalid remote node config (Username/Password/IP), use 'single quotes' to pass password") - }*/ + } } var err error diff --git a/pkg/cmdexec/executor_test.go b/pkg/cmdexec/executor_test.go index 8158ecbe..49cfb872 100644 --- a/pkg/cmdexec/executor_test.go +++ b/pkg/cmdexec/executor_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/platform9/pf9ctl/pkg/objects" + "github.com/platform9/pf9ctl/pkg/util" "github.com/stretchr/testify/assert" ) @@ -13,7 +14,7 @@ func TestGetExecutor(t *testing.T) { localExecutor := LocalExecutor{ProxyUrl: proxyURL} // Test local executor - executor, err := GetExecutor(proxyURL, &objects.NodeConfig{}) + executor, err := GetExecutor(proxyURL, util.Node, &objects.NodeConfig{}) assert.Equal(t, nil, err) assert.Equal(t, localExecutor, executor) } diff --git a/pkg/config/config.go b/pkg/config/config.go index ff61e8af..24b1f5a3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -173,12 +173,6 @@ func ValidateUserCredentials(cfg *objects.Config) error { return err } - /*c, err := createClient(cfg, nc) - defer c.Segment.Close() - if err != nil { - return fmt.Errorf("Error validating credentials %w", err) - }*/ - k := keystone.NewKeystone(cfg.Spec.AccountUrl) auth, err := k.GetAuth( cfg.Spec.Username, @@ -365,18 +359,6 @@ func ConfigCmdCreateRun(cfg *objects.Config) error { return SetProxy(cfg.Spec.ProxyURL) } -/*func createClient(cfg *objects.Config, nc *objects.NodeConfig) (client.Client, error) { - var host objects.Node - executor, err := cmdexec.GetExecutor(cfg.Spec.ProxyURL, host, nc) - if err != nil { - //debug first since Fatalf calls os.Exit - zap.S().Debug("Error connecting to host %s", err.Error()) - zap.S().Fatalf(" Invalid (Username/Password/IP), use 'single quotes' to pass password") - } - - return client.NewClient(cfg.Spec.AccountUrl, executor, cfg.Spec.OtherData.AllowInsecure, false) -}*/ - //This function clears the context if it is invalid. Before storing it. func clearContext(v interface{}) { p := reflect.ValueOf(v).Elem() From cbd5f2b4eb530313cab0fd4e17f136de3b07dd5d Mon Sep 17 00:00:00 2001 From: devidask27 Date: Mon, 1 Aug 2022 16:49:48 +0530 Subject: [PATCH 7/7] spinner for decommission --- pkg/pmk/decomissionNode.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/pmk/decomissionNode.go b/pkg/pmk/decomissionNode.go index 7c3c688f..4d9ba545 100644 --- a/pkg/pmk/decomissionNode.go +++ b/pkg/pmk/decomissionNode.go @@ -111,7 +111,6 @@ func DecommissionNode(cfg *objects.Config, nc *objects.NodeConfig, removePf9 boo if nodeInfo.ClusterName == "" { fmt.Println(color.Green("✓ ") + "Node is not connected to any cluster") if nodeConnectedToDU { - fmt.Println("Deauthorizing node:", hostID[0]) err = c.Qbert.DeauthoriseNode(hostID[0], auth.Token) if err != nil { zap.S().Fatalf("Failed to deauthorize node") @@ -138,13 +137,13 @@ func DecommissionNode(cfg *objects.Config, nc *objects.NodeConfig, removePf9 boo if removePf9 { removePf9Installation(c) } - //fmt.Println("Node decommissioning started....This may take a few minutes....Check the latest status in UI") - s.Restart() + + s.Start() s.Suffix = " Node decommissioning started....This may take a few minutes....Check the latest status in UI" - //s.FinalMSG = color.Green("✓ ") + "Node decommission completed" + s.FinalMSG = color.Green("✓ ") + "Node decommission completed\n" time.Sleep(50 * time.Second) s.Stop() - fmt.Println(color.Green("✓ ") + "Node decommission completed") + } else { //detach node from cluster fmt.Printf(color.Green("✓ ")+"Node is connected to %s cluster\n", nodeInfo.ClusterName) @@ -184,9 +183,9 @@ func DecommissionNode(cfg *objects.Config, nc *objects.NodeConfig, removePf9 boo } s.Restart() s.Suffix = " Node decommissioning started....This may take a few minutes....Check the latest status in UI" + s.FinalMSG = color.Green("✓ ") + "Node decommission completed\n" time.Sleep(50 * time.Second) s.Stop() - fmt.Println(color.Green("✓ ") + "Node decommission completed") } } else { fmt.Println("Host is not connected to Platform9 Management Plane")