diff --git a/cmd/provision/provision.go b/cmd/provision/provision.go new file mode 100644 index 00000000..a70b4090 --- /dev/null +++ b/cmd/provision/provision.go @@ -0,0 +1,86 @@ +// 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 provision + +import ( + "fmt" + "regexp" + + "internal/apiclient" + "internal/client/provision" + + "github.com/spf13/cobra" +) + +// Cmd to provision App Integration +var Cmd = &cobra.Command{ + Use: "provision", + Short: "Provisions application integration", + Long: "Provisions application integration in the region", + Args: func(cmd *cobra.Command, args []string) (err error) { + cmdProject := cmd.Flag("proj") + cmdRegion := cmd.Flag("reg") + if err = apiclient.SetRegion(cmdRegion.Value.String()); err != nil { + return err + } + return apiclient.SetProjectID(cmdProject.Value.String()) + }, + RunE: func(cmd *cobra.Command, args []string) (err error) { + cloudKMS := cmd.Flag("cloudkms").Value.String() + serviceAccount := cmd.Flag("service-account").Value.String() + + if cloudKMS != "" { + re := regexp.MustCompile(`projects\/([a-zA-Z0-9_-]+)\/locations\/([a-zA-Z0-9_-]+)\/` + + `keyRings\/([a-zA-Z0-9_-]+)\/cryptoKeys\/([a-zA-Z0-9_-]+)\/cryptoKeyVersions\/([0-9]+)`) + ok := re.Match([]byte(cloudKMS)) + if !ok { + return fmt.Errorf("CloudKMS key must be of the format " + + "projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{cryptoKey}" + + "/cryptoKeyVersions/{cryptoKeyVersion}") + } + } + + if serviceAccount != "" { + re := regexp.MustCompile(`[a-zA-Z0-9-]+@[a-zA-Z0-9-]+\.iam\.gserviceaccount\.com`) + ok := re.Match([]byte(serviceAccount)) + if !ok { + return fmt.Errorf("service account must of the format " + + "@.iam.gserviceaccount.com") + } + } + + _, err = provision.Provision(cloudKMS, samples, gmek, serviceAccount) + return err + }, +} + +var samples, gmek bool + +func init() { + var cloudKMS, serviceAccount, project, region string + + Cmd.PersistentFlags().StringVarP(&project, "proj", "p", + "", "Integration GCP Project name") + Cmd.PersistentFlags().StringVarP(®ion, "reg", "r", + "", "Integration region name") + Cmd.Flags().StringVarP(&cloudKMS, "cloudkms", "k", + "", "Cloud KMS config for AuthModule to encrypt/decrypt credentials") + Cmd.Flags().BoolVarP(&samples, "samples", "s", + true, "Indicates if sample workflow should be created along with provisioning") + Cmd.Flags().BoolVarP(&gmek, "gmek", "g", + true, "Indicates provision with GMEK or CMEK") + Cmd.Flags().StringVarP(&serviceAccount, "service-account", "", + "", "User input run-as service account") +} diff --git a/cmd/root.go b/cmd/root.go index 5c48d40e..da2e7511 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -29,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/endpoints" "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/integrations" "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/preferences" + "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/provision" "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/sfdcchannels" "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/sfdcinstances" "github.com/GoogleCloudPlatform/application-integration-management-toolkit/cmd/token" @@ -142,6 +143,7 @@ func init() { RootCmd.AddCommand(sfdcinstances.Cmd) RootCmd.AddCommand(sfdcchannels.Cmd) RootCmd.AddCommand(endpoints.Cmd) + RootCmd.AddCommand(provision.Cmd) } func initConfig() { diff --git a/internal/client/integrations/integrations.go b/internal/client/integrations/integrations.go index 97dc33c7..51c17a12 100644 --- a/internal/client/integrations/integrations.go +++ b/internal/client/integrations/integrations.go @@ -757,7 +757,6 @@ func GetSfdcInstances(integration []byte) (instances map[string]string, err erro // GetConnections func GetConnections(integration []byte) (connections []string, err error) { - iversion := integrationVersion{} err = json.Unmarshal(integration, &iversion) @@ -779,7 +778,6 @@ func GetConnections(integration []byte) (connections []string, err error) { // GetConnectionsWithRegion func GetConnectionsWithRegion(integration []byte) (connections []integrationConnection, err error) { - iversion := integrationVersion{} err = json.Unmarshal(integration, &iversion) diff --git a/internal/client/provision/provision.go b/internal/client/provision/provision.go new file mode 100644 index 00000000..50cf37f9 --- /dev/null +++ b/internal/client/provision/provision.go @@ -0,0 +1,55 @@ +// 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 provision + +import ( + "fmt" + "net/url" + "path" + "strconv" + "strings" + + "internal/apiclient" +) + +// Provision +func Provision(cloudkms string, samples bool, gmek bool, serviceAccount string) (respBody []byte, err error) { + u, _ := url.Parse(apiclient.GetBaseIntegrationURL()) + provStr := []string{} + + if serviceAccount != "" { + provStr = append(provStr, "\"runAsServiceAccount\":\""+serviceAccount+"\"") + } + + if cloudkms != "" { + kmsConfig := getCloudKMSConfig(cloudkms) + provStr = append(provStr, "\"cloudKmsConfig\":"+kmsConfig) + } + + provStr = append(provStr, "\"createSampleWorkflows\":"+strconv.FormatBool(samples)) + provStr = append(provStr, "\"provisionGmek\":"+strconv.FormatBool(gmek)) + + u.Path = path.Join(u.Path, "client:provision") + + payload := "{" + strings.Join(provStr, ",") + "}" + respBody, err = apiclient.HttpClient(u.String(), payload) + return respBody, err +} + +func getCloudKMSConfig(cloudkms string) string { + kmsParts := strings.Split(cloudkms, "/") + return fmt.Sprintf("{\"kmsLocation\":\"%s\",\"kmsRing\":\"%s\",\"key\":\"%s\",\"keyVersion\":\"%s\",\"kmsProjectId\":\"%s\"}", + kmsParts[3], kmsParts[5], kmsParts[7], kmsParts[9], kmsParts[1]) +}