[run] add sample code for gcs events (#4078) · code4ward/python-docs-samples@377309b · GitHub
Skip to content

Commit 377309b

Browse files
authored
[run] add sample code for gcs events (GoogleCloudPlatform#4078)
* events-gcs init * Modified README from events-pubsub to events-gcs instructions Signed-off-by: Curtis Mason <cumason@google.com> * renamed folder gcs-events to events-gcs Signed-off-by: Curtis Mason <cumason@google.com> * README with unauth * Adjusted documentation for unauth * Readme adjustments Signed-off-by: Curtis Mason <cumason@google.com> * changed set NEARLINE to set STANDARD in README * lint style adjustments Signed-off-by: Curtis Mason <cumason@google.com> * Update README.md * removed PORT env from dockerfile * removed duplicate region tag from main.py * removed pubsub from readme * logging gcs cloud event type in main.py Signed-off-by: Curtis Mason <cumason@google.com> * fixing readme nit picks * Fixed env var formatting * Added more testing and error handling * README nit pick * changed uuid import for convenience in main_test.py * Fixed README typo
1 parent daf5983 commit 377309b

6 files changed

Lines changed: 229 additions & 0 deletions

File tree

run/events-gcs/Dockerfile

Lines changed: 41 additions & 0 deletions

run/events-gcs/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Events for Cloud Run – GCS tutorial
2+
3+
This sample shows how to create a service that processes GCS events.
4+
5+
## Setup
6+
7+
Login to gcloud:
8+
9+
```sh
10+
gcloud auth login
11+
```
12+
13+
Configure project id:
14+
15+
```sh
16+
gcloud config set project [PROJECT-ID]
17+
```
18+
19+
Configure environment variables:
20+
21+
```sh
22+
MY_RUN_SERVICE=gcs-service
23+
MY_RUN_CONTAINER=gcs-container
24+
MY_GCS_TRIGGER=gcs-trigger
25+
MY_GCS_BUCKET=gcs-bucket
26+
```
27+
28+
## Quickstart
29+
30+
Deploy your Cloud Run service:
31+
32+
```sh
33+
gcloud builds submit \
34+
--tag gcr.io/$(gcloud config get-value project)/$MY_RUN_CONTAINER
35+
gcloud run deploy $MY_RUN_SERVICE \
36+
--image gcr.io/$(gcloud config get-value project)/$MY_RUN_CONTAINER \
37+
--allow-unauthenticated
38+
```
39+
40+
Create a bucket:
41+
42+
```sh
43+
gsutil mb -p $(gcloud config get-value project) -l \
44+
us-central1 gs://"$MY_GCS_BUCKET"
45+
```
46+
47+
Create Cloud Storage trigger:
48+
49+
```sh
50+
gcloud alpha events triggers create $MY_GCS_TRIGGER \
51+
--target-service "$MY_RUN_SERVICE" \
52+
--type com.google.cloud.auditlog.event \
53+
--parameters methodName=storage.buckets.update \
54+
--parameters serviceName=storage.googleapis.com \
55+
--parameters resourceName=projects/_/buckets/"$MY_GCS_BUCKET"
56+
```
57+
58+
## Test
59+
60+
Test your Cloud Run service by publishing a message to the topic:
61+
62+
```sh
63+
gsutil defstorageclass set STANDARD gs://$MY_GCS_BUCKET
64+
```
65+
66+
Observe the Cloud Run service printing upon receiving an event in
67+
Cloud Logging:
68+
69+
```sh
70+
gcloud logging read "resource.type=cloud_run_revision AND \
71+
resource.labels.service_name=$MY_RUN_SERVICE" --project \
72+
$(gcloud config get-value project) --limit 30 --format 'value(textPayload)'
73+
```

run/events-gcs/main.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2020 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+
# [START run_events_pubsub_server_setup]
15+
import os
16+
17+
from flask import Flask, request
18+
19+
20+
required_fields = ['Ce-Id', 'Ce-Source', 'Ce-Type', 'Ce-Specversion']
21+
22+
app = Flask(__name__)
23+
# [END run_events_pubsub_server_setup]
24+
25+
26+
# [START run_events_pubsub_handler]
27+
@app.route('/', methods=['POST'])
28+
def index():
29+
for field in required_fields:
30+
if field not in request.headers:
31+
errmsg = f'Bad Request: missing required header {field}'
32+
print(errmsg)
33+
return errmsg, 400
34+
35+
if 'Ce-Subject' not in request.headers:
36+
errmsg = 'Bad Request: expected header Ce-Subject'
37+
print(errmsg)
38+
return errmsg, 400
39+
40+
ce_subject = request.headers.get('Ce-Subject')
41+
print(f'GCS CloudEvent type: {ce_subject}')
42+
return (f'GCS CloudEvent type: {ce_subject}', 200)
43+
# [END run_events_pubsub_handler]
44+
45+
46+
# [START run_events_pubsub_server]
47+
if __name__ == "__main__":
48+
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
49+
# [END run_events_pubsub_server]

run/events-gcs/main_test.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright 2020 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+
import copy
15+
16+
from uuid import uuid4
17+
18+
import pytest
19+
20+
import main
21+
22+
23+
required_fields = ['Ce-Id', 'Ce-Source', 'Ce-Type', 'Ce-Specversion']
24+
25+
header_data = {field: str(uuid4()) for field in required_fields}
26+
27+
28+
@pytest.fixture
29+
def client():
30+
main.app.testing = True
31+
return main.app.test_client()
32+
33+
34+
def test_endpoint(client, capsys):
35+
test_headers = copy.copy(header_data)
36+
test_headers['Ce-Subject'] = 'test-subject'
37+
38+
r = client.post('/', headers=test_headers)
39+
assert r.status_code == 200
40+
41+
out, _ = capsys.readouterr()
42+
assert f"GCS CloudEvent type: {test_headers['Ce-Subject']}" in out
43+
44+
45+
def test_missing_subject(client, capsys):
46+
r = client.post('/', headers=header_data)
47+
assert r.status_code == 400
48+
49+
out, _ = capsys.readouterr()
50+
assert 'Bad Request: expected header Ce-Subject' in out
51+
52+
53+
def test_missing_required_fields(client, capsys):
54+
for field in required_fields:
55+
test_headers = copy.copy(header_data)
56+
test_headers.pop(field)
57+
58+
r = client.post('/', headers=test_headers)
59+
assert r.status_code == 400
60+
61+
out, _ = capsys.readouterr()
62+
assert f'Bad Request: missing required header {field}' in out
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pytest==5.4.3
2+

run/events-gcs/requirements.txt

Lines changed: 2 additions & 0 deletions

0 commit comments

Comments
 (0)