Skip to content

Commit afea096

Browse files
committed
finalized the cos-to-sql sample code and readme instructions
1 parent 544f697 commit afea096

File tree

13 files changed

+2074
-1606
lines changed

13 files changed

+2074
-1606
lines changed

cos-to-sql/.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.dockerignore
2+
.gitignore
3+
build
4+
Dockerfile
5+
node_modules

cos-to-sql/Dockerfile

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
FROM registry.access.redhat.com/ubi9/nodejs-22:latest AS build-env
2-
WORKDIR /app
1+
# Download dependencies in builder stage
2+
FROM registry.access.redhat.com/ubi9/nodejs-22:latest AS builder
33

4-
# Copy job dependency manifests to the container image.
5-
COPY package.json ./
4+
COPY --chown=${CNB_USER_ID}:${CNB_GROUP_ID} package.json package-lock.json /app/
5+
WORKDIR /app
6+
RUN npm ci --omit=dev
67

7-
# Install production dependencies.
8-
RUN npm install --production
98

109
# Use a small distroless image for as runtime image
11-
FROM gcr.io/distroless/nodejs22-debian12
12-
13-
WORKDIR /app
10+
FROM gcr.io/distroless/nodejs22
1411

15-
# Copy local code to the container image.
16-
COPY ./src ./
12+
COPY --chown=1001:0 --from=builder /app/node_modules /app/node_modules
13+
COPY --chown=1001:0 app.mjs /app
14+
COPY --chown=1001:0 utils/ /app/utils
15+
COPY --chown=1001:0 public/ /app/public
1716

18-
# Copy the dependencies and other project related files
19-
COPY --from=build-env /app ./
17+
USER 1001:0
18+
WORKDIR /app
2019
EXPOSE 8080
20+
2121
CMD ["app.mjs"]

cos-to-sql/Dockerfile.job

Lines changed: 0 additions & 21 deletions
This file was deleted.

cos-to-sql/README.md

Lines changed: 103 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# IBM Cloud Code Engine - Integrate Cloud Object Storage and PostgreSQL through a job and an event subscription
1+
# IBM Cloud Code Engine - Integrate Cloud Object Storage and PostgreSQL through a app and an event subscription
22

33
This sample demonstrates how to read CSV files hosted on a IBM Cloud Object Storage and save their contents line by line into relational PostgreSQL database.
44

