I'm trying to learn how to use Google App Engine, and I'm using the QuickStart documentation for Python here. It's a simple code to write timestamps to a datastore, and then print them back to the user.
I'm following the code and steps fairly strictly, but I'm using the Cloud Shell and Cloud Console instead of downloading the SDK and running the code locally.
The first half of the code works perfectly, and I'm able to deploy the web service. When I start using the datastore, however, I get a 500 Internal Server Error
in my app. The full main.py
is provided below. I commented out sections of the code and figured out that the issue seems to come when writing to the datastore. The error log shows a PERMISSION DENIED
error (log below).
From what I can see, using the Cloud Shell should mean that the authentication between my python script and the datastore should "just work", but it looks like it doesn't. I'm also using the exact code from Google's documentation, so I don't get why it should get an error.
Any ideas on what I might try?
Here's my main.py
:
import datetime
from flask import Flask, render_template
from google.cloud import datastore
datastore_client = datastore.Client()
app = Flask(__name__)
def store_time(dt):
entity = datastore.Entity(key=datastore_client.key('visit'))
entity.update({
'timestamp': dt
})
datastore_client.put(entity)
def fetch_times(limit):
query = datastore_client.query(kind='visit')
query.order = ['-timestamp']
times = query.fetch(limit=limit)
return times
@app.route('/')
def root():
store_time(datetime.datetime.now())
times = fetch_times(10)
return render_template(
'index.html', times=times)
The error log shows the following error:
File "", line 3, in raise_from: google.api_core.exceptions.PermissionDenied: 403 Missing or insufficient permissions. at error_remapped_callable (/env/lib/python3.7/site-packages/google/api_core/grpc_helpers.py:59) at func_with_timeout (/env/lib/python3.7/site-packages/google/api_core/timeout.py:214) at retry_target (/env/lib/python3.7/site-packages/google/api_core/retry.py:184) at retry_wrapped_func (/env/lib/python3.7/site-packages/google/api_core/retry.py:286) at call (/env/lib/python3.7/site-packages/google/api_core/gapic_v1/method.py:143) at commit (/env/lib/python3.7/site-packages/google/cloud/datastore_v1/gapic/datastore_client.py:571) at _commit (/env/lib/python3.7/site-packages/google/cloud/datastore/batch.py:250) at commit (/env/lib/python3.7/site-packages/google/cloud/datastore/batch.py:274) at put_multi (/env/lib/python3.7/site-packages/google/cloud/datastore/client.py:490) at put (/env/lib/python3.7/site-packages/google/cloud/datastore/client.py:463) at store_time (/srv/main.py:20) at root (/srv/main.py:36) at dispatch_request (/env/lib/python3.7/site-packages/flask/app.py:1935) at full_dispatch_request (/env/lib/python3.7/site-packages/flask/app.py:1949) at reraise (/env/lib/python3.7/site-packages/flask/_compat.py:39) at handle_user_exception (/env/lib/python3.7/site-packages/flask/app.py:1820) at full_dispatch_request (/env/lib/python3.7/site-packages/flask/app.py:1951) at wsgi_app (/env/lib/python3.7/site-packages/flask/app.py:2446)
I used Cloud Shell and took your code as-is. Your code works for me.
Created:
PROJECT=[[YOUR-PROJECT]]
REGION=[[YOUR-REGION]] # us-west2
gcloud app create --project=${PROJECT} --region=${REGION}
With:
app.yaml
:
runtime: python37
entrypoint: gunicorn -b :$PORT main:app
NB
entrypoint
is optional but I prefer to be explicit
requirements.txt
:
Flask==1.1.2
gunicorn==20.0.4
google-cloud-datastore==1.12.0
and used the exemplar template:
templates/index.html
:
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h2>Visits:</h2>
{% for time in times %}
<p>{{ time }}</p>
{% endfor %}
</body>
</html>
And:
gcloud app deploy app.yaml --project=${PROJECT}
Then browsing the app's endpoint:
Visits:
<Entity('visit', 5079418695319552) {'timestamp': datetime.datetime(2020, 4, 12, 20, 20, 29, 417656, tzinfo=<UTC>)}>
<Entity('visit', 5702893864747008) {'timestamp': datetime.datetime(2020, 4, 12, 20, 16, 28, 305081, tzinfo=<UTC>)}>
<Entity('visit', 5636645067948032) {'timestamp': datetime.datetime(2020, 4, 12, 20, 16, 26, 495333, tzinfo=<UTC>)}>
<Entity('visit', 5642368648740864) {'timestamp': datetime.datetime(2020, 4, 12, 20, 16, 22, 369022, tzinfo=<UTC>)}>
<Entity('visit', 5632499082330112) {'timestamp': datetime.datetime(2020, 4, 12, 20, 16, 20, 659993, tzinfo=<UTC>)}>