From 02c099892359c8eed4fd20349eb5ac79a2544901 Mon Sep 17 00:00:00 2001 From: Nandan Sridhar Date: Mon, 5 Aug 2019 21:56:05 -0700 Subject: [PATCH] export apis --- README.md | 18 +++++- cmd/apis/apis.go | 2 + cmd/apis/expapis/expapis.go | 126 ++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 cmd/apis/expapis/expapis.go diff --git a/README.md b/README.md index 4ea76409..5a841210 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ ___ * [deploy](#depapi) * [fetch](#fetchapi) * [import](#impapis) +* [export](#expapis) * [list](#listorgs) * [listdeploy](#listdeploy) * [undeploy](#undepapi) @@ -165,7 +166,7 @@ The following parameters are supported. See Common Reference for a list of addit Upload a folder containing API proxy bundles ``` -apigeecli apis fetch -o org -f /tmp +apigeecli apis import -o org -f /tmp ``` Parameters The following parameters are supported. See Common Reference for a list of additional parameters. @@ -173,6 +174,19 @@ The following parameters are supported. See Common Reference for a list of addit * `--org -o` (required) Apigee organization name * `--folder -f` (required) path containing API proxy bundles +### export + +Export latest revisions of API proxy bundles from an org + +``` +apigeecli apis export -o org +``` +Parameters +The following parameters are supported. See Common Reference for a list of additional parameters. + +* `--org -o` (required) Apigee organization name + + ### list List APIs in an Apigee Org @@ -185,8 +199,10 @@ The following parameters are supported. See Common Reference for a list of addit * `--org -o` (required) Apigee organization name * `--env -e` (optional) Apigee environment name +* `--rev -r` (optional) Include proxy revisions If the environment name is passed, lists the deployed proxies in the environment +If the revision flag is enabled, lists all the revisions for the proxy ### listdeploy diff --git a/cmd/apis/apis.go b/cmd/apis/apis.go index 5a340b40..b5a466b8 100644 --- a/cmd/apis/apis.go +++ b/cmd/apis/apis.go @@ -5,6 +5,7 @@ import ( crtapi "github.com/srinandan/apigeecli/cmd/apis/crtapi" delapi "github.com/srinandan/apigeecli/cmd/apis/delapi" "github.com/srinandan/apigeecli/cmd/apis/depapi" + "github.com/srinandan/apigeecli/cmd/apis/expapis" fetch "github.com/srinandan/apigeecli/cmd/apis/fetchapi" impapis "github.com/srinandan/apigeecli/cmd/apis/impapis" "github.com/srinandan/apigeecli/cmd/apis/listapis" @@ -29,6 +30,7 @@ func init() { Cmd.AddCommand(listapis.Cmd) Cmd.AddCommand(listdeploy.Cmd) Cmd.AddCommand(crtapi.Cmd) + Cmd.AddCommand(expapis.Cmd) Cmd.AddCommand(depapi.Cmd) Cmd.AddCommand(delapi.Cmd) Cmd.AddCommand(fetch.Cmd) diff --git a/cmd/apis/expapis/expapis.go b/cmd/apis/expapis/expapis.go new file mode 100644 index 00000000..8e838b28 --- /dev/null +++ b/cmd/apis/expapis/expapis.go @@ -0,0 +1,126 @@ +package expapis + +import ( + "encoding/json" + "net/url" + "path" + "sync" + + "github.com/spf13/cobra" + "github.com/srinandan/apigeecli/cmd/shared" +) + +type proxies struct { + Proxies []proxy `json:"proxies,omitempty"` +} + +type proxy struct { + Name string `json:"name,omitempty"` + Revision []string `json:"revision,omitempty"` +} + +var Cmd = &cobra.Command{ + Use: "export", + Short: "export API proxy bundles from an org", + Long: "export API proxy bundles from an org", + RunE: func(cmd *cobra.Command, args []string) (err error) { + return exportProxies() + }, +} + +var conn int + +func init() { + + Cmd.Flags().IntVarP(&conn, "conn", "c", + 4, "Number of connections") +} + +func fetchProxy(entityType string, name string, revision string, wg *sync.WaitGroup) { + + defer wg.Done() + + u, _ := url.Parse(shared.BaseURL) + q := u.Query() + q.Set("format", "bundle") + u.RawQuery = q.Encode() + u.Path = path.Join(u.Path, shared.RootArgs.Org, entityType, name, "revisions", revision) + + err := shared.DownloadResource(u.String(), name) + if err != nil { + shared.Error.Fatalln("Error with entity: %s", name) + shared.Error.Fatalln(err) + } +} + +func batch(entities []proxy, entityType string, pwg *sync.WaitGroup) { + + defer pwg.Done() + //batch workgroup + var bwg sync.WaitGroup + + bwg.Add(len(entities)) + + for _, entity := range entities { + //download only the last revision + lastRevision := len(entity.Revision) + go fetchProxy(entityType, entity.Name, entity.Revision[lastRevision-1], &bwg) + } + bwg.Wait() +} + +func exportProxies() error { + + //parent workgroup + var pwg sync.WaitGroup + const entityType = "apis" + + u, _ := url.Parse(shared.BaseURL) + q := u.Query() + q.Set("includeRevisions", "true") + u.RawQuery = q.Encode() + u.Path = path.Join(u.Path, shared.RootArgs.Org, entityType) + + //don't print to sysout + respBody, err := shared.HttpClient(false, u.String()) + if err != nil { + return err + } + + var entities = proxies{} + err = json.Unmarshal(respBody, &entities) + if err != nil { + return err + } + + numEntities := len(entities.Proxies) + shared.Info.Printf("Found %d API Proxies in the org\n", numEntities) + shared.Info.Printf("Exporting bundles with %d connections\n", conn) + + numOfLoops, remaining := numEntities/conn, numEntities%conn + + //ensure connections aren't greater than products + if conn > numEntities { + conn = numEntities + } + + start := 0 + + for i, end := 0, 0; i < numOfLoops; i++ { + pwg.Add(1) + end = (i * conn) + conn + shared.Info.Printf("Exporting batch %d of proxies\n", (i + 1)) + go batch(entities.Proxies[start:end], entityType, &pwg) + start = end + pwg.Wait() + } + + if remaining > 0 { + pwg.Add(1) + shared.Info.Printf("Exporting remaining %d proxies\n", remaining) + go batch(entities.Proxies[start:numEntities], entityType, &pwg) + pwg.Wait() + } + + return nil +}