diff --git a/Dockerfile.builder b/Dockerfile.builder index 7dd37ca3e..5ee073600 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -1,4 +1,4 @@ -FROM golang:1.15 +FROM golang:1.16 RUN apt-get update && apt-get install -y golint diff --git a/Makefile b/Makefile index 6df1fdd9b..988cf0480 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,10 @@ build: $(TARGET) build-all: builder GOOS=linux GOARCH=amd64 $(GO) go build $(BUILD_FLAGS) -o bin/launchpad-linux-x64 main.go + GOOS=linux GOARCH=arm64 $(GO) go build $(BUILD_FLAGS) -o bin/launchpad-linux-arm64 main.go GOOS=windows GOARCH=amd64 $(GO) go build $(BUILD_FLAGS) -o bin/launchpad-win-x64.exe main.go GOOS=darwin GOARCH=amd64 $(GO) go build $(BUILD_FLAGS) -o bin/launchpad-darwin-x64 main.go + GOOS=darwin GOARCH=arm64 $(GO) go build $(BUILD_FLAGS) -o bin/launchpad-darwin-arm64 main.go release: build-all ./release.sh diff --git a/README.md b/README.md index 14f2c271d..16214cc53 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > The Next Generation Mirantis Cluster Installer & Lifecycle Management Tool -The purpose of `launchpad` is to provide amazing new user experience for anyone interested in getting started with cluster products. It will simplify the complex installation processes and provides "from zero to hero" experience in less than 5mins for IT admin / DevOps people who are experienced with various command line tools and cloud technologies. In addition, it'll provide functionality to upgrade existing clusters to new versions with no downtime or service interruptions (high availability clusters). In the future, more functionality may be added. +The purpose of `launchpad` is to provide an amazing new user experience for anyone interested in getting started with cluster products. It will simplify the complex installation processes and provides "from zero to hero" experience in less than 5mins for IT admin / DevOps people who are experienced with various command line tools and cloud technologies. In addition, it'll provide functionality to upgrade existing clusters to new versions with no downtime or service interruptions (high availability clusters). In the future, more functionality may be added. See the public Github repo for getting started instructions, documentation and more at https://github.com/mirantis/launchpad. diff --git a/go.mod b/go.mod index 416508f94..fb732aeca 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Mirantis/mcc -go 1.15 +go 1.16 require ( github.com/AlecAivazis/survey/v2 v2.0.7 diff --git a/pkg/analytics/analytics.go b/pkg/analytics/analytics.go index 2512b8af7..dabe7985e 100644 --- a/pkg/analytics/analytics.go +++ b/pkg/analytics/analytics.go @@ -1,7 +1,7 @@ package analytics import ( - "io/ioutil" + "io" logger "log" "runtime" @@ -51,7 +51,7 @@ func init() { // NewSegmentClient returns a Segment client for uploading analytics data. func NewSegmentClient(segmentToken string) (Analytics, error) { - segmentLogger := analytics.StdLogger(logger.New(ioutil.Discard, "segment ", logger.LstdFlags)) + segmentLogger := analytics.StdLogger(logger.New(io.Discard, "segment ", logger.LstdFlags)) segmentConfig := analytics.Config{ Logger: segmentLogger, } diff --git a/pkg/config/config.go b/pkg/config/config.go index 23ad5e547..4c94bd98d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,7 +2,7 @@ package config import ( "fmt" - "io/ioutil" + "io" "os" "path/filepath" "regexp" @@ -97,7 +97,7 @@ func resolveClusterFile(clusterFile string) ([]byte, error) { stat, err := os.Stdin.Stat() if err == nil { if (stat.Mode() & os.ModeCharDevice) == 0 { - return ioutil.ReadAll(os.Stdin) + return io.ReadAll(os.Stdin) } } @@ -110,7 +110,7 @@ func resolveClusterFile(clusterFile string) ([]byte, error) { return nil, err } - return ioutil.ReadAll(file) + return io.ReadAll(file) } func openClusterFile(clusterFile string) (*os.File, error) { diff --git a/pkg/config/user/config.go b/pkg/config/user/config.go index 49a90b0ae..4c383fa1a 100644 --- a/pkg/config/user/config.go +++ b/pkg/config/user/config.go @@ -1,7 +1,6 @@ package user import ( - "io/ioutil" "os" "path/filepath" @@ -62,7 +61,7 @@ func SaveConfig(config *Config) error { if err != nil { return err } - err = ioutil.WriteFile(configFile, d, 0644) + err = os.WriteFile(configFile, d, 0644) if err != nil { return err } diff --git a/pkg/mke/mke.go b/pkg/mke/mke.go index 1157ea3d3..1a104218d 100644 --- a/pkg/mke/mke.go +++ b/pkg/mke/mke.go @@ -8,7 +8,7 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "strings" @@ -99,7 +99,7 @@ func GetClientBundle(mkeURL *url.URL, tlsConfig *tls.Config, username, password log.Debugf("Failed to get bundle: %v", err) return nil, err } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) resp.Body.Close() if resp.StatusCode != http.StatusOK { if err == nil { @@ -127,7 +127,7 @@ func GetToken(client *http.Client, mkeURL *url.URL, username, password string) ( log.Debugf("Failed to POST %s: %v", mkeURL.String(), err) return "", err } - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) resp.Body.Close() if resp.StatusCode == 200 { var authToken AuthToken diff --git a/pkg/product/mke/api/cluster_test.go b/pkg/product/mke/api/cluster_test.go index 26815038a..9941f3c24 100644 --- a/pkg/product/mke/api/cluster_test.go +++ b/pkg/product/mke/api/cluster_test.go @@ -2,7 +2,6 @@ package api import ( "encoding/json" - "io/ioutil" "os" "path" "strings" @@ -31,7 +30,7 @@ import ( ) func TestHostRequireManagerValidationPass(t *testing.T) { - kf, _ := ioutil.TempFile("", "testkey") + kf, _ := os.CreateTemp("", "testkey") defer kf.Close() data := ` apiVersion: "launchpad.mirantis.com/mke/v1.4" @@ -55,7 +54,7 @@ spec: } func TestHostRequireManagerValidationFail(t *testing.T) { - kf, _ := ioutil.TempFile("", "testkey") + kf, _ := os.CreateTemp("", "testkey") defer kf.Close() data := ` apiVersion: "launchpad.mirantis.com/mke/v1.4" @@ -406,7 +405,7 @@ spec: } func TestValidationWithMSRRole(t *testing.T) { - kf, _ := ioutil.TempFile("", "testkey") + kf, _ := os.CreateTemp("", "testkey") defer kf.Close() t.Run("the role is not ucp, worker or msr", func(t *testing.T) { data := ` diff --git a/pkg/product/mke/exec.go b/pkg/product/mke/exec.go index ce0c0b187..4a8e208cf 100644 --- a/pkg/product/mke/exec.go +++ b/pkg/product/mke/exec.go @@ -2,7 +2,7 @@ package mke import ( "fmt" - "io/ioutil" + "io" "os" "strconv" "strings" @@ -134,7 +134,7 @@ func (p *MKE) Exec(targets []string, interactive, first, all, parallel bool, rol if interactive { return fmt.Errorf("--interactive given but there's piped data in stdin") } - data, err := ioutil.ReadAll(os.Stdin) + data, err := io.ReadAll(os.Stdin) if err != nil { return err } diff --git a/pkg/product/mke/phase/download_bundle.go b/pkg/product/mke/phase/download_bundle.go index d8c96185c..99f52ed54 100644 --- a/pkg/product/mke/phase/download_bundle.go +++ b/pkg/product/mke/phase/download_bundle.go @@ -3,7 +3,7 @@ package phase import ( "archive/zip" "fmt" - "io/ioutil" + "io" "os" "path" "path/filepath" @@ -88,7 +88,7 @@ func (p *DownloadBundle) writeBundle(bundleDir string, bundle *zip.Reader) error } defer src.Close() var data []byte - data, err = ioutil.ReadAll(src) + data, err = io.ReadAll(src) if err != nil { return err } @@ -105,7 +105,7 @@ func (p *DownloadBundle) writeBundle(bundleDir string, bundle *zip.Reader) error } } - err = ioutil.WriteFile(filepath.Join(bundleDir, zf.Name), data, os.FileMode(mode)) + err = os.WriteFile(filepath.Join(bundleDir, zf.Name), data, os.FileMode(mode)) if err != nil { return err } diff --git a/pkg/product/mke/phase/remove_nodes.go b/pkg/product/mke/phase/remove_nodes.go index 257f6000c..0c1c65faf 100644 --- a/pkg/product/mke/phase/remove_nodes.go +++ b/pkg/product/mke/phase/remove_nodes.go @@ -3,7 +3,7 @@ package phase import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "regexp" "strings" @@ -299,7 +299,7 @@ func (p *RemoveNodes) getReplicaIDFromHostname(config *api.ClusterConfig, h *api } var containersResponse []dockerContainer - respBody, err := ioutil.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { return "", err } diff --git a/pkg/product/mke/phase/upload_images.go b/pkg/product/mke/phase/upload_images.go index f666bb5c3..aba8ff69c 100644 --- a/pkg/product/mke/phase/upload_images.go +++ b/pkg/product/mke/phase/upload_images.go @@ -1,7 +1,7 @@ package phase import ( - "io/ioutil" + "os" "path" "path/filepath" @@ -32,25 +32,28 @@ func (p *LoadImages) HostFilterFunc(h *api.Host) bool { } log.Debugf("%s: listing images in imageDir '%s'", h, h.ImageDir) - files, err := ioutil.ReadDir(h.ImageDir) + files, err := os.ReadDir(h.ImageDir) if err != nil { log.Errorf("%s: failed to list images in imageDir '%s': %s", h, h.ImageDir, err.Error()) return false } - for _, info := range files { - if info.IsDir() { + for _, entry := range files { + if entry.IsDir() { continue } - ext := filepath.Ext(info.Name()) + ext := filepath.Ext(entry.Name()) if ext != ".tar" && ext != ".gz" { continue } - imagePath := filepath.Join(h.ImageDir, info.Name()) + imagePath := filepath.Join(h.ImageDir, entry.Name()) h.Metadata.ImagesToUpload = append(h.Metadata.ImagesToUpload, imagePath) - h.Metadata.TotalImageBytes += uint64(info.Size()) + info, err := entry.Info() + if err == nil { + h.Metadata.TotalImageBytes += uint64(info.Size()) + } } return h.Metadata.TotalImageBytes > 0 diff --git a/pkg/product/mke/phase/validate_hosts.go b/pkg/product/mke/phase/validate_hosts.go index c5909a84d..4f00ace1f 100644 --- a/pkg/product/mke/phase/validate_hosts.go +++ b/pkg/product/mke/phase/validate_hosts.go @@ -3,7 +3,6 @@ package phase import ( "fmt" "io" - "io/ioutil" "os" "strings" @@ -60,7 +59,7 @@ func (p *ValidateHosts) formatErrors() error { } func (p *ValidateHosts) validateHostConnection() error { - f, err := ioutil.TempFile("", "uploadTest") + f, err := os.CreateTemp("", "uploadTest") if err != nil { return err } diff --git a/pkg/util/install.go b/pkg/util/install.go index 3ad5a8984..51f783ba3 100644 --- a/pkg/util/install.go +++ b/pkg/util/install.go @@ -2,7 +2,7 @@ package util import ( "fmt" - "io/ioutil" + "os" "strings" ) @@ -11,7 +11,7 @@ import ( // SetupLicenseFile reads the license file and returns a license string command // flag to be used with MSR and MKE installers func SetupLicenseFile(licenseFilePath string) (string, error) { - license, err := ioutil.ReadFile(licenseFilePath) + license, err := os.ReadFile(licenseFilePath) if err != nil { return "", err } diff --git a/pkg/util/io.go b/pkg/util/io.go index b8afb3a33..d0e083cdf 100644 --- a/pkg/util/io.go +++ b/pkg/util/io.go @@ -2,7 +2,6 @@ package util import ( "fmt" - "io/ioutil" "os" "github.com/mitchellh/go-homedir" @@ -26,7 +25,7 @@ var LoadExternalFile = func(path string) ([]byte, error) { return []byte{}, err } - filedata, err := ioutil.ReadFile(realpath) + filedata, err := os.ReadFile(realpath) if err != nil { return []byte{}, err } diff --git a/version/version.go b/version/version.go index 6788ac39a..4e7fce390 100644 --- a/version/version.go +++ b/version/version.go @@ -3,7 +3,7 @@ package version import ( "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "runtime" "sort" @@ -109,7 +109,7 @@ func latestTag(timeout time.Duration) string { log.Debugf("%s returned http %d", baseMsg, resp.StatusCode) return "" // ignore backend failures } - body, readErr := ioutil.ReadAll(resp.Body) + body, readErr := io.ReadAll(resp.Body) if readErr != nil { log.Debugf("%s failed to read body: %s", baseMsg, err.Error()) return "" // ignore reading errors @@ -173,7 +173,7 @@ func GetLatest(timeout time.Duration) *LaunchpadRelease { log.Debugf("%s returned http %d", baseMsg, resp.StatusCode) return nil // ignore backend failures } - body, readErr := ioutil.ReadAll(resp.Body) + body, readErr := io.ReadAll(resp.Body) if readErr != nil { log.Debugf("%s failed to read body: %s", baseMsg, err.Error()) return nil // ignore reading errors