Skip to content
This repository was archived by the owner on Mar 9, 2023. It is now read-only.

Commit 4e52052

Browse files
committed
handle sdfc and connectors #134
1 parent e3383f1 commit 4e52052

File tree

23 files changed

+931
-96
lines changed

23 files changed

+931
-96
lines changed

.github/workflows/docker-cloudbuild.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
name: Cloud Builder Docker
216

317
# This workflow uses actions that are not certified by GitHub.

.github/workflows/docker-publish.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
name: Docker
216

317
# This workflow uses actions that are not certified by GitHub.

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
FROM golang:1.19 as builder
216

317
ADD ./apiclient /go/src/integrationcli/apiclient

cicd/README.md

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,42 +44,17 @@ Grant the Application Integration Admin role to the Cloud Build Service Agent
4444

4545
## Steps
4646

47-
1. Download the integration from the UI or using `integrationcli`. Here is an example to download via CLI:
47+
1. Generate a scaffolding:
4848

4949
```sh
5050

5151
token=$(gcloud auth print-access-token)
52-
integrationcli integrations versions get -n <integration-name> -v <version> -p <project-id> -r <region-name> -t $token > ./src/<integration-name>.json
52+
integrationcli integrations scaffolding -n <integration-name> -s <snapShot> -p <project-id> -r <region-name> -t $token
5353
```
5454

55-
You can also download via a snapshot number like this:
55+
Inspect the generated `overrides`, `connectors` and `authconfigs`
5656

57-
```sh
58-
59-
token=$(gcloud auth print-access-token)
60-
integrationcli integrations versions get -n <integration-name> -s <snapshot> -p <dev-project-id> -r <region-name> -t $token > ./src/<integration-name>.json
61-
```
62-
63-
2. Author overrides (specific for the environment) and store them in the overrides folder. Here is an example overrides for the URL in the REST task
64-
65-
```json
66-
{
67-
"task_overrides": [{
68-
"taskId": "1",
69-
"task:": "GenericRestV2Task",
70-
"parameters": {
71-
"url": {
72-
"key": "url",
73-
"value": {
74-
"stringValue": "https://httpbin.org/ip"
75-
}
76-
}
77-
}
78-
}]
79-
}
80-
```
81-
82-
3. Trigger the build manually
57+
2. Trigger the build manually
8358

