From 36e7c2076baaa92ca88bf0e69dfc9d4041bc9324 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Fri, 14 Jan 2022 14:51:28 -0600 Subject: [PATCH 1/7] Add parsing of metros, faclities, and plans Signed-off-by: Chris Privitere --- internal/capacity/retrieve.go | 104 +++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index 87dff17f..498b7a75 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -21,33 +21,52 @@ package capacity import ( + "github.com/packethost/packngo" "github.com/pkg/errors" "github.com/spf13/cobra" ) func (c *Client) Retrieve() *cobra.Command { var ( - checkFacility bool - checkMetro bool + metros, facilities, plans, locs []string + metro, facility, plan string ) // retrieveCapacitiesCmd represents the retrieveCapacity command var retrieveCapacityCmd = &cobra.Command{ - Use: "get", + Use: `get {-m [metros,...] | -f [facilities,...]} -P [plans,...]`, Aliases: []string{"list"}, - Short: "Returns a list of facilities or metros and plans with their current capacity.", - Long: `Example: -Retrieve capacities: -metal capacity get { --metro | --facility } -`, + Short: "Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans.", + Example: `metal capacity get -m sv,ny,da -P c3.large.arm,c3.medium.x86`, + RunE: func(cmd *cobra.Command, args []string) error { - cmd.SilenceUsage = true var err error - lister := c.Service.List - fieldName := "Facility" + var lister func() (*packngo.CapacityReport, *packngo.Response, error) + var locationField string + + if metro != "" { + metros = append(metros, metro) + } + if facility != "" { + facilities = append(facilities, facility) + } + + if (len(facilities) > 0) == (len(metros) > 0) { + return errors.New("Either facilities or metros should be set") + } + cmd.SilenceUsage = true - if checkMetro { - fieldName = "Metro" + if plan != "" { + plans = append(plans, plan) + } + + if len(facilities) > 0 { + lister = c.Service.List + locationField = "Facility" + locs = append(locs, facilities...) + } else if len(metros) > 0 { lister = c.Service.ListMetros + locationField = "Metro" + locs = append(locs, metros...) } capacities, _, err := lister() @@ -55,21 +74,62 @@ metal capacity get { --metro | --facility } return errors.Wrap(err, "Could not get Capacity") } - header := []string{fieldName, "Plan", "Level"} - requiredDataFormat := [][]string{} + header := []string{locationField, "Plan", "Level"} + data := [][]string{} for locCode, capacity := range *capacities { for plan, bm := range capacity { - loc := []string{} - loc = append(loc, locCode, plan, bm.Level) - requiredDataFormat = append(requiredDataFormat, loc) + if len(locs) > 0 { + for _, location := range locs { + if location == locCode { + if len(plans) > 0 { + for _, p := range plans { + if plan == p { + loc := []string{} + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) + } + } + } else { + loc := []string{} + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) + } + } + } + } else { + if len(plans) > 0 { + for _, p := range plans { + if plan == p { + loc := []string{} + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) + } + } + } else { + loc := []string{} + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) + } + } } } - - return c.Out.Output(capacities, header, &requiredDataFormat) + return c.Out.Output(capacities, header, &data) }, } - retrieveCapacityCmd.Flags().BoolVarP(&checkFacility, "facility", "f", true, "Facility code (sv15)") - retrieveCapacityCmd.Flags().BoolVarP(&checkMetro, "metro", "m", false, "Metro code (sv)") + + fs := retrieveCapacityCmd.Flags() + + fs.StringSliceVarP(&metros, "metros", "m", []string{}, "Codes of the metros") + fs.StringSliceVarP(&facilities, "facilities", "f", []string{}, "Codes of the facilities") + fs.StringSliceVarP(&plans, "plans", "P", []string{}, "Names of the plans") + + fs.StringVar(&metro, "metro", "", "Code of the metro") + fs.StringVar(&facility, "facility", "", "Code of the facility") + fs.StringVar(&plan, "plan", "", "Name of the plan") + _ = fs.MarkDeprecated("metro", "use --metros instead") + _ = fs.MarkDeprecated("plan", "use --plans instead") + _ = fs.MarkDeprecated("facility", "use --facilities instead") + return retrieveCapacityCmd } From 62ac4c2226ede074cf0c4576f315d06433a2ce6c Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Fri, 14 Jan 2022 15:21:07 -0600 Subject: [PATCH 2/7] Simplified loop Signed-off-by: Chris Privitere --- internal/capacity/retrieve.go | 45 ++++++++++------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index 498b7a75..c22454e1 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -79,38 +79,10 @@ func (c *Client) Retrieve() *cobra.Command { for locCode, capacity := range *capacities { for plan, bm := range capacity { - if len(locs) > 0 { - for _, location := range locs { - if location == locCode { - if len(plans) > 0 { - for _, p := range plans { - if plan == p { - loc := []string{} - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) - } - } - } else { - loc := []string{} - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) - } - } - } - } else { - if len(plans) > 0 { - for _, p := range plans { - if plan == p { - loc := []string{} - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) - } - } - } else { - loc := []string{} - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) - } + loc := []string{} + if !(len(plans) > 0 && !contains(plans, plan)) && !(len(locs) > 0 && !contains(locs, locCode)) { + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) } } } @@ -133,3 +105,12 @@ func (c *Client) Retrieve() *cobra.Command { return retrieveCapacityCmd } + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} From a748d29436f341591d25bd9d5a0f69ca9cc784c0 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Fri, 14 Jan 2022 15:22:31 -0600 Subject: [PATCH 3/7] Add docs changes. Signed-off-by: Chris Privitere --- docs/metal_capacity.md | 2 +- docs/metal_capacity_get.md | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/metal_capacity.md b/docs/metal_capacity.md index ec5806b5..740cdcea 100644 --- a/docs/metal_capacity.md +++ b/docs/metal_capacity.md @@ -30,5 +30,5 @@ Capacities operations: get, check * [metal](metal.md) - Command line interface for Equinix Metal * [metal capacity check](metal_capacity_check.md) - Validates if a deploy can be fulfilled with the given quantity in any of the given locations and plans -* [metal capacity get](metal_capacity_get.md) - Returns a list of facilities or metros and plans with their current capacity. +* [metal capacity get](metal_capacity_get.md) - Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans. diff --git a/docs/metal_capacity_get.md b/docs/metal_capacity_get.md index bd80480d..c2750754 100644 --- a/docs/metal_capacity_get.md +++ b/docs/metal_capacity_get.md @@ -1,24 +1,24 @@ ## metal capacity get -Returns a list of facilities or metros and plans with their current capacity. +Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans. -### Synopsis - -Example: -Retrieve capacities: -metal capacity get { --metro | --facility } +``` +metal capacity get {-m [metros,...] | -f [facilities,...]} -P [plans,...] [flags] +``` +### Examples ``` -metal capacity get [flags] +metal capacity get -m sv,ny,da -P c3.large.arm,c3.medium.x86 ``` ### Options ``` - -f, --facility Facility code (sv15) (default true) - -h, --help help for get - -m, --metro Metro code (sv) + -f, --facilities strings Codes of the facilities + -h, --help help for get + -m, --metros strings Codes of the metros + -P, --plans strings Names of the plans ``` ### Options inherited from parent commands From 0d95788877e8e791b20e2fbefe71ffeb74f4014f Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Thu, 20 Jan 2022 17:42:45 -0600 Subject: [PATCH 4/7] Filtering works now. Co-authored-by: Marques Johansson Signed-off-by: Chris Privitere --- internal/capacity/retrieve.go | 65 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index c22454e1..c9bd3148 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -21,49 +21,48 @@ package capacity import ( - "github.com/packethost/packngo" "github.com/pkg/errors" "github.com/spf13/cobra" ) func (c *Client) Retrieve() *cobra.Command { var ( + checkFacility, checkMetro bool metros, facilities, plans, locs []string - metro, facility, plan string ) // retrieveCapacitiesCmd represents the retrieveCapacity command var retrieveCapacityCmd = &cobra.Command{ - Use: `get {-m [metros,...] | -f [facilities,...]} -P [plans,...]`, + Use: `get [[-m | -f] | [--metros metros,... | --facilities facilities,...]] [-P plans,...]`, Aliases: []string{"list"}, - Short: "Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans.", + Short: "Returns a list of facilities or metros and plans with their current capacity, with filtering.", Example: `metal capacity get -m sv,ny,da -P c3.large.arm,c3.medium.x86`, RunE: func(cmd *cobra.Command, args []string) error { var err error - var lister func() (*packngo.CapacityReport, *packngo.Response, error) var locationField string + lister := c.Service.List // Default to facilities - if metro != "" { - metros = append(metros, metro) + fs := cmd.Flags() + if fs.Changed("metros") && fs.Changed("facilities") { + return errors.New("Either facilities or metros, but not both, can be set") } - if facility != "" { - facilities = append(facilities, facility) + if fs.Changed("facility") && fs.Changed("metro") { + return errors.New("Either --facility (-f) or --metro (-m), but not both, can be set") } - - if (len(facilities) > 0) == (len(metros) > 0) { - return errors.New("Either facilities or metros should be set") + if fs.Changed("facility") && fs.Changed("metros") || fs.Changed("facilities") && fs.Changed("metro") { + return errors.New("Cannot specify both facility and metro filtering") } - cmd.SilenceUsage = true - - if plan != "" { - plans = append(plans, plan) + if fs.Changed("metro") && fs.Changed("metros") || fs.Changed("facility") && fs.Changed("facilities") { + return errors.New("Cannot use both --metro (-m) and --metros or --facility (-f) and --facilities") } + // add other bad combos + + cmd.SilenceUsage = true if len(facilities) > 0 { - lister = c.Service.List locationField = "Facility" locs = append(locs, facilities...) - } else if len(metros) > 0 { + } else if len(metros) > 0 || checkMetro { lister = c.Service.ListMetros locationField = "Metro" locs = append(locs, metros...) @@ -78,31 +77,29 @@ func (c *Client) Retrieve() *cobra.Command { data := [][]string{} for locCode, capacity := range *capacities { - for plan, bm := range capacity { - loc := []string{} - if !(len(plans) > 0 && !contains(plans, plan)) && !(len(locs) > 0 && !contains(locs, locCode)) { - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) + // If the list of locations isn't empty and contains this location code + if !(len(locs) > 0 && !contains(locs, locCode)) { + for plan, bm := range capacity { + loc := []string{} + // If the list of plans isn't empty and contains this plan + if !(len(plans) > 0 && !contains(plans, plan)) { + loc = append(loc, locCode, plan, bm.Level) + data = append(data, loc) + } } } } + return c.Out.Output(capacities, header, &data) }, } fs := retrieveCapacityCmd.Flags() - - fs.StringSliceVarP(&metros, "metros", "m", []string{}, "Codes of the metros") - fs.StringSliceVarP(&facilities, "facilities", "f", []string{}, "Codes of the facilities") + fs.BoolVarP(&checkFacility, "facility", "f", true, "Report all facilites") + fs.BoolVarP(&checkMetro, "metro", "m", false, "Report all metros") + fs.StringSliceVar(&metros, "metros", []string{}, "Codes of the metros (client side filtering)") + fs.StringSliceVar(&facilities, "facilities", []string{}, "Codes of the facilities (client side filtering)") fs.StringSliceVarP(&plans, "plans", "P", []string{}, "Names of the plans") - - fs.StringVar(&metro, "metro", "", "Code of the metro") - fs.StringVar(&facility, "facility", "", "Code of the facility") - fs.StringVar(&plan, "plan", "", "Name of the plan") - _ = fs.MarkDeprecated("metro", "use --metros instead") - _ = fs.MarkDeprecated("plan", "use --plans instead") - _ = fs.MarkDeprecated("facility", "use --facilities instead") - return retrieveCapacityCmd } From 3a18e9c4810abffb93dd96803a87179fd186202d Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Thu, 20 Jan 2022 17:45:52 -0600 Subject: [PATCH 5/7] Generated Docs for metal capacity get Signed-off-by: Chris Privitere --- docs/metal_capacity.md | 2 +- docs/metal_capacity_get.md | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/metal_capacity.md b/docs/metal_capacity.md index 740cdcea..8cdcdd69 100644 --- a/docs/metal_capacity.md +++ b/docs/metal_capacity.md @@ -30,5 +30,5 @@ Capacities operations: get, check * [metal](metal.md) - Command line interface for Equinix Metal * [metal capacity check](metal_capacity_check.md) - Validates if a deploy can be fulfilled with the given quantity in any of the given locations and plans -* [metal capacity get](metal_capacity_get.md) - Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans. +* [metal capacity get](metal_capacity_get.md) - Returns a list of facilities or metros and plans with their current capacity, with filtering. diff --git a/docs/metal_capacity_get.md b/docs/metal_capacity_get.md index c2750754..aef1ab88 100644 --- a/docs/metal_capacity_get.md +++ b/docs/metal_capacity_get.md @@ -1,9 +1,9 @@ ## metal capacity get -Returns a list of facilities or metros and plans with their current capacity, optionally filtered by given locations and plans. +Returns a list of facilities or metros and plans with their current capacity, with filtering. ``` -metal capacity get {-m [metros,...] | -f [facilities,...]} -P [plans,...] [flags] +metal capacity get [[-m | -f] | [--metros metros,... | --facilities facilities,...]] [-P plans,...] [flags] ``` ### Examples @@ -15,9 +15,11 @@ metal capacity get -m sv,ny,da -P c3.large.arm,c3.medium.x86 ### Options ``` - -f, --facilities strings Codes of the facilities + --facilities strings Codes of the facilities (client side filtering) + -f, --facility Report all facilites (default true) -h, --help help for get - -m, --metros strings Codes of the metros + -m, --metro Report all metros + --metros strings Codes of the metros (client side filtering) -P, --plans strings Names of the plans ``` From 7bc2f50afb6c61713bf31dbecbd2ee3f81b1829d Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Thu, 20 Jan 2022 17:48:46 -0600 Subject: [PATCH 6/7] Remove todo comment. Signed-off-by: Chris Privitere --- internal/capacity/retrieve.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index c9bd3148..83cedfbb 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -55,7 +55,6 @@ func (c *Client) Retrieve() *cobra.Command { if fs.Changed("metro") && fs.Changed("metros") || fs.Changed("facility") && fs.Changed("facilities") { return errors.New("Cannot use both --metro (-m) and --metros or --facility (-f) and --facilities") } - // add other bad combos cmd.SilenceUsage = true From 01e5ac03094b186b8ae8f576466b640f32915465 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Fri, 21 Jan 2022 10:21:48 -0600 Subject: [PATCH 7/7] Added Marques's suggested changes to fix json output. Signed-off-by: Chris Privitere --- internal/capacity/retrieve.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/internal/capacity/retrieve.go b/internal/capacity/retrieve.go index 83cedfbb..cdb78921 100644 --- a/internal/capacity/retrieve.go +++ b/internal/capacity/retrieve.go @@ -75,21 +75,26 @@ func (c *Client) Retrieve() *cobra.Command { header := []string{locationField, "Plan", "Level"} data := [][]string{} + filtered := map[string]map[string]map[string]string{} + for locCode, capacity := range *capacities { - // If the list of locations isn't empty and contains this location code - if !(len(locs) > 0 && !contains(locs, locCode)) { - for plan, bm := range capacity { - loc := []string{} - // If the list of plans isn't empty and contains this plan - if !(len(plans) > 0 && !contains(plans, plan)) { - loc = append(loc, locCode, plan, bm.Level) - data = append(data, loc) - } + if len(locs) > 0 && !contains(locs, locCode) { + continue + } + for plan, bm := range capacity { + if len(plans) > 0 && !contains(plans, plan) { + continue + } + loc := []string{locCode, plan, bm.Level} + data = append(data, loc) + if len(filtered[locCode]) == 0 { + filtered[locCode] = map[string]map[string]string{} } + filtered[locCode][plan] = map[string]string{"levels": bm.Level} } } - return c.Out.Output(capacities, header, &data) + return c.Out.Output(filtered, header, &data) }, }