Skip to content

Commit

Permalink
Merge pull request #337 from apigee/issue336
Browse files Browse the repository at this point in the history
feat: adds support to create and deploy proxy and sf #336
  • Loading branch information
ssvaidyanathan authored Nov 29, 2023
2 parents 1ede3b3 + 5aed2cb commit f7fa956
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 84 deletions.
43 changes: 38 additions & 5 deletions cmd/apis/bundlecrtapis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"path/filepath"

"internal/apiclient"
"internal/clilog"

proxybundle "internal/bundlegen/proxybundle"

Expand All @@ -32,7 +33,7 @@ import (
var BundleCreateCmd = &cobra.Command{
Use: "bundle",
Short: "Creates an API proxy from an Zip or folder",
Long: "Creates an API proxy from an Zip or folder",
Long: "Creates an API proxy from an Zip or folder; Optionally deploy the API to an env",
Args: func(cmd *cobra.Command, args []string) (err error) {
if proxyZip != "" && proxyFolder != "" {
return fmt.Errorf("proxy bundle (zip) and folder to an API proxy cannot be combined")
Expand All @@ -45,11 +46,15 @@ var BundleCreateCmd = &cobra.Command{
return err
}
}
if env != "" {
apiclient.SetApigeeEnv(env)
}
return apiclient.SetApigeeOrg(org)
},
RunE: func(cmd *cobra.Command, args []string) (err error) {
var respBody []byte
if proxyZip != "" {
_, err = apis.CreateProxy(name, proxyZip)
respBody, err = apis.CreateProxy(name, proxyZip)
} else if proxyFolder != "" {
if stat, err := os.Stat(folder); err == nil && !stat.IsDir() {
return fmt.Errorf("supplied path is not a folder")
Expand All @@ -68,11 +73,25 @@ var BundleCreateCmd = &cobra.Command{
if err = proxybundle.GenerateArchiveBundle(proxyFolder, proxyBundlePath, false); err != nil {
return err
}
if _, err = apis.CreateProxy(name, proxyBundlePath); err != nil {
if respBody, err = apis.CreateProxy(name, proxyBundlePath); err != nil {
return err
}
if err = os.Remove(proxyBundlePath); err != nil {
return err
}

return os.Remove(proxyBundlePath)
}
if env != "" {
clilog.Info.Printf("Deploying the API Proxy %s to environment %s\n", name, env)
if revision, err = GetRevision(respBody); err != nil {
return err
}
if _, err = apis.DeployProxy(name, revision, overrides,
sequencedRollout, safeDeploy, serviceAccountName); err != nil {
return err
}
if wait {
return Wait(name, revision)
}
}
return err
},
Expand All @@ -89,5 +108,19 @@ func init() {
BundleCreateCmd.Flags().StringVarP(&proxyFolder, "proxy-folder", "f",
"", "Path to the Proxy Bundle; ex: ./test/apiproxy")

BundleCreateCmd.Flags().StringVarP(&env, "env", "e",
"", "Name of the environment to deploy the proxy")
BundleCreateCmd.Flags().BoolVarP(&overrides, "ovr", "r",
false, "Forces deployment of the new revision")
BundleCreateCmd.Flags().BoolVarP(&wait, "wait", "",
false, "Waits for the deployment to finish, with success or error")
BundleCreateCmd.Flags().BoolVarP(&sequencedRollout, "sequencedrollout", "",
false, "If set to true, the routing rules will be rolled out in a safe order; default is false")
BundleCreateCmd.Flags().BoolVarP(&safeDeploy, "safedeploy", "",
true, "When set to true, generateDeployChangeReport will be executed and "+
"deployment will proceed if there are no conflicts; default is true")
BundleCreateCmd.Flags().StringVarP(&serviceAccountName, "sa", "s",
"", "The format must be {ACCOUNT_ID}@{PROJECT}.iam.gserviceaccount.com.")

_ = BundleCreateCmd.MarkFlagRequired("name")
}
77 changes: 77 additions & 0 deletions cmd/apis/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2023 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 apis

import (
"encoding/json"
"fmt"
"strconv"
"time"

"internal/apiclient"
"internal/client/apis"
"internal/clilog"
)

func GetRevision(respBody []byte) (revision int, err error) {
var apiProxyRevResp map[string]interface{}

err = json.Unmarshal(respBody, &apiProxyRevResp)
if err != nil {
return -1, err
}
apiProxyRev, err := strconv.Atoi(fmt.Sprintf("%v", apiProxyRevResp["revision"]))
if err != nil {
return -1, err
}
return apiProxyRev, nil
}

func Wait(name string, revision int) error {
var err error

clilog.Info.Printf("Checking deployment 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 = apis.ListProxyRevisionDeployments(name, revision); err != nil {
clilog.Error.Printf("Error fetching proxy revision status: %v", err)
return false
}

if err = json.Unmarshal(respBody, &respMap); err != nil {
return true
}

switch respMap["state"] {
case "PROGRESSING":
clilog.Info.Printf("Proxy deployment status is: %s. Waiting %d seconds.\n", respMap["state"], interval)
return true
case "READY":
clilog.Info.Println("Proxy deployment completed with status: ", respMap["state"])
default:
clilog.Info.Println("Proxy deployment failed with status: ", respMap["state"])
}

return false
})

<-stop

return err
}
34 changes: 1 addition & 33 deletions cmd/apis/depapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@
package apis

import (
"encoding/json"
"time"

"internal/apiclient"
"internal/clilog"

"internal/client/apis"

Expand Down Expand Up @@ -51,37 +47,9 @@ var DepCmd = &cobra.Command{
return err
}

apiclient.DisableCmdPrintHttpResponse()

if wait {
clilog.Info.Printf("Checking deployment status in %d seconds\n", interval)

stop := apiclient.Every(interval*time.Second, func(time.Time) bool {
var respBody []byte
respMap := make(map[string]interface{})
if respBody, err = apis.ListProxyRevisionDeployments(name, revision); err != nil {
clilog.Error.Printf("Error fetching proxy revision status: %v", err)
return false
}

if err = json.Unmarshal(respBody, &respMap); err != nil {
return true
}

if respMap["state"] == "PROGRESSING" {
clilog.Info.Printf("Proxy deployment status is: %s. Waiting %d seconds.\n", respMap["state"], interval)
return true
} else if respMap["state"] == "READY" {
clilog.Info.Println("Proxy deployment completed with status: ", respMap["state"])
} else {
clilog.Info.Println("Proxy deployment failed with status: ", respMap["state"])
}
return false
})

<-stop
err = Wait(name, revision)
}

return err
},
}
Expand Down
35 changes: 31 additions & 4 deletions cmd/sharedflows/bundlecrtsf.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"path/filepath"

"internal/apiclient"
"internal/clilog"

"internal/bundlegen/proxybundle"

Expand All @@ -33,7 +34,7 @@ import (
var BundleCreateCmd = &cobra.Command{
Use: "bundle",
Short: "Creates a sharedflow in an Apigee Org",
Long: "Creates a sharedflow in an Apigee Org",
Long: "Creates a sharedflow in an Apigee Org; Optionally deploy the sharedflow to an env",
Args: func(cmd *cobra.Command, args []string) (err error) {
apiclient.SetApigeeEnv(env)
if sfZip != "" && sfFolder != "" {
Expand All @@ -47,11 +48,15 @@ var BundleCreateCmd = &cobra.Command{
return err
}
}
if env != "" {
apiclient.SetApigeeEnv(env)
}
return apiclient.SetApigeeOrg(org)
},
RunE: func(cmd *cobra.Command, args []string) (err error) {
var respBody []byte
if sfZip != "" {
_, err = sharedflows.Create(name, sfZip)
respBody, err = sharedflows.Create(name, sfZip)
} else if sfFolder != "" {
if stat, err := os.Stat(folder); err == nil && !stat.IsDir() {
return fmt.Errorf("supplied path is not a folder")
Expand All @@ -70,10 +75,24 @@ var BundleCreateCmd = &cobra.Command{
if err = proxybundle.GenerateArchiveBundle(sfFolder, sfBundlePath, true); err != nil {
return err
}
if _, err = sharedflows.Create(name, sfBundlePath); err != nil {
if respBody, err = sharedflows.Create(name, sfBundlePath); err != nil {
return err
}
if err = os.Remove(sfBundlePath); err != nil {
return err
}
return os.Remove(sfBundlePath)
}
if env != "" {
clilog.Info.Printf("Deploying the Sharedflow %s to environment %s\n", name, env)
if revision, err = GetRevision(respBody); err != nil {
return err
}
if _, err = sharedflows.Deploy(name, revision, overrides, serviceAccountName); err != nil {
return err
}
if wait {
return Wait(name, revision)
}
}
return err
},
Expand All @@ -88,6 +107,14 @@ func init() {
"", "Path to the Sharedflow bundle/zip file")
BundleCreateCmd.Flags().StringVarP(&sfFolder, "sf-folder", "f",
"", "Path to the Sharedflow Bundle; ex: ./test/sharedflowbundle")
BundleCreateCmd.Flags().StringVarP(&env, "env", "e",
"", "Apigee environment name")
BundleCreateCmd.Flags().BoolVarP(&overrides, "ovr", "r",
false, "Forces deployment of the new revision")
BundleCreateCmd.Flags().BoolVarP(&wait, "wait", "",
false, "Waits for the deployment to finish, with success or error")
BundleCreateCmd.Flags().StringVarP(&serviceAccountName, "sa", "s",
"", "The format must be {ACCOUNT_ID}@{PROJECT}.iam.gserviceaccount.com.")

_ = BundleCreateCmd.MarkFlagRequired("name")
}
76 changes: 76 additions & 0 deletions cmd/sharedflows/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 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 sharedflows

import (
"encoding/json"
"fmt"
"strconv"
"time"

"internal/apiclient"
"internal/client/sharedflows"
"internal/clilog"
)

func GetRevision(respBody []byte) (revision int, err error) {
var apiProxyRevResp map[string]interface{}

err = json.Unmarshal(respBody, &apiProxyRevResp)
if err != nil {
return -1, err
}
apiProxyRev, err := strconv.Atoi(fmt.Sprintf("%v", apiProxyRevResp["revision"]))
if err != nil {
return -1, err
}
return apiProxyRev, nil
}

func Wait(name string, revision int) error {
var err error

apiclient.DisableCmdPrintHttpResponse()

clilog.Info.Printf("Checking deployment status in %d seconds\n", interval)

stop := apiclient.Every(interval*time.Second, func(time.Time) bool {
var respBody []byte
respMap := make(map[string]interface{})
if respBody, err = sharedflows.ListRevisionDeployments(name, revision); err != nil {
clilog.Error.Printf("Error fetching sharedflow revision status: %v", err)
return false
}

if err = json.Unmarshal(respBody, &respMap); err != nil {
return true
}

switch respMap["state"] {
case "PROGRESSING":
clilog.Info.Printf("Sharedflow deployment status is: %s. Waiting %d seconds.\n", respMap["state"], interval)
return true
case "READY":
clilog.Info.Println("Sharedflow deployment completed with status: ", respMap["state"])
default:
clilog.Info.Println("Sharedflow deployment failed with status: ", respMap["state"])
}
return false
})

<-stop

return err
}
Loading

0 comments on commit f7fa956

Please sign in to comment.