@@ -7,123 +7,52 @@ This sample demonstrates how to read CSV files hosted on a IBM Cloud Object Stor
77
Make sure the following [IBM Cloud CLI](https://cloud.ibm.com/docs/cli/reference/ibmcloud?topic=cloud-cli-getting-started) and the following list of plugins are installed
88
- `ibmcloud plugin install code-engine`
99
- `ibmcloud plugin install cloud-object-storage`
10+
- `ibmcloud plugin install secrets-manager`
1011

1112
Install `jq`. On MacOS, you can use following [brew formulae](https://formulae.brew.sh/formula/jq) to do a `brew install jq`.
12-
## CLI Setup
1313

14-
Login to IBM Cloud via the CLI
15-
```
16-
ibmcloud login
17-
```
14+
## Setting up all IBM Cloud Service instances
1815

19-
Target the `ca-tor` region:
16+
* Login to IBM Cloud via the CLI and target the `ca-tor` region:
2017
```
2118
export REGION=ca-tor
22-
ibmcloud -r $REGION
23-
```
24-
25-
Create the project:
26-
```
27-
ibmcloud code-engine project create -n ce-objectstorage-to-sql
28-
```
29-
30-
Store the project guid:
31-
```
32-
export CE_ID=$(ibmcloud ce project current -o json | jq -r .guid)
33-
```
34-
35-
Create the job:
36-
```
37-
ibmcloud code-engine job create \
38-
--name csv-to-sql \
39-
--source ./ \
40-
--retrylimit 0 \
41-
--cpu 0.25 \
42-
--memory 0.5G \
43-
--wait
19+
export RESOURCE_GROUP=Default
20+
ibmcloud login -r ${REGION} -g $RESOURCE_GROUP
4421
```
4522

46-
Create the app:
47-
```
48-
ibmcloud code-engine app create \
49-
--name csv-to-sql-app \
50-
--source ./ \
51-
--cpu 0.25 \
52-
--memory 0.5G \
53-
--env COS_REGION=eu-es \
54-
--env COS_TRUSTED_PROFILE_NAME=code-engine-cos-access \
55-
--env SM_TRUSTED_PROFILE_NAME=code-engine-sm-access \
56-
--env SM_SERVICE_URL=https://4e61488a-b76f-4d44-ba0e-ed2489d8a57a.private.eu-es.secrets-manager.appdomain.cloud \
57-
--env SM_PG_SECRET_ID=04abb32c-bbe3-a069-e4c4-8899853ef053
23+
* Create the Code Engine project
5824
```
25+
export CE_INSTANCE_NAME=cos-to-sql--ce
26+
ibmcloud code-engine project create -n ${CE_INSTANCE_NAME}
5927
60-
Create the COS instance:
61-
```
62-
ibmcloud resource service-instance-create csv-to-sql-cos cloud-object-storage standard global
28+
export CE_INSTANCE_GUID=$(ibmcloud ce project current -o json | jq -r .guid)
29+
export CE_INSTANCE_ID=$(ibmcloud resource service-instance ${CE_INSTANCE_NAME} --output json | jq -r '.[0] | .id')
6330
```
6431

65-
Store the COS CRN:
66-
```
67-
export COS_ID=$(ibmcloud resource service-instance csv-to-sql-cos --output json | jq -r '.[0] | .id')
32+
* Create the COS instance
6833
```
34+
export COS_INSTANCE_NAME=cos-to-sql--cos
35+
ibmcloud resource service-instance-create ${COS_INSTANCE_NAME} cloud-object-storage standard global
6936
70-
Create an authorization policy to allow the Code Engine project receive events from COS:
71-
```
72-
ibmcloud iam authorization-policy-create codeengine cloud-object-storage \
73-
"Notifications Manager" \
74-
--source-service-instance-id $CE_ID \
75-
--target-service-instance-id $COS_ID
37+
export COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --output json | jq -r '.[0] | .id')
7638
```
7739

78-
Create a COS bucket:
40+
* Create a COS bucket
7941
```
80-
ibmcloud cos config crn --crn $COS_ID --force
42+
ibmcloud cos config crn --crn ${COS_INSTANCE_ID} --force
8143
ibmcloud cos config auth --method IAM
82-
ibmcloud cos config region --region $REGION
83-
ibmcloud cos config endpoint-url --url s3.$REGION.cloud-object-storage.appdomain.cloud
84-
export BUCKET=$CE_ID-csv-to-sql
44+
ibmcloud cos config region --region ${REGION}
45+
ibmcloud cos config endpoint-url --url s3.${REGION}.cloud-object-storage.appdomain.cloud
46+
export COS_BUCKET_NAME=${CE_INSTANCE_GUID}-csv-to-sql
8547
ibmcloud cos bucket-create \
8648
--class smart \
87-
--bucket $BUCKET
88-
```
89-
90-
Creating a trusted profile that grants a Code Engine Job access to your COS bucket
91-
```
92-
REGION=eu-es
93-
RESOURCE_GROUP=Default
94-
COS_INSTANCE_NAME=csv-to-sql-cos
95-
COS_BUCKET=$CE_ID-csv-to-sql
96-
CE_PROJECT_NAME=ce-objectstorage-to-sql
97-
JOB_NAME=csv-to-sql
98-
TRUSTED_PROFILE_NAME=code-engine-cos-access
99-
100-
CE_PROJECT_CRN=$(ibmcloud resource service-instance ${CE_PROJECT_NAME} --location ${REGION} -g ${RESOURCE_GROUP} --crn 2>/dev/null | grep ':codeengine:')
101-
COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:')
102-
103-
ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_NAME}
104-
ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_NAME} --name ce-job-${JOB_NAME} --cr-type CE --link-crn ${CE_PROJECT_CRN} --link-component-type job --link-component-name ${JOB_NAME}
105-
ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_NAME} --roles "Content Reader" --service-name cloud-object-storage --service-instance ${COS_INSTANCE_ID} --resource-type bucket --resource ${COS_BUCKET}
106-
```
107-
108-
Create the subscription for all COS events:
109-
```
110-
ibmcloud ce sub cos create \
111-
--name coswatch \
112-
--bucket $BUCKET \
113-
--destination csv-to-sql \
114-
--destination-type job
115-
116-
ibmcloud ce sub cos create \
117-
--name coswatch \
118-
--bucket $BUCKET \
119-
--destination csv-to-sql-app \
120-
--destination-type app \
121-
--path /cos-to-sql
49+
--bucket $COS_BUCKET_NAME
12250
```
12351

124-
Create a PostgreSQL service instance:
52+
* Create the PostgreSQL instance
12553
```
126-
ibmcloud resource service-instance-create csv-to-sql-postgresql databases-for-postgresql standard $REGION --service-endpoints private -p \
54+
export DB_INSTANCE_NAME=cos-to-sql--pg
55+
ibmcloud resource service-instance-create $DB_INSTANCE_NAME databases-for-postgresql standard ${REGION} --service-endpoints private -p \
12756
'{
12857
"disk_encryption_instance_crn": "none",
12958
"disk_encryption_key_crn": "none",
@@ -135,90 +64,113 @@ ibmcloud resource service-instance-create csv-to-sql-postgresql databases-for-po
13564
"service-endpoints": "private",
13665
"version": "16"
13766
}'
138-
```
13967
140-
Create a trusted profile that grants this Code Engine job access to the COS instance
68+
export DB_INSTANCE_ID=$(ibmcloud resource service-instance $DB_INSTANCE_NAME --location ${REGION} --output json | jq -r '.[0] | .id')
14169
```
142-
REGION=eu-es
143-
RESOURCE_GROUP=Default
144-
COS_INSTANCE_NAME=my-first-cos
145-
COS_BUCKET=my-first-bucket-31292
146-
CE_PROJECT_NAME=trusted-profiles-test
147-
JOB_NAME=list-cos-files
148-
COS_TRUSTED_PROFILE_NAME=code-engine-cos-access
149-
SM_TRUSTED_PROFILE_NAME=code-engine-sm-access
150-
SM_SERVICE_URL=https://4e61488a-b76f-4d44-ba0e-ed2489d8a57a.private.eu-es.secrets-manager.appdomain.cloud
151-
SM_PG_SECRET_ID=
15270

153-
CE_PROJECT_CRN=$(ibmcloud resource service-instance ${CE_PROJECT_NAME} --location ${REGION} -g ${RESOURCE_GROUP} --crn 2>/dev/null | grep ':codeengine:')
154-
COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:')
71+
* Create the Secrets Manager instance
72+
```
73+
export SM_INSTANCE_NAME=cos-to-sql--sm
74+
ibmcloud resource service-instance-create $SM_INSTANCE_NAME secrets-manager 7713c3a8-3be8-4a9a-81bb-ee822fcaac3d ${REGION} -p \
75+
'{
76+
"allowed_network": "public-and-private"
77+
}'
15578
156-
ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_NAME}
157-
ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_NAME} --name ce-job-${JOB_NAME} --cr-type CE --link-crn ${CE_PROJECT_CRN} --link-component-type job --link-component-name ${JOB_NAME}
158-
ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_NAME} --roles "Content Reader" --service-name cloud-object-storage --service-instance ${COS_INSTANCE_ID} --resource-type bucket --resource ${COS_BUCKET}
79+
export SM_INSTANCE_ID=$(ibmcloud resource service-instance $SM_INSTANCE_NAME --location ${REGION} --output json | jq -r '.[0] | .id')
80+
export SM_INSTANCE_GUID=$(ibmcloud resource service-instance $SM_INSTANCE_NAME --location ${REGION} --output json | jq -r '.[0] | .guid')
81+
export SECRETS_MANAGER_URL=https://$SM_INSTANCE_GUID.${REGION}.secrets-manager.appdomain.cloud
15982
```
16083

161-
Update the job by adding a binding to the PostgreSQL instance:
84+
* Create a S2S policy "Key Manager" between SM and the DB
16285
```
163-
ibmcloud code-engine job update \
164-
--name csv-to-sql \
165-
--trusted-profiles-enabled true \
166-
--env COS_REGION=${REGION} \
167-
--env COS_TRUSTED_PROFILE_NAME=${COS_TRUSTED_PROFILE_NAME} \
168-
--env SM_TRUSTED_PROFILE_NAME=${SM_TRUSTED_PROFILE_NAME}\
169-
--env SM_SERVICE_URL=${SM_SERVICE_URL} \
170-
--env SM_PG_SECRET_ID=${SM_PG_SECRET_ID}
86+
ibmcloud iam authorization-policy-create secrets-manager databases-for-postgresql \
87+
"Key Manager" \
88+
--source-service-instance-id $SM_INSTANCE_ID \
89+
--target-service-instance-id $DB_INSTANCE_ID
17190
```
17291

173-
Create a Secrets Manager instance
174-
```
175-
ibmcloud resource service-instance-create credential-store secrets-manager 7713c3a8-3be8-4a9a-81bb-ee822fcaac3d eu-es -p \
176-
'{
177-
"allowed_network": "private-only"
178-
}'
92+
* Create the service credential to access the PostgreSQL instance
17993
```
94+
SM_SECRET_FOR_PG_NAME=pg-access-credentials
95+
ibmcloud secrets-manager secret-create --secret-type="service_credentials" --secret-name="$SM_SECRET_FOR_PG_NAME" --secret-source-service="{\"instance\": {\"crn\": \"$DB_INSTANCE_ID\"},\"parameters\": {},\"role\": {\"crn\": \"crn:v1:bluemix:public:iam::::serviceRole:Writer\"}}"
18096
181-
// Create a Trusted Profile for Secrets Manager
97+
export SM_SECRET_FOR_PG_ID=$(ibmcloud sm secret-by-name --name $SM_SECRET_FOR_PG_NAME --secret-type service_credentials --secret-group-name default --output JSON|jq -r '.id')
98+
```
18299

