Skip to content

Commit

Permalink
First draft of postgres without the git mistake
Browse files Browse the repository at this point in the history
Add README

Address comments; 'samples test app' still fails

Address comments + make tests pass

Enable Cloud SQL tests.
  • Loading branch information
Ace Nassri authored and jmdobry committed May 25, 2017
1 parent 37a3cb2 commit 5880a0c
Show file tree
Hide file tree
Showing 9 changed files with 644 additions and 267 deletions.
52 changes: 34 additions & 18 deletions appengine/cloudsql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
This sample demonstrates how to use [Google Cloud SQL][sql] (or any other SQL
server) on [Google App Engine Flexible][flexible].

This sample has instructions for both [MySQL][mysql] and [Postgres][postgres].

## Setup

### General steps
Before you can run or deploy the sample, you will need to do the following:

1. In order for some of the commands below to work, you need to enable the
Expand All @@ -26,6 +29,10 @@ SDK use the following command:
where `[YOUR_INSTANCE_NAME]` is the name you chose in step 1 and
`[YOUR_INSTANCE_ROOT_PASSWORD]` is a password of your choice.

1. Using the [Cloud SQL console][sql_console], select your Cloud SQL instance.
Then, create a [user][user] (using the button in the *Access Control* > *Users* tab) and a
[database][database] (using the button in the *Databases* tab).

1. Create and download a [Service Account][service] for your project. You will
use this service account to connect to your Cloud SQL instance locally.

Expand All @@ -35,51 +42,60 @@ use this service account to connect to your Cloud SQL instance locally.
machine:

./cloud_sql_proxy \
-instances=[YOUR_INSTANCE_CONNECTION_NAME]=tcp:3306 \
-instances=[YOUR_INSTANCE_CONNECTION_NAME]=tcp:[PORT] \
-credential_file=PATH_TO_YOUR_SERVICE_ACCOUNT_JSON_FILE

where `[YOUR_INSTANCE_CONNECTION_NAME]` is the connection name of your
instance on its Overview page in the Google Cloud Platform Console, or use
`[YOUR_PROJECT_ID]:[YOUR_REGION]:[YOUR_INSTANCE_NAME]`.
`[YOUR_PROJECT_ID]:[YOUR_REGION]:[YOUR_INSTANCE_NAME]`. If you're using
MySQL, `[PORT]` will be `3306`; for Postgres, it will be `5432`.

1. Use the MySQL command line tools (or a management tool of your choice) to
create a [new user][user] and [database][database] for your application:
1. In a separate terminal, set the `SQL_USER`, `SQL_PASSWORD`, and `SQL_DATABASE` environment
variables to their respective values. This allows your local app to connect to your Cloud SQL
instance through the proxy.

mysql -h 127.0.0.1 -P 3306 -u root -p
mysql> create database `YOUR_DATABASE`;
mysql> create user 'YOUR_USER'@'%' identified by 'PASSWORD';
mysql> grant all on YOUR_DATABASE.* to 'YOUR_USER'@'%';
export SQL_USER="..."
export SQL_PASSWORD="..."
export SQL_DATABASE="..."

1. Set the `MYSQL_USER`, `MYSQL_PASSWORD`, and `MYSQL_DATABASE` environment
variables (see below). This allows your local app to connect to your Cloud SQL
instance through the proxy.
### Choosing a SQL client
Choose which database connector to use via the `SQL_CLIENT` environment variable.

To use MySQL, set it to `mysql`:

export SQL_CLIENT="mysql"

To use Postgres, set it to `pg`:

export SQL_CLIENT="pg"

1. Update the values in in `app.yaml` with your instance configuration.
### Final setup steps
1. Update the values in `app.yaml` with your instance configuration.

1. Finally, run `createTables.js` to ensure that the database is properly
configured and to create the tables needed for the sample.

## Running locally
### Running locally

Refer to the [top-level README](../README.md) for instructions on running and deploying.

It's recommended to follow the instructions above to run the Cloud SQL proxy.
You will need to set the following environment variables via your shell before
running the sample:
You will need to set the appropriate environment variables (as shown above) and
run the following commands via your shell to run the sample:

export MYSQL_USER="YOUR_USER"
export MYSQL_PASSWORD="YOUR_PASSWORD"
export MYSQL_DATABASE="YOUR_DATABASE"
npm install
npm start

[sql]: https://cloud.google.com/sql/
[flexible]: https://cloud.google.com/appengine
[gen]: https://cloud.google.com/sql/docs/create-instance
[console]: https://console.developers.google.com
[sql_console]: https://console.developers.google.com/sql/instances/
[sdk]: https://cloud.google.com/sdk
[service]: https://cloud.google.com/sql/docs/external#createServiceAccount
[proxy]: https://cloud.google.com/sql/docs/external#install
[start]: https://cloud.google.com/sql/docs/external#6_start_the_proxy
[user]: https://cloud.google.com/sql/docs/create-user
[database]: https://cloud.google.com/sql/docs/create-database
[mysql]: https://www.mysql.com/downloads/
[postgres]: https://www.postgresql.org/download/
7 changes: 4 additions & 3 deletions appengine/cloudsql/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ env: flex

