From eac678513b4a4a7a0006d644a697d3b560bdd9fd Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Thu, 1 Oct 2020 19:50:29 +0530 Subject: [PATCH 01/14] Wrapped the host functions in host interface --- pkg/pmk/common.go | 30 +++++------- pkg/pmk/host.go | 114 +++++++++++++++++++++++++++++++++++++++++++++ pkg/pmk/node.go | 80 +++++++++++++------------------ pkg/util/helper.go | 12 +++++ 4 files changed, 170 insertions(+), 66 deletions(-) create mode 100644 pkg/pmk/host.go diff --git a/pkg/pmk/common.go b/pkg/pmk/common.go index 8cf5f3cf..932c839b 100644 --- a/pkg/pmk/common.go +++ b/pkg/pmk/common.go @@ -12,34 +12,23 @@ import ( func setupNode(hostOS string) (err error) { log.Debug("Received a call to setup the node") - if err := swapOff(); err != nil { - return err + if err := host.SwapOff(); err != nil { + return fmt.Errorf("Unable to disable swap: %w", err) } if err := handlePF9UserGroup(); err != nil { return err } - switch hostOS { - case "redhat": - err = redhatCentosPackageInstall() - if err != nil { - return - } - err = ntpInstallActivateRedhatCentos() - - case "debian": - err = ubuntuPackageInstall() - if err != nil { - return - } - err = ntpInstallActivateUbuntu() + if err := host.Setup(); err != nil { + return fmt.Errorf("Unable to setup the host: %w", err) + } - default: - err = fmt.Errorf("Invalid Host: %s", hostOS) + if err := host.EnableNTP(); err != nil { + return fmt.Errorf("Unable to enable NTP for host: %w", err) } - return + return nil } func handlePF9UserGroup() error { @@ -95,6 +84,7 @@ func createPF9Group(name string) error { return nil } +<<<<<<< HEAD func ubuntuPackageInstall() error { log.Info("Installing required ubuntu packages") @@ -148,3 +138,5 @@ func swapOff() error { _, err := exec.Command("bash", "-c", "swapoff -a").Output() return err } +======= +>>>>>>> Wrapped the host functions in host interface diff --git a/pkg/pmk/host.go b/pkg/pmk/host.go new file mode 100644 index 00000000..a617b1c2 --- /dev/null +++ b/pkg/pmk/host.go @@ -0,0 +1,114 @@ +package pmk + +import ( + "fmt" + + "github.com/platform9/pf9ctl/pkg/pmk/clients" +) + +// Host interface exposes the functions +// required to setup the host correctly. +type Host interface { + Setup() error + InstallPackage(...string) error + EnableNTP() error + SwapOff() error + String() string + PackagePresent(name string) bool +} + +//Redhat host encapsulates menthods +//required to bootup the redhat host. +type Redhat struct { + exec clients.Executor +} + +func (h Redhat) String() string { + return "redhat" +} + +// PackagePresent checks for the package in the Redhat host. +func (h Redhat) PackagePresent(name string) bool { + err := h.exec.Run("bash", "-c", fmt.Sprintf("yum list | grep -i '%s'", name)) + return err == nil +} + +// Setup installes the necessary packages for the +// host to start functioning correctly. +func (h Redhat) Setup() error { + return h.InstallPackage("libselinux-python") +} + +// InstallPackage installs packages provided in the arguments +// for the Redhat host. +func (h Redhat) InstallPackage(names ...string) error { + packages := "" + for _, name := range names { + packages += " " + name + } + return h.exec.Run( + "bash", + "-c", + fmt.Sprintf("yum install -y %s", packages)) +} + +//EnableNTP enables the NTP service for the Redhat host. +func (h Redhat) EnableNTP() error { + err := h.InstallPackage("ntp") + err = h.exec.Run("bash", "-c", "systemctl enable --now ntp") + return err +} + +//SwapOff disables the swap for the Redhat host. +func (h Redhat) SwapOff() error { + return h.exec.Run("bash", "-c", "swapoff -a") +} + +type Debian struct { + exec clients.Executor +} + +//Setup sets the host up with required packages for +//the preping the node up. +func (h Debian) Setup() error { + err := h.exec.Run("bash", "-c", "apt-get update") + err = h.InstallPackage("curl", "uuid-runtime", "software-properties-common", "logrotate") + return err +} + +// InstallPackage installs packages provided in the arguments +// for the DebianHost +func (h Debian) InstallPackage(names ...string) error { + + packages := "" + for _, p := range names { + packages += " " + p + } + + return h.exec.Run( + "bash", + "-c", + fmt.Sprintf("apt-get install -y %s", packages)) +} + +// EnableNTP service for the DebianHost +func (h Debian) EnableNTP() error { + err := h.InstallPackage("ntp") + err = h.exec.Run("bash", "-c", "systemctl enable --now ntp") + return err +} + +// SwapOff disables the swap. +func (h Debian) SwapOff() error { + return h.exec.Run("bash", "-c", "swapoff -a") +} + +func (h Debian) String() string { + return "debian" +} + +//PackagePresent checks if the package present on the host. +func (h Debian) PackagePresent(name string) bool { + err := h.exec.Run("bash", "-c", fmt.Sprintf("dpkg -l | grep '%s'", name)) + return err == nil +} diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 31f85f59..38e8aedb 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -8,11 +8,10 @@ import ( "os/exec" "runtime" "strings" - "time" - "github.com/platform9/pf9ctl/pkg/constants" "github.com/platform9/pf9ctl/pkg/log" "github.com/platform9/pf9ctl/pkg/pmk/clients" + "github.com/platform9/pf9ctl/pkg/util" ) // PrepNode sets up prerequisites for k8s stack @@ -26,17 +25,17 @@ func PrepNode( log.Debug("Received a call to start preping node(s).") - hostOS, err := validatePlatform() + host, err := getHost("/etc/os-release", c.Executor) if err != nil { return fmt.Errorf("Invalid host os: %s", err.Error()) } - present := pf9PackagesPresent(hostOS, c.Executor) + present := host.PackagePresent("pf9-") if present { return fmt.Errorf("Platform9 packages already present on the host. Please uninstall these packages if you want to prep the node again") } - err = setupNode(hostOS) + err = setupNode(host) if err != nil { return fmt.Errorf("Unable to setup node: %s", err.Error()) } @@ -51,7 +50,7 @@ func PrepNode( return fmt.Errorf("Unable to locate keystone credentials: %s", err.Error()) } - if err := installHostAgent(ctx, auth, hostOS); err != nil { + if err := installHostAgent(ctx, auth, host.String()); err != nil { return fmt.Errorf("Unable to install hostagent: %w", err) } @@ -64,7 +63,6 @@ func PrepNode( } hostID := strings.TrimSuffix(output, "\n") - time.Sleep(constants.WaitPeriod * time.Second) if err := c.Resmgr.AuthorizeHost(hostID, auth.Token); err != nil { return err @@ -77,10 +75,10 @@ func PrepNode( return nil } -func installHostAgent(ctx Context, auth clients.KeystoneAuth, hostOS string) error { - log.Debug("Downloading Hostagent") +func installHostAgent(ctx Context, auth clients.KeystoneAuth, host string) error { + log.Info("Download Hostagent") - url := fmt.Sprintf("%s/clarity/platform9-install-%s.sh", ctx.Fqdn, hostOS) + url := fmt.Sprintf("%s/clarity/platform9-install-%s.sh", ctx.Fqdn, host) req, err := http.NewRequest("GET", url, nil) if err != nil { return fmt.Errorf("Unable to create a http request: %w", err) @@ -94,9 +92,9 @@ func installHostAgent(ctx Context, auth clients.KeystoneAuth, hostOS string) err switch resp.StatusCode { case 404: - return installHostAgentLegacy(ctx, auth, hostOS) + return installHostAgentLegacy(ctx, auth, host) case 200: - return installHostAgentCertless(ctx, auth, hostOS) + return installHostAgentCertless(ctx, auth, host) default: return fmt.Errorf("Invalid status code when identifiying hostagent type: %d", resp.StatusCode) } @@ -140,64 +138,52 @@ func installHostAgentCertless(ctx Context, auth clients.KeystoneAuth, hostOS str return nil } -func validatePlatform() (string, error) { +func getHost(hostReleaseLoc string, exec clients.Executor) (Host, error) { log.Debug("Received a call to validate platform") OS := runtime.GOOS if OS != "linux" { - return "", fmt.Errorf("Unsupported OS: %s", OS) + return nil, fmt.Errorf("Unsupported OS: %s", OS) } - data, err := ioutil.ReadFile("/etc/os-release") + data, err := ioutil.ReadFile(hostReleaseLoc) if err != nil { - return "", fmt.Errorf("failed reading data from file: %s", err) + return nil, fmt.Errorf("failed reading data from file: %w", err) } - strDataLower := strings.ToLower(string(data)) + release := strings.ToLower(string(data)) switch { - case strings.Contains(strDataLower, "centos") || strings.Contains(strDataLower, "redhat"): - out, err := exec.Command( + case strings.Contains(release, "centos") || strings.Contains(release, "redhat"): + out, err := exec.RunWithStdout( "bash", "-c", - "cat /etc/*release | grep '(Core)' | grep 'CentOS Linux release' -m 1 | cut -f4 -d ' '").Output() + "cat /etc/*release | grep '(Core)' | grep 'CentOS Linux release' -m 1 | cut -f4 -d ' '") if err != nil { - return "", fmt.Errorf("Couldn't read the OS configuration file os-release: %s", err.Error()) + return nil, fmt.Errorf("Couldn't read the OS configuration file os-release: %w", err) } - if strings.Contains(string(out), "7.5") || strings.Contains(string(out), "7.6") || strings.Contains(string(out), "7.7") || strings.Contains(string(out), "7.8") { - return "redhat", nil + + if util.StringContainsAny(out, []string{"7.5", "7.6", "7.7", "7.8"}) { + return Redhat{exec}, nil } + return nil, fmt.Errorf("Only %s versions of centos are supported", "7.5 7.6 7.7 7.8") - case strings.Contains(strDataLower, "ubuntu"): - out, err := exec.Command( + case strings.Contains(release, "ubuntu"): + out, err := exec.RunWithStdout( "bash", "-c", - "cat /etc/*os-release | grep -i pretty_name | cut -d ' ' -f 2").Output() + "cat /etc/*os-release | grep -i pretty_name | cut -d ' ' -f 2") if err != nil { - return "", fmt.Errorf("Couldn't read the OS configuration file os-release: %s", err.Error()) - } - if strings.Contains(string(out), "16") || strings.Contains(string(out), "18") { - return "debian", nil + return nil, fmt.Errorf("Couldn't read the OS configuration file os-release: %s", err.Error()) } - } - return "", nil -} + if util.StringContainsAny(out, []string{"16", "18"}) { + return Debian{exec: exec}, nil + } + return nil, fmt.Errorf("Only %s versions of ubuntu are supported", "16 18") -func pf9PackagesPresent(hostOS string, exec clients.Executor) bool { - var err error - if hostOS == "debian" { - err = exec.Run("bash", - "-c", - "dpkg -l | grep -i 'pf9-'") - } else { - // not checking for redhat because if it has already passed validation - // it must be either debian or redhat based - err = exec.Run("bash", - "-c", - "yum list | grep -i 'pf9-'") + default: + return nil, fmt.Errorf("Invalid release: %s", release) } - - return err == nil } func installHostAgentLegacy(ctx Context, auth clients.KeystoneAuth, hostOS string) error { diff --git a/pkg/util/helper.go b/pkg/util/helper.go index 3ab9107d..15174047 100644 --- a/pkg/util/helper.go +++ b/pkg/util/helper.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "regexp" + "strings" ) var ( @@ -98,3 +99,14 @@ func AskBool(msg string, args ...interface{}) (bool, error) { return false, fmt.Errorf("Please provide input as y or n, provided: %s", resp) } + +func StringContainsAny(base string, contains []string) bool { + + for _, contain := range contains { + if strings.Contains(base, contain) { + return true + } + } + + return false +} From 16d8f9b13c4ad550c18498809cfc60017ba18148 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 00:05:23 +0530 Subject: [PATCH 02/14] Added base support for proxy configuration handling --- cmd/bootstrap.go | 2 +- cmd/context.go | 5 ++++ cmd/prepNode.go | 2 +- pkg/pmk/clients/clients.go | 24 ++++++++++++---- pkg/pmk/clients/http.go | 56 +++++++++++++++++++++++++++++++++++++ pkg/pmk/clients/keystone.go | 17 +++++++---- pkg/pmk/clients/qbert.go | 35 ++++++++++------------- pkg/pmk/clients/resmgr.go | 15 ++++------ pkg/pmk/cluster.go | 9 ++---- pkg/pmk/context.go | 1 + pkg/pmk/host.go | 2 +- 11 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 pkg/pmk/clients/http.go diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 472a7311..3c60b990 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -50,7 +50,7 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { log.Fatalf("Unable to load context: %s", err.Error()) } - c, err := clients.New(ctx.Fqdn) + c, err := clients.New(ctx.Fqdn, ctx.Proxy) if err != nil { log.Fatalf("Unable to load clients: %s", err.Error()) } diff --git a/cmd/context.go b/cmd/context.go index 31da2003..ae484795 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -47,6 +47,10 @@ func contextCmdCreateRun(cmd *cobra.Command, args []string) { service, _ := reader.ReadString('\n') service = strings.TrimSuffix(service, "\n") + fmt.Printf("Proxy: ") + proxy, _ := reader.ReadString('\n') + proxy = strings.TrimSuffix(proxy, "\n") + if region == "" { region = "RegionOne" } @@ -61,6 +65,7 @@ func contextCmdCreateRun(cmd *cobra.Command, args []string) { Password: encodedPasswd, Region: region, Tenant: service, + Proxy: proxy, } if err := pmk.StoreContext(ctx, constants.Pf9DBLoc); err != nil { diff --git a/cmd/prepNode.go b/cmd/prepNode.go index f90f410e..5ed887b9 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -44,7 +44,7 @@ func prepNodeRun(cmd *cobra.Command, args []string) { log.Fatalf("Unable to load the context: %s\n", err.Error()) } - c, err := clients.New(ctx.Fqdn) + clients, err := clients.New(ctx.Fqdn, ctx.Proxy) if err != nil { log.Fatalf("Unable to load clients needed for the Cmd. Error: %s", err.Error()) } diff --git a/pkg/pmk/clients/clients.go b/pkg/pmk/clients/clients.go index 57d05c16..974e4030 100644 --- a/pkg/pmk/clients/clients.go +++ b/pkg/pmk/clients/clients.go @@ -1,8 +1,10 @@ package clients +import "github.com/platform9/pf9ctl/pkg/util" + const HTTPMaxRetry = 5 -// Clients struct encapsulate the collection of +// Client struct encapsulate the collection of // external services type Client struct { Resmgr Resmgr @@ -10,16 +12,28 @@ type Client struct { Qbert Qbert Executor Executor Segment Segment + HTTP HTTP } // New creates the clients needed by the CLI // to interact with the external services. -func New(fqdn string) (Client, error) { +func New(fqdn string, proxy string) (Client, error) { + + http, err := NewHTTP( + func(impl *HTTPImpl) { impl.Proxy = proxy }, + func(impl *HTTPImpl) { impl.RetryPolicy = util.RetryPolicyOn404 }, + func(impl *HTTPImpl) { impl.Retry = HTTPMaxRetry }) + + if err != nil { + return Client{}, err + } + return Client{ - Resmgr: NewResmgr(fqdn), - Keystone: NewKeystone(fqdn), - Qbert: NewQbert(fqdn), + Resmgr: NewResmgr(fqdn, http), + Keystone: NewKeystone(fqdn, http), + Qbert: NewQbert(fqdn, http), Executor: ExecutorImpl{}, Segment: NewSegment(fqdn), + HTTP: http, }, nil } diff --git a/pkg/pmk/clients/http.go b/pkg/pmk/clients/http.go new file mode 100644 index 00000000..26eacf7b --- /dev/null +++ b/pkg/pmk/clients/http.go @@ -0,0 +1,56 @@ +package clients + +import ( + "net/http" + "net/url" + + rhttp "github.com/hashicorp/go-retryablehttp" +) + +type HTTP interface { + Do(req *rhttp.Request) (*http.Response, error) +} + +type HTTPImpl struct { + Proxy string + Retry int + client *rhttp.Client + RetryPolicy rhttp.CheckRetry + Backoff rhttp.Backoff + ProxyURL *url.URL +} + +func NewHTTP(options ...func(*HTTPImpl)) (*HTTPImpl, error) { + resp := &HTTPImpl{} + + for _, option := range options { + option(resp) + } + + if resp.Proxy != "" { + proxyURL, err := url.Parse(resp.Proxy) + if err != nil { + return nil, err + } + resp.ProxyURL = proxyURL + } + + client := &rhttp.Client{} + client.RetryMax = resp.Retry + + if resp.RetryPolicy != nil { + client.CheckRetry = resp.RetryPolicy + } + + if resp.Backoff != nil { + client.Backoff = resp.Backoff + } + + resp.client = client + return resp, nil +} + +// Do function simply calls the underlying client to make the request. +func (c HTTPImpl) Do(req *rhttp.Request) (*http.Response, error) { + return c.client.Do(req) +} diff --git a/pkg/pmk/clients/keystone.go b/pkg/pmk/clients/keystone.go index ed922fd5..f52e337e 100644 --- a/pkg/pmk/clients/keystone.go +++ b/pkg/pmk/clients/keystone.go @@ -4,9 +4,9 @@ import ( "encoding/base64" "encoding/json" "fmt" - "net/http" "strings" + rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" ) @@ -21,11 +21,12 @@ type Keystone interface { } type KeystoneImpl struct { - fqdn string + fqdn string + client HTTP } -func NewKeystone(fqdn string) Keystone { - return KeystoneImpl{fqdn} +func NewKeystone(fqdn string, client HTTP) Keystone { + return KeystoneImpl{fqdn: fqdn, client: client} } func (k KeystoneImpl) GetAuth( @@ -65,7 +66,13 @@ func (k KeystoneImpl) GetAuth( } }`, username, decodedPassword, tenant) - resp, err := http.Post(url, "application/json", strings.NewReader(body)) + req, err := rhttp.NewRequest("POST", url, strings.NewReader(body)) + if err != nil { + return auth, nil + } + req.Header.Add("Content-Type", "application/json") + + resp, err := k.client.Do(req) if err != nil { return auth, err } diff --git a/pkg/pmk/clients/qbert.go b/pkg/pmk/clients/qbert.go index 00a9808d..128ec2da 100644 --- a/pkg/pmk/clients/qbert.go +++ b/pkg/pmk/clients/qbert.go @@ -4,12 +4,10 @@ import ( "encoding/json" "errors" "fmt" - "net/http" "strings" rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" - "github.com/platform9/pf9ctl/pkg/util" ) // CloudProviderType specifies the infrastructure where the cluster runs @@ -24,12 +22,13 @@ type Qbert interface { GetNodePoolID(projectID, token string) (string, error) } -func NewQbert(fqdn string) Qbert { - return QbertImpl{fqdn} +func NewQbert(fqdn string, client HTTP) Qbert { + return QbertImpl{fqdn, client} } type QbertImpl struct { - fqdn string + fqdn string + client HTTP } type ClusterCreateRequest struct { @@ -75,17 +74,14 @@ func (c QbertImpl) CreateCluster( url := fmt.Sprintf("%s/qbert/v3/%s/clusters", c.fqdn, projectID) - client := http.Client{} - req, err := http.NewRequest("POST", url, strings.NewReader(string(byt))) - + req, err := rhttp.NewRequest("POST", url, strings.NewReader(string(byt))) if err != nil { - fmt.Println(err.Error()) return "", err } req.Header.Set("X-Auth-Token", token) req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + resp, err := c.client.Do(req) if err != nil { return "", err } @@ -122,10 +118,6 @@ func (c QbertImpl) AttachNode(clusterID, nodeID, projectID, token string) error "%s/qbert/v3/%s/clusters/%s/attach", c.fqdn, projectID, clusterID) - client := rhttp.Client{} - client.RetryMax = 5 - client.CheckRetry = rhttp.CheckRetry(util.RetryPolicyOn404) - req, err := rhttp.NewRequest("POST", attachEndpoint, strings.NewReader(string(byt))) if err != nil { return fmt.Errorf("Unable to create a request: %w", err) @@ -133,7 +125,7 @@ func (c QbertImpl) AttachNode(clusterID, nodeID, projectID, token string) error req.Header.Set("X-Auth-Token", token) req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + resp, err := c.client.Do(req) if err != nil { return fmt.Errorf("Unable to POST request through client: %w", err) } @@ -148,24 +140,25 @@ func (c QbertImpl) AttachNode(clusterID, nodeID, projectID, token string) error func (c QbertImpl) GetNodePoolID(projectID, token string) (string, error) { - qbertAPIEndpoint := fmt.Sprintf("%s/qbert/v3/%s/cloudProviders", c.fqdn, projectID) // Context should return projectID,make changes to keystoneAuth. - client := http.Client{} - - req, err := http.NewRequest("GET", qbertAPIEndpoint, nil) + qbertAPIEndpoint := fmt.Sprintf("%s/qbert/v3/%s/cloudProviders", c.fqdn, projectID) + req, err := rhttp.NewRequest("GET", qbertAPIEndpoint, nil) if err != nil { return "", err } - req.Header.Set("X-Auth-Token", token) // + req.Header.Set("X-Auth-Token", token) req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + + resp, err := c.client.Do(req) if err != nil { return "", err } + if resp.StatusCode != 200 { return "", fmt.Errorf("Couldn't query the qbert Endpoint: %s", err.Error()) } + var payload []map[string]string decoder := json.NewDecoder(resp.Body) diff --git a/pkg/pmk/clients/resmgr.go b/pkg/pmk/clients/resmgr.go index 57885b2b..7b014c97 100644 --- a/pkg/pmk/clients/resmgr.go +++ b/pkg/pmk/clients/resmgr.go @@ -5,7 +5,6 @@ import ( rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" - "github.com/platform9/pf9ctl/pkg/util" ) type Resmgr interface { @@ -13,22 +12,18 @@ type Resmgr interface { } type ResmgrImpl struct { - fqdn string + fqdn string + client HTTP } -func NewResmgr(fqdn string) Resmgr { - return &ResmgrImpl{fqdn} +func NewResmgr(fqdn string, client HTTP) Resmgr { + return &ResmgrImpl{fqdn: fqdn, client: client} } // AuthorizeHost registers the host with hostID to the resmgr. func (c *ResmgrImpl) AuthorizeHost(hostID string, token string) error { log.Debugf("Authorizing the host: %s with DU: %s", hostID, c.fqdn) - client := rhttp.NewClient() - client.RetryMax = HTTPMaxRetry - client.CheckRetry = rhttp.CheckRetry(util.RetryPolicyOn404) - client.Logger = nil - url := fmt.Sprintf("%s/resmgr/v1/hosts/%s/roles/pf9-kube", c.fqdn, hostID) req, err := rhttp.NewRequest("PUT", url, nil) if err != nil { @@ -38,7 +33,7 @@ func (c *ResmgrImpl) AuthorizeHost(hostID string, token string) error { req.Header.Set("X-Auth-Token", token) req.Header.Set("Content-Type", "application/json") - resp, err := client.Do(req) + resp, err := c.client.Do(req) if err != nil { return fmt.Errorf("Unable to send request to the client: %w", err) } diff --git a/pkg/pmk/cluster.go b/pkg/pmk/cluster.go index 74b1d733..9acb8baa 100644 --- a/pkg/pmk/cluster.go +++ b/pkg/pmk/cluster.go @@ -3,9 +3,7 @@ package pmk import ( "fmt" "strings" - "time" - "github.com/platform9/pf9ctl/pkg/constants" "github.com/platform9/pf9ctl/pkg/log" "github.com/platform9/pf9ctl/pkg/pmk/clients" "github.com/platform9/pf9ctl/pkg/util" @@ -43,17 +41,16 @@ func Bootstrap(ctx Context, c clients.Client, req clients.ClusterCreateRequest) if err != nil { return fmt.Errorf("Unable to create cluster: %w", err) } + log.Info.Println("Cluster created successfully") cmd := `cat /etc/pf9/host_id.conf | grep ^host_id | cut -d = -f2 | cut -d ' ' -f2` output, err := c.Executor.RunWithStdout("bash", "-c", cmd) if err != nil { return fmt.Errorf("Unable to execute command: %w", err) } - nodeID := strings.TrimSuffix(string(output), "\n") - - time.Sleep(constants.WaitPeriod * time.Second) - log.Info("Attaching node to the cluster...") + nodeID := strings.TrimSuffix(output, "\n") + err = c.Qbert.AttachNode( clusterID, nodeID, diff --git a/pkg/pmk/context.go b/pkg/pmk/context.go index c5cdbeda..dd5b09b9 100644 --- a/pkg/pmk/context.go +++ b/pkg/pmk/context.go @@ -15,6 +15,7 @@ type Context struct { Password string `json:"os_password"` Tenant string `json:"os_tenant"` Region string `json:"os_region"` + Proxy string `json:"proxy"` } // StoreContext simply updates the in-memory object diff --git a/pkg/pmk/host.go b/pkg/pmk/host.go index a617b1c2..397c39cf 100644 --- a/pkg/pmk/host.go +++ b/pkg/pmk/host.go @@ -54,7 +54,7 @@ func (h Redhat) InstallPackage(names ...string) error { //EnableNTP enables the NTP service for the Redhat host. func (h Redhat) EnableNTP() error { - err := h.InstallPackage("ntp") + err := h.InstallPackage("ntpd") err = h.exec.Run("bash", "-c", "systemctl enable --now ntp") return err } From d70327aaf4f865c7a58255db29edce5bf9321ccd Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 14:46:06 +0530 Subject: [PATCH 03/14] Fixed process of setting the proxy settings --- go.mod | 3 +++ go.sum | 7 +++++++ pkg/pmk/clients/clients.go | 3 --- pkg/pmk/clients/http.go | 37 +++++++++++++++++-------------------- pkg/pmk/clients/keystone.go | 4 ++-- pkg/pmk/clients/qbert.go | 8 ++++---- pkg/pmk/clients/resmgr.go | 4 ++-- pkg/pmk/cluster.go | 1 - pkg/pmk/node.go | 4 ++++ 9 files changed, 39 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index c63ec8b4..7102b38b 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,9 @@ module github.com/platform9/pf9ctl go 1.14 require ( + github.com/PuerkitoBio/rehttp v1.0.0 + github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 // indirect + github.com/benbjohnson/clock v1.0.3 // indirect github.com/google/uuid v1.1.2 github.com/hashicorp/go-retryablehttp v0.6.7 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index 8ed2a06e..7a6fb602 100644 --- a/go.sum +++ b/go.sum @@ -2,11 +2,17 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/rehttp v1.0.0 h1:aJ7A7YI2lIvOxcJVeUZY4P6R7kKZtLeONjgyKGwOIu8= +github.com/PuerkitoBio/rehttp v1.0.0/go.mod h1:ItsOiHl4XeMOV3rzbZqQRjLc3QQxbE6391/9iNG7rE8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= +github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= +github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -158,6 +164,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/pmk/clients/clients.go b/pkg/pmk/clients/clients.go index 974e4030..c81fa6c9 100644 --- a/pkg/pmk/clients/clients.go +++ b/pkg/pmk/clients/clients.go @@ -1,7 +1,5 @@ package clients -import "github.com/platform9/pf9ctl/pkg/util" - const HTTPMaxRetry = 5 // Client struct encapsulate the collection of @@ -21,7 +19,6 @@ func New(fqdn string, proxy string) (Client, error) { http, err := NewHTTP( func(impl *HTTPImpl) { impl.Proxy = proxy }, - func(impl *HTTPImpl) { impl.RetryPolicy = util.RetryPolicyOn404 }, func(impl *HTTPImpl) { impl.Retry = HTTPMaxRetry }) if err != nil { diff --git a/pkg/pmk/clients/http.go b/pkg/pmk/clients/http.go index 26eacf7b..6763dc2f 100644 --- a/pkg/pmk/clients/http.go +++ b/pkg/pmk/clients/http.go @@ -3,21 +3,20 @@ package clients import ( "net/http" "net/url" + "time" - rhttp "github.com/hashicorp/go-retryablehttp" + "github.com/PuerkitoBio/rehttp" ) type HTTP interface { - Do(req *rhttp.Request) (*http.Response, error) + Do(req *http.Request) (*http.Response, error) } type HTTPImpl struct { - Proxy string - Retry int - client *rhttp.Client - RetryPolicy rhttp.CheckRetry - Backoff rhttp.Backoff - ProxyURL *url.URL + Proxy string + Retry int + client *http.Client + ProxyURL *url.URL } func NewHTTP(options ...func(*HTTPImpl)) (*HTTPImpl, error) { @@ -27,30 +26,28 @@ func NewHTTP(options ...func(*HTTPImpl)) (*HTTPImpl, error) { option(resp) } + var transport *http.Transport if resp.Proxy != "" { proxyURL, err := url.Parse(resp.Proxy) if err != nil { return nil, err } - resp.ProxyURL = proxyURL - } - - client := &rhttp.Client{} - client.RetryMax = resp.Retry - if resp.RetryPolicy != nil { - client.CheckRetry = resp.RetryPolicy + resp.ProxyURL = proxyURL + transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)} } - if resp.Backoff != nil { - client.Backoff = resp.Backoff - } + t := rehttp.NewTransport(transport, rehttp.RetryAny( + rehttp.RetryMaxRetries(resp.Retry), + rehttp.RetryTemporaryErr(), + rehttp.RetryStatuses(400, 404)), + rehttp.ExpJitterDelay(time.Second*time.Duration(2), time.Second*time.Duration(60))) - resp.client = client + resp.client = &http.Client{Transport: t} return resp, nil } // Do function simply calls the underlying client to make the request. -func (c HTTPImpl) Do(req *rhttp.Request) (*http.Response, error) { +func (c HTTPImpl) Do(req *http.Request) (*http.Response, error) { return c.client.Do(req) } diff --git a/pkg/pmk/clients/keystone.go b/pkg/pmk/clients/keystone.go index f52e337e..c15170af 100644 --- a/pkg/pmk/clients/keystone.go +++ b/pkg/pmk/clients/keystone.go @@ -4,9 +4,9 @@ import ( "encoding/base64" "encoding/json" "fmt" + "net/http" "strings" - rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" ) @@ -66,7 +66,7 @@ func (k KeystoneImpl) GetAuth( } }`, username, decodedPassword, tenant) - req, err := rhttp.NewRequest("POST", url, strings.NewReader(body)) + req, err := http.NewRequest("POST", url, strings.NewReader(body)) if err != nil { return auth, nil } diff --git a/pkg/pmk/clients/qbert.go b/pkg/pmk/clients/qbert.go index 128ec2da..b38ad3a5 100644 --- a/pkg/pmk/clients/qbert.go +++ b/pkg/pmk/clients/qbert.go @@ -4,9 +4,9 @@ import ( "encoding/json" "errors" "fmt" + "net/http" "strings" - rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" ) @@ -74,7 +74,7 @@ func (c QbertImpl) CreateCluster( url := fmt.Sprintf("%s/qbert/v3/%s/clusters", c.fqdn, projectID) - req, err := rhttp.NewRequest("POST", url, strings.NewReader(string(byt))) + req, err := http.NewRequest("POST", url, strings.NewReader(string(byt))) if err != nil { return "", err } @@ -118,7 +118,7 @@ func (c QbertImpl) AttachNode(clusterID, nodeID, projectID, token string) error "%s/qbert/v3/%s/clusters/%s/attach", c.fqdn, projectID, clusterID) - req, err := rhttp.NewRequest("POST", attachEndpoint, strings.NewReader(string(byt))) + req, err := http.NewRequest("POST", attachEndpoint, strings.NewReader(string(byt))) if err != nil { return fmt.Errorf("Unable to create a request: %w", err) } @@ -141,7 +141,7 @@ func (c QbertImpl) AttachNode(clusterID, nodeID, projectID, token string) error func (c QbertImpl) GetNodePoolID(projectID, token string) (string, error) { qbertAPIEndpoint := fmt.Sprintf("%s/qbert/v3/%s/cloudProviders", c.fqdn, projectID) - req, err := rhttp.NewRequest("GET", qbertAPIEndpoint, nil) + req, err := http.NewRequest("GET", qbertAPIEndpoint, nil) if err != nil { return "", err diff --git a/pkg/pmk/clients/resmgr.go b/pkg/pmk/clients/resmgr.go index 7b014c97..6b08ffb1 100644 --- a/pkg/pmk/clients/resmgr.go +++ b/pkg/pmk/clients/resmgr.go @@ -2,8 +2,8 @@ package clients import ( "fmt" + "net/http" - rhttp "github.com/hashicorp/go-retryablehttp" "github.com/platform9/pf9ctl/pkg/log" ) @@ -25,7 +25,7 @@ func (c *ResmgrImpl) AuthorizeHost(hostID string, token string) error { log.Debugf("Authorizing the host: %s with DU: %s", hostID, c.fqdn) url := fmt.Sprintf("%s/resmgr/v1/hosts/%s/roles/pf9-kube", c.fqdn, hostID) - req, err := rhttp.NewRequest("PUT", url, nil) + req, err := http.NewRequest("PUT", url, nil) if err != nil { return fmt.Errorf("Unable to create a new request: %w", err) } diff --git a/pkg/pmk/cluster.go b/pkg/pmk/cluster.go index 9acb8baa..cc48854e 100644 --- a/pkg/pmk/cluster.go +++ b/pkg/pmk/cluster.go @@ -50,7 +50,6 @@ func Bootstrap(ctx Context, c clients.Client, req clients.ClusterCreateRequest) } log.Info("Attaching node to the cluster...") nodeID := strings.TrimSuffix(output, "\n") - err = c.Qbert.AttachNode( clusterID, nodeID, diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 38e8aedb..00748339 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -204,6 +204,10 @@ func installHostAgentLegacy(ctx Context, auth clients.KeystoneAuth, hostOS strin return err } + if ctx.Proxy != "" { + + } + cmd = fmt.Sprintf(`/tmp/installer.sh --no-proxy --skip-os-check --ntpd %s`, installOptions) _, err = exec.Command("bash", "-c", cmd).Output() if err != nil { From 58c7bb5400a1349baa505568f6936d597aece925 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 18:48:27 +0530 Subject: [PATCH 04/14] Fixed the condition for retrying --- pkg/pmk/clients/http.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/pmk/clients/http.go b/pkg/pmk/clients/http.go index 6763dc2f..c552c806 100644 --- a/pkg/pmk/clients/http.go +++ b/pkg/pmk/clients/http.go @@ -26,7 +26,7 @@ func NewHTTP(options ...func(*HTTPImpl)) (*HTTPImpl, error) { option(resp) } - var transport *http.Transport + var transport http.RoundTripper if resp.Proxy != "" { proxyURL, err := url.Parse(resp.Proxy) if err != nil { @@ -35,13 +35,19 @@ func NewHTTP(options ...func(*HTTPImpl)) (*HTTPImpl, error) { resp.ProxyURL = proxyURL transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)} + } else { + transport = http.DefaultTransport } - t := rehttp.NewTransport(transport, rehttp.RetryAny( + t := rehttp.NewTransport(transport, rehttp.RetryAll( + rehttp.RetryAny( + rehttp.RetryTemporaryErr(), + rehttp.RetryStatuses(400, 404), + ), rehttp.RetryMaxRetries(resp.Retry), - rehttp.RetryTemporaryErr(), - rehttp.RetryStatuses(400, 404)), - rehttp.ExpJitterDelay(time.Second*time.Duration(2), time.Second*time.Duration(60))) + ), + // rehttp.ExpJitterDelay(time.Second*time.Duration(2), time.Second*time.Duration(60)) + rehttp.ConstDelay(time.Second*time.Duration(10))) resp.client = &http.Client{Transport: t} return resp, nil From f4bdbe952e6c604f533978e49640112c141a2c4b Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 18:49:16 +0530 Subject: [PATCH 05/14] Fix enabling ntp service in Redhat host --- pkg/pmk/host.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pmk/host.go b/pkg/pmk/host.go index 397c39cf..4a90b093 100644 --- a/pkg/pmk/host.go +++ b/pkg/pmk/host.go @@ -55,7 +55,7 @@ func (h Redhat) InstallPackage(names ...string) error { //EnableNTP enables the NTP service for the Redhat host. func (h Redhat) EnableNTP() error { err := h.InstallPackage("ntpd") - err = h.exec.Run("bash", "-c", "systemctl enable --now ntp") + err = h.exec.Run("bash", "-c", "systemctl enable --now ntpd") return err } From f44ea09e300e4d191329ed42067b915d20cb9693 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 20:59:07 +0530 Subject: [PATCH 06/14] Started downloading hostagent through http client and enabled installing hostagent through proxy --- pkg/pmk/node.go | 96 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 00748339..7fc43511 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -3,9 +3,10 @@ package pmk import ( "encoding/base64" "fmt" + "io" "io/ioutil" "net/http" - "os/exec" + "os" "runtime" "strings" @@ -50,7 +51,7 @@ func PrepNode( return fmt.Errorf("Unable to locate keystone credentials: %s", err.Error()) } - if err := installHostAgent(ctx, auth, host.String()); err != nil { + if err := installHostAgent(ctx, c, auth, host.String()); err != nil { return fmt.Errorf("Unable to install hostagent: %w", err) } @@ -75,7 +76,8 @@ func PrepNode( return nil } -func installHostAgent(ctx Context, auth clients.KeystoneAuth, host string) error { +func installHostAgent( + ctx Context, c clients.Client, auth clients.KeystoneAuth, host string) error { log.Info("Download Hostagent") url := fmt.Sprintf("%s/clarity/platform9-install-%s.sh", ctx.Fqdn, host) @@ -87,34 +89,39 @@ func installHostAgent(ctx Context, auth clients.KeystoneAuth, host string) error client := http.Client{} resp, err := client.Do(req) if err != nil { - return fmt.Errorf("Unable to send a request to clientL %w", err) + return fmt.Errorf("Unable to send a request to client %w", err) } switch resp.StatusCode { case 404: - return installHostAgentLegacy(ctx, auth, host) + return installHostAgentLegacy( + ctx, auth, c.HTTP, c.Executor, host) case 200: - return installHostAgentCertless(ctx, auth, host) + return installHostAgentCertless( + ctx, auth, c.HTTP, c.Executor, host) default: return fmt.Errorf("Invalid status code when identifiying hostagent type: %d", resp.StatusCode) } } -func installHostAgentCertless(ctx Context, auth clients.KeystoneAuth, hostOS string) error { +func installHostAgentCertless( + ctx Context, auth clients.KeystoneAuth, httpClient clients.HTTP, exec clients.Executor, hostOS string) error { log.Info("Downloading Hostagent Installer Certless") url := fmt.Sprintf( "%s/clarity/platform9-install-%s.sh", ctx.Fqdn, hostOS) - cmd := fmt.Sprintf(`curl --silent --show-error %s -o /tmp/installer.sh`, url) - _, err := exec.Command("bash", "-c", cmd).Output() + req, err := http.NewRequest("GET", url, nil) if err != nil { - return err + return fmt.Errorf("Unable to create request: %w", err) + } + + if err := downloadFile(httpClient, req, "/tmp/installer.sh"); err != nil { + return fmt.Errorf("Unable to download hostagent installer: %w", err) } - log.Debug("Hostagent download completed successfully") - // Decoding base64 encoded password + log.Info("Hostagent download completed successfully") decodedBytePassword, err := base64.StdEncoding.DecodeString(ctx.Password) if err != nil { return err @@ -122,13 +129,17 @@ func installHostAgentCertless(ctx Context, auth clients.KeystoneAuth, hostOS str decodedPassword := string(decodedBytePassword) installOptions := fmt.Sprintf(`--no-project --controller=%s --username=%s --password=%s`, ctx.Fqdn, ctx.Username, decodedPassword) - _, err = exec.Command("bash", "-c", "chmod +x /tmp/installer.sh").Output() + err = exec.Run("bash", "-c", "chmod +x /tmp/installer.sh") if err != nil { return err } - cmd = fmt.Sprintf(`/tmp/installer.sh --no-proxy --skip-os-check --ntpd %s`, installOptions) - _, err = exec.Command("bash", "-c", cmd).Output() + cmd := fmt.Sprintf(`/tmp/installer.sh --no-proxy --skip-os-check --ntpd %s`, installOptions) + if ctx.Proxy != "" { + cmd = fmt.Sprintf(`/tmp/installer.sh --proxy=%s --skip-os-check --ntpd %s`, ctx.Proxy, installOptions) + } + + err = exec.Run("bash", "-c", cmd) if err != nil { return err } @@ -186,35 +197,66 @@ func getHost(hostReleaseLoc string, exec clients.Executor) (Host, error) { } } -func installHostAgentLegacy(ctx Context, auth clients.KeystoneAuth, hostOS string) error { +func installHostAgentLegacy( + ctx Context, + auth clients.KeystoneAuth, + httpClient clients.HTTP, + exec clients.Executor, + hostOS string) error { log.Info("Downloading Hostagent Installer Legacy") url := fmt.Sprintf("%s/private/platform9-install-%s.sh", ctx.Fqdn, hostOS) - installOptions := fmt.Sprintf("--insecure --project-name=%s 2>&1 | tee -a /tmp/agent_install", auth.ProjectID) - - cmd := fmt.Sprintf(`curl --silent --show-error -H "X-Auth-Token: %s" %s -o /tmp/installer.sh`, auth.Token, url) - _, err := exec.Command("bash", "-c", cmd).Output() + req, err := http.NewRequest("GET", url, nil) if err != nil { - return err + return fmt.Errorf("Unable to create request: %w", err) + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Auth-Token", auth.Token) + + if err := downloadFile(httpClient, req, "/tmp/installer.sh"); err != nil { + return fmt.Errorf("Unable to download hostagent installer: %w", err) } log.Debug("Hostagent download completed successfully") _, err = exec.Command("bash", "-c", "chmod +x /tmp/installer.sh").Output() + + installOptions := fmt.Sprintf("--insecure --project-name=%s 2>&1 | tee -a /tmp/agent_install.log", auth.ProjectID) + + cmd := fmt.Sprintf(`/tmp/installer.sh --no-proxy --skip-os-check --ntpd %s`, installOptions) + if ctx.Proxy != "" { + cmd = fmt.Sprintf(`/tmp/installer.sh --proxy=%s --skip-os-check --ntpd %s`, ctx.Proxy, installOptions) + } + + err = exec.Run("bash", "-c", cmd) if err != nil { return err } - if ctx.Proxy != "" { + log.Info.Println("Hostagent installed successfully") + return nil +} + +func downloadFile(client clients.HTTP, req *http.Request, loc string) error { + f, err := os.Open(loc) + if err != nil { + return fmt.Errorf("Unable to create a file for download: %w", err) } - cmd = fmt.Sprintf(`/tmp/installer.sh --no-proxy --skip-os-check --ntpd %s`, installOptions) - _, err = exec.Command("bash", "-c", cmd).Output() + defer f.Close() + + resp, err := client.Do(req) if err != nil { - return err + return fmt.Errorf("Unable to make a request to client: %w", err) + } + + defer resp.Body.Close() + + _, err = io.Copy(f, resp.Body) + if err != nil { + return fmt.Errorf("Unable to copy the body into file: %w", err) } - // TODO: here we actually need additional validation by checking /tmp/agent_install. log - log.Info("Hostagent installed successfully") return nil } From ed7054ffe130b42772d7fdcb81a1503f0996f7e9 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Fri, 2 Oct 2020 21:07:14 +0530 Subject: [PATCH 07/14] File create fix --- pkg/pmk/node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 7fc43511..05615417 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -239,7 +239,7 @@ func installHostAgentLegacy( func downloadFile(client clients.HTTP, req *http.Request, loc string) error { - f, err := os.Open(loc) + f, err := os.Create(loc) if err != nil { return fmt.Errorf("Unable to create a file for download: %w", err) } From 7a9efa7ffa6e4d12235edb007d8b57aac2916da6 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Sat, 3 Oct 2020 01:00:36 +0530 Subject: [PATCH 08/14] Added test cases and fixed internal logic --- go.mod | 1 + pkg/pmk/cluster.go | 20 +++++++++++++------- pkg/util/encode_test.go | 25 +++++++++++++++++++++++++ pkg/util/helper_test.go | 19 +++++++++++++++++++ pkg/util/keystone/keystone.go | 1 - 5 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 pkg/util/encode_test.go create mode 100644 pkg/util/helper_test.go delete mode 100644 pkg/util/keystone/keystone.go diff --git a/go.mod b/go.mod index 7102b38b..db4fef39 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/sethgrid/pester v1.1.0 github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.6.3 + github.com/stretchr/testify v1.3.0 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect go.uber.org/zap v1.10.0 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 diff --git a/pkg/pmk/cluster.go b/pkg/pmk/cluster.go index cc48854e..9a8de7c8 100644 --- a/pkg/pmk/cluster.go +++ b/pkg/pmk/cluster.go @@ -11,16 +11,22 @@ import ( // Bootstrap simply preps the local node and attach it as master to a newly // created cluster. -func Bootstrap(ctx Context, c clients.Client, req clients.ClusterCreateRequest) error { - log.Debug("Received a call to boostrap the local node") +func Bootstrap( + ctx Context, + c clients.Client, + req clients.ClusterCreateRequest) error { + log.Info.Println("Received a call to boostrap the local node") - resp, err := util.AskBool("Prep local node for kubernetes cluster") - if err != nil || !resp { - log.Errorf("Couldn't fetch user content") + prep, err := util.AskBool("PrepLocal node for kubernetes cluster") + if err != nil { + return fmt.Errorf("Unable to capture user response: %w", err) } - if err := PrepNode(ctx, c, "", "", "", []string{}); err != nil { - return fmt.Errorf("Unable to prepnode: %w", err) + if prep { + err = PrepNode(ctx, c, "", "", "", []string{}) + if err != nil { + return fmt.Errorf("Unable to prepnode: %w", err) + } } keystoneAuth, err := c.Keystone.GetAuth( diff --git a/pkg/util/encode_test.go b/pkg/util/encode_test.go new file mode 100644 index 00000000..3e10779d --- /dev/null +++ b/pkg/util/encode_test.go @@ -0,0 +1,25 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEncode(t *testing.T) { + ip := "Hello World" + + expect := "SGVsbG8gV29ybGQ=" + actual := EncodeString(ip) + + assert.Equal(t, expect, actual) +} + +func TestDecode(t *testing.T) { + + encoded := "SGVsbG8gV29ybGQ=" + decoded := "Hello World" + + actual := DecodeString(encoded) + assert.Equal(t, decoded, actual) +} diff --git a/pkg/util/helper_test.go b/pkg/util/helper_test.go new file mode 100644 index 00000000..4083b402 --- /dev/null +++ b/pkg/util/helper_test.go @@ -0,0 +1,19 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStringContainsAny(t *testing.T) { + + base := "Ubuntu16" + + actual := StringContainsAny(base, []string{"16", "18"}) + assert.Equal(t, true, actual) + + actual = StringContainsAny(base, []string{"7.5"}) + assert.Equal(t, false, actual) + +} diff --git a/pkg/util/keystone/keystone.go b/pkg/util/keystone/keystone.go deleted file mode 100644 index 2fb6fb5d..00000000 --- a/pkg/util/keystone/keystone.go +++ /dev/null @@ -1 +0,0 @@ -package keystone From 09c2c90450f5d8c4a21af3565aa1ccaeccd63b5f Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Sat, 3 Oct 2020 01:09:00 +0530 Subject: [PATCH 09/14] Fixed rebase master issues --- cmd/prepNode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/prepNode.go b/cmd/prepNode.go index 5ed887b9..8dbd4982 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -44,7 +44,7 @@ func prepNodeRun(cmd *cobra.Command, args []string) { log.Fatalf("Unable to load the context: %s\n", err.Error()) } - clients, err := clients.New(ctx.Fqdn, ctx.Proxy) + c, err := clients.New(ctx.Fqdn, ctx.Proxy) if err != nil { log.Fatalf("Unable to load clients needed for the Cmd. Error: %s", err.Error()) } From 3e9cc31d7266360e3f67d002def20573d282c996 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Mon, 5 Oct 2020 12:49:07 +0530 Subject: [PATCH 10/14] Check for hostagent through HTTP Client --- pkg/pmk/node.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 05615417..da2e2a86 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -86,8 +86,7 @@ func installHostAgent( return fmt.Errorf("Unable to create a http request: %w", err) } - client := http.Client{} - resp, err := client.Do(req) + resp, err := c.HTTP.Do(req) if err != nil { return fmt.Errorf("Unable to send a request to client %w", err) } From c914c241945ecc51bd6c7a7765eb776ce47fb826 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Tue, 6 Oct 2020 20:01:15 +0530 Subject: [PATCH 11/14] Added Proxy variable when creating cluster --- cmd/bootstrap.go | 1 + pkg/pmk/clients/qbert.go | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 3c60b990..a12e045b 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -69,6 +69,7 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { MetalLBAddressPool: metallbIPRange, AllowWorkloadOnMaster: allowWorkloadsOnMaster, Privileged: privileged, + HTTPProxy: ctx.Proxy, } err = pmk.Bootstrap(ctx, c, payload) diff --git a/pkg/pmk/clients/qbert.go b/pkg/pmk/clients/qbert.go index b38ad3a5..664dfee8 100644 --- a/pkg/pmk/clients/qbert.go +++ b/pkg/pmk/clients/qbert.go @@ -45,6 +45,7 @@ type ClusterCreateRequest struct { NodePoolUUID string `json:"nodePoolUuid"` EnableMetalLb bool `json:"enableMetallb"` Masterless bool `json:"masterless"` + HTTPProxy string `json:"httpProxy,omitempty"` } func (c QbertImpl) CreateCluster( From 70d18674644c16f000a33afc2bb7d6d1286e3ece Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Tue, 6 Oct 2020 20:02:30 +0530 Subject: [PATCH 12/14] Chmoding the hostagent in legacy installer --- pkg/pmk/node.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index da2e2a86..76a12d0c 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -218,7 +218,10 @@ func installHostAgentLegacy( } log.Debug("Hostagent download completed successfully") - _, err = exec.Command("bash", "-c", "chmod +x /tmp/installer.sh").Output() + err = exec.Run("bash", "-c", "chmod +x /tmp/installer.sh") + if err != nil { + return err + } installOptions := fmt.Sprintf("--insecure --project-name=%s 2>&1 | tee -a /tmp/agent_install.log", auth.ProjectID) From af7d4207e5894389218b69763e9e8886c1c1f64b Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Tue, 6 Oct 2020 20:04:20 +0530 Subject: [PATCH 13/14] Increasing the retry count to a more mangeable number --- pkg/pmk/clients/clients.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/pmk/clients/clients.go b/pkg/pmk/clients/clients.go index c81fa6c9..f5d66136 100644 --- a/pkg/pmk/clients/clients.go +++ b/pkg/pmk/clients/clients.go @@ -1,6 +1,8 @@ package clients -const HTTPMaxRetry = 5 +// HTTPMaxRetry indicates the number of +// retries to be carried out before giving up. +const HTTPMaxRetry = 9 // Client struct encapsulate the collection of // external services From 1af6be0f620b736fd5a3c2163a78820763426694 Mon Sep 17 00:00:00 2001 From: Abhimanyu Babbar Date: Wed, 14 Oct 2020 13:36:02 +0530 Subject: [PATCH 14/14] Build Fixes after rebasing --- pkg/pmk/cluster.go | 4 ++-- pkg/pmk/common.go | 5 +---- pkg/pmk/node.go | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pkg/pmk/cluster.go b/pkg/pmk/cluster.go index 9a8de7c8..f1e24c44 100644 --- a/pkg/pmk/cluster.go +++ b/pkg/pmk/cluster.go @@ -15,7 +15,7 @@ func Bootstrap( ctx Context, c clients.Client, req clients.ClusterCreateRequest) error { - log.Info.Println("Received a call to boostrap the local node") + log.Info("Received a call to boostrap the local node") prep, err := util.AskBool("PrepLocal node for kubernetes cluster") if err != nil { @@ -47,7 +47,7 @@ func Bootstrap( if err != nil { return fmt.Errorf("Unable to create cluster: %w", err) } - log.Info.Println("Cluster created successfully") + log.Info("Cluster created successfully") cmd := `cat /etc/pf9/host_id.conf | grep ^host_id | cut -d = -f2 | cut -d ' ' -f2` output, err := c.Executor.RunWithStdout("bash", "-c", cmd) diff --git a/pkg/pmk/common.go b/pkg/pmk/common.go index 932c839b..e3d05728 100644 --- a/pkg/pmk/common.go +++ b/pkg/pmk/common.go @@ -9,7 +9,7 @@ import ( "github.com/platform9/pf9ctl/pkg/log" ) -func setupNode(hostOS string) (err error) { +func setupNode(host Host) (err error) { log.Debug("Received a call to setup the node") if err := host.SwapOff(); err != nil { @@ -84,7 +84,6 @@ func createPF9Group(name string) error { return nil } -<<<<<<< HEAD func ubuntuPackageInstall() error { log.Info("Installing required ubuntu packages") @@ -138,5 +137,3 @@ func swapOff() error { _, err := exec.Command("bash", "-c", "swapoff -a").Output() return err } -======= ->>>>>>> Wrapped the host functions in host interface diff --git a/pkg/pmk/node.go b/pkg/pmk/node.go index 76a12d0c..7efab51b 100644 --- a/pkg/pmk/node.go +++ b/pkg/pmk/node.go @@ -235,7 +235,7 @@ func installHostAgentLegacy( return err } - log.Info.Println("Hostagent installed successfully") + log.Info("Hostagent installed successfully") return nil }