183-
// Create a S2S policy "Key Manager" between SM and the DB
184100

185-
// Create a service credential for PG with automatic key rotation
101+
* Create the Code Engine app:
102+
```
103+
export CE_APP_NAME=csv-to-sql
104+
export TRUSTED_PROFILE_FOR_COS_NAME=cos-to-sql--ce-to-cos-access
105+
export TRUSTED_PROFILE_FOR_SM_NAME=cos-to-sql--ce-to-sm-access
186106
107+
ibmcloud code-engine app create \
108+
--name ${CE_APP_NAME} \
109+
--source ./ \
110+
--cpu 0.25 \
111+
--memory 0.5G \
112+
--trusted-profiles-enabled="true" \
113+
--probe-ready type=http \
114+
--probe-ready path=/readiness \
115+
--probe-ready interval=30 \
116+
--env COS_REGION=${REGION} \
117+
--env COS_TRUSTED_PROFILE_NAME=${TRUSTED_PROFILE_FOR_COS_NAME} \
118+
--env SM_TRUSTED_PROFILE_NAME=${TRUSTED_PROFILE_FOR_SM_NAME} \
119+
--env SM_SERVICE_URL=${SECRETS_MANAGER_URL} \
120+
--env SM_PG_SECRET_ID=${SM_SECRET_FOR_PG_ID}
121+
```
187122