# [START env]
env_variables:
MYSQL_USER: YOUR_USER
MYSQL_PASSWORD: YOUR_PASSWORD
MYSQL_DATABASE: YOUR_DATABASE
SQL_USER: YOUR_USER
SQL_PASSWORD: YOUR_PASSWORD
SQL_DATABASE: YOUR_DATABASE
# e.g. my-awesome-project:us-central1:my-cloud-sql-instance
INSTANCE_CONNECTION_NAME: YOUR_INSTANCE_CONNECTION_NAME
SQL_CLIENT: YOUR_SQL_CLIENT # either 'pg' or 'mysql' (all lowercase)
# [END env]

# [START cloudsql_settings]
Expand Down
105 changes: 60 additions & 45 deletions appengine/cloudsql/createTables.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,71 +13,86 @@
* limitations under the License.
*/

'use strict';

// Require process, so we can mock environment variables
const process = require('process');

// [START createTables]
// [START setup]
const mysql = require('mysql');
const Knex = require('knex');
const prompt = require('prompt');
// [END setup]

// [START createTable]
const SQL_STRING = `CREATE TABLE visits (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
timestamp DATETIME NULL,
userIp VARCHAR(46) NULL,
PRIMARY KEY (id)
);`;

/**
* Create the "visits" table.
*
* @param {object} connection A mysql connection object.
* @param {function} callback The callback function.
* @param {object} knex A Knex client object.
*/
function createTable (connection, callback) {
connection.query(SQL_STRING, callback);
function createTable (knex) {
return knex.schema.createTable('visits', (table) => {
table.increments();
table.timestamp('timestamp');
table.string('userIp');
})
.then(() => {
console.log(`Successfully created 'visits' table.`);
return knex;
})
.catch((err) => {
console.error(`Failed to create 'visits' table:`, err);
return knex;
});
}
// [END createTable]

// [START getConnection]
const FIELDS = ['user', 'password', 'database'];

/**
* Ask the user for connection configuration and create a new connection.
*
* @param {function} callback The callback function.
*/
function getConnection (callback) {
prompt.start();
prompt.get(FIELDS, (err, config) => {
if (err) {
callback(err);
return;
}

const user = encodeURIComponent(config.user);
const password = encodeURIComponent(config.password);
const database = encodeURIComponent(config.database);
function getConnection () {
const FIELDS = ['user', 'password', 'database'];
return new Promise((resolve, reject) => {
prompt.start();
prompt.get(FIELDS, (err, config) => {
if (err) {
return reject(err);
}

const uri = `mysql://${user}:${password}@127.0.0.1:3306/${database}`;
callback(null, mysql.createConnection(uri));
// Connect to the database
return resolve(Knex({
client: process.env.SQL_CLIENT,
connection: config
}));
});
});
}
// [END getConnection]

// [START main]
getConnection((err, connection) => {
if (err) {
console.error(err);
return;
}
createTable(connection, (err, result) => {
connection.end();
if (err) {
console.error(err);
return;
}
console.log(result);
});
});
// [END main]
exports.main = function () {
// [START main]
getConnection()
.then((knex) => {
return createTable(knex);
})
.then((knex) => {
return knex.destroy();
})
.catch((err, knex) => {
console.error(`Failed to create database connection:`, err);
if (knex) {
knex.destroy();
}
});
// [END main]
};
// [END createTables]

// Get type of SQL client to use
const sqlClient = process.env.SQL_CLIENT;
if (sqlClient === 'pg' || sqlClient === 'mysql') {
exports.main();
} else {
throw new Error(`The SQL_CLIENT environment variable must be set to lowercase 'pg' or 'mysql'.`);
}
23 changes: 12 additions & 11 deletions appengine/cloudsql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
},
"dependencies": {
"express": "4.15.2",
"knex": "^0.13.0",
"mysql": "2.13.0",
"pg": "^6.2.3",
"prompt": "1.0.0"
},
"devDependencies": {
Expand All @@ -35,19 +37,18 @@
"test": {
"app": {
"requiredEnvVars": [
"MYSQL_USER",
"MYSQL_PASSWORD",
"MYSQL_DATABASE",
"YOUR_INSTANCE_CONNECTION_NAME"
"SQL_CLIENT",
"SQL_USER",
"SQL_PASSWORD",
"SQL_DATABASE",
"INSTANCE_CONNECTION_NAME"
],
"msg": "Last 10 visits:",
"args": ["server.js"]
},
"deploy": {
"substitutions": "YOUR_USER=$MYSQL_USER,YOUR_PASSWORD=$MYSQL_PASSWORD,YOUR_DATABASE=$MYSQL_DATABASE,YOUR_INSTANCE_CONNECTION_NAME=$INSTANCE_CONNECTION_NAME"
"substitutions": "YOUR_SQL_CLIENT=$SQL_CLIENT,YOUR_USER=$SQL_USER,YOUR_PASSWORD=$SQL_PASSWORD,YOUR_DATABASE=$SQL_DATABASE,YOUR_INSTANCE_CONNECTION_NAME=$INSTANCE_CONNECTION_NAME",
"args": [
"server.js"
]
}
},
"requiresKeyFile": true,
"requiresProjectId": true
}
}
}
Loading

0 comments on commit 5880a0c

Please sign in to comment.