Skip to content

Fork cloud sql sample into a separate postgres sample #1025

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion appengine/flexible/cloudsql/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ Flask==0.12.2
Flask-SQLAlchemy==2.2
gunicorn==19.7.1
PyMySQL==0.7.11
psycopg2==2.7.1
21 changes: 21 additions & 0 deletions appengine/flexible/cloudsql_postgresql/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app

runtime_config:
python_version: 3

#[START env]
env_variables:
# Replace user, password, database, and instance connection name with the values obtained
# when configuring your Cloud SQL instance.
SQLALCHEMY_DATABASE_URI: >-
postgresql+psycopg2://USER:PASSWORD@/DATABASE?host=/cloudsql/INSTANCE_CONNECTION_NAME
#[END env]

#[START cloudsql_settings]
# Replace project and instance with the values obtained when configuring your
# Cloud SQL instance.
beta_settings:
cloud_sql_instances: INSTANCE_CONNECTION_NAME
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need both this beta_setting and the SQLALCHEMY_DATABASE_URI? Networking or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the beta setting actually tells the cloud sql proxy running on your instance to create the socket for the cloud sql instance.

#[END cloudsql_settings]
25 changes: 25 additions & 0 deletions appengine/flexible/cloudsql_postgresql/create_tables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#! /usr/bin/env python
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START all]

from main import db


if __name__ == '__main__':
print('Creating all database tables...')
db.create_all()
print('Done!')
# [END all]
104 changes: 104 additions & 0 deletions appengine/flexible/cloudsql_postgresql/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This sample shows how to connect to PostgreSQL running on Cloud SQL.

See the documentation for details on how to setup and use this sample:
https://cloud.google.com/appengine/docs/flexible/python\
/using-cloud-sql-postgres
"""

import datetime
import logging
import os
import socket

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
import sqlalchemy


app = Flask(__name__)


def is_ipv6(addr):
"""Checks if a given address is an IPv6 address."""
try:
socket.inet_pton(socket.AF_INET6, addr)
return True
except socket.error:
return False


# [START example]
# Environment variables are defined in app.yaml.
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['SQLALCHEMY_DATABASE_URI']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Visit(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime())
user_ip = db.Column(db.String(46))

def __init__(self, timestamp, user_ip):
self.timestamp = timestamp
self.user_ip = user_ip


@app.route('/')
def index():
user_ip = request.remote_addr

# Keep only the first two octets of the IP address.
if is_ipv6(user_ip):
user_ip = ':'.join(user_ip.split(':')[:2])
else:
user_ip = '.'.join(user_ip.split('.')[:2])

visit = Visit(
user_ip=user_ip,
timestamp=datetime.datetime.utcnow()
)

db.session.add(visit)
db.session.commit()

visits = Visit.query.order_by(sqlalchemy.desc(Visit.timestamp)).limit(10)

results = [
'Time: {} Addr: {}'.format(x.timestamp, x.user_ip)
for x in visits]

output = 'Last 10 visits:\n{}'.format('\n'.join(results))

return output, 200, {'Content-Type': 'text/plain; charset=utf-8'}
# [END example]


@app.errorhandler(500)
def server_error(e):
logging.exception('An error occurred during a request.')
return """
An internal error occurred: <pre>{}</pre>
See logs for full stacktrace.
""".format(e), 500


if __name__ == '__main__':
# This is used when running locally. Gunicorn is used to run the
# application on Google App Engine. See entrypoint in app.yaml.
app.run(host='127.0.0.1', port=8080, debug=True)
26 changes: 26 additions & 0 deletions appengine/flexible/cloudsql_postgresql/main_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import main


def test_index():
main.db.create_all()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any way to safely tear these test tables down afterwards?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, but it's not needed.


main.app.testing = True
client = main.app.test_client()

r = client.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
assert r.status_code == 200
assert '127.0' in r.data.decode('utf-8')
4 changes: 4 additions & 0 deletions appengine/flexible/cloudsql_postgresql/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Flask==0.12.2
Flask-SQLAlchemy==2.2
gunicorn==19.7.1
psycopg2==2.7.1