123+
## Trusted Profile setup
188124

189-
// ibmcloud secrets-manager secret-by-name --secret-type service_credentials --name pg-credentials --secret-group-name --service-url https://4e61488a-b76f-4d44-ba0e-ed2489d8a57a.private.eu-es.secrets-manager.appdomain.cloud
125+
* Create a trusted profile that grants a Code Engine app access to your COS bucket
126+
```
127+
ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_FOR_COS_NAME}
128+
ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_FOR_COS_NAME} --name ce-app-${CE_APP_NAME} --cr-type CE --link-crn ${CE_INSTANCE_ID} --link-component-type application --link-component-name ${CE_APP_NAME}
129+
ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_FOR_COS_NAME} --roles "Content Reader" --service-name cloud-object-storage --service-instance ${COS_INSTANCE_ID} --resource-type bucket --resource ${COS_BUCKET_NAME}
130+
```
190131

191-
// https://github.com/IBM/secrets-manager-node-sdk
192132

193-
Upload a CSV file to COS, to initate an event that leads to a job execution:
133+
* Create the trusted profile to access Secrets Manager
194134
```
195-
ibmcloud cos object-put \
196-
--bucket $BUCKET \
197-
--key users.csv \
198-
--body ./samples/users.csv \
199-
--content-type text/csv
135+
ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_FOR_SM_NAME}
136+
ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_FOR_SM_NAME} --name ce-app-${CE_APP_NAME} --cr-type CE --link-crn ${CE_INSTANCE_ID} --link-component-type application --link-component-name ${CE_APP_NAME}
137+
ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_FOR_SM_NAME} --roles "SecretsReader" --service-name secrets-manager --service-instance ${SM_INSTANCE_ID}
200138
```
201139