8459
```sh
8560

client/connections/connectors.go

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ type nodeConfig struct {
150150
}
151151

152152
// Create
153-
func Create(name string, content []byte, serviceAccountName string, serviceAccountProject string, encryptionKey string, grantPermission bool) (respBody []byte, err error) {
153+
func Create(name string, content []byte, serviceAccountName string, serviceAccountProject string, encryptionKey string, grantPermission bool, createSecret bool) (respBody []byte, err error) {
154154

155155
var secretVersion string
156156

@@ -278,34 +278,54 @@ func Create(name string, content []byte, serviceAccountName string, serviceAccou
278278
c.ConnectorDetails = nil
279279

280280
//handle secrets for username
281-
if c.AuthConfig != nil && c.AuthConfig.UserPassword.PasswordDetails != nil {
282-
payload, err := readSecretFile(c.AuthConfig.UserPassword.PasswordDetails.Reference)
283-
if err != nil {
284-
return nil, err
285-
}
286-
287-
//check if a Cloud KMS key was passsed, assume the file is encrypted
288-
if encryptionKey != "" {
289-
encryptionKey := path.Join("projects", apiclient.GetProjectID(), encryptionKey)
290-
payload, err = cloudkms.DecryptSymmetric(encryptionKey, payload)
291-
if err != nil {
292-
return nil, err
281+
if c.AuthConfig != nil {
282+
switch c.AuthConfig.AuthType {
283+
case "USER_PASSWORD":
284+
if c.AuthConfig.UserPassword.PasswordDetails != nil {
285+
if createSecret {
286+
payload, err := readSecretFile(c.AuthConfig.UserPassword.PasswordDetails.Reference)
287+
if err != nil {
288+
return nil, err
289+
}
290+
291+
//check if a Cloud KMS key was passsed, assume the file is encrypted
292+
if encryptionKey != "" {
293+
encryptionKey := path.Join("projects", apiclient.GetProjectID(), encryptionKey)
294+
payload, err = cloudkms.DecryptSymmetric(encryptionKey, payload)
295+
if err != nil {
296+
return nil, err
297+
}
298+
}
299+
300+
if secretVersion, err = secmgr.Create(apiclient.GetProjectID(), c.AuthConfig.UserPassword.PasswordDetails.SecretName, payload); err != nil {
301+
return nil, err
302+
}
303+
304+
secretName := c.AuthConfig.UserPassword.PasswordDetails.SecretName
305+
c.AuthConfig.UserPassword.Password = new(secret)
306+
c.AuthConfig.UserPassword.Password.SecretVersion = secretVersion
307+
c.AuthConfig.UserPassword.PasswordDetails = nil //clean the input
308+
if grantPermission && c.ServiceAccount != nil {
309+
//grant connector service account access to secretVersion
310+
if err = apiclient.SetSecretManagerIAMPermission(apiclient.GetProjectID(), secretName, *c.ServiceAccount); err != nil {
311+
return nil, err
312+
}
313+
}
314+
} else {
315+
c.AuthConfig.UserPassword.Password = new(secret)
316+
c.AuthConfig.UserPassword.Password.SecretVersion = fmt.Sprintf("projects/%s/secrets/%s/versions/1", apiclient.GetProjectID(), c.AuthConfig.UserPassword.PasswordDetails.SecretName)
317+
c.AuthConfig.UserPassword.PasswordDetails = nil //clean the input
318+
}
293319
}
294-
}
295-
296-
if secretVersion, err = secmgr.Create(apiclient.GetProjectID(), c.AuthConfig.UserPassword.PasswordDetails.SecretName, payload); err != nil {
297-
return nil, err
298-
}
299-
secretName := c.AuthConfig.UserPassword.PasswordDetails.SecretName
300-
c.AuthConfig.UserPassword.Password = new(secret)
301-
c.AuthConfig.UserPassword.Password.SecretVersion = secretVersion
302-
c.AuthConfig.UserPassword.PasswordDetails = nil //clean the input
303-
304-
if grantPermission && c.ServiceAccount != nil {
305-
//grant connector service account access to secretVersion
306-
if err = apiclient.SetSecretManagerIAMPermission(apiclient.GetProjectID(), secretName, *c.ServiceAccount); err != nil {
307-
return nil, err
320+
case "OAUTH2_JWT_BEARER":
321+
if createSecret {
322+
clilog.Warning.Println("Creating secrets for OAUTH2_JET_BEARER is not implemented")
323+
} else {
324+
c.AuthConfig.Oauth2JwtBearer.ClientKey.SecretVersion = fmt.Sprintf("projects/%s/secrets/%s/versions/1", apiclient.GetProjectID(), c.AuthConfig.Oauth2JwtBearer.ClientKeyDetails.SecretName)
308325
}
326+
case "OAUTH2_CLIENT_CREDENTIALS":
327+
default:
328+
clilog.Warning.Printf("Creating secrets for %s is not implemented\n", c.AuthConfig.AuthType)
309329
}
310330
}
311331

@@ -331,7 +351,7 @@ func Delete(name string) (respBody []byte, err error) {
331351
}
332352

333353
// Get
334-
func Get(name string, view string, minimal bool) (respBody []byte, err error) {
354+
func Get(name string, view string, minimal bool, overrides bool) (respBody []byte, err error) {
335355
u, _ := url.Parse(apiclient.GetBaseConnectorURL())
336356
q := u.Query()
337357
if view != "" {
@@ -358,6 +378,27 @@ func Get(name string, view string, minimal bool) (respBody []byte, err error) {
358378
c.ConnectorDetails.Version = getConnectorVersion(*c.ConnectorVersion)
359379
c.ConnectorVersion = nil
360380
c.Name = nil
381+
if overrides {
382+
switch c.AuthConfig.AuthType {
383+
case "USER_PASSWORD":
384+
p := c.AuthConfig.UserPassword.Password.SecretVersion
385+
c.AuthConfig.UserPassword.PasswordDetails = new(secretDetails)
386+
c.AuthConfig.UserPassword.PasswordDetails.SecretName = strings.Split(p, "/")[3]
387+
c.AuthConfig.UserPassword.Password = nil
388+
case "OAUTH2_JWT_BEARER":
389+
p := c.AuthConfig.Oauth2JwtBearer.ClientKey.SecretVersion
390+
c.AuthConfig.Oauth2JwtBearer.ClientKeyDetails = new(secretDetails)
391+
c.AuthConfig.Oauth2JwtBearer.ClientKeyDetails.SecretName = strings.Split(p, "/")[3]
392+
c.AuthConfig.Oauth2JwtBearer.ClientKey = nil
393+
}
394+
if isGoogleConnection(c.ConnectorDetails.Name) {
395+
for _, configVar := range c.ConfigVariables {
396+
if configVar.Key == "project_id" {
397+
*configVar.StringValue = "$PROJECT_ID$"
398+
}
399+
}
400+
}
401+
}
361402
connectionPayload, err := json.Marshal(c)
362403
if err != nil {
363404
return nil, err
@@ -426,7 +467,7 @@ func readSecretFile(name string) (payload []byte, err error) {
426467
}
427468

428469
// Import
429-
func Import(folder string) (err error) {
470+
func Import(folder string, createSecret bool) (err error) {
430471

431472
apiclient.SetPrintOutput(false)
432473
errs := []string{}
@@ -448,8 +489,8 @@ func Import(folder string) (err error) {
448489
return err
449490
}
450491

451-
if _, err := Get(name, "", false); err != nil { //create only if connection doesn't exist
452-
_, err = Create(name, content, "", "", "", false)
492+
if _, err := Get(name, "", false, false); err != nil { //create only if connection doesn't exist
493+
_, err = Create(name, content, "", "", "", false, createSecret)
453494
if err != nil {
454495
errs = append(errs, err.Error())
455496
}
@@ -525,3 +566,11 @@ func getConnectorVersion(version string) int {
525566
func getConnectionName(name string) string {
526567
return name[strings.LastIndex(name, "/")+1:]
527568
}
569+
570+
func isGoogleConnection(connectionName string) bool {
571+
if connectionName == "pubsub" || connectionName == "gcs" || connectionName == "biqguery" ||
572+
connectionName == "cloudsql-mysql" || connectionName == "cloudsql-postgresql" || connectionName == "cloudsql-sqlserver" {
573+
return true
574+
}
575+
return false
576+
}

client/integrations/integrations.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,12 +702,38 @@ func GetAuthConfigs(integration []byte) (authconfigs []string, err error) {
702702
authConfigUuid := getAuthConfigUuid(*authConfigParams.Value.JsonValue)
703703
authconfigs = append(authconfigs, authConfigUuid)
704704
}
705+
} else if taskConfig.Task == "CloudFunctionTask" {
706+
authConfigParams := taskConfig.Parameters["authConfig"]
707+
if authConfigParams.Key == "authConfig" {
708+
authConfigUuid := getAuthConfigUuid(*authConfigParams.Value.JsonValue)
709+
authconfigs = append(authconfigs, authConfigUuid)
710+
}
705711
}
706712
}
707713

708714
return authconfigs, err
709715
}
710716

717+
// GetSfdcInstances
718+
func GetSfdcInstances(integration []byte) (instances map[string]string, err error) {
719+
iversion := integrationVersion{}
720+
721+
err = json.Unmarshal(integration, &iversion)
722+
if err != nil {
723+
return instances, err
724+
}
725+
726+
instances = make(map[string]string)
727+
728+
for _, triggerConfig := range iversion.TriggerConfigs {
729+
if triggerConfig.TriggerType == "SFDC_CHANNEL" {
730+
instances[triggerConfig.Properties["SFDC instance name"]] = triggerConfig.Properties["Channel name"]
731+
}
732+
}
733+
734+
return instances, err
735+
}
736+
711737
// GetConnections
712738
func GetConnections(integration []byte) (connections []string, err error) {
713739
iversion := integrationVersion{}

client/integrations/overrides.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,19 @@ func extractOverrides(iversion integrationVersion) (overrides, error) {
199199
taskOverrides.ParamOverrides = append(taskOverrides.ParamOverrides, ip)
200200
}
201201
}
202+
for _, triggerConfig := range iversion.TriggerConfigs {
203+
if triggerConfig.TriggerType == "CLOUD_PUBSUB_EXTERNAL" {
204+
subscription := triggerConfig.Properties["Subscription name"]
205+
triggerOverride := triggeroverrides{}
206+
triggerOverride.ProjectId = new(string)
207+
triggerOverride.TopicName = new(string)
208+
*triggerOverride.ProjectId = strings.Split(subscription, "_")[0]
209+
*triggerOverride.TopicName = strings.Split(subscription, "_")[1]
210+
triggerOverride.TriggerNumber = triggerConfig.TriggerNumber
211+
taskOverrides.TriggerOverrides = append(taskOverrides.TriggerOverrides, triggerOverride)
212+
}
213+
}
214+
202215
return taskOverrides, nil
203216
}
204217

@@ -302,7 +315,7 @@ func getNewConnectionParams(connectionName string, connectionLocation string) (c
302315
integrationRegion = apiclient.GetRegion() //store the integration location
303316
apiclient.SetRegion(connectionLocation) //set the connector region
304317
}
305-
connResp, err := connections.Get(connectionName, "BASIC", false) //get connector details
318+
connResp, err := connections.Get(connectionName, "BASIC", false, false) //get connector details
306319
apiclient.SetPrintOutput(true)
307320
if connectionLocation != "" {
308321
apiclient.SetRegion(integrationRegion) //set the integration region back

0 commit comments

Comments
 (0)