diff --git a/internal/client/envgroups/envgroups.go b/internal/client/envgroups/envgroups.go index 6ad3b786e..ccf68e048 100644 --- a/internal/client/envgroups/envgroups.go +++ b/internal/client/envgroups/envgroups.go @@ -155,6 +155,14 @@ func ListAttach(name string) (respBody []byte, err error) { return respBody, err } +// GetAttach +func GetAttach(name string, attachment string) (respBody []byte, err error) { + u, _ := url.Parse(apiclient.GetApigeeBaseURL()) + u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "envgroups", name, "attachments", attachment) + respBody, err = apiclient.HttpClient(u.String()) + return respBody, err +} + func getArrayStr(str []string) string { tmp := strings.Join(str, ",") tmp = strings.ReplaceAll(tmp, ",", "\",\"") diff --git a/internal/client/instances/attachments.go b/internal/client/instances/attachments.go index a34ba5397..6177de1cf 100644 --- a/internal/client/instances/attachments.go +++ b/internal/client/instances/attachments.go @@ -24,6 +24,8 @@ import ( "internal/apiclient" ) +const interval = 10 + // Attach func Attach(name string, environment string) (respBody []byte, err error) { envgroup := []string{} diff --git a/internal/client/operations/operations.go b/internal/client/operations/operations.go index 32f7a25e0..f1ab6a536 100644 --- a/internal/client/operations/operations.go +++ b/internal/client/operations/operations.go @@ -18,8 +18,10 @@ import ( "encoding/json" "net/url" "path" + "time" "internal/apiclient" + "internal/clilog" ) type ops struct { @@ -59,6 +61,8 @@ const ( Both OperationCompleteState = "Both" ) +const interval = 10 + // Get func Get(name string) (respBody []byte, err error) { u, _ := url.Parse(apiclient.GetApigeeBaseURL()) @@ -116,3 +120,43 @@ func filterOperation(respBody []byte, state string, completeState OperationCompl } return operationsRespBody, nil } + +// WaitForOperation +func WaitForOperation(operationName string) error { + var err error + + clilog.Info.Printf("Checking operation status in %d seconds\n", interval) + + apiclient.DisableCmdPrintHttpResponse() + + stop := apiclient.Every(interval*time.Second, func(time.Time) bool { + var respBody []byte + respMap := make(map[string]interface{}) + if respBody, err = Get(operationName); err != nil { + clilog.Error.Printf("Error fetching operation status: %v", err) + return false + } + + if err = json.Unmarshal(respBody, &respMap); err != nil { + return true + } + + if respMap["done"] == true { + if respMap["error"] != nil { + clilog.Info.Printf("Operation failed with status: %v\n", respMap["error"]) + } + clilog.Info.Println("Operation completed") + } else { + metadata, _ := respMap["metadata"].(map[string]interface{}) + state, _ := metadata["state"].(string) + clilog.Info.Printf("Operation status is: %s. Waiting %d seconds.\n", state, interval) + return true + } + + return false + }) + + <-stop + + return err +} diff --git a/internal/cmd/env/crtenv.go b/internal/cmd/env/crtenv.go index 0fd97e2ab..855a04481 100644 --- a/internal/cmd/env/crtenv.go +++ b/internal/cmd/env/crtenv.go @@ -15,12 +15,15 @@ package env import ( + "encoding/json" "fmt" "net/url" + "path/filepath" "internal/apiclient" "internal/client/env" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -42,7 +45,17 @@ var CreateCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = env.Create(envType, deploymentType, fwdProxyURI) + respBody, err := env.Create(envType, deploymentType, fwdProxyURI) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -58,6 +71,7 @@ func init() { "", "Deployment type - must be PROXY or ARCHIVE") CreateCmd.Flags().StringVarP(&fwdProxyURI, "fwdproxyuri", "f", "", "URL of the forward proxy to be applied to the runtime instances in this env") - + CreateCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the create to finish, with success or error") _ = CreateCmd.MarkFlagRequired("env") } diff --git a/internal/cmd/env/delenv.go b/internal/cmd/env/delenv.go index 0aefab051..9906b35ad 100644 --- a/internal/cmd/env/delenv.go +++ b/internal/cmd/env/delenv.go @@ -15,9 +15,12 @@ package env import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/env" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,7 +38,17 @@ var DelCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = env.Delete() + respBody, err := env.Delete() + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -43,6 +56,8 @@ var DelCmd = &cobra.Command{ func init() { DelCmd.Flags().StringVarP(&environment, "env", "e", "", "Apigee environment name") + DelCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the deletion to finish, with success or error") _ = DelCmd.MarkFlagRequired("env") } diff --git a/internal/cmd/envgroup/attachenv.go b/internal/cmd/envgroup/attachenv.go index 929cc6fc1..360817cfd 100644 --- a/internal/cmd/envgroup/attachenv.go +++ b/internal/cmd/envgroup/attachenv.go @@ -15,9 +15,12 @@ package envgroup import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/envgroups" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -34,7 +37,17 @@ var AttachCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = envgroups.Attach(name, environment) + respBody, err := envgroups.Attach(name, environment) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -42,12 +55,12 @@ var AttachCmd = &cobra.Command{ func init() { AttachCmd.Flags().StringVarP(&org, "org", "o", "", "Apigee organization name") - AttachCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the environment group") - AttachCmd.Flags().StringVarP(&environment, "env", "e", "", "Name of the environment") + AttachCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the attachment to finish, with success or error") _ = AttachCmd.MarkFlagRequired("name") _ = AttachCmd.MarkFlagRequired("env") diff --git a/internal/cmd/envgroup/crtenvgroup.go b/internal/cmd/envgroup/crtenvgroup.go index 66743d843..e24c71afb 100644 --- a/internal/cmd/envgroup/crtenvgroup.go +++ b/internal/cmd/envgroup/crtenvgroup.go @@ -15,9 +15,12 @@ package envgroup import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/envgroups" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -34,16 +37,30 @@ var CreateCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = envgroups.Create(name, hostnames) + respBody, err := envgroups.Create(name, hostnames) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } +var wait bool + func init() { CreateCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the Environment Group") CreateCmd.Flags().StringArrayVarP(&hostnames, "hosts", "d", []string{}, "A list of hostnames") + CreateCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the create to finish, with success or error") _ = CreateCmd.MarkFlagRequired("name") _ = CreateCmd.MarkFlagRequired("hosts") diff --git a/internal/cmd/envgroup/delenvgroup.go b/internal/cmd/envgroup/delenvgroup.go index ee7543c98..2d45d67a4 100644 --- a/internal/cmd/envgroup/delenvgroup.go +++ b/internal/cmd/envgroup/delenvgroup.go @@ -15,9 +15,12 @@ package envgroup import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/envgroups" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -34,7 +37,17 @@ var DelCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = envgroups.Delete(name) + respBody, err := envgroups.Delete(name) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } diff --git a/internal/cmd/eptattachment/crteptattachment.go b/internal/cmd/eptattachment/crteptattachment.go index efafca2d0..624e1d98c 100644 --- a/internal/cmd/eptattachment/crteptattachment.go +++ b/internal/cmd/eptattachment/crteptattachment.go @@ -15,12 +15,15 @@ package eptattachment import ( + "encoding/json" "fmt" + "path/filepath" "regexp" "internal/apiclient" "internal/client/eptattachment" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -44,12 +47,23 @@ var CreateCmd = &cobra.Command{ return fmt.Errorf("disk encryption key must be of the format " + "projects/{project-id}/regions/{location}/serviceAttachments/{sa-name}") } - _, err = eptattachment.Create(name, serviceAttachment, location) + respBody, err := eptattachment.Create(name, serviceAttachment, location) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return err }, } var location, serviceAttachment string +var wait bool func init() { CreateCmd.Flags().StringVarP(&name, "name", "n", @@ -58,6 +72,8 @@ func init() { "", "Location of the service endpoint") CreateCmd.Flags().StringVarP(&serviceAttachment, "service-attachment", "s", "", "Service attachment url: projects/{project-id}/regions/{location}/serviceAttachments/{sa-name}") + CreateCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the create to finish, with success or error") _ = CreateCmd.MarkFlagRequired("name") _ = CreateCmd.MarkFlagRequired("service-attachment") diff --git a/internal/cmd/eptattachment/deleptattachment.go b/internal/cmd/eptattachment/deleptattachment.go index 6b4abdba8..201cbcce2 100644 --- a/internal/cmd/eptattachment/deleptattachment.go +++ b/internal/cmd/eptattachment/deleptattachment.go @@ -15,9 +15,12 @@ package eptattachment import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/eptattachment" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -34,7 +37,17 @@ var RemoveCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = eptattachment.Delete(name) + respBody, err := eptattachment.Delete(name) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -42,6 +55,8 @@ var RemoveCmd = &cobra.Command{ func init() { RemoveCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the service endpoint") + RemoveCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the delete to finish, with success or error") _ = RemoveCmd.MarkFlagRequired("name") } diff --git a/internal/cmd/instances/activatenat.go b/internal/cmd/instances/activatenat.go index d4f4af36b..8115726f3 100644 --- a/internal/cmd/instances/activatenat.go +++ b/internal/cmd/instances/activatenat.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,7 +38,17 @@ var ActivateNatCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.ActivateNatIP(name, natid) + respBody, err := instances.ActivateNatIP(name, natid) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -43,6 +56,8 @@ var ActivateNatCmd = &cobra.Command{ func init() { ActivateNatCmd.Flags().StringVarP(&natid, "natid", "i", "", "NAT identifier") + ActivateNatCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the activate to finish, with success or error") _ = ActivateNatCmd.MarkFlagRequired("natid") } diff --git a/internal/cmd/instances/crtattachment.go b/internal/cmd/instances/crtattachment.go index 46719fa34..50577a0b5 100644 --- a/internal/cmd/instances/crtattachment.go +++ b/internal/cmd/instances/crtattachment.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,16 +38,30 @@ var CreateAttachCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.Attach(name, environment) + respBody, err := instances.Attach(name, environment) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } +var wait bool + func init() { CreateAttachCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the Instance") CreateAttachCmd.Flags().StringVarP(&environment, "env", "e", "", "Apigee environment name") + CreateAttachCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the attachment to finish, with success or error") _ = CreateAttachCmd.MarkFlagRequired("name") _ = CreateAttachCmd.MarkFlagRequired("env") diff --git a/internal/cmd/instances/crtinstance.go b/internal/cmd/instances/crtinstance.go index ab437a280..91db19987 100644 --- a/internal/cmd/instances/crtinstance.go +++ b/internal/cmd/instances/crtinstance.go @@ -15,12 +15,15 @@ package instances import ( + "encoding/json" "fmt" + "path/filepath" "regexp" "internal/apiclient" "internal/client/instances" + "internal/client/operations" "internal/client/orgs" "github.com/spf13/cobra" @@ -62,7 +65,17 @@ var CreateCmd = &cobra.Command{ } } - _, err = instances.Create(name, location, diskEncryptionKeyName, ipRange, consumerAcceptList) + respBody, err := instances.Create(name, location, diskEncryptionKeyName, ipRange, consumerAcceptList) + if err != nil { + return err + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return err }, @@ -85,6 +98,8 @@ func init() { CreateCmd.Flags().StringArrayVarP(&consumerAcceptList, "consumer-accept-list", "c", []string{}, "Customer accept list represents the list of "+ "projects (id/number) that can connect to the service attachment") + CreateCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the instance to finish, with success or error") _ = CreateCmd.MarkFlagRequired("name") _ = CreateCmd.MarkFlagRequired("location") diff --git a/internal/cmd/instances/delattachment.go b/internal/cmd/instances/delattachment.go index effc4a066..456240b06 100644 --- a/internal/cmd/instances/delattachment.go +++ b/internal/cmd/instances/delattachment.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,7 +38,17 @@ var DeleteAttachCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.DetachEnv(name) + respBody, err := instances.DetachEnv(name) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -45,6 +58,8 @@ func init() { "", "Name of the Instance") DeleteAttachCmd.Flags().StringVarP(&environment, "env", "e", "", "Apigee environment name") + DeleteAttachCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the deletion to finish, with success or error") _ = DeleteAttachCmd.MarkFlagRequired("name") _ = DeleteAttachCmd.MarkFlagRequired("env") diff --git a/internal/cmd/instances/deletenat.go b/internal/cmd/instances/deletenat.go index 2bcbe86b3..a06843824 100644 --- a/internal/cmd/instances/deletenat.go +++ b/internal/cmd/instances/deletenat.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,7 +38,17 @@ var DeleteNatCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.DeleteNatIP(name, natid) + respBody, err := instances.DeleteNatIP(name, natid) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -43,5 +56,8 @@ var DeleteNatCmd = &cobra.Command{ func init() { DeleteNatCmd.Flags().StringVarP(&natid, "natid", "i", "", "NAT identifier") + DeleteNatCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the delete to finish, with success or error") + _ = DeleteNatCmd.MarkFlagRequired("natid") } diff --git a/internal/cmd/instances/delinstance.go b/internal/cmd/instances/delinstance.go index bd9b6eba2..b73707fb3 100644 --- a/internal/cmd/instances/delinstance.go +++ b/internal/cmd/instances/delinstance.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -34,7 +37,17 @@ var DeleteCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.Delete(name) + respBody, err := instances.Delete(name) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -42,9 +55,10 @@ var DeleteCmd = &cobra.Command{ func init() { DeleteCmd.Flags().StringVarP(&org, "org", "o", "", "Apigee organization name") - DeleteCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the instance") + DeleteCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the deletion to finish, with success or error") _ = DeleteCmd.MarkFlagRequired("name") } diff --git a/internal/cmd/instances/reservenat.go b/internal/cmd/instances/reservenat.go index 250453907..46953ab7f 100644 --- a/internal/cmd/instances/reservenat.go +++ b/internal/cmd/instances/reservenat.go @@ -15,9 +15,12 @@ package instances import ( + "encoding/json" "internal/apiclient" + "path/filepath" "internal/client/instances" + "internal/client/operations" "github.com/spf13/cobra" ) @@ -35,7 +38,17 @@ var ReserveNatCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = instances.ReserveNatIP(name, natid) + respBody, err := instances.ReserveNatIP(name, natid) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -43,6 +56,8 @@ var ReserveNatCmd = &cobra.Command{ func init() { ReserveNatCmd.Flags().StringVarP(&natid, "natid", "i", "", "NAT identifier") + ReserveNatCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the reserve to finish, with success or error") _ = ReserveNatCmd.MarkFlagRequired("natid") } diff --git a/internal/cmd/org/createorg.go b/internal/cmd/org/createorg.go index 8fa8c1436..d04bc89e4 100644 --- a/internal/cmd/org/createorg.go +++ b/internal/cmd/org/createorg.go @@ -15,10 +15,13 @@ package org import ( + "encoding/json" "fmt" + "path/filepath" "internal/apiclient" + "internal/client/operations" "internal/client/orgs" "github.com/spf13/cobra" @@ -51,10 +54,20 @@ var CreateCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) (err error) { cmd.SilenceUsage = true - _, err = orgs.Create(description, analyticsRegion, authorizedNetwork, + respBody, err := orgs.Create(description, analyticsRegion, authorizedNetwork, disableVpcPeering, runtimeType, billingType, runtimeDatabaseEncryptionKeyName, portalDisabled, apiConsumerDataEncryptionKeyName, controlPlaneEncryptionKeyName, apiConsumerDataLocation) + if err != nil { + return + } + if wait { + respMap := make(map[string]interface{}) + if err = json.Unmarshal(respBody, &respMap); err != nil { + return err + } + err = operations.WaitForOperation(filepath.Base(respMap["name"].(string))) + } return }, } @@ -63,7 +76,7 @@ var ( analyticsRegion, projectID, authorizedNetwork, runtimeType string description, runtimeDatabaseEncryptionKeyName, billingType string apiConsumerDataEncryptionKeyName, controlPlaneEncryptionKeyName, apiConsumerDataLocation string - disableVpcPeering, portalDisabled bool + disableVpcPeering, portalDisabled, wait bool ) func init() { @@ -96,6 +109,9 @@ func init() { CreateCmd.Flags().BoolVarP(&portalDisabled, "disable-portal", "", false, "Disable creation of Developer Portals; default false") + CreateCmd.Flags().BoolVarP(&wait, "wait", "", + false, "Waits for the create to finish, with success or error") + _ = CreateCmd.MarkFlagRequired("prj") _ = CreateCmd.MarkFlagRequired("reg") _ = CreateCmd.MarkFlagRequired("runtime-type")