From 0f1ad0be25bb54d2f11413d1ce607617460a4bc5 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 2 Nov 2022 18:26:59 +0330 Subject: [PATCH 01/10] Remove gateways --- pkg/paas/migration.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index f38042d..a29492f 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -521,9 +521,7 @@ func successOutput(data StepData) { } nonFreeDomainTable.Render() - } - if len(freeSourceDomains) > 0 { gatewayTable := tablewriter.NewWriter(os.Stdout) gatewayTable.SetHeader([]string{"old gateway", "new gateway"}) From 9c4e3097aeabdca9b0151a2d27f1cc7eb35d11a3 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 5 Nov 2022 10:53:14 +0330 Subject: [PATCH 02/10] Replace deprecated package --- pkg/paas/migration.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index a29492f..25fee2a 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -18,6 +18,8 @@ import ( "github.com/arvancloud/cli/pkg/api" "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/utl" + "golang.org/x/text/cases" + "golang.org/x/text/language" "github.com/gosuri/uilive" "github.com/olekukonko/tablewriter" @@ -362,7 +364,9 @@ func sprintResponse(response ProgressResponse, w io.Writer) error { detail = s.Data.Detail } - responseStr += fmt.Sprintf("\t%s \t\t\t%s\t%s\n", s.Title, strings.Title(s.State), detail) + caser := cases.Title(language.English) + + responseStr += fmt.Sprintf("\t%s \t\t\t%s\t%s\n", s.Title, caser.String(s.State), detail) } fmt.Fprintf(w, "%s", responseStr) From 8da15786ee2d555eea399a1668a40c4fed1ba638 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 5 Nov 2022 14:51:59 +0330 Subject: [PATCH 03/10] Add unmarshal error handler --- go.mod | 1 + pkg/paas/migration.go | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5ab9b98..ab668ab 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/spf13/cobra v1.1.1 github.com/xeipuuv/gojsonschema v1.2.0 // indirect golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect + golang.org/x/text v0.3.4 gopkg.in/yaml.v2 v2.3.0 k8s.io/api v0.20.0-beta.2 k8s.io/apimachinery v0.20.0-beta.2 diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 25fee2a..47ba6aa 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -18,16 +18,22 @@ import ( "github.com/arvancloud/cli/pkg/api" "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/utl" - "golang.org/x/text/cases" - "golang.org/x/text/language" "github.com/gosuri/uilive" "github.com/olekukonko/tablewriter" "github.com/openshift/oc/pkg/helpers/term" "github.com/spf13/cobra" + "golang.org/x/text/cases" + "golang.org/x/text/language" "k8s.io/client-go/rest" ) +var ( + migrateLong = ` + Migration of user's namespaces from one region to another + ` +) + const ( migrationEndpoint = "/paas/v1/%s/migrate" redColor = "\033[31m" @@ -99,7 +105,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "migrate", Short: "Migrate namespaces to destination region", - Long: loginLong, + Long: migrateLong, Run: func(c *cobra.Command, args []string) { explainOut := term.NewResponsiveWriter(out) c.SetOutput(explainOut) @@ -460,6 +466,7 @@ func httpGet(endpoint string) (*ProgressResponse, error) { var response ProgressResponse err = json.Unmarshal(responseBody, &response) if err != nil { + failureOutput("Migration is running in the background. You can continue monitoring the process using 'arvan paas migrate'.") return nil, err } From 238ea58a2ddc50f495678525bcd04fa92e248792 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 5 Nov 2022 15:31:14 +0330 Subject: [PATCH 04/10] Add migration not found handler --- Makefile | 4 ++-- pkg/paas/migration.go | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 1748932..a32f194 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,9 @@ export GOPROXY=https://proxy.golang.org,direct export ENV=development -LDFLAGS+=-X k8s.io/client-go/pkg/version.gitVersion=v1.0.2 +LDFLAGS+=-X k8s.io/client-go/pkg/version.gitVersion=v1.2.2 LDFLAGS+=-X k8s.io/client-go/pkg/version.gitCommit=4f75300 -LDFLAGS+=-X github.com/openshift/oc/pkg/version.versionFromGit=v1.0.2 +LDFLAGS+=-X github.com/openshift/oc/pkg/version.versionFromGit=v1.2.2 LDFLAGS+=-X github.com/openshift/oc/pkg/version.commitFromGit=4f75300 build: go build -v -o $(ROOT)/bin/arvan -ldflags="$(LDFLAGS)" $(ROOT)/cmd/arvan/*.go diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 47ba6aa..01fce9a 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -137,7 +137,11 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { } } +<<<<<<< HEAD if response.State == Completed || response.State == Failed || response.StatusCode == http.StatusNotFound { +======= + if response.StatusCode == http.StatusNotFound || response.State == Completed || response.State == Failed { +>>>>>>> 16d1fc0 (Add migration not found handler) project, err := getSelectedProject(in, explainOut) if err != nil { failureOutput(err.Error()) @@ -274,13 +278,13 @@ func sprintProjects(projects []string) string { // migrationConfirm gets confirmation of proceeding namespace migration by asking user to enter namespace's name. func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bool { - explain := fmt.Sprintf("\nYou're about to migrate \"%s\" from region \"%s\" to \"%s\".\n", project, getCurrentRegion(), region) + explain := fmt.Sprintf("\nYou're about to migrate \"%s\" from region \"%s\" to \"%s\".\n\n"+yellowColor+"WARNING:\nThis will STOP applications during migration process. Your data would still be safe and available in source region. Migration is running in the background and may take a while. You can optionally detach(Ctrl+C) for now and continue monitoring the process after using 'arvan paas migrate'."+resetColor+"\n\n", project, getCurrentRegion(), region) _, err := fmt.Fprint(writer, explain) if err != nil { return false } - inputExplain := fmt.Sprintf(yellowColor+"\nWARNING:\nThis will STOP applications during migration process. Your data would still be safe and available in source region. Migration is running in the background and may take a while. You can optionally detach(Ctrl+C) for now and continue monitoring the process after using 'arvan paas migrate'."+resetColor+"\n\nPlease enter project's name [%s] to proceed: ", project) + inputExplain := fmt.Sprintf("Please enter project's name [%s] to proceed: ", project) defaultVal := "" From f59025cf5bbaa378e9adb3494b549b6b305a84ef Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 5 Nov 2022 20:48:53 +0330 Subject: [PATCH 05/10] Resolve conflicts --- pkg/paas/migration.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 01fce9a..9487297 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -137,11 +137,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { } } -<<<<<<< HEAD if response.State == Completed || response.State == Failed || response.StatusCode == http.StatusNotFound { -======= - if response.StatusCode == http.StatusNotFound || response.State == Completed || response.State == Failed { ->>>>>>> 16d1fc0 (Add migration not found handler) project, err := getSelectedProject(in, explainOut) if err != nil { failureOutput(err.Error()) From 2561b5b1fc4645257fcbb3ac7e8a60a07f074357 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Tue, 8 Nov 2022 09:48:59 +0330 Subject: [PATCH 06/10] Add warning on creating new project to avoid project duplicate creation --- pkg/paas/login.go | 16 ++++++++-------- pkg/paas/migration.go | 12 +++++------- pkg/paas/paas.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/pkg/paas/login.go b/pkg/paas/login.go index 21603dc..e0242e3 100644 --- a/pkg/paas/login.go +++ b/pkg/paas/login.go @@ -145,14 +145,14 @@ func getSelectedRegion(in io.Reader, writer io.Writer) (*config.Zone, error) { return nil, errors.New("invalid region info") } - activeZones, inactiveZones := getActiveAndInactiveZones(regions.Zones) + upZones, downZones := getUpAndDownZones(regions.Zones) - if len(activeZones) < 1 { + if len(upZones) < 1 { return nil, errors.New("no active region available") } explain := "Select arvan region:\n" - explain += sprintRegions(activeZones, inactiveZones) + explain += sprintRegions(upZones, downZones) _, err = fmt.Fprint(writer, explain) if err != nil { @@ -162,17 +162,17 @@ func getSelectedRegion(in io.Reader, writer io.Writer) (*config.Zone, error) { defaultVal := "1" - if len(activeZones) == 1 { + if len(upZones) == 1 { fmt.Fprintf(writer, inputExplain+"1\n") - return &activeZones[0], nil + return &upZones[0], nil } - validator := regionValidator{len(activeZones)} + validator := regionValidator{len(upZones)} regionIndex := utl.ReadInput(inputExplain, defaultVal, writer, in, validator.validate) intIndex, _ := strconv.Atoi(regionIndex) - return &activeZones[intIndex-1], nil + return &upZones[intIndex-1], nil } type regionValidator struct { @@ -218,7 +218,7 @@ func sprintRegions(activeZones, inactiveRegions []config.Zone) string { return result } -func getActiveAndInactiveZones(zones []config.Zone) ([]config.Zone, []config.Zone) { +func getUpAndDownZones(zones []config.Zone) ([]config.Zone, []config.Zone) { var activeZones, inactiveZones []config.Zone for i := 0; i < len(zones); i++ { if zones[i].Status == "UP" { diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 9487297..0bbc5d0 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -552,19 +552,17 @@ func getZoneByName(name string) (*config.Zone, error) { return nil, errors.New("invalid region info") } - activeZones, _ := getActiveAndInactiveZones(regions.Zones) + upZones, _ := getUpAndDownZones(regions.Zones) - if len(activeZones) < 1 { + if len(upZones) < 1 { return nil, errors.New("no active region available") } - for i, zone := range activeZones { + for i, zone := range upZones { if zone.Name == name { - return &activeZones[i], nil + return &upZones[i], nil } } - log.Printf("destination region not found") - - return nil, nil + return nil, errors.New("destination region not found") } diff --git a/pkg/paas/paas.go b/pkg/paas/paas.go index f217702..2affdf1 100644 --- a/pkg/paas/paas.go +++ b/pkg/paas/paas.go @@ -61,6 +61,32 @@ func NewCmdPaas() *cobra.Command { fmt.Fprint(w, strings.Repeat("*", 50)) fmt.Fprint(w, "\n") } + + // To warn user not to duplicate projects if they have a migration plan + if cmd.Name() == "new-project" { + regions, err := api.GetZones() + if err != nil { + failureOutput("failed to get zones") + return + } + + if len(regions.Zones) < 1 { + failureOutput("invalid region info") + return + } + + currentRegionAbbr := getCurrentRegion() + + currentRegionName := currentRegionAbbr[strings.LastIndex(currentRegionAbbr, "-")+1:] + + currentRegion, err := getZoneByName(currentRegionName) + utl.CheckErr(err) + + _, inactiveZones := getActiveAndInactiveZones(regions.Zones) + if len(inactiveZones) > 0 && currentRegion.Active { + fmt.Print(yellowColor + "\nWARNING: " + resetColor + "If you have any intention to migrate projects, do not try to create a new project in destination region!\n\n") + } + } } return paasCommand @@ -304,3 +330,15 @@ func getArvanServerDomainPort() (string, error) { result := hostnameEscaped + ":" + port return result, nil } + +func getActiveAndInactiveZones(zones []config.Zone) ([]config.Zone, []config.Zone) { + var activeZones, inactiveZones []config.Zone + for i := 0; i < len(zones); i++ { + if zones[i].Active { + activeZones = append(activeZones, zones[i]) + } else { + inactiveZones = append(inactiveZones, zones[i]) + } + } + return activeZones, inactiveZones +} From b1dde382c38826c42ec42704414ef5b3e78f5327 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Tue, 8 Nov 2022 11:22:16 +0330 Subject: [PATCH 07/10] Fix update old config file on update --- pkg/config/config.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 642759c..55a038a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "sync" + "github.com/arvancloud/cli/pkg/utl" + "gopkg.in/yaml.v2" ) @@ -12,6 +14,7 @@ type configFile struct { ApiVersion string `yaml:"apiVersion"` Server string `yaml:"server"` ApiKey string `yaml:"apikey"` + Region string `yaml:"region"` } var instance *ConfigInfo @@ -40,6 +43,12 @@ func LoadConfigFile() (bool, error) { if err != nil { return false, err } + + if configFileStruct.Region != "" { + _, err = arvanConfig.SaveConfig() + utl.CheckErr(err) + } + arvanConfig.apiKey = configFileStruct.ApiKey arvanConfig.server = configFileStruct.Server return true, nil From d4bad6c4ba93b3d8408d9d9035ac4a975e8be17b Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 9 Nov 2022 14:57:24 +0330 Subject: [PATCH 08/10] Fix warning on new project creation --- pkg/paas/login.go | 2 +- pkg/paas/migration.go | 10 ++++++++++ pkg/paas/paas.go | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/pkg/paas/login.go b/pkg/paas/login.go index e0242e3..f144fbe 100644 --- a/pkg/paas/login.go +++ b/pkg/paas/login.go @@ -97,7 +97,7 @@ func NewCmdSwitchRegion(in io.Reader, out, errout io.Writer) *cobra.Command { _, err = arvanConfig.SaveConfig() utl.CheckErr(err) - err = prepareConfig(c) + err = prepareConfigSwtichRegion(c) utl.CheckErr(err) fmt.Fprintf(explainOut, "Region Switched successfully.\n") diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 0bbc5d0..db9643f 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -188,6 +188,16 @@ func reMigrationConfirm(in io.Reader, writer io.Writer) bool { return value == "y" } +// newProjectConfirm makes sure that user enters yes/no correctly. +func newProjectConfirm(in io.Reader, writer io.Writer) bool { + inputExplain := "Do you want to continue?[y/N]: " + + defaultVal := "N" + + value := utl.ReadInput(inputExplain, defaultVal, writer, in, confirmationValidate) + return value == "y" +} + // confirmationValidate checks yes/no entry func confirmationValidate(input string) (bool, error) { if input != "y" && input != "N" { diff --git a/pkg/paas/paas.go b/pkg/paas/paas.go index 2affdf1..e0a4a39 100644 --- a/pkg/paas/paas.go +++ b/pkg/paas/paas.go @@ -67,12 +67,12 @@ func NewCmdPaas() *cobra.Command { regions, err := api.GetZones() if err != nil { failureOutput("failed to get zones") - return + utl.CheckErr(errors.New("failed to get zones")) } if len(regions.Zones) < 1 { failureOutput("invalid region info") - return + utl.CheckErr(errors.New("invalid region info")) } currentRegionAbbr := getCurrentRegion() @@ -85,6 +85,10 @@ func NewCmdPaas() *cobra.Command { _, inactiveZones := getActiveAndInactiveZones(regions.Zones) if len(inactiveZones) > 0 && currentRegion.Active { fmt.Print(yellowColor + "\nWARNING: " + resetColor + "If you have any intention to migrate projects, do not try to create a new project in destination region!\n\n") + + if !newProjectConfirm(in, out) { + utl.CheckErr(errors.New("")) + } } } } @@ -131,6 +135,33 @@ func prepareConfig(cmd *cobra.Command) error { return nil } +func prepareConfigSwtichRegion(cmd *cobra.Command) error { + // #TODO do not use InsecureSkipVerify + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + username, httpStatusCode, err := whoAmI() + if err != nil { + if httpStatusCode == 401 { + return fmt.Errorf("%v\n%s", err, `Try "arvan login".`) + } + if httpStatusCode >= 500 { + return fmt.Errorf("%v\n%s", err, `Please try again later`) + } + return err + } + + projects, err := projectList() + if err != nil { + return err + } + + kubeConfigPath := paasConfigPath() + err = syncKubeConfig(kubeConfigPath, username, projects) + if err != nil { + return err + } + return nil +} + func prepareCommand(cmd *cobra.Command) error { arvanConfig := config.GetConfigInfo() kubeConfigPath := paasConfigPath() From 73b6c5f3d61150b6fb9aefc63bf2a8f47c1ff300 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 9 Nov 2022 18:45:37 +0330 Subject: [PATCH 09/10] Fix invalid characher 'j' bug --- pkg/config/config.go | 10 ++++++++-- pkg/config/config_info.go | 11 +++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 55a038a..75c975f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -10,6 +10,10 @@ import ( "gopkg.in/yaml.v2" ) +const ( + regionsEndpoint = "/paas/v1/regions/" +) + type configFile struct { ApiVersion string `yaml:"apiVersion"` Server string `yaml:"server"` @@ -44,13 +48,15 @@ func LoadConfigFile() (bool, error) { return false, err } + arvanConfig.apiKey = configFileStruct.ApiKey + arvanConfig.server = configFileStruct.Server + if configFileStruct.Region != "" { + arvanConfig.server = configFileStruct.Server + regionsEndpoint + configFileStruct.Region _, err = arvanConfig.SaveConfig() utl.CheckErr(err) } - arvanConfig.apiKey = configFileStruct.ApiKey - arvanConfig.server = configFileStruct.Server return true, nil } diff --git a/pkg/config/config_info.go b/pkg/config/config_info.go index 8805766..7231c2e 100644 --- a/pkg/config/config_info.go +++ b/pkg/config/config_info.go @@ -25,24 +25,26 @@ type ConfigInfo struct { // path to arvan config directroy e.g /home/jane/.arvan homeDir string + + region string } -//GetServer returns base url to access arvan api server +// GetServer returns base url to access arvan api server func (c *ConfigInfo) GetServer() string { return c.server } -//GetApiKey returns an api key used to authorize request to arvan api server +// GetApiKey returns an api key used to authorize request to arvan api server func (c *ConfigInfo) GetApiKey() string { return c.apiKey } -//GetConfigFilePath returns path to arvan config file e.g /home/jane/.arvan/config +// GetConfigFilePath returns path to arvan config file e.g /home/jane/.arvan/config func (c *ConfigInfo) GetConfigFilePath() string { return c.configFilePath } -//GetHomeDir returns path to arvan config directroy e.g /home/jane/.arvan +// GetHomeDir returns path to arvan config directroy e.g /home/jane/.arvan func (c *ConfigInfo) GetHomeDir() string { return c.homeDir } @@ -94,6 +96,7 @@ func (c *ConfigInfo) SaveConfig() (bool, error) { ApiVersion: configFileApiVersion, Server: c.server, ApiKey: c.apiKey, + Region: c.region, } configFileStr, err := yaml.Marshal(&configFileStruct) From cf376674e7195b20eab1fdf9d35702e51bd9527a Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 9 Nov 2022 19:29:10 +0330 Subject: [PATCH 10/10] Add omitempty to region field --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 75c975f..8c1d6cb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -18,7 +18,7 @@ type configFile struct { ApiVersion string `yaml:"apiVersion"` Server string `yaml:"server"` ApiKey string `yaml:"apikey"` - Region string `yaml:"region"` + Region string `yaml:"region,omitempty"` } var instance *ConfigInfo