202-
List all jobs to determine the one, that processes the COS bucket update:
140+
## Setting up eventing
141+
142+
* Create an authorization policy to allow the Code Engine project receive events from COS:
203143
```
204-
ibmcloud code-engine jobrun list \
205-
--job csv-to-sql \
206-
--sort-by age
144+
ibmcloud iam authorization-policy-create codeengine cloud-object-storage \
145+
"Notifications Manager" \
146+
--source-service-instance-id ${CE_INSTANCE_ID} \
147+
--target-service-instance-id ${COS_INSTANCE_ID}
207148
```
208149

209-
Inspect the job execution by opening the logs:
150+
* Create the subscription for all COS events:
210151
```
211-
ibmcloud code-engine jobrun logs \
212-
--name <jobrun-name>
152+
ibmcloud ce sub cos create \
153+
--name "coswatch-${CE_APP_NAME}" \
154+
--bucket ${COS_BUCKET_NAME} \
155+
--destination ${CE_APP_NAME} \
156+
--destination-type app \
157+
--path /cos-to-sql
213158
```
214159

215-
Or do the two commands in one, using this one-liner:
160+
## Verify the solution
161+
162+
* Upload a CSV file to COS, to initate an event that leads to a job execution:
216163
```
217-
jobrunname=$(ibmcloud ce jr list -j csv-to-sql -s age -o json | jq -r '.items[0] | .metadata.name') && ibmcloud ce jr logs -n $jobrunname -f
164+
ibmcloud cos object-put \
165+
--bucket ${COS_BUCKET_NAME} \
166+
--key users.csv \
167+
--body ./samples/users.csv \
168+
--content-type text/csv
218169
```
219170

220-
171+
* Inspect the app execution by opening the logs:
172+
```
173+
ibmcloud code-engine app logs \
174+
--name ${CE_APP_NAME} \
175+
--follow
221176
```
222-
kubectl patch jobdefinitions csv-to-sql --type='json' -p='[{"op": "add", "path": "/spec/template/mountComputeResourceToken", "value":true}]'
223-
kubectl patch ksvc csv-to-sql-app --type='json' -p='[{"op": "add", "path": "/spec/template/metadata/annotations/codeengine.cloud.ibm.com~1mount-compute-resource-token", "value":"true"}]'
224-
```

0 commit comments

Comments
 (0)