From 8dadb12d556792f54bac65d7e305cbc55ca0dacd Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Tue, 11 Oct 2022 18:10:25 +0330 Subject: [PATCH 01/17] Add data center migration --- pkg/cli/cli.go | 18 +++--- pkg/paas/migration.go | 138 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 pkg/paas/migration.go diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 7df5c3b..db26cbe 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -2,20 +2,19 @@ package cli import ( "fmt" - "github.com/arvancloud/cli/pkg/api" - "github.com/arvancloud/cli/pkg/utl" - "github.com/inconshreveable/go-update" "net/http" "os" "path/filepath" "runtime" - "github.com/spf13/cobra" - - "github.com/openshift/oc/pkg/helpers/term" - + "github.com/arvancloud/cli/pkg/api" "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/paas" + "github.com/arvancloud/cli/pkg/utl" + "github.com/inconshreveable/go-update" + + "github.com/openshift/oc/pkg/helpers/term" + "github.com/spf13/cobra" ) var ( @@ -60,7 +59,10 @@ func NewCommandCLI() *cobra.Command { cmd.AddCommand(loginCommand) paasCommand := paas.NewCmdPaas() - cmd.AddCommand(paasCommand) + cmd.AddCommand(paasCommand) + + migrateCommand := paas.NewCmdMigrate(in, out, errout) + cmd.AddCommand(migrateCommand) cmd.AddCommand(updateCmd()) return cmd diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go new file mode 100644 index 0000000..b533648 --- /dev/null +++ b/pkg/paas/migration.go @@ -0,0 +1,138 @@ +package paas + +import ( + "errors" + "fmt" + "io" + "log" + "strings" + "time" + + "github.com/arvancloud/cli/pkg/config" + "github.com/arvancloud/cli/pkg/utl" + "github.com/openshift/oc/pkg/helpers/term" + "github.com/spf13/cobra" +) + +const ( + checkmark = "[\u2713]" +) + +// NewCmdMigrate returns new cobra commad enables user to migrate objects to another region on arvan servers +func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { + // Main command + cmd := &cobra.Command{ + Use: "migrate", + Short: "Migrate to region", + Long: loginLong, + Run: func(c *cobra.Command, args []string) { + /* TODO + check current region(if asiatech migration is acceptable) + select projects/namespaces to migrate + select destination region2 + migration proccess + output(if failed why and what to do/ if success message) + */ + explainOut := term.NewResponsiveWriter(out) + c.SetOutput(explainOut) + + currentRegionName := getCurrentRegion() + + if currentRegionName == "ir-thr-ba1" { + log.Printf("migration from region %s is not possible now\nplease first switch your region using command:\n\n \tarvan paas region\n\n", currentRegionName) + return + } + log.Println(currentRegionName) + + region, err := getSelectedRegion(in, explainOut) + utl.CheckErr(err) + + if currentRegionName == getRegionFromEndpoint(region.Endpoint) { + log.Printf("can not migrate to this region") + return + } + + fmt.Println(getRegionFromEndpoint(region.Endpoint)) + + project, _ := getSelectedProject(in, explainOut) + fmt.Println("migrating project: ", project) + migrationSteps() + + fmt.Fprintf(explainOut, "All objects migrated successfully!\n") + }, + } + + return cmd +} + +func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { + projects, err := projectList() + if err != nil { + return "", err + } + if len(projects) < 1 { + return "", errors.New("no project to migrate") + } + + explain := "Select project:\n" + explain += sprintProjects(projects) + + _, err = fmt.Fprint(writer, explain) + if err != nil { + return "", err + } + inputExplain := "Project Number[1]: " + + defaultVal := "1" + + return utl.ReadInput(inputExplain, defaultVal, writer, in, projectValidator), nil +} + +func projectValidator(input string) (bool, error) { + return true, nil +} + +func getCurrentRegion() string { + _, err := config.LoadConfigFile() + utl.CheckErr(err) + + arvanConfig := config.GetConfigInfo() + + return getRegionFromEndpoint(arvanConfig.GetServer()) +} + +func getRegionFromEndpoint(endpoint string) string { + currentRegionNameIndex := strings.LastIndex(endpoint, "/") + + return endpoint[currentRegionNameIndex+1:] +} + +func sprintProjects(projects []string) string { + result := "" + var projectIndex int + for i := 0; i < len(projects); i++ { + projectIndex++ + log.Println(projects[i]) + + result += fmt.Sprintf(" [%d] %s\n", projectIndex, projects[i]) + } + return result +} + +func migrationSteps() { + fmt.Print("- Step1") + time.Sleep(2 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Step2") + time.Sleep(3 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Step3") + time.Sleep(1 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Step4") + time.Sleep(1 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Step5") + time.Sleep(2 * time.Second) + fmt.Println(" ", checkmark) +} From c4919e46b74eb7fcd2597e4d45992b224b89e526 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 12 Oct 2022 17:42:47 +0330 Subject: [PATCH 02/17] Change progress steps --- pkg/paas/migration.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index b533648..e9afc89 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -120,19 +120,28 @@ func sprintProjects(projects []string) string { } func migrationSteps() { - fmt.Print("- Step1") + fmt.Print("- Getting all resources") time.Sleep(2 * time.Second) fmt.Println(" ", checkmark) - fmt.Print("- Step2") + fmt.Print("- Step 2") + time.Sleep(2 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Transfering volumes to new region") time.Sleep(3 * time.Second) fmt.Println(" ", checkmark) - fmt.Print("- Step3") + fmt.Print("- Checking memories with old region") time.Sleep(1 * time.Second) fmt.Println(" ", checkmark) - fmt.Print("- Step4") + fmt.Print("- Transfering manifests to new region") time.Sleep(1 * time.Second) fmt.Println(" ", checkmark) - fmt.Print("- Step5") + fmt.Print("- Checking get resources result") time.Sleep(2 * time.Second) fmt.Println(" ", checkmark) + fmt.Print("- Connecting volumes to pods and starting services") + time.Sleep(1 * time.Second) + fmt.Println(" ", checkmark) + fmt.Print("- Creating checklist of all services") + time.Sleep(1 * time.Second) + fmt.Println(" ", checkmark) } From 02d3c93301f0cb6d4339f34d8bccfeb34e048168 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 13:22:37 +0330 Subject: [PATCH 03/17] Move migrate command to paas subcommands --- pkg/cli/cli.go | 3 --- pkg/paas/paas.go | 6 ++++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index db26cbe..e9eb655 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -61,9 +61,6 @@ func NewCommandCLI() *cobra.Command { paasCommand := paas.NewCmdPaas() cmd.AddCommand(paasCommand) - migrateCommand := paas.NewCmdMigrate(in, out, errout) - cmd.AddCommand(migrateCommand) - cmd.AddCommand(updateCmd()) return cmd } diff --git a/pkg/paas/paas.go b/pkg/paas/paas.go index 7100493..f217702 100644 --- a/pkg/paas/paas.go +++ b/pkg/paas/paas.go @@ -30,7 +30,6 @@ const ( projectListPath = "apis/project.openshift.io/v1/projects" ) - // NewCmdPaas return new cobra cli for paas func NewCmdPaas() *cobra.Command { @@ -40,6 +39,9 @@ func NewCmdPaas() *cobra.Command { paasCommand.AddCommand(NewCmdSwitchRegion(in, out, errout)) + migrateCommand := NewCmdMigrate(in, out, errout) + paasCommand.AddCommand(migrateCommand) + paasCommand.PersistentPreRun = func(cmd *cobra.Command, args []string) { err := prepareCommand(cmd) utl.CheckErr(err) @@ -263,7 +265,7 @@ func getArvanAuthorization() string { func getArvanPaasServerBase() string { arvanConfig := config.GetConfigInfo() arvanServer := arvanConfig.GetServer() - return arvanServer + paasUrlPostfix + return arvanServer + paasUrlPostfix } func syncKubeConfig(path, username string, projects []string) error { From 5d9be275c4c06662d3f819a42f1a93fec7e79e9d Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 14:36:32 +0330 Subject: [PATCH 04/17] Change inputs order --- pkg/paas/migration.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index e9afc89..cccc538 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "log" + "strconv" "strings" "time" @@ -16,14 +17,15 @@ import ( const ( checkmark = "[\u2713]" + at1 = "ir-thr-ba1" ) -// NewCmdMigrate returns new cobra commad enables user to migrate objects to another region on arvan servers +// NewCmdMigrate returns new cobra commad enables user to migrate projects to another region on arvan servers func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { // Main command cmd := &cobra.Command{ Use: "migrate", - Short: "Migrate to region", + Short: "Migrate namespaces to destination region", Long: loginLong, Run: func(c *cobra.Command, args []string) { /* TODO @@ -36,13 +38,15 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { explainOut := term.NewResponsiveWriter(out) c.SetOutput(explainOut) + project, _ := getSelectedProject(in, explainOut) + fmt.Println("migrating project:", project) + currentRegionName := getCurrentRegion() - if currentRegionName == "ir-thr-ba1" { + if currentRegionName == at1 { log.Printf("migration from region %s is not possible now\nplease first switch your region using command:\n\n \tarvan paas region\n\n", currentRegionName) return } - log.Println(currentRegionName) region, err := getSelectedRegion(in, explainOut) utl.CheckErr(err) @@ -54,11 +58,9 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { fmt.Println(getRegionFromEndpoint(region.Endpoint)) - project, _ := getSelectedProject(in, explainOut) - fmt.Println("migrating project: ", project) migrationSteps() - fmt.Fprintf(explainOut, "All objects migrated successfully!\n") + fmt.Fprintf(explainOut, "All namespaces migrated successfully!\n") }, } @@ -67,9 +69,11 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { projects, err := projectList() + if err != nil { return "", err } + if len(projects) < 1 { return "", errors.New("no project to migrate") } @@ -85,7 +89,12 @@ func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { defaultVal := "1" - return utl.ReadInput(inputExplain, defaultVal, writer, in, projectValidator), nil + projectIndex, err := strconv.Atoi(utl.ReadInput(inputExplain, defaultVal, writer, in, projectValidator)) + if err != nil { + return "", err + } + + return projects[projectIndex-1], nil } func projectValidator(input string) (bool, error) { @@ -110,12 +119,12 @@ func getRegionFromEndpoint(endpoint string) string { func sprintProjects(projects []string) string { result := "" var projectIndex int + for i := 0; i < len(projects); i++ { projectIndex++ - log.Println(projects[i]) - result += fmt.Sprintf(" [%d] %s\n", projectIndex, projects[i]) } + return result } From 3feebf92eaca2175d3027e491935d402dde42fe0 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 15:15:01 +0330 Subject: [PATCH 05/17] Add projects bound validator --- pkg/paas/migration.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index cccc538..699b49e 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -11,6 +11,7 @@ import ( "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/utl" + "github.com/openshift/oc/pkg/helpers/term" "github.com/spf13/cobra" ) @@ -89,7 +90,9 @@ func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { defaultVal := "1" - projectIndex, err := strconv.Atoi(utl.ReadInput(inputExplain, defaultVal, writer, in, projectValidator)) + validator := projectValidator{len(projects)} + + projectIndex, err := strconv.Atoi(utl.ReadInput(inputExplain, defaultVal, writer, in, validator.validate)) if err != nil { return "", err } @@ -97,7 +100,15 @@ func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { return projects[projectIndex-1], nil } -func projectValidator(input string) (bool, error) { +type projectValidator struct { + upperBound int +} + +func (p projectValidator) validate(input string) (bool, error) { + intInput, err := strconv.Atoi(input) + if err != nil || intInput < 1 || intInput > p.upperBound { + return false, fmt.Errorf("enter a number between '1' and '%d'\n", p.upperBound) + } return true, nil } From 9abf66e7fee4e9807584649a90690fd99241b708 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 15:48:20 +0330 Subject: [PATCH 06/17] Fix region name --- pkg/paas/migration.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 699b49e..29051b2 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -18,24 +18,17 @@ import ( const ( checkmark = "[\u2713]" - at1 = "ir-thr-ba1" + xmark = "[x]" + ba1 = "ir-thr-ba1" ) // NewCmdMigrate returns new cobra commad enables user to migrate projects to another region on arvan servers func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { - // Main command cmd := &cobra.Command{ Use: "migrate", Short: "Migrate namespaces to destination region", Long: loginLong, Run: func(c *cobra.Command, args []string) { - /* TODO - check current region(if asiatech migration is acceptable) - select projects/namespaces to migrate - select destination region2 - migration proccess - output(if failed why and what to do/ if success message) - */ explainOut := term.NewResponsiveWriter(out) c.SetOutput(explainOut) @@ -44,7 +37,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { currentRegionName := getCurrentRegion() - if currentRegionName == at1 { + if currentRegionName == ba1 { log.Printf("migration from region %s is not possible now\nplease first switch your region using command:\n\n \tarvan paas region\n\n", currentRegionName) return } @@ -142,8 +135,8 @@ func sprintProjects(projects []string) string { func migrationSteps() { fmt.Print("- Getting all resources") time.Sleep(2 * time.Second) - fmt.Println(" ", checkmark) - fmt.Print("- Step 2") + fmt.Println(" ", xmark) + fmt.Print("- Stopping user services") time.Sleep(2 * time.Second) fmt.Println(" ", checkmark) fmt.Print("- Transfering volumes to new region") From 017395a30cbd4fb8b357d29dd6b287550eb175b5 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 16:22:40 +0330 Subject: [PATCH 07/17] Remove unnecessary log --- pkg/paas/login.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/paas/login.go b/pkg/paas/login.go index ae90d0a..ece6b90 100644 --- a/pkg/paas/login.go +++ b/pkg/paas/login.go @@ -83,7 +83,7 @@ func NewCmdSwitchRegion(in io.Reader, out, errout io.Writer) *cobra.Command { region, err := getSelectedRegion(in, explainOut) utl.CheckErr(err) - + _, err = config.LoadConfigFile() if err != nil { log.Println(err) @@ -189,18 +189,17 @@ func (r regionValidator) validate(input string) (bool, error) { func sprintRegions(activeZones, inactiveRegions []config.Zone) string { result := "" - var activeZoneIndex int + var activeZoneIndex int for i := 0; i < len(activeZones); i++ { if activeZones[i].Default { activeZoneIndex++ - log.Println(activeZones[i].Release) if activeZones[i].Release == "STABLE" { result += fmt.Sprintf(" [%d] %s-%s\n", activeZoneIndex, activeZones[i].RegionName, activeZones[i].Name) } else { result += fmt.Sprintf(" [%d] %s-%s(%s)\n", activeZoneIndex, activeZones[i].RegionName, activeZones[i].Name, activeZones[i].Release) } - + } } for i := 0; i < len(activeZones); i++ { @@ -211,7 +210,8 @@ func sprintRegions(activeZones, inactiveRegions []config.Zone) string { } else { result += fmt.Sprintf(" [%d] %s-%s(%s)\n", activeZoneIndex, activeZones[i].RegionName, activeZones[i].Name, activeZones[i].Release) } - } } + } + } for i := 0; i < len(inactiveRegions); i++ { result += fmt.Sprintf(" [-] %s-%s (inactive)\n", inactiveRegions[i].RegionName, inactiveRegions[i].Name) } From ddbfb3863ab24684e02fc8575115c6e4400b02ab Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 15 Oct 2022 17:22:34 +0330 Subject: [PATCH 08/17] Add confirmation --- pkg/paas/migration.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 29051b2..a1190b3 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -52,6 +52,11 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { fmt.Println(getRegionFromEndpoint(region.Endpoint)) + confirmed := migrationConfirm(project, region.Name, in, explainOut) + if !confirmed { + return + } + migrationSteps() fmt.Fprintf(explainOut, "All namespaces migrated successfully!\n") @@ -132,6 +137,31 @@ func sprintProjects(projects []string) string { return result } +func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bool { + explain := fmt.Sprintf("You're about to migrate \"%s\" to region \"%s\" :\n", project, region) + + _, err := fmt.Fprint(writer, explain) + if err != nil { + return false + } + inputExplain := "Are you sure?[Y/n]: " + + defaultVal := "Y" + + value := utl.ReadInput(inputExplain, defaultVal, writer, in, confirmationValidate) + if value != "Y" { + return false + } + return true +} + +func confirmationValidate(input string) (bool, error) { + if input != "Y" && input != "n" { + return false, fmt.Errorf("enter a valid answer 'Y' for \"yes\" or 'n' for \"no\"") + } + return true, nil +} + func migrationSteps() { fmt.Print("- Getting all resources") time.Sleep(2 * time.Second) From 9d95ee2472ca03e588d303b426b3a91b4aab90c0 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Tue, 18 Oct 2022 19:30:10 +0330 Subject: [PATCH 09/17] Init api call in migration cli --- go.sum | 1 - pkg/paas/migration.go | 325 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 290 insertions(+), 36 deletions(-) diff --git a/go.sum b/go.sum index abb6774..cf98f8d 100644 --- a/go.sum +++ b/go.sum @@ -1451,7 +1451,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201013081832-0aaa2718063a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs= golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index a1190b3..37800b3 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -1,27 +1,76 @@ package paas import ( + "bytes" + "encoding/json" "errors" "fmt" "io" + "io/ioutil" "log" + "net/http" + "net/url" + "os" "strconv" "strings" + "text/tabwriter" "time" "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/utl" + "k8s.io/client-go/rest" "github.com/openshift/oc/pkg/helpers/term" "github.com/spf13/cobra" ) const ( - checkmark = "[\u2713]" - xmark = "[x]" - ba1 = "ir-thr-ba1" + prepareEndpoint = "/prepare" + backupManifestsEndpoint = "/backup" + restoreManifestsEndpoint = "/restore" + syncImagesEndpoint = "/sync" + cloneVolumesEndpoint = "/clone" + finalizeEndpoint = "/finalize" + migrationServer = "https://cli.arvan.run" + checkmark = "[\u2713]" + xmark = "[x]" + redColor = "\033[31m" + greenColor = "\033[32m" + resetColor = "\033[0m" + bamdad = "ir-thr-ba1" + targetMigrationDestination = "destination" + targetMigrationSource = "source" ) +type Migration struct { + Namespace string + SourceRegion string + DestinationRegion string +} + +type Request struct { + Namespace string + Target string +} + +type Response struct { + Services []Service + Routes []Route + Gateway string + Status int +} + +type Service struct { + Name string + IP string +} + +type Route struct { + Name string + Address string + IsFree bool +} + // NewCmdMigrate returns new cobra commad enables user to migrate projects to another region on arvan servers func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { cmd := &cobra.Command{ @@ -37,29 +86,32 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { currentRegionName := getCurrentRegion() - if currentRegionName == ba1 { + if currentRegionName == bamdad { log.Printf("migration from region %s is not possible now\nplease first switch your region using command:\n\n \tarvan paas region\n\n", currentRegionName) return } - region, err := getSelectedRegion(in, explainOut) + destinationRegion, err := getSelectedRegion(in, explainOut) utl.CheckErr(err) - if currentRegionName == getRegionFromEndpoint(region.Endpoint) { + if currentRegionName == getRegionFromEndpoint(destinationRegion.Endpoint) { log.Printf("can not migrate to this region") return } - fmt.Println(getRegionFromEndpoint(region.Endpoint)) + fmt.Println(getRegionFromEndpoint(destinationRegion.Endpoint)) - confirmed := migrationConfirm(project, region.Name, in, explainOut) + confirmed := migrationConfirm(project, destinationRegion.Name, in, explainOut) if !confirmed { return } - migrationSteps() - - fmt.Fprintf(explainOut, "All namespaces migrated successfully!\n") + migration := Migration{ + Namespace: project, + SourceRegion: currentRegionName, + DestinationRegion: destinationRegion.RegionName, + } + migrationSteps(migration) }, } @@ -105,7 +157,7 @@ type projectValidator struct { func (p projectValidator) validate(input string) (bool, error) { intInput, err := strconv.Atoi(input) if err != nil || intInput < 1 || intInput > p.upperBound { - return false, fmt.Errorf("enter a number between '1' and '%d'\n", p.upperBound) + return false, fmt.Errorf("enter a number between '1' and '%d'", p.upperBound) } return true, nil } @@ -149,10 +201,7 @@ func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bo defaultVal := "Y" value := utl.ReadInput(inputExplain, defaultVal, writer, in, confirmationValidate) - if value != "Y" { - return false - } - return true + return value == "Y" } func confirmationValidate(input string) (bool, error) { @@ -162,29 +211,235 @@ func confirmationValidate(input string) (bool, error) { return true, nil } -func migrationSteps() { - fmt.Print("- Getting all resources") - time.Sleep(2 * time.Second) - fmt.Println(" ", xmark) - fmt.Print("- Stopping user services") - time.Sleep(2 * time.Second) - fmt.Println(" ", checkmark) - fmt.Print("- Transfering volumes to new region") - time.Sleep(3 * time.Second) +func migrationSteps(migration Migration) error { + /* + 1. Prepare Destination (input: ns, region, target(source/destination)) (failure output: Display error and Return) + 2. Prepare Source (input: ns, region, target(source/destination)) (failure output: SourceFinalize(input: fail status)) + 3. Backup Manifests (input: ns, region(source)) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) + 4. Restore Manifests (input: ns, region(destination)) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) + 5. SyncData including sync images and clone volumes (input: ns) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) + 6. Finalize Source (input: status(call on success) - region(source), target(source/destination)) (success output: {[]services[{name,ip}], routes[{name,address,isFree(bool)}], gateway(string)}) + 7. Finalize Destination (input: status(call on success) - region(destination), target(source/destination)) (success output: {[]services[{name,ip}], routes[{name,address,isFree(bool)}], gateway(string)}) + Final Output report: compare services name to display old and new ips also for routes + */ + _, err := Prepare(migration.Namespace, migration.DestinationRegion, targetMigrationDestination) + if err != nil { + failureOutput() + + return err + } + + time.Sleep(70 * time.Millisecond) + + prepareSourceResponse, err := Prepare(migration.Namespace, migration.SourceRegion, targetMigrationSource) + if err != nil { + Finilize(prepareSourceResponse.Status, migration.SourceRegion, targetMigrationSource) + failureOutput() + + return err + } + time.Sleep(200 * time.Millisecond) + backupManifestsResponse, err := BackupManifests(migration.Namespace, migration.SourceRegion) + if err != nil { + Finilize(backupManifestsResponse.Status, migration.SourceRegion, targetMigrationSource) + Finilize(backupManifestsResponse.Status, migration.DestinationRegion, targetMigrationDestination) + failureOutput() + + return err + } + time.Sleep(500 * time.Millisecond) + restoreManifestsResponse, err := RestoreManifests(migration.Namespace, migration.DestinationRegion) + if err != nil { + Finilize(restoreManifestsResponse.Status, migration.SourceRegion, targetMigrationSource) + Finilize(restoreManifestsResponse.Status, migration.DestinationRegion, targetMigrationDestination) + failureOutput() + + return err + } + time.Sleep(1000 * time.Microsecond) + syncImagesResponse, err := SyncImages(migration.Namespace) + if err != nil { + Finilize(syncImagesResponse.Status, migration.SourceRegion, targetMigrationSource) + Finilize(syncImagesResponse.Status, migration.DestinationRegion, targetMigrationDestination) + failureOutput() + + return err + } + time.Sleep(70 * time.Millisecond) + cloneVolumesResponse, err := CloneVolumes(migration.Namespace) + if err != nil { + Finilize(cloneVolumesResponse.Status, migration.SourceRegion, targetMigrationSource) + Finilize(cloneVolumesResponse.Status, migration.DestinationRegion, targetMigrationDestination) + failureOutput() + + return err + } + time.Sleep(3000 * time.Millisecond) + sourceRegionFinalizeResponse, err := Finilize(200, migration.SourceRegion, targetMigrationSource) + if err != nil { + failureOutput() + + return err + } + time.Sleep(700 * time.Millisecond) + destinationbRegionFinalizeResponse, err := Finilize(200, migration.DestinationRegion, targetMigrationDestination) + if err != nil { + failureOutput() + + return err + } + + successOutput(sourceRegionFinalizeResponse, destinationbRegionFinalizeResponse) + + return nil +} + +func Prepare(ns, region, target string) (*Response, error) { + fmt.Print("- Preparing ", region) + + completeURL, err := url.Parse(migrationServer + prepareEndpoint) + if err != nil { + return nil, err + } + + payload := Request{ + Namespace: ns, + Target: target, + } + + return HttpPost(*completeURL, payload) +} + +func SyncImages(ns string) (*Response, error) { fmt.Println(" ", checkmark) - fmt.Print("- Checking memories with old region") - time.Sleep(1 * time.Second) + fmt.Print("- Syncing Images") + + completeURL, err := url.Parse(migrationServer + syncImagesEndpoint) + if err != nil { + return nil, err + } + + return HttpPost(*completeURL, nil) +} + +func CloneVolumes(ns string) (*Response, error) { fmt.Println(" ", checkmark) - fmt.Print("- Transfering manifests to new region") - time.Sleep(1 * time.Second) + fmt.Print("- Cloning Volumes") + + completeURL, err := url.Parse(migrationServer + cloneVolumesEndpoint) + if err != nil { + return nil, err + } + + return HttpPost(*completeURL, nil) +} + +func BackupManifests(ns, region string) (*Response, error) { fmt.Println(" ", checkmark) - fmt.Print("- Checking get resources result") - time.Sleep(2 * time.Second) + fmt.Print("- Saving Manifests Backups") + + completeURL, err := url.Parse(migrationServer + backupManifestsEndpoint) + if err != nil { + return nil, err + } + + return HttpPost(*completeURL, nil) +} + +func RestoreManifests(ns, region string) (*Response, error) { fmt.Println(" ", checkmark) - fmt.Print("- Connecting volumes to pods and starting services") - time.Sleep(1 * time.Second) + fmt.Print("- Restoring Manifests") + + completeURL, err := url.Parse(migrationServer + restoreManifestsEndpoint) + if err != nil { + return nil, err + } + + return HttpPost(*completeURL, nil) +} + +func Finilize(status int, region, target string) (*Response, error) { fmt.Println(" ", checkmark) - fmt.Print("- Creating checklist of all services") - time.Sleep(1 * time.Second) + fmt.Print("- Finilize ", region) + + _, err := url.Parse(migrationServer + finalizeEndpoint) + if err != nil { + return nil, err + } + + completeURL, err := url.Parse(migrationServer + finalizeEndpoint) + if err != nil { + return nil, err + } + + payload := Request{ + Target: target, + } + + return HttpPost(*completeURL, payload) +} + +func HttpPost(u url.URL, payload interface{}) (*Response, error) { + requestBody, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + httpReq, err := http.NewRequest(http.MethodPost, migrationServer+prepareEndpoint, bytes.NewBuffer(requestBody)) + if err != nil { + return nil, err + } + httpReq.Header.Add("accept", "application/json") + httpReq.Header.Add("User-Agent", rest.DefaultKubernetesUserAgent()) + httpResp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return nil, err + } + + if httpResp.StatusCode == http.StatusNoContent { + return nil, nil + } + + if httpResp.StatusCode != http.StatusOK { + return nil, errors.New("server error. try again later") + } + + // read body + defer httpResp.Body.Close() + responseBody, err := ioutil.ReadAll(httpResp.Body) + if err != nil { + return nil, err + } + + // parse response + var response Response + err = json.Unmarshal(responseBody, &response) + if err != nil { + return nil, err + } + return &response, nil +} + +func failureOutput() { + fmt.Println(" ", xmark) + fmt.Println("failed to migrate") +} + +func successOutput(source, destination *Response) { fmt.Println(" ", checkmark) + + w := new(tabwriter.Writer) + w.Init(os.Stdout, 0, 12, 1, '\t', tabwriter.AlignRight) + + defer w.Flush() + + for i := 0; i < len(source.Services); i++ { + fmt.Fprintln(w, "\t", redColor, source.Services[i].IP, "\t", resetColor, "-->", "\t", greenColor, destination.Services[i].IP) + } + + for i := 0; i < len(source.Routes); i++ { + fmt.Fprintln(w, "\t", redColor, source.Routes[i].Name, "\t", resetColor, "-->", "\t", greenColor, destination.Routes[i].Name) + } + + fmt.Fprintln(w, "\t", redColor, source.Gateway, "\t", resetColor, "-->", "\t", greenColor, destination.Gateway) } From f4ee4b0a6ca7f173f2501c24d63a7830786e7c23 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Wed, 19 Oct 2022 18:01:33 +0330 Subject: [PATCH 10/17] Add table to report output --- go.mod | 1 + go.sum | 2 + pkg/paas/migration.go | 271 +++++++++++++++--------------------------- 3 files changed, 100 insertions(+), 174 deletions(-) diff --git a/go.mod b/go.mod index 58770ef..62a042a 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/moby/buildkit v0.8.0 // indirect github.com/moby/term v0.0.0-20201110203204-bea5bbe245bf // indirect + github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5 github.com/openshift/api v3.9.0+incompatible github.com/openshift/client-go v3.9.0+incompatible // indirect github.com/openshift/library-go v0.0.0-20201211095848-8399bf6288d6 diff --git a/go.sum b/go.sum index cf98f8d..95e48c3 100644 --- a/go.sum +++ b/go.sum @@ -835,6 +835,7 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= @@ -915,6 +916,7 @@ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5 h1:58+kh9C6jJVXYjt8IE48G2eWl6BjwU5Gj0gqY84fy78= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 37800b3..86ed66e 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -13,11 +13,11 @@ import ( "os" "strconv" "strings" - "text/tabwriter" - "time" + "github.com/arvancloud/cli/pkg/api" "github.com/arvancloud/cli/pkg/config" "github.com/arvancloud/cli/pkg/utl" + "github.com/olekukonko/tablewriter" "k8s.io/client-go/rest" "github.com/openshift/oc/pkg/helpers/term" @@ -36,8 +36,9 @@ const ( xmark = "[x]" redColor = "\033[31m" greenColor = "\033[32m" + yellowColor = "\033[33m" resetColor = "\033[0m" - bamdad = "ir-thr-ba1" + bamdad = "ba1" targetMigrationDestination = "destination" targetMigrationSource = "source" ) @@ -91,7 +92,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { return } - destinationRegion, err := getSelectedRegion(in, explainOut) + destinationRegion, err := GetZone(bamdad) utl.CheckErr(err) if currentRegionName == getRegionFromEndpoint(destinationRegion.Endpoint) { @@ -99,9 +100,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { return } - fmt.Println(getRegionFromEndpoint(destinationRegion.Endpoint)) - - confirmed := migrationConfirm(project, destinationRegion.Name, in, explainOut) + confirmed := migrationConfirm(project, getRegionFromEndpoint(destinationRegion.Endpoint), in, explainOut) if !confirmed { return } @@ -111,6 +110,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { SourceRegion: currentRegionName, DestinationRegion: destinationRegion.RegionName, } + migrationSteps(migration) }, } @@ -190,23 +190,29 @@ func sprintProjects(projects []string) string { } func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bool { - explain := fmt.Sprintf("You're about to migrate \"%s\" to region \"%s\" :\n", project, region) + explain := fmt.Sprintf("You're about to migrate \"%s\" to region \"%s\".\n", project, region) _, err := fmt.Fprint(writer, explain) if err != nil { return false } - inputExplain := "Are you sure?[Y/n]: " + inputExplain := fmt.Sprintf("This will STOP your applications.\nPlease enter project's name [%s] to proceed:\n", project) - defaultVal := "Y" + defaultVal := "" - value := utl.ReadInput(inputExplain, defaultVal, writer, in, confirmationValidate) - return value == "Y" + v := confirmationValidator{project: project} + + value := utl.ReadInput(inputExplain, defaultVal, writer, in, v.confirmationValidate) + return value == project } -func confirmationValidate(input string) (bool, error) { - if input != "Y" && input != "n" { - return false, fmt.Errorf("enter a valid answer 'Y' for \"yes\" or 'n' for \"no\"") +type confirmationValidator struct { + project string +} + +func (v confirmationValidator) confirmationValidate(input string) (bool, error) { + if input != v.project { + return false, fmt.Errorf("please enter project name: \"%s\"", v.project) } return true, nil } @@ -222,163 +228,15 @@ func migrationSteps(migration Migration) error { 7. Finalize Destination (input: status(call on success) - region(destination), target(source/destination)) (success output: {[]services[{name,ip}], routes[{name,address,isFree(bool)}], gateway(string)}) Final Output report: compare services name to display old and new ips also for routes */ - _, err := Prepare(migration.Namespace, migration.DestinationRegion, targetMigrationDestination) - if err != nil { - failureOutput() - - return err - } - - time.Sleep(70 * time.Millisecond) - prepareSourceResponse, err := Prepare(migration.Namespace, migration.SourceRegion, targetMigrationSource) - if err != nil { - Finilize(prepareSourceResponse.Status, migration.SourceRegion, targetMigrationSource) - failureOutput() - - return err - } - time.Sleep(200 * time.Millisecond) - backupManifestsResponse, err := BackupManifests(migration.Namespace, migration.SourceRegion) - if err != nil { - Finilize(backupManifestsResponse.Status, migration.SourceRegion, targetMigrationSource) - Finilize(backupManifestsResponse.Status, migration.DestinationRegion, targetMigrationDestination) - failureOutput() - - return err - } - time.Sleep(500 * time.Millisecond) - restoreManifestsResponse, err := RestoreManifests(migration.Namespace, migration.DestinationRegion) - if err != nil { - Finilize(restoreManifestsResponse.Status, migration.SourceRegion, targetMigrationSource) - Finilize(restoreManifestsResponse.Status, migration.DestinationRegion, targetMigrationDestination) - failureOutput() - - return err - } - time.Sleep(1000 * time.Microsecond) - syncImagesResponse, err := SyncImages(migration.Namespace) - if err != nil { - Finilize(syncImagesResponse.Status, migration.SourceRegion, targetMigrationSource) - Finilize(syncImagesResponse.Status, migration.DestinationRegion, targetMigrationDestination) - failureOutput() - - return err - } - time.Sleep(70 * time.Millisecond) - cloneVolumesResponse, err := CloneVolumes(migration.Namespace) - if err != nil { - Finilize(cloneVolumesResponse.Status, migration.SourceRegion, targetMigrationSource) - Finilize(cloneVolumesResponse.Status, migration.DestinationRegion, targetMigrationDestination) - failureOutput() - - return err - } - time.Sleep(3000 * time.Millisecond) - sourceRegionFinalizeResponse, err := Finilize(200, migration.SourceRegion, targetMigrationSource) - if err != nil { - failureOutput() - - return err - } - time.Sleep(700 * time.Millisecond) - destinationbRegionFinalizeResponse, err := Finilize(200, migration.DestinationRegion, targetMigrationDestination) - if err != nil { - failureOutput() - - return err - } + sourceRegionFinalizeResponse := &Response{Services: []Service{{Name: "name1", IP: "1.1.1.1"}}, Routes: []Route{{Name: "route1-0", Address: "https://route1-0/", IsFree: true}, {Name: "route1-1", Address: "https://route1-1/", IsFree: false}}, Gateway: "gateway1"} + destinationbRegionFinalizeResponse := &Response{Services: []Service{{Name: "name2", IP: "2.2.2.2"}}, Routes: []Route{{Name: "route2-0", Address: "https://route2-0/", IsFree: true}, {Name: "route2-1", Address: "https://route2-1/", IsFree: false}}, Gateway: "gateway2"} successOutput(sourceRegionFinalizeResponse, destinationbRegionFinalizeResponse) return nil } -func Prepare(ns, region, target string) (*Response, error) { - fmt.Print("- Preparing ", region) - - completeURL, err := url.Parse(migrationServer + prepareEndpoint) - if err != nil { - return nil, err - } - - payload := Request{ - Namespace: ns, - Target: target, - } - - return HttpPost(*completeURL, payload) -} - -func SyncImages(ns string) (*Response, error) { - fmt.Println(" ", checkmark) - fmt.Print("- Syncing Images") - - completeURL, err := url.Parse(migrationServer + syncImagesEndpoint) - if err != nil { - return nil, err - } - - return HttpPost(*completeURL, nil) -} - -func CloneVolumes(ns string) (*Response, error) { - fmt.Println(" ", checkmark) - fmt.Print("- Cloning Volumes") - - completeURL, err := url.Parse(migrationServer + cloneVolumesEndpoint) - if err != nil { - return nil, err - } - - return HttpPost(*completeURL, nil) -} - -func BackupManifests(ns, region string) (*Response, error) { - fmt.Println(" ", checkmark) - fmt.Print("- Saving Manifests Backups") - - completeURL, err := url.Parse(migrationServer + backupManifestsEndpoint) - if err != nil { - return nil, err - } - - return HttpPost(*completeURL, nil) -} - -func RestoreManifests(ns, region string) (*Response, error) { - fmt.Println(" ", checkmark) - fmt.Print("- Restoring Manifests") - - completeURL, err := url.Parse(migrationServer + restoreManifestsEndpoint) - if err != nil { - return nil, err - } - - return HttpPost(*completeURL, nil) -} - -func Finilize(status int, region, target string) (*Response, error) { - fmt.Println(" ", checkmark) - fmt.Print("- Finilize ", region) - - _, err := url.Parse(migrationServer + finalizeEndpoint) - if err != nil { - return nil, err - } - - completeURL, err := url.Parse(migrationServer + finalizeEndpoint) - if err != nil { - return nil, err - } - - payload := Request{ - Target: target, - } - - return HttpPost(*completeURL, payload) -} - func HttpPost(u url.URL, payload interface{}) (*Response, error) { requestBody, err := json.Marshal(payload) if err != nil { @@ -421,25 +279,90 @@ func HttpPost(u url.URL, payload interface{}) (*Response, error) { } func failureOutput() { - fmt.Println(" ", xmark) fmt.Println("failed to migrate") } func successOutput(source, destination *Response) { - fmt.Println(" ", checkmark) + fmt.Println("Your IPs changed successfully") - w := new(tabwriter.Writer) - w.Init(os.Stdout, 0, 12, 1, '\t', tabwriter.AlignRight) - - defer w.Flush() + ipTable := tablewriter.NewWriter(os.Stdout) + ipTable.SetHeader([]string{"Old IPs", "New IPs"}) for i := 0; i < len(source.Services); i++ { - fmt.Fprintln(w, "\t", redColor, source.Services[i].IP, "\t", resetColor, "-->", "\t", greenColor, destination.Services[i].IP) + ipTable.Append([]string{redColor + source.Services[i].IP + resetColor, greenColor + destination.Services[i].IP + resetColor}) } + ipTable.Render() + + freeSourceRoutes := make([]Route, 0) + freeDestinationRoutes := make([]Route, 0) + nonfreeSourceRoutes := make([]Route, 0) + nonfreeDestinationRoutes := make([]Route, 0) + for i := 0; i < len(source.Routes); i++ { - fmt.Fprintln(w, "\t", redColor, source.Routes[i].Name, "\t", resetColor, "-->", "\t", greenColor, destination.Routes[i].Name) + if source.Routes[i].IsFree { + freeSourceRoutes = append(freeSourceRoutes, source.Routes[i]) + freeDestinationRoutes = append(freeDestinationRoutes, destination.Routes[i]) + } else { + nonfreeSourceRoutes = append(nonfreeSourceRoutes, source.Routes[i]) + nonfreeDestinationRoutes = append(nonfreeDestinationRoutes, destination.Routes[i]) + } + } + + if len(freeSourceRoutes) > 0 { + fmt.Println("Your free routes changed successfully:") + + freeRouteTable := tablewriter.NewWriter(os.Stdout) + freeRouteTable.SetHeader([]string{"old free routes", "new free routes"}) + + for i := 0; i < len(freeSourceRoutes); i++ { + freeRouteTable.Append([]string{redColor + freeSourceRoutes[i].Address + resetColor, greenColor + freeDestinationRoutes[i].Address + resetColor}) + } + + freeRouteTable.Render() + } + + if len(nonfreeSourceRoutes) > 0 { + nonFreeRouteTable := tablewriter.NewWriter(os.Stdout) + nonFreeRouteTable.SetHeader([]string{"non-free routes"}) + + for i := 0; i < len(nonfreeSourceRoutes); i++ { + nonFreeRouteTable.Append([]string{yellowColor + nonfreeDestinationRoutes[i].Address + resetColor}) + } + + nonFreeRouteTable.Render() + } + + gatewayTable := tablewriter.NewWriter(os.Stdout) + gatewayTable.SetHeader([]string{"old gateway", "new gateway"}) + + fmt.Println("For non-free domains above, please change your gateway in your DNS provider as bellow:") + gatewayTable.Append([]string{redColor + source.Gateway + resetColor, greenColor + destination.Gateway + resetColor}) + gatewayTable.Render() +} + +func GetZone(target string) (*config.Zone, error) { + regions, err := api.GetZones() + if err != nil { + return nil, err + } + if len(regions.Zones) < 1 { + return nil, errors.New("invalid region info") } - fmt.Fprintln(w, "\t", redColor, source.Gateway, "\t", resetColor, "-->", "\t", greenColor, destination.Gateway) + activeZones, _ := getActiveAndInactiveZones(regions.Zones) + + if len(activeZones) < 1 { + return nil, errors.New("no active region available") + } + + for i, zone := range activeZones { + if zone.Name == target { + return &activeZones[i], nil + } + } + + log.Printf("destination region not found") + + return nil, nil } From 044e401d97977e692a7a57205acb7848665a3204 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 22 Oct 2022 10:54:39 +0330 Subject: [PATCH 11/17] Add free spaces between messages --- pkg/paas/migration.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 86ed66e..16215c2 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -83,7 +83,6 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { c.SetOutput(explainOut) project, _ := getSelectedProject(in, explainOut) - fmt.Println("migrating project:", project) currentRegionName := getCurrentRegion() @@ -190,13 +189,13 @@ func sprintProjects(projects []string) string { } func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bool { - explain := fmt.Sprintf("You're about to migrate \"%s\" to region \"%s\".\n", project, region) + explain := fmt.Sprintf("\nYou're about to migrate \"%s\" from region \"%s\" to \"%s\".\n", project, getCurrentRegion(), region) _, err := fmt.Fprint(writer, explain) if err != nil { return false } - inputExplain := fmt.Sprintf("This will STOP your applications.\nPlease enter project's name [%s] to proceed:\n", project) + inputExplain := fmt.Sprintf(yellowColor+"\nWARNING: This will STOP your applications."+resetColor+"\n\nPlease enter project's name [%s] to proceed: ", project) defaultVal := "" @@ -212,7 +211,7 @@ type confirmationValidator struct { func (v confirmationValidator) confirmationValidate(input string) (bool, error) { if input != v.project { - return false, fmt.Errorf("please enter project name: \"%s\"", v.project) + return false, fmt.Errorf("please enter project name correctly: \"%s\"", v.project) } return true, nil } @@ -283,7 +282,7 @@ func failureOutput() { } func successOutput(source, destination *Response) { - fmt.Println("Your IPs changed successfully") + fmt.Println("\nYour IPs changed successfully") ipTable := tablewriter.NewWriter(os.Stdout) ipTable.SetHeader([]string{"Old IPs", "New IPs"}) From d1c294ba13e0b0a05f9048d06c264a3d5608a558 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 22 Oct 2022 11:14:17 +0330 Subject: [PATCH 12/17] Add comments to functions --- pkg/paas/migration.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 16215c2..814e96b 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -72,7 +72,7 @@ type Route struct { IsFree bool } -// NewCmdMigrate returns new cobra commad enables user to migrate projects to another region on arvan servers +// NewCmdMigrate returns new cobra commad enables user to migrate namespaces to another region on arvan servers. func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "migrate", @@ -117,6 +117,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { return cmd } +// getSelectedProject gets intending namespace to migrate. func getSelectedProject(in io.Reader, writer io.Writer) (string, error) { projects, err := projectList() @@ -153,6 +154,7 @@ type projectValidator struct { upperBound int } +// validate makes sure the inserted namespace is correct. func (p projectValidator) validate(input string) (bool, error) { intInput, err := strconv.Atoi(input) if err != nil || intInput < 1 || intInput > p.upperBound { @@ -161,6 +163,7 @@ func (p projectValidator) validate(input string) (bool, error) { return true, nil } +// getCurrentRegion returns users current region, fetched from config, in string. func getCurrentRegion() string { _, err := config.LoadConfigFile() utl.CheckErr(err) @@ -170,12 +173,14 @@ func getCurrentRegion() string { return getRegionFromEndpoint(arvanConfig.GetServer()) } +// getRegionFromEndpoint parses endpoint to return region name. func getRegionFromEndpoint(endpoint string) string { currentRegionNameIndex := strings.LastIndex(endpoint, "/") return endpoint[currentRegionNameIndex+1:] } +// sprintProjects displays projects to select in lines. func sprintProjects(projects []string) string { result := "" var projectIndex int @@ -188,6 +193,7 @@ func sprintProjects(projects []string) string { return result } +// 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) @@ -209,6 +215,7 @@ type confirmationValidator struct { project string } +// confirmationValidate makes sure that user enters namespace correctly. func (v confirmationValidator) confirmationValidate(input string) (bool, error) { if input != v.project { return false, fmt.Errorf("please enter project name correctly: \"%s\"", v.project) @@ -236,6 +243,7 @@ func migrationSteps(migration Migration) error { return nil } +// HttpPost sends POST request to inserted url. func HttpPost(u url.URL, payload interface{}) (*Response, error) { requestBody, err := json.Marshal(payload) if err != nil { @@ -277,10 +285,12 @@ func HttpPost(u url.URL, payload interface{}) (*Response, error) { return &response, nil } +// failureOutput displays failure output. func failureOutput() { fmt.Println("failed to migrate") } +// successOutput displays success output. func successOutput(source, destination *Response) { fmt.Println("\nYour IPs changed successfully") @@ -340,6 +350,7 @@ func successOutput(source, destination *Response) { gatewayTable.Render() } +// GetZone gets target zone from list of active zones. func GetZone(target string) (*config.Zone, error) { regions, err := api.GetZones() if err != nil { From eb3bf44530478830a13c78b39e60fc170c427355 Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 22 Oct 2022 16:00:17 +0330 Subject: [PATCH 13/17] Modify request and response --- pkg/paas/migration.go | 127 +++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 71 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 814e96b..2234715 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -6,10 +6,8 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net/http" - "net/url" "os" "strconv" "strings" @@ -25,40 +23,18 @@ import ( ) const ( - prepareEndpoint = "/prepare" - backupManifestsEndpoint = "/backup" - restoreManifestsEndpoint = "/restore" - syncImagesEndpoint = "/sync" - cloneVolumesEndpoint = "/clone" - finalizeEndpoint = "/finalize" - migrationServer = "https://cli.arvan.run" - checkmark = "[\u2713]" - xmark = "[x]" - redColor = "\033[31m" - greenColor = "\033[32m" - yellowColor = "\033[33m" - resetColor = "\033[0m" - bamdad = "ba1" - targetMigrationDestination = "destination" - targetMigrationSource = "source" + migrationEndpoint = "/migrations" + redColor = "\033[31m" + greenColor = "\033[32m" + yellowColor = "\033[33m" + resetColor = "\033[0m" + bamdad = "ba1" ) -type Migration struct { - Namespace string - SourceRegion string - DestinationRegion string -} - type Request struct { - Namespace string - Target string -} - -type Response struct { - Services []Service - Routes []Route - Gateway string - Status int + Namespace string `json:"namespace"` + Source string `json:"source"` + Destination string `json:"destination"` } type Service struct { @@ -72,6 +48,18 @@ type Route struct { IsFree bool } +type ZoneInfo struct { + Services []Service `json:"services"` + Routes []Route `json:"routes"` + Gateway string `json:"gateway"` +} + +type Response struct { + Source ZoneInfo `json:"source"` + Destination ZoneInfo `json:"destination"` + Status int `json:"status"` +} + // NewCmdMigrate returns new cobra commad enables user to migrate namespaces to another region on arvan servers. func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { cmd := &cobra.Command{ @@ -91,7 +79,7 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { return } - destinationRegion, err := GetZone(bamdad) + destinationRegion, err := getZoneByName(bamdad) utl.CheckErr(err) if currentRegionName == getRegionFromEndpoint(destinationRegion.Endpoint) { @@ -104,13 +92,13 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { return } - migration := Migration{ - Namespace: project, - SourceRegion: currentRegionName, - DestinationRegion: destinationRegion.RegionName, + requset := Request{ + Namespace: project, + Source: currentRegionName, + Destination: destinationRegion.RegionName, } - migrationSteps(migration) + migrate(requset) }, } @@ -201,7 +189,7 @@ func migrationConfirm(project, region string, in io.Reader, writer io.Writer) bo if err != nil { return false } - inputExplain := fmt.Sprintf(yellowColor+"\nWARNING: This will STOP your applications."+resetColor+"\n\nPlease enter project's name [%s] to proceed: ", project) + inputExplain := fmt.Sprintf(yellowColor+"\nWARNING: This will STOP your applications during migration process."+resetColor+"\n\nPlease enter project's name [%s] to proceed: ", project) defaultVal := "" @@ -223,34 +211,31 @@ func (v confirmationValidator) confirmationValidate(input string) (bool, error) return true, nil } -func migrationSteps(migration Migration) error { - /* - 1. Prepare Destination (input: ns, region, target(source/destination)) (failure output: Display error and Return) - 2. Prepare Source (input: ns, region, target(source/destination)) (failure output: SourceFinalize(input: fail status)) - 3. Backup Manifests (input: ns, region(source)) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) - 4. Restore Manifests (input: ns, region(destination)) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) - 5. SyncData including sync images and clone volumes (input: ns) (failure output: SourceFinalize(input: fail status), DestinationFinalize(input: fail status)) - 6. Finalize Source (input: status(call on success) - region(source), target(source/destination)) (success output: {[]services[{name,ip}], routes[{name,address,isFree(bool)}], gateway(string)}) - 7. Finalize Destination (input: status(call on success) - region(destination), target(source/destination)) (success output: {[]services[{name,ip}], routes[{name,address,isFree(bool)}], gateway(string)}) - Final Output report: compare services name to display old and new ips also for routes - */ +// migrate sends migration request and displays response. +func migrate(request Request) error { - sourceRegionFinalizeResponse := &Response{Services: []Service{{Name: "name1", IP: "1.1.1.1"}}, Routes: []Route{{Name: "route1-0", Address: "https://route1-0/", IsFree: true}, {Name: "route1-1", Address: "https://route1-1/", IsFree: false}}, Gateway: "gateway1"} - destinationbRegionFinalizeResponse := &Response{Services: []Service{{Name: "name2", IP: "2.2.2.2"}}, Routes: []Route{{Name: "route2-0", Address: "https://route2-0/", IsFree: true}, {Name: "route2-1", Address: "https://route2-1/", IsFree: false}}, Gateway: "gateway2"} + response, err := httpPost(request) + if err != nil { + return err + } + + if response.Status == http.StatusOK { + successOutput(response) + } - successOutput(sourceRegionFinalizeResponse, destinationbRegionFinalizeResponse) + failureOutput() return nil } -// HttpPost sends POST request to inserted url. -func HttpPost(u url.URL, payload interface{}) (*Response, error) { +// httpPost sends POST request to inserted url. +func httpPost(payload interface{}) (*Response, error) { requestBody, err := json.Marshal(payload) if err != nil { return nil, err } - httpReq, err := http.NewRequest(http.MethodPost, migrationServer+prepareEndpoint, bytes.NewBuffer(requestBody)) + httpReq, err := http.NewRequest(http.MethodPost, getArvanPaasServerBase()+migrationEndpoint, bytes.NewBuffer(requestBody)) if err != nil { return nil, err } @@ -271,7 +256,7 @@ func HttpPost(u url.URL, payload interface{}) (*Response, error) { // read body defer httpResp.Body.Close() - responseBody, err := ioutil.ReadAll(httpResp.Body) + responseBody, err := io.ReadAll(httpResp.Body) if err != nil { return nil, err } @@ -291,14 +276,14 @@ func failureOutput() { } // successOutput displays success output. -func successOutput(source, destination *Response) { +func successOutput(response *Response) { fmt.Println("\nYour IPs changed successfully") ipTable := tablewriter.NewWriter(os.Stdout) ipTable.SetHeader([]string{"Old IPs", "New IPs"}) - for i := 0; i < len(source.Services); i++ { - ipTable.Append([]string{redColor + source.Services[i].IP + resetColor, greenColor + destination.Services[i].IP + resetColor}) + for i := 0; i < len(response.Source.Services); i++ { + ipTable.Append([]string{redColor + response.Source.Services[i].IP + resetColor, greenColor + response.Destination.Services[i].IP + resetColor}) } ipTable.Render() @@ -308,13 +293,13 @@ func successOutput(source, destination *Response) { nonfreeSourceRoutes := make([]Route, 0) nonfreeDestinationRoutes := make([]Route, 0) - for i := 0; i < len(source.Routes); i++ { - if source.Routes[i].IsFree { - freeSourceRoutes = append(freeSourceRoutes, source.Routes[i]) - freeDestinationRoutes = append(freeDestinationRoutes, destination.Routes[i]) + for i := 0; i < len(response.Source.Routes); i++ { + if response.Source.Routes[i].IsFree { + freeSourceRoutes = append(freeSourceRoutes, response.Source.Routes[i]) + freeDestinationRoutes = append(freeDestinationRoutes, response.Destination.Routes[i]) } else { - nonfreeSourceRoutes = append(nonfreeSourceRoutes, source.Routes[i]) - nonfreeDestinationRoutes = append(nonfreeDestinationRoutes, destination.Routes[i]) + nonfreeSourceRoutes = append(nonfreeSourceRoutes, response.Source.Routes[i]) + nonfreeDestinationRoutes = append(nonfreeDestinationRoutes, response.Destination.Routes[i]) } } @@ -346,12 +331,12 @@ func successOutput(source, destination *Response) { gatewayTable.SetHeader([]string{"old gateway", "new gateway"}) fmt.Println("For non-free domains above, please change your gateway in your DNS provider as bellow:") - gatewayTable.Append([]string{redColor + source.Gateway + resetColor, greenColor + destination.Gateway + resetColor}) + gatewayTable.Append([]string{redColor + response.Source.Gateway + resetColor, greenColor + response.Destination.Gateway + resetColor}) gatewayTable.Render() } -// GetZone gets target zone from list of active zones. -func GetZone(target string) (*config.Zone, error) { +// getZoneByName gets zone from list of active zones giving it's name. +func getZoneByName(name string) (*config.Zone, error) { regions, err := api.GetZones() if err != nil { return nil, err @@ -367,7 +352,7 @@ func GetZone(target string) (*config.Zone, error) { } for i, zone := range activeZones { - if zone.Name == target { + if zone.Name == name { return &activeZones[i], nil } } From 55e218cdd8846a54a4ce15baf33c5ce43b23dbbf Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 22 Oct 2022 20:40:55 +0330 Subject: [PATCH 14/17] Add endpoint --- pkg/paas/migration.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 2234715..0ccc432 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -23,7 +23,7 @@ import ( ) const ( - migrationEndpoint = "/migrations" + migrationEndpoint = "/paas/v1/migrations" redColor = "\033[31m" greenColor = "\033[32m" yellowColor = "\033[33m" @@ -38,14 +38,14 @@ type Request struct { } type Service struct { - Name string - IP string + Name string `json:"name"` + IP string `json:"ip"` } type Route struct { - Name string - Address string - IsFree bool + Name string `json:"name"` + Host string `json:"host"` + IsFree bool `json:"is_free"` } type ZoneInfo struct { @@ -310,7 +310,7 @@ func successOutput(response *Response) { freeRouteTable.SetHeader([]string{"old free routes", "new free routes"}) for i := 0; i < len(freeSourceRoutes); i++ { - freeRouteTable.Append([]string{redColor + freeSourceRoutes[i].Address + resetColor, greenColor + freeDestinationRoutes[i].Address + resetColor}) + freeRouteTable.Append([]string{redColor + freeSourceRoutes[i].Host + resetColor, greenColor + freeDestinationRoutes[i].Host + resetColor}) } freeRouteTable.Render() @@ -321,7 +321,7 @@ func successOutput(response *Response) { nonFreeRouteTable.SetHeader([]string{"non-free routes"}) for i := 0; i < len(nonfreeSourceRoutes); i++ { - nonFreeRouteTable.Append([]string{yellowColor + nonfreeDestinationRoutes[i].Address + resetColor}) + nonFreeRouteTable.Append([]string{yellowColor + nonfreeDestinationRoutes[i].Host + resetColor}) } nonFreeRouteTable.Render() From 8c2cc672eeefcee6a54609830c3c173a9e9a973a Mon Sep 17 00:00:00 2001 From: Payam Qorbanpour Date: Sat, 22 Oct 2022 20:42:34 +0330 Subject: [PATCH 15/17] Add get endpoint from input --- pkg/paas/migration.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index 0ccc432..d1e03bd 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -213,8 +213,7 @@ func (v confirmationValidator) confirmationValidate(input string) (bool, error) // migrate sends migration request and displays response. func migrate(request Request) error { - - response, err := httpPost(request) + response, err := httpPost(migrationEndpoint, request) if err != nil { return err } @@ -229,13 +228,13 @@ func migrate(request Request) error { } // httpPost sends POST request to inserted url. -func httpPost(payload interface{}) (*Response, error) { +func httpPost(endpoint string, payload interface{}) (*Response, error) { requestBody, err := json.Marshal(payload) if err != nil { return nil, err } - httpReq, err := http.NewRequest(http.MethodPost, getArvanPaasServerBase()+migrationEndpoint, bytes.NewBuffer(requestBody)) + httpReq, err := http.NewRequest(http.MethodPost, getArvanPaasServerBase()+endpoint, bytes.NewBuffer(requestBody)) if err != nil { return nil, err } From 229ebcabe2290239308f446b0ceaf47e4732eb73 Mon Sep 17 00:00:00 2001 From: pejman fahimi Date: Sun, 23 Oct 2022 15:23:10 +0330 Subject: [PATCH 16/17] add authorization header to migrate api call --- pkg/api/api.go | 3 ++- pkg/paas/migration.go | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 1f188df..38b7d40 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "errors" + "fmt" "io/ioutil" "net/http" "net/url" @@ -66,7 +67,7 @@ func GetZones() (config.Region, error) { arvanConfig := config.GetConfigInfo() arvanURL, err := url.Parse(arvanConfig.GetServer()) if err != nil { - return regions, nil + return regions, fmt.Errorf("invalid config") } httpReq, err := http.NewRequest("GET", arvanURL.Scheme + "://" + arvanURL.Host+regionsEndpoint, nil) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index d1e03bd..e99437b 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -11,6 +11,7 @@ import ( "os" "strconv" "strings" + "net/url" "github.com/arvancloud/cli/pkg/api" "github.com/arvancloud/cli/pkg/config" @@ -23,7 +24,7 @@ import ( ) const ( - migrationEndpoint = "/paas/v1/migrations" + migrationEndpoint = "/paas/v1/migrate" redColor = "\033[31m" greenColor = "\033[32m" yellowColor = "\033[33m" @@ -95,10 +96,13 @@ func NewCmdMigrate(in io.Reader, out, errout io.Writer) *cobra.Command { requset := Request{ Namespace: project, Source: currentRegionName, - Destination: destinationRegion.RegionName, + Destination: fmt.Sprintf("%s-%s", destinationRegion.RegionName, destinationRegion.Name), } - migrate(requset) + err = migrate(requset) + if err != nil { + log.Println(err) + } }, } @@ -233,11 +237,21 @@ func httpPost(endpoint string, payload interface{}) (*Response, error) { if err != nil { return nil, err } + arvanConfig := config.GetConfigInfo() + arvanURL, err := url.Parse(arvanConfig.GetServer()) + if err != nil { + return nil, fmt.Errorf("invalid config") + } - httpReq, err := http.NewRequest(http.MethodPost, getArvanPaasServerBase()+endpoint, bytes.NewBuffer(requestBody)) + httpReq, err := http.NewRequest(http.MethodPost, arvanURL.Scheme + "://" + arvanURL.Host+endpoint, bytes.NewBuffer(requestBody)) if err != nil { return nil, err } + apikey := arvanConfig.GetApiKey() + if apikey != "" { + httpReq.Header.Add("Authorization", apikey) + } + httpReq.Header.Add("accept", "application/json") httpReq.Header.Add("User-Agent", rest.DefaultKubernetesUserAgent()) httpResp, err := http.DefaultClient.Do(httpReq) From c85f350592b17314766ab5a53fc6df6da2c66283 Mon Sep 17 00:00:00 2001 From: pejman fahimi Date: Sat, 29 Oct 2022 10:34:35 +0330 Subject: [PATCH 17/17] fix http post on migrate --- pkg/paas/migration.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/pkg/paas/migration.go b/pkg/paas/migration.go index e99437b..d8114c0 100644 --- a/pkg/paas/migration.go +++ b/pkg/paas/migration.go @@ -58,7 +58,6 @@ type ZoneInfo struct { type Response struct { Source ZoneInfo `json:"source"` Destination ZoneInfo `json:"destination"` - Status int `json:"status"` } // NewCmdMigrate returns new cobra commad enables user to migrate namespaces to another region on arvan servers. @@ -219,15 +218,11 @@ func (v confirmationValidator) confirmationValidate(input string) (bool, error) func migrate(request Request) error { response, err := httpPost(migrationEndpoint, request) if err != nil { + failureOutput() return err } - - if response.Status == http.StatusOK { - successOutput(response) - } - - failureOutput() - + successOutput(response) + return nil } @@ -259,10 +254,6 @@ func httpPost(endpoint string, payload interface{}) (*Response, error) { return nil, err } - if httpResp.StatusCode == http.StatusNoContent { - return nil, nil - } - if httpResp.StatusCode != http.StatusOK { return nil, errors.New("server error. try again later") }