diff --git a/cmd/config_add.go b/cmd/config_add.go index 79337e51..782f6c09 100644 --- a/cmd/config_add.go +++ b/cmd/config_add.go @@ -9,6 +9,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/utils" exo "github.com/exoscale/egoscale/v2" ) @@ -120,7 +121,7 @@ func promptAccountInformation() (*account.Account, error) { account.DefaultZone, err = chooseZone(client, nil) if err != nil { for { - defaultZone, err := chooseZone(globalstate.EgoscaleClient, allZones) + defaultZone, err := chooseZone(globalstate.EgoscaleClient, utils.AllZones) if err != nil { return nil, err } diff --git a/cmd/dbaas_list.go b/cmd/dbaas_list.go index b9b3b40b..99fc41f7 100644 --- a/cmd/dbaas_list.go +++ b/cmd/dbaas_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -55,7 +56,7 @@ func (c *dbaasServiceListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(dbaasServiceListOutput, 0) @@ -68,7 +69,7 @@ func (c *dbaasServiceListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListDatabaseServices(ctx, zone) diff --git a/cmd/deploy_target_list.go b/cmd/deploy_target_list.go index 87fdf788..414f85b4 100644 --- a/cmd/deploy_target_list.go +++ b/cmd/deploy_target_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -55,7 +56,7 @@ func (c *deployTargetListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(deployTargetListOutput, 0) @@ -68,7 +69,7 @@ func (c *deployTargetListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListDeployTargets(ctx, zone) diff --git a/cmd/elastic_ip_list.go b/cmd/elastic_ip_list.go index b70b64e0..4521d1b3 100644 --- a/cmd/elastic_ip_list.go +++ b/cmd/elastic_ip_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -54,7 +55,7 @@ func (c *elasticIPListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(elasticIPListOutput, 0) @@ -67,7 +68,7 @@ func (c *elasticIPListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListElasticIPs(ctx, zone) diff --git a/cmd/instance_list.go b/cmd/instance_list.go index 91feed80..a2a898e1 100644 --- a/cmd/instance_list.go +++ b/cmd/instance_list.go @@ -64,7 +64,7 @@ func (c *instanceListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(instanceListOutput, 0) @@ -79,7 +79,7 @@ func (c *instanceListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListInstances(ctx, zone) diff --git a/cmd/instance_pool_list.go b/cmd/instance_pool_list.go index 6be7082c..9b9be713 100644 --- a/cmd/instance_pool_list.go +++ b/cmd/instance_pool_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -56,7 +57,7 @@ func (c *instancePoolListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(instancePoolListOutput, 0) @@ -69,7 +70,7 @@ func (c *instancePoolListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListInstancePools(ctx, zone) diff --git a/cmd/instance_snapshot_list.go b/cmd/instance_snapshot_list.go index fa152978..4cc3b999 100644 --- a/cmd/instance_snapshot_list.go +++ b/cmd/instance_snapshot_list.go @@ -11,6 +11,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" egoscale "github.com/exoscale/egoscale/v2" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -58,7 +59,7 @@ func (c *instanceSnapshotListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(instanceSnapshotListOutput, 0) @@ -73,7 +74,7 @@ func (c *instanceSnapshotListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListSnapshots(ctx, zone) diff --git a/cmd/nlb_list.go b/cmd/nlb_list.go index 095fa659..3b9c1f7c 100644 --- a/cmd/nlb_list.go +++ b/cmd/nlb_list.go @@ -56,7 +56,7 @@ func (c *nlbListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(nlbListOutput, 0) @@ -69,7 +69,7 @@ func (c *nlbListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListNetworkLoadBalancers(ctx, zone) diff --git a/cmd/private_network_list.go b/cmd/private_network_list.go index dd4f4ed4..640fc479 100644 --- a/cmd/private_network_list.go +++ b/cmd/private_network_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -54,7 +55,7 @@ func (c *privateNetworkListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(privateNetworkListOutput, 0) @@ -67,7 +68,7 @@ func (c *privateNetworkListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListPrivateNetworks(ctx, zone) diff --git a/cmd/request.go b/cmd/request.go deleted file mode 100644 index 80e5b90b..00000000 --- a/cmd/request.go +++ /dev/null @@ -1,20 +0,0 @@ -package cmd - -import ( - "github.com/hashicorp/go-multierror" -) - -// forEachZone executes the function f for each specified zone, and return a multierror.Error containing all -// errors that may have occurred during execution. -func forEachZone(zones []string, f func(zone string) error) error { - meg := new(multierror.Group) - - for _, zone := range zones { - zone := zone - meg.Go(func() error { - return f(zone) - }) - } - - return meg.Wait().ErrorOrNil() -} diff --git a/cmd/security_group_show.go b/cmd/security_group_show.go index 04a89a9d..bb7105e4 100644 --- a/cmd/security_group_show.go +++ b/cmd/security_group_show.go @@ -219,7 +219,7 @@ func (c *securityGroupShowCmd) cmdRun(_ *cobra.Command, _ []string) error { } } - instances, err := utils.GetInstancesInSecurityGroup(ctx, globalstate.EgoscaleClient, *securityGroup.ID, zone) + instances, err := utils.GetInstancesInSecurityGroup(ctx, globalstate.EgoscaleClient, *securityGroup.ID) if err != nil { return fmt.Errorf("error retrieving instances in Security Group: %w", err) } diff --git a/cmd/sks_list.go b/cmd/sks_list.go index 840145b1..71e73649 100644 --- a/cmd/sks_list.go +++ b/cmd/sks_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -54,7 +55,7 @@ func (c *sksListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(sksClusterListOutput, 0) @@ -67,7 +68,7 @@ func (c *sksListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListSKSClusters(ctx, zone) diff --git a/cmd/sks_nodepool_list.go b/cmd/sks_nodepool_list.go index 069ef204..3873bbcb 100644 --- a/cmd/sks_nodepool_list.go +++ b/cmd/sks_nodepool_list.go @@ -10,6 +10,7 @@ import ( "github.com/exoscale/cli/pkg/account" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/utils" exoapi "github.com/exoscale/egoscale/v2/api" ) @@ -57,7 +58,7 @@ func (c *sksNodepoolListCmd) cmdRun(_ *cobra.Command, _ []string) error { if c.Zone != "" { zones = []string{c.Zone} } else { - zones = allZones + zones = utils.AllZones } out := make(sksNodepoolListOutput, 0) @@ -70,7 +71,7 @@ func (c *sksNodepoolListCmd) cmdRun(_ *cobra.Command, _ []string) error { } done <- struct{}{} }() - err := forEachZone(zones, func(zone string) error { + err := utils.ForEachZone(zones, func(zone string) error { ctx := exoapi.WithEndpoint(gContext, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) list, err := globalstate.EgoscaleClient.ListSKSClusters(ctx, zone) diff --git a/cmd/zone.go b/cmd/zone.go index 88f6e8ea..6468aa09 100644 --- a/cmd/zone.go +++ b/cmd/zone.go @@ -11,20 +11,6 @@ import ( "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" exoapi "github.com/exoscale/egoscale/v2/api" - "github.com/exoscale/egoscale/v2/oapi" -) - -var ( - // allZones represents the list of known Exoscale zones, in case we need it without performing API lookup. - allZones = []string{ - string(oapi.ZoneNameAtVie1), - string(oapi.ZoneNameAtVie2), - string(oapi.ZoneNameBgSof1), - string(oapi.ZoneNameChDk2), - string(oapi.ZoneNameChGva2), - string(oapi.ZoneNameDeFra1), - string(oapi.ZoneNameDeMuc1), - } ) type zoneListItemOutput struct { diff --git a/utils/utils.go b/utils/utils.go index 222240e5..404bdb50 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -9,7 +9,26 @@ import ( "strconv" "strings" + "github.com/hashicorp/go-multierror" + + exoapi "github.com/exoscale/egoscale/v2/api" + + "github.com/exoscale/cli/pkg/account" v2 "github.com/exoscale/egoscale/v2" + "github.com/exoscale/egoscale/v2/oapi" +) + +var ( + // utils.AllZones represents the list of known Exoscale zones, in case we need it without performing API lookup. + AllZones = []string{ + string(oapi.ZoneNameAtVie1), + string(oapi.ZoneNameAtVie2), + string(oapi.ZoneNameBgSof1), + string(oapi.ZoneNameChDk2), + string(oapi.ZoneNameChGva2), + string(oapi.ZoneNameDeFra1), + string(oapi.ZoneNameDeMuc1), + } ) // RandStringBytes Generate random string of n bytes @@ -22,8 +41,20 @@ func RandStringBytes(n int) (string, error) { return base64.StdEncoding.EncodeToString(b), nil } -func GetInstancesInSecurityGroup(ctx context.Context, client *v2.Client, securityGroupID, zone string) ([]*v2.Instance, error) { - allInstances, err := client.ListInstances(ctx, zone) +func GetInstancesInSecurityGroup(ctx context.Context, client *v2.Client, securityGroupID string) ([]*v2.Instance, error) { + allInstances := make([]*v2.Instance, 0) + err := ForEachZone(AllZones, func(zone string) error { + ctx := exoapi.WithEndpoint(ctx, exoapi.NewReqEndpoint(account.CurrentAccount.Environment, zone)) + + instances, err := client.ListInstances(ctx, zone) + if err != nil { + return err + } + + allInstances = append(allInstances, instances...) + + return nil + }) if err != nil { return nil, err } @@ -190,3 +221,18 @@ func VersionIsNewer(old, new string) bool { func VersionsAreEquivalent(a, b string) bool { return (VersionMajor(b) == VersionMajor(a) && VersionMinor(b) == VersionMinor(a)) } + +// ForEachZone executes the function f for each specified zone, and return a multierror.Error containing all +// errors that may have occurred during execution. +func ForEachZone(zones []string, f func(zone string) error) error { + meg := new(multierror.Group) + + for _, zone := range zones { + zone := zone + meg.Go(func() error { + return f(zone) + }) + } + + return meg.Wait().ErrorOrNil() +}