Skip to content

Commit 6e9ab2e

Browse files
dinagravesleahecole
andcommitted
"Hello Broken" python sample (GoogleCloudPlatform#2618)
* Hello broken python sample * Updating README * Updating test file * Fixing README nits * Fixing README link * Updating test instructions in README and moving region tag * Noxfile change to signal only python 3 tests Co-authored-by: Leah E. Cole <[email protected]>
1 parent 6e8425c commit 6e9ab2e

File tree

6 files changed

+213
-0
lines changed

6 files changed

+213
-0
lines changed

noxfile.py

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def _setup_appengine_sdk(session):
175175
or sample.startswith("./functions/")
176176
or sample.startswith("./bigquery/pandas-gbq-migration")
177177
or sample.startswith("./run/system-package")
178+
or sample.startswith("./run/hello-broken")
178179
)
179180
]
180181
NON_GAE_STANDARD_SAMPLES_PY2 = sorted(

run/hello-broken/Dockerfile

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright 2019 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+
15+
# Use the official Python image.
16+
# https://hub.docker.com/_/python
17+
FROM python:3.7
18+
19+
# Copy application dependency manifests to the container image.
20+
# Copying this separately prevents re-running pip install on every code change.
21+
COPY requirements.txt .
22+
23+
# Install production dependencies.
24+
RUN pip install -r requirements.txt
25+
26+
# Copy local code to the container image.
27+
ENV APP_HOME /app
28+
WORKDIR $APP_HOME
29+
COPY . .
30+
31+
# Run the web service on container startup.
32+
# Use gunicorn webserver with one worker process and 8 threads.
33+
# For environments with multiple CPU cores, increase the number of workers
34+
# to be equal to the cores available.
35+
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 main:app

run/hello-broken/README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Cloud Run Broken Sample
2+
3+
This sample presents broken code in need of troubleshooting. View [improved](main.py#L43) for a more stable implementation.
4+
5+
Troubleshoot this code by following the [Local Container Troubleshooting Tutorial](http://cloud.google.com/run/docs/tutorials/local-troubleshooting).
6+
7+
[![Run in Google Cloud][run_img]][run_link]
8+
9+
[run_img]: https://storage.googleapis.com/cloudrun/button.svg
10+
[run_link]: https://console.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_image=gcr.io/cloudrun/button&cloudshell_git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&cloudshell_working_dir=run/hello-broken
11+
12+
## Build
13+
14+
```
15+
docker build --tag hello-broken:python .
16+
```
17+
18+
## Run Locally
19+
20+
```
21+
docker run --rm -p 9090:8080 hello-broken:python
22+
```
23+
24+
## Test
25+
26+
```
27+
nox -s "py36(sample='./run/hello-broken')"
28+
```
29+
30+
_Note: you may need to install `nox` using `pip install nox`._
31+
32+
## Deploy
33+
34+
```sh
35+
# Set an environment variable with your GCP Project ID
36+
export GOOGLE_CLOUD_PROJECT=<PROJECT_ID>
37+
38+
# Submit a build using Google Cloud Build
39+
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-broken
40+
41+
# Deploy to Cloud Run
42+
gcloud run deploy hello-broken \
43+
--image gcr.io/${GOOGLE_CLOUD_PROJECT}/hello-broken
44+
```
45+
46+
47+
For more details on how to work with this sample read the [Python Cloud Run Samples README](https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/run)

run/hello-broken/main.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright 2019 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+
15+
# [START run_broken_service]
16+
from flask import Flask
17+
import json
18+
import os
19+
import sys
20+
21+
app = Flask(__name__)
22+
23+
24+
@app.route("/", methods=["GET"])
25+
def index():
26+
print("hello: received request.")
27+
28+
# [START run_broken_service_problem]
29+
NAME = os.getenv("NAME")
30+
31+
if not NAME:
32+
print("Environment validation failed.")
33+
raise Exception("Missing required service parameter.")
34+
# [END run_broken_service_problem]
35+
36+
# Flush the stdout to avoid log buffering.
37+
sys.stdout.flush()
38+
39+
return f"Hello {NAME}"
40+
# [END run_broken_service]
41+
42+
43+
@app.route("/improved", methods=["GET"])
44+
def improved():
45+
print("hello: received request.")
46+
47+
# [START run_broken_service_upgrade]
48+
NAME = os.getenv("NAME")
49+
50+
if not NAME:
51+
NAME = "World"
52+
error_message = {
53+
"severity": "WARNING",
54+
"message": f"NAME not set, default to {NAME}",
55+
}
56+
print(json.dumps(error_message))
57+
# [END run_broken_service_upgrade]
58+
59+
# Flush the stdout to avoid log buffering.
60+
sys.stdout.flush()
61+
62+
return f"Hello {NAME}"
63+
64+
65+
# [START run_broken_service]
66+
if __name__ == "__main__":
67+
PORT = int(os.getenv("PORT")) if os.getenv("PORT") else 8080
68+
69+
# This is used when running locally. Gunicorn is used to run the
70+
# application on Cloud Run. See entrypoint in Dockerfile.
71+
app.run(host="127.0.0.1", port=PORT, debug=True)
72+
# [END run_broken_service]

run/hello-broken/main_test.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright 2019 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+
15+
import os
16+
import pytest
17+
import main
18+
19+
20+
@pytest.fixture
21+
def client():
22+
main.app.testing = True
23+
return main.app.test_client()
24+
25+
26+
def test_broken_handler(client):
27+
with pytest.raises(Exception) as e:
28+
client.get("/")
29+
30+
assert "Missing required service parameter" in str(e.value)
31+
32+
33+
def test_broken_handler_with_env_variable(client):
34+
os.environ["NAME"] = "Foo"
35+
r = client.get("/")
36+
37+
assert r.data.decode() == "Hello Foo"
38+
assert r.status_code == 200
39+
40+
41+
def test_improved_handler_no_env_variable(client):
42+
os.environ["NAME"] = ""
43+
r = client.get("/improved")
44+
45+
assert r.data.decode() == "Hello World"
46+
assert r.status_code == 200
47+
48+
49+
def test_improved_handler_with_env_variable(client):
50+
os.environ["NAME"] = "Foo"
51+
r = client.get("/improved")
52+
53+
assert r.data.decode() == "Hello Foo"
54+
assert r.status_code == 200

run/hello-broken/requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Flask==1.1.1
2+
pytest==5.3.0; python_version > "3.0"
3+
pytest==4.6.6; python_version < "3.0"
4+
gunicorn==19.9.0

0 commit comments

Comments
 (0)