From 25ad9e4921034d751c2257ed7706bd72a58c4ced Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Wed, 26 Feb 2025 15:41:23 -0800 Subject: [PATCH 1/8] feat: apigee space with apiproducts --- internal/client/products/products.go | 1 + internal/cmd/products/crtprod.go | 3 +++ internal/cmd/products/products.go | 11 +++++++---- internal/cmd/products/updprod.go | 3 +++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/internal/client/products/products.go b/internal/client/products/products.go index 54e2a8c06..7555696ec 100644 --- a/internal/client/products/products.go +++ b/internal/client/products/products.go @@ -57,6 +57,7 @@ type APIProduct struct { QuotaTimeUnit string `json:"quotaTimeUnit,omitempty"` Scopes []string `json:"scopes,omitempty"` QuotaCounterScope string `json:"quotaCounterScope,omitempty"` + Space string `json:"space,omitempty"` } type OperationGroup struct { diff --git a/internal/cmd/products/crtprod.go b/internal/cmd/products/crtprod.go index 46f8f3309..36953eb15 100644 --- a/internal/cmd/products/crtprod.go +++ b/internal/cmd/products/crtprod.go @@ -51,6 +51,7 @@ var CreateCmd = &cobra.Command{ p.Environments = environments p.Proxies = proxies p.Scopes = scopes + p.Space = space p.OperationGroup, err = getOperationGroup(operationGroupFile) if err != nil { @@ -117,6 +118,8 @@ func init() { "", "File containing gRPC Operation Group JSON. See samples for how to create the file") CreateCmd.Flags().StringVarP("aCounterScope, "quota-counter-scope", "", "", "Scope of the quota decides how the quota counter gets applied; can be PROXY or OPERATION") + CreateCmd.Flags().StringVarP(&space, "space", "", + "", "Apigee Space to associate to") // TODO: apiresource -r later _ = CreateCmd.MarkFlagRequired("name") diff --git a/internal/cmd/products/products.go b/internal/cmd/products/products.go index 0148eb7da..4f881a55b 100644 --- a/internal/cmd/products/products.go +++ b/internal/cmd/products/products.go @@ -37,9 +37,9 @@ var ( ) var ( - description, approval, displayName, quota, quotaInterval, quotaUnit string - environments, proxies, scopes []string - attrs map[string]string + description, approval, displayName, quota, quotaInterval, quotaUnit, space string + environments, proxies, scopes []string + attrs map[string]string ) var examples = []string{ @@ -47,12 +47,15 @@ var examples = []string{ --display-name $product_name \ --opgrp $ops_file \ --envs $env \ +--space $space \ --approval auto \ ---attrs access=public --default-token`, `apigeecli products create --name $product_name \ +--attrs access=public --default-token`, + `apigeecli products create --name $product_name \ --display-name $product_name \ --opgrp $ops_file \ --envs $env \ --approval auto \ +--space $space \ --attrs access=public \ --quota 100 --interval 1 --unit minute --default-token`, `apigeecli products import -f samples/apiproduct-legacy.json --default-token`, diff --git a/internal/cmd/products/updprod.go b/internal/cmd/products/updprod.go index d3f780015..e75b254cf 100644 --- a/internal/cmd/products/updprod.go +++ b/internal/cmd/products/updprod.go @@ -51,6 +51,7 @@ var UpdateCmd = &cobra.Command{ p.Environments = environments p.Proxies = proxies p.Scopes = scopes + p.Space = space p.OperationGroup, err = getOperationGroup(operationGroupFile) if err != nil { @@ -110,6 +111,8 @@ func init() { "", "File containing gRPC Operation Group JSON. See samples for how to create the file") UpdateCmd.Flags().StringVarP("aCounterScope, "quota-counter-scope", "", "", "Scope of the quota decides how the quota counter gets applied; can be PROXY or OPERATION") + UpdateCmd.Flags().StringVarP(&space, "space", "", + "", "Associated Apigee Space. Pass this if the API Product being updated is part of a space") // TODO: apiresource -r later _ = UpdateCmd.MarkFlagRequired("name") From 48094fe8dd8fbd45c485d250a18d3a51e1a8ab18 Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Thu, 27 Feb 2025 10:54:42 -0800 Subject: [PATCH 2/8] feat: move products between spaces --- internal/client/products/products.go | 11 ++++++ internal/cmd/products/moveprod.go | 50 ++++++++++++++++++++++++++++ internal/cmd/products/products.go | 1 + 3 files changed, 62 insertions(+) create mode 100644 internal/cmd/products/moveprod.go diff --git a/internal/client/products/products.go b/internal/client/products/products.go index 7555696ec..20130faa2 100644 --- a/internal/client/products/products.go +++ b/internal/client/products/products.go @@ -143,6 +143,17 @@ func Delete(name string) (respBody []byte, err error) { return respBody, err } +// Move +func Move(name string, space string) (respBody []byte, err error) { + u, _ := url.Parse(apiclient.GetApigeeBaseURL()) + q := u.Query() + q.Set("space", space) + u.RawQuery = q.Encode() + u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "apiproducts", name, ":move") + respBody, err = apiclient.HttpClient(u.String(), "") + return respBody, err +} + // upsert - use Action to control if upsert is enabled func upsert(p APIProduct, a Action) (respBody []byte, err error) { u, _ := url.Parse(apiclient.GetApigeeBaseURL()) diff --git a/internal/cmd/products/moveprod.go b/internal/cmd/products/moveprod.go new file mode 100644 index 000000000..4cc31cd41 --- /dev/null +++ b/internal/cmd/products/moveprod.go @@ -0,0 +1,50 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package products + +import ( + "internal/apiclient" + "internal/client/products" + + "github.com/spf13/cobra" +) + +// MoveCmd to move products between spaces +var MoveCmd = &cobra.Command{ + Use: "move", + Short: "Move an API product between Spaces", + Long: "Move an API product between Spaces", + Args: func(cmd *cobra.Command, args []string) (err error) { + apiclient.SetRegion(region) + return apiclient.SetApigeeOrg(org) + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + cmd.SilenceUsage = true + _, err = products.Move(name, space) + return err + }, +} + +func init() { + MoveCmd.Flags().StringVarP(&name, "name", "n", + "", "Name of the API Product") + MoveCmd.Flags().StringVarP(&space, "space", "", + "", "Name of the Apigee Space moving to") + + // TODO: apiresource -r later + + _ = UpdateCmd.MarkFlagRequired("name") + _ = UpdateCmd.MarkFlagRequired("space") +} diff --git a/internal/cmd/products/products.go b/internal/cmd/products/products.go index 4f881a55b..c4668a9f8 100644 --- a/internal/cmd/products/products.go +++ b/internal/cmd/products/products.go @@ -78,6 +78,7 @@ func init() { Cmd.AddCommand(UpdateCmd) Cmd.AddCommand(AttributesCmd) Cmd.AddCommand(RatePlanCmd) + Cmd.AddCommand(MoveCmd) } func getOperationGroup(operationGroupFile string) (*products.OperationGroup, error) { From 3c1dd662424c2b997976b384cc18a6f11c226242 Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Thu, 27 Feb 2025 10:56:46 -0800 Subject: [PATCH 3/8] chore: update --- internal/client/products/products.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/client/products/products.go b/internal/client/products/products.go index 20130faa2..361e20660 100644 --- a/internal/client/products/products.go +++ b/internal/client/products/products.go @@ -143,7 +143,7 @@ func Delete(name string) (respBody []byte, err error) { return respBody, err } -// Move +// Move between spaces func Move(name string, space string) (respBody []byte, err error) { u, _ := url.Parse(apiclient.GetApigeeBaseURL()) q := u.Query() From 555a570a298debf43457f75dedd47badde82fd9d Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Thu, 27 Feb 2025 10:57:47 -0800 Subject: [PATCH 4/8] chore: update copyright --- internal/cmd/products/moveprod.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/products/moveprod.go b/internal/cmd/products/moveprod.go index 4cc31cd41..7aca69e4e 100644 --- a/internal/cmd/products/moveprod.go +++ b/internal/cmd/products/moveprod.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 8c941e95b23bf5750ffbd8d06c8d3e9cc05e58a1 Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Thu, 27 Feb 2025 11:01:51 -0800 Subject: [PATCH 5/8] fix: Update moveprod.go --- internal/cmd/products/moveprod.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/cmd/products/moveprod.go b/internal/cmd/products/moveprod.go index 7aca69e4e..7ab158e27 100644 --- a/internal/cmd/products/moveprod.go +++ b/internal/cmd/products/moveprod.go @@ -43,8 +43,6 @@ func init() { MoveCmd.Flags().StringVarP(&space, "space", "", "", "Name of the Apigee Space moving to") - // TODO: apiresource -r later - - _ = UpdateCmd.MarkFlagRequired("name") - _ = UpdateCmd.MarkFlagRequired("space") + _ = MoveCmd.MarkFlagRequired("name") + _ = MoveCmd.MarkFlagRequired("space") } From 5c4ae8cde19a59aae08c751c3feb5cd4840018bd Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Fri, 28 Feb 2025 12:19:56 -0800 Subject: [PATCH 6/8] feat: list products using spaces --- internal/client/products/products.go | 9 ++++++--- internal/cmd/products/listproducts.go | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/client/products/products.go b/internal/client/products/products.go index 361e20660..a6ad01a11 100644 --- a/internal/client/products/products.go +++ b/internal/client/products/products.go @@ -225,7 +225,7 @@ func ListAttributes(name string) (respBody []byte, err error) { } // List -func List(count int, startKey string, expand bool) (respBody []byte, err error) { +func List(count int, startKey string, expand bool, space string) (respBody []byte, err error) { u, _ := url.Parse(apiclient.GetApigeeBaseURL()) u.Path = path.Join(u.Path, apiclient.GetApigeeOrg(), "apiproducts") q := u.Query() @@ -240,6 +240,9 @@ func List(count int, startKey string, expand bool) (respBody []byte, err error) if startKey != "" { q.Set("startKey", startKey) } + if space != "" { + q.Set("space", space) + } u.RawQuery = q.Encode() @@ -249,7 +252,7 @@ func List(count int, startKey string, expand bool) (respBody []byte, err error) } // ListFilter -func ListFilter(filter map[string]string) (respBody []byte, err error) { +func ListFilter(filter map[string]string, space string) (respBody []byte, err error) { maxProducts := 1000 nextPage := true startKey := "" @@ -259,7 +262,7 @@ func ListFilter(filter map[string]string) (respBody []byte, err error) { apiclient.ClientPrintHttpResponse.Set(false) for nextPage { - pageResp, err := List(maxProducts, startKey, true) + pageResp, err := List(maxProducts, startKey, true, space) if err != nil { return nil, err } diff --git a/internal/cmd/products/listproducts.go b/internal/cmd/products/listproducts.go index a848b507e..a69fece8d 100644 --- a/internal/cmd/products/listproducts.go +++ b/internal/cmd/products/listproducts.go @@ -42,9 +42,9 @@ var ListCmd = &cobra.Command{ cmd.SilenceUsage = true if len(filter) > 0 { - _, err = products.ListFilter(filter) + _, err = products.ListFilter(filter, space) } else { - _, err = products.List(count, startKey, expand) + _, err = products.List(count, startKey, expand, space) } return err }, @@ -72,4 +72,7 @@ func init() { ListCmd.Flags().BoolVarP(&expand, "expand", "x", false, "Expand Details") + + ListCmd.Flags().StringVarP(&space, "space", "", + "", "Apigee Space associated to") } From 7785d6ea308ea9ce8e7c13f2387b00097d03de74 Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Mon, 3 Mar 2025 21:14:34 -0800 Subject: [PATCH 7/8] feat: export products with spaces --- internal/client/products/products.go | 16 +++++++++------- internal/cmd/org/export.go | 4 +++- internal/cmd/org/org.go | 2 +- internal/cmd/products/expprod.go | 4 +++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/internal/client/products/products.go b/internal/client/products/products.go index a6ad01a11..806aa4c45 100644 --- a/internal/client/products/products.go +++ b/internal/client/products/products.go @@ -320,13 +320,13 @@ func ListFilter(filter map[string]string, space string) (respBody []byte, err er } // Export -func Export(conn int) (payload [][]byte, err error) { +func Export(conn int, space string) (payload [][]byte, err error) { // parent workgroup var pwg sync.WaitGroup var mu sync.Mutex entityType := "apiproducts" - products, err := listAllProducts() + products, err := listAllProducts(space) if err != nil { return apiclient.GetEntityPayloadList(), err } @@ -476,7 +476,7 @@ func readProductsFile(filePath string) ([]APIProduct, error) { return products, nil } -func listAllProducts() (products apiProducts, err error) { +func listAllProducts(space string) (products apiProducts, err error) { var startKey string products = apiProducts{} @@ -489,14 +489,16 @@ func listAllProducts() (products apiProducts, err error) { for { p := apiProducts{} - + q := u.Query() if startKey != "" { - q := u.Query() + q.Set("startKey", startKey) q.Set("count", "1000") - u.RawQuery = q.Encode() } - + if space != "" { + q.Set("space", space) + } + u.RawQuery = q.Encode() respBody, err := apiclient.HttpClient(u.String()) startKey = "" if err != nil { diff --git a/internal/cmd/org/export.go b/internal/cmd/org/export.go index fd878f2f8..7bd3b9adb 100644 --- a/internal/cmd/org/export.go +++ b/internal/cmd/org/export.go @@ -87,7 +87,7 @@ var ExportCmd = &cobra.Command{ } clilog.Info.Println("Exporting API Products...") - if productResponse, err = products.Export(conn); proceedOnError(err) != nil { + if productResponse, err = products.Export(conn, space); proceedOnError(err) != nil { return err } if err = apiclient.WriteArrayByteArrayToFile( @@ -336,6 +336,8 @@ func init() { "", "Apigee organization name") ExportCmd.Flags().IntVarP(&conn, "conn", "c", 4, "Number of connections") + ExportCmd.Flags().StringVarP(&space, "space", "", + "", "Apigee space associated to") /*ExportCmd.Flags().StringVarP(&folder, "folder", "f", "", "Folder to export org data")*/ ExportCmd.Flags().BoolVarP(&exportEntries, "export-entries", "", diff --git a/internal/cmd/org/org.go b/internal/cmd/org/org.go index 2d79e2324..a247dec15 100644 --- a/internal/cmd/org/org.go +++ b/internal/cmd/org/org.go @@ -26,7 +26,7 @@ var Cmd = &cobra.Command{ Long: "Manage Apigee Orgs", } -var org, region string +var org, region, space string func init() { Cmd.PersistentFlags().StringVarP(®ion, "region", "r", diff --git a/internal/cmd/products/expprod.go b/internal/cmd/products/expprod.go index 4e722d3b6..0e4975ddb 100644 --- a/internal/cmd/products/expprod.go +++ b/internal/cmd/products/expprod.go @@ -35,7 +35,7 @@ var ExpCmd = &cobra.Command{ const exportFileName = "products.json" apiclient.DisableCmdPrintHttpResponse() - payload, err := products.Export(conn) + payload, err := products.Export(conn, space) if err != nil { return err } @@ -46,4 +46,6 @@ var ExpCmd = &cobra.Command{ func init() { ExpCmd.Flags().IntVarP(&conn, "conn", "c", 4, "Number of connections") + ExpCmd.Flags().StringVarP(&space, "space", "", + "", "Apigee Space associated to") } From cdf3e9d2ef2de187a83f05636a9769b832c0ccf2 Mon Sep 17 00:00:00 2001 From: Sai Saran Vaidyanathan Date: Mon, 3 Mar 2025 21:32:27 -0800 Subject: [PATCH 8/8] fix: variable space --- internal/cmd/org/import.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/org/import.go b/internal/cmd/org/import.go index d6ed9961c..8e723d36e 100644 --- a/internal/cmd/org/import.go +++ b/internal/cmd/org/import.go @@ -223,7 +223,7 @@ var ImportCmd = &cobra.Command{ var ( importTrace, importDebugmask bool - folder, space string + folder string ) func init() {