Skip to content

Commit f1433ff

Browse files
authored
feat(cloudsql/sqlserver): update to V2 sample. (GoogleCloudPlatform#2586)
* feat(cloudsql/sqlserver): update to V2 sample. * Lint. * Lint. * Restore env. vars for non-sqlserver tests. * Address review comment. * Address review comments. * Lint. * Update to fix tests.
1 parent b99b4a8 commit f1433ff

File tree

10 files changed

+128
-55
lines changed

10 files changed

+128
-55
lines changed

.kokoro/build.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ if [[ $SQL_CLIENT ]]; then
118118
wget --quiet https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
119119
chmod +x cloud_sql_proxy
120120
if [[ $SQL_CLIENT == 'sqlserver' ]]; then
121+
export INSTANCE_HOST=127.0.0.1
122+
export DB_PORT=1433
121123
./cloud_sql_proxy -instances="${INSTANCE_CONNECTION_NAME}"=tcp:1433 &>> cloud_sql_proxy.log &
122124
elif [[ $SQL_CLIENT == 'mysql' ]]; then
123125
export INSTANCE_HOST=127.0.0.1

cloud-sql/sqlserver/mssql/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
[create a project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
77

88
1. [Create a Google Cloud SQL "SQL Server" instance](
9-
https://console.cloud.google.com/sql/choose-instance-engine).
10-
11-
1. Under the instance's "USERS" tab, create a new user. Note the "User name" and "Password".
9+
https://cloud.google.com/sql/docs/sqlserver/create-instance). Note the instance `connection name` of the instance that you create,
10+
and password that you specify for the default 'sqlserver' user.
1211

1312
1. Under the instance's "DATABASES" tab, create a new database.
1413

@@ -28,6 +27,8 @@ Use the information noted in the previous steps to set the following environment
2827
```bash
2928
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service/account/key.json
3029
export INSTANCE_CONNECTION_NAME='<MY-PROJECT>:<INSTANCE-REGION>:<INSTANCE-NAME>'
30+
export INSTANCE_HOST='127.0.0.1'
31+
export DB_PORT='1433'
3132
export DB_USER='my-db-user'
3233
export DB_PASS='my-db-pass'
3334
export DB_NAME='my_db'

cloud-sql/sqlserver/mssql/app.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ env_variables:
2020
DB_USER: MY_DB_USER
2121
DB_PASS: MY_DB_PASSWORD
2222
DB_NAME: MY_DATABASE
23-
DEPLOYED: true
23+
INSTANCE_HOST: '172.17.0.1'
24+
DB_PORT: '1433'
2425

2526
beta_settings:
2627
# The connection name of your instance, available by using
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2022 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 strict';
16+
// [START cloud_sql_sqlserver_mssql_connect_tcp]
17+
const mssql = require('mssql');
18+
19+
// connectTcpPool initializes a TCP connection pool for a Cloud SQL
20+
// instance of SQL Server.
21+
const createTcpPool = async config => {
22+
// Note: Saving credentials in environment variables is convenient, but not
23+
// secure - consider a more secure solution such as
24+
// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
25+
// keep secrets safe.
26+
const dbConfig = {
27+
server: process.env.INSTANCE_HOST, // e.g. '127.0.0.1'
28+
port: parseInt(process.env.DB_PORT), // e.g. 1433
29+
user: process.env.DB_USER, // e.g. 'my-db-user'
30+
password: process.env.DB_PASS, // e.g. 'my-db-password'
31+
database: process.env.DB_NAME, // e.g. 'my-database'
32+
options: {
33+
trustServerCertificate: true,
34+
},
35+
// ... Specify additional properties here.
36+
...config,
37+
};
38+
return await mssql.connect(dbConfig);
39+
};
40+
// [END cloud_sql_sqlserver_mssql_connect_tcp]
41+
module.exports = createTcpPool;

cloud-sql/sqlserver/mssql/deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ spec:
3838
env:
3939
- name: PORT
4040
value: "8080"
41-
- name: DB_HOST
41+
- name: INSTANCE_HOST
4242
value: "127.0.0.1"
4343
- name: DB_PORT
4444
value: "1433"

cloud-sql/sqlserver/mssql/server.js renamed to cloud-sql/sqlserver/mssql/index.js

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
'use strict';
1616

1717
const express = require('express');
18+
const createTcpPool = require('./connect-tcp.js');
1819
const mssql = require('mssql');
1920

2021
const app = express();
@@ -50,32 +51,8 @@ async function accessSecretVersion(secretName) {
5051
return version.payload.data;
5152
}
5253

53-
// [START cloud_sql_sqlserver_mssql_create]
5454
const createPool = async () => {
55-
const config = {pool: {}, options: {}};
56-
57-
// Check if a Secret Manager secret version is defined
58-
// If a version is defined, retrieve the secret from Secret Manager and set as the DB_PASS
59-
const {CLOUD_SQL_CREDENTIALS_SECRET} = process.env;
60-
if (CLOUD_SQL_CREDENTIALS_SECRET) {
61-
const secrets = await accessSecretVersion(CLOUD_SQL_CREDENTIALS_SECRET);
62-
try {
63-
process.env.DB_PASS = secrets.toString();
64-
} catch (err) {
65-
err.message = `Unable to parse secret from Secret Manager. Make sure that the secret is JSON formatted: \n ${err.message} `;
66-
throw err;
67-
}
68-
}
69-
70-
config.user = process.env.DB_USER; // e.g. 'my-db-user'
71-
config.password = process.env.DB_PASS; // e.g. 'my-db-password'
72-
config.database = process.env.DB_NAME; // e.g. 'my-database'
73-
// set the server to '172.17.0.1' when connecting from App Engine Flex
74-
config.server = process.env.DEPLOYED ? '172.17.0.1' : '127.0.0.1';
75-
config.port = 1433;
76-
77-
// [START_EXCLUDE]
78-
55+
const config = {pool: {}};
7956
// [START cloud_sql_sqlserver_mssql_timeout]
8057
// 'connectionTimeout` is the maximum number of milliseconds to wait trying to establish an
8158
// initial connection. After the specified amount of time, an exception will be thrown.
@@ -87,7 +64,6 @@ const createPool = async () => {
8764
// and not be checked out before it is automatically closed
8865
(config.pool.idleTimeoutMillis = 600000),
8966
// [END cloud_sql_sqlserver_mssql_timeout]
90-
9167
// [START cloud_sql_sqlserver_mssql_limit]
9268
// 'max' limits the total number of concurrent connections this pool will keep. Ideal
9369
// values for this setting are highly variable on app design, infrastructure, and database.
@@ -103,11 +79,21 @@ const createPool = async () => {
10379
config.pool.createRetryIntervalMillis = 200;
10480
// [END cloud_sql_sqlserver_mssql_backoff]
10581

106-
// [END_EXCLUDE]
107-
config.options.trustServerCertificate = true;
108-
return await mssql.connect(config);
82+
// Check if a Secret Manager secret version is defined
83+
// If a version is defined, retrieve the secret from Secret Manager and set as the DB_PASS
84+
const {CLOUD_SQL_CREDENTIALS_SECRET} = process.env;
85+
if (CLOUD_SQL_CREDENTIALS_SECRET) {
86+
const secrets = await accessSecretVersion(CLOUD_SQL_CREDENTIALS_SECRET);
87+
try {
88+
process.env.DB_PASS = secrets.toString();
89+
} catch (err) {
90+
err.message = `Unable to parse secret from Secret Manager. Make sure that the secret is JSON formatted: \n ${err.message} `;
91+
throw err;
92+
}
93+
}
94+
95+
return createTcpPool(config);
10996
};
110-
// [END cloud_sql_sqlserver_mssql_create]
11197

11298
const ensureSchema = async pool => {
11399
// Wait for tables to be created (if they don't already exist).
@@ -148,7 +134,7 @@ app.use(async (req, res, next) => {
148134
});
149135

150136
// Serve the index page, showing vote tallies.
151-
app.get('/', async (req, res) => {
137+
const httpGet = async (req, res) => {
152138
try {
153139
// Get the 5 most recent votes.
154140
const recentVotesQuery = pool
@@ -192,10 +178,12 @@ app.get('/', async (req, res) => {
192178
)
193179
.end();
194180
}
195-
});
181+
};
182+
183+
app.get('/', httpGet);
196184

197185
// Handle incoming vote requests and inserting them into the database.
198-
app.post('/', async (req, res) => {
186+
const httpPost = async (req, res) => {
199187
const {team} = req.body;
200188
const timestamp = new Date();
201189

@@ -236,20 +224,28 @@ app.post('/', async (req, res) => {
236224
// [END cloud_sql_sqlserver_mssql_connection]
237225

238226
res.status(200).send(`Successfully voted for ${team} at ${timestamp}`).end();
239-
});
240-
241-
const PORT = parseInt(process.env.PORT) || 8080;
242-
const server = app.listen(PORT, () => {
243-
console.log(`App listening on port ${PORT}`);
244-
console.log('Press Ctrl+C to quit.');
245-
});
227+
};
246228

247-
const environment = process.env.NODE_ENV || 'development';
248-
if (environment === 'development') {
249-
process.on('unhandledRejection', err => {
250-
console.error(err);
251-
throw err;
252-
});
253-
}
229+
app.post('*', httpPost);
230+
231+
/**
232+
* Responds to GET and POST requests for TABS vs SPACES sample app.
233+
*
234+
* @param {Object} req Cloud Function request context.
235+
* @param {Object} res Cloud Function response context.
236+
*/
237+
exports.votes = (req, res) => {
238+
switch (req.method) {
239+
case 'GET':
240+
httpGet(req, res);
241+
break;
242+
case 'POST':
243+
httpPost(req, res);
244+
break;
245+
default:
246+
res.status(405).send({error: 'Something blew up!'});
247+
break;
248+
}
249+
};
254250

255-
module.exports = server;
251+
module.exports = app;

cloud-sql/sqlserver/mssql/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"node": ">=10.0.0"
1313
},
1414
"scripts": {
15+
"start": "node server/server.js",
1516
"system-test": "mocha test/*.test.js --timeout=60000 --exit",
1617
"test": "npm run system-test"
1718
},
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2022 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+
const app = require('../index.js');
16+
17+
const PORT = parseInt(process.env.PORT) || 8080;
18+
const server = app.listen(PORT, () => {
19+
console.log(`App listening on port ${PORT}`);
20+
console.log('Press Ctrl+C to quit.');
21+
});
22+
23+
const environment = process.env.NODE_ENV || 'development';
24+
if (environment === 'development') {
25+
process.on('unhandledRejection', err => {
26+
console.error(err);
27+
throw err;
28+
});
29+
}
30+
31+
module.exports = server;

cloud-sql/sqlserver/mssql/test/server.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const path = require('path');
1818
const request = require('supertest');
1919
const assert = require('assert');
2020

21-
const SAMPLE_PATH = path.join(__dirname, '../server.js');
21+
const SAMPLE_PATH = path.join(__dirname, '../server/server.js');
2222

2323
const server = require(SAMPLE_PATH);
2424

cloud-sql/sqlserver/mssql/views/index.pug

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ html(lang="en")
5858
}
5959
}
6060
};
61-
xhr.open("POST", "/", true);
61+
xhr.open("POST", "/votes", true);
6262
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
6363
xhr.send("team=" + team);
6464
}

0 commit comments

Comments
 (0)