Skip to content

Commit 85ca4d3

Browse files
committed
feat: enhance MySQL support and improve script logging
1 parent e6504b3 commit 85ca4d3

File tree

6 files changed

+93
-32
lines changed

6 files changed

+93
-32
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ This module creates database and users on an existing CloudSQL instance. The str
44

55
To enforce permissions, the module executes SQL commands with the mysql cli, which is therefore a prerequisite (it must be present in the filesystem where terraform apply is executed).
66

7+
For MySQL 8.x instances, the module automatically removes the default `cloudsqlsuperuser` role, clears any global privileges and assigns the target database as the only default role so that new users are scoped exclusively to their database.
8+
79
In addition, the script must be able to connect to the CloudSQL instance. In case this is not easily accessible from the terraform cli, the module is able to:
810

911
1. Start an instance of [CloudSQL Auth Proxy](https://cloud.google.com/sql/docs/mysql/sql-proxy), for this purpose two null resources will be created for each user added to the database, enabling this option requires the [presence of the proxy executable](https://cloud.google.com/sql/docs/mysql/sql-proxy) in the filesystem where `terraform apply` is executed.
@@ -33,7 +35,7 @@ CloudSQL Auth Proxy needs the CloudSQL instance to expose a public IP address in
3335

3436
| Name | Description | Type | Default | Required |
3537
|------|-------------|------|---------|:--------:|
36-
| <a name="input_cloudsql_instance_name"></a> [cloudsql\_instance\_name](#input\_cloudsql\_instance\_name) | The name of the existing Google CloudSQL Instance name. Actually only a MySQL 5.7 or 8 instance is supported. | `string` | n/a | yes |
38+
| <a name="input_cloudsql_instance_name"></a> [cloudsql\_instance\_name](#input\_cloudsql\_instance\_name) | The name of the existing Google CloudSQL Instance name. MySQL 5.7, 8.0 and 8.4 are supported. | `string` | n/a | yes |
3739
| <a name="input_cloudsql_privileged_user_name"></a> [cloudsql\_privileged\_user\_name](#input\_cloudsql\_privileged\_user\_name) | The name of the privileged user of the Cloud SQL instance | `string` | n/a | yes |
3840
| <a name="input_cloudsql_privileged_user_password"></a> [cloudsql\_privileged\_user\_password](#input\_cloudsql\_privileged\_user\_password) | The password of the privileged user of the Cloud SQL instance | `string` | n/a | yes |
3941
| <a name="input_cloudsql_proxy_host"></a> [cloudsql\_proxy\_host](#input\_cloudsql\_proxy\_host) | The host of the Cloud SQL Auth Proxy; if a value other than localhost or 127.0.0.1 (default) is entered, it is assumed that there is a CloudSQL Auth Proxy instance defined and already configured outside this module, and therefore the proxy will not be launched. | `string` | `"127.0.0.1"` | no |

scripts/execute_cloud_sql_proxy.sh

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,50 @@
11
#!/usr/bin/env sh
22

3-
if ! [ -x "$(command -v cloud_sql_proxy)" ]; then
4-
echo "Error: cannot find the cloud_sql_proxy executable, please install it or add to your path." >&2
3+
set -eu
4+
5+
# shellcheck disable=SC3040
6+
if (set -o pipefail 2>/dev/null); then
7+
set -o pipefail
8+
fi
9+
10+
log() {
11+
printf '[sql-proxy] %s\n' "${1}"
12+
}
13+
14+
PROXY_BIN=""
15+
if command -v cloud_sql_proxy >/dev/null 2>&1; then
16+
PROXY_BIN="cloud_sql_proxy"
17+
else
18+
log "Error: cannot find the Cloud SQL Auth Proxy executable cloud_sql_proxy. Please install it or add it to your PATH." >&2
519
exit 1
6-
elif ! [ -x "$(command -v nc)" ]; then
7-
echo "Error: Netcat is not installed." >&2
20+
fi
21+
22+
if ! command -v nc >/dev/null 2>&1; then
23+
log "Error: Netcat is not installed." >&2
824
exit 1
925
fi
1026

11-
SERVICE="cloud_sql_proxy"
27+
CONNECTION_NAME="${CLOUDSDK_CORE_PROJECT}:${GCLOUD_PROJECT_REGION}:${CLOUDSQL_INSTANCE_NAME}"
1228

13-
if ! pgrep -x "$SERVICE" >/dev/null
14-
then
15-
exec cloud_sql_proxy -instances="${CLOUDSDK_CORE_PROJECT}:${GCLOUD_PROJECT_REGION}:${CLOUDSQL_INSTANCE_NAME}"="tcp:0.0.0.0:${CLOUDSQL_PROXY_PORT}" /dev/null 2>&1 &
29+
if ! pgrep -x "$PROXY_BIN" >/dev/null; then
30+
log "Starting Cloud SQL Auth Proxy (${PROXY_BIN}) for ${CONNECTION_NAME} on localhost:${CLOUDSQL_PROXY_PORT}."
31+
"${PROXY_BIN}" "${CONNECTION_NAME}" --port "${CLOUDSQL_PROXY_PORT}" >/dev/null 2>&1 &
32+
sleep 1s
33+
else
34+
log "Cloud SQL Auth Proxy already running; skipping start."
1635
fi
1736

1837
for j in $(seq 1 10); do
1938
READY=$(sh -c 'nc -v ${CLOUDSQL_PROXY_HOST} ${CLOUDSQL_PROXY_PORT} </dev/null; echo $?;' 2>/dev/null)
2039
if [ "$READY" -eq 0 ]; then
21-
echo "Connection with with CloudSQL Auth Proxy established at ${CLOUDSQL_PROXY_HOST}."
40+
log "Connection with Cloud SQL Auth Proxy established at ${CLOUDSQL_PROXY_HOST}:${CLOUDSQL_PROXY_PORT}."
2241
break
2342
fi
24-
echo "Waiting for Cloud SQL Proxy to start... $j"
43+
log "Waiting for Cloud SQL Proxy to start (attempt ${j}/10)..."
2544
sleep 1s
2645
done
2746

28-
if [ "$READY" -eq 1 ]; then
29-
echo "ERROR: cannot connect to the CloudSQL Auth Proxy at ${CLOUDSQL_PROXY_HOST}, please check your settings."
47+
if [ "$READY" -ne 0 ]; then
48+
log "ERROR: cannot connect to the Cloud SQL Auth Proxy at ${CLOUDSQL_PROXY_HOST}:${CLOUDSQL_PROXY_PORT}, please check your settings." >&2
3049
exit 1
3150
fi

scripts/execute_sql.sh

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,65 @@
11
#!/usr/bin/env sh
22

3+
set -eu
4+
5+
# shellcheck disable=SC3040
6+
if (set -o pipefail 2>/dev/null); then
7+
set -o pipefail
8+
fi
9+
10+
log() {
11+
printf '[sql-grant] %s\n' "${1}"
12+
}
13+
314
if ! [ -x "$(command -v mysql)" ]; then
4-
echo "Error: the mysql client is not installed or is not in your path. Please add the mysql client executable." >&2
15+
log "Error: the mysql client is not installed or is not in your path. Please add the mysql client executable." >&2
516
exit 1
617
elif ! [ -x "$(command -v nc)" ]; then
7-
echo "Error: Netcat is not installed." >&2
18+
log "Error: Netcat is not installed." >&2
819
exit 1
920
fi
1021

1122
for j in $(seq 1 10); do
1223
READY=$(sh -c 'nc -v ${CLOUDSQL_PROXY_HOST} ${CLOUDSQL_PROXY_PORT} </dev/null; echo $?;' 2>/dev/null)
1324

1425
if [ "$READY" -eq 0 ]; then
15-
echo "Connection with with CloudSQL Auth Proxy established at ${CLOUDSQL_PROXY_HOST}."
26+
log "Connection with CloudSQL Auth Proxy established at ${CLOUDSQL_PROXY_HOST}:${CLOUDSQL_PROXY_PORT}."
1627
break
1728
fi
18-
echo "Waiting for Cloud SQL Proxy to start... $j"
29+
log "Waiting for Cloud SQL Proxy to start (attempt ${j}/10)..."
1930
sleep 1s
2031
done
2132

2233
if [ "$READY" -eq 0 ]; then
23-
if [ "${MYSQL_VERSION:0:9}" = "MYSQL_5_7" ]; then
24-
mysql --host=${CLOUDSQL_PROXY_HOST} --port=${CLOUDSQL_PROXY_PORT} --user=${CLOUDSQL_PRIVILEGED_USER_NAME} --password=${CLOUDSQL_PRIVILEGED_USER_PASSWORD} --execute="REVOKE ALL PRIVILEGES, GRANT OPTION FROM '${USER}'@'${USER_HOST}'; GRANT ALL ON ${DATABASE}.* TO ${USER}@'${USER_HOST}';"
25-
fi
34+
USER_IDENTIFIER="'${USER}'@'${USER_HOST}'"
35+
DATABASE_IDENTIFIER="\`${DATABASE}\`.*"
2636

27-
if [ "${MYSQL_VERSION:0:9}" = "MYSQL_8_0" ]; then
28-
mysql --host=${CLOUDSQL_PROXY_HOST} --port=${CLOUDSQL_PROXY_PORT} --user=${CLOUDSQL_PRIVILEGED_USER_NAME} --password=${CLOUDSQL_PRIVILEGED_USER_PASSWORD} --execute="REVOKE cloudsqlsuperuser FROM '${USER}'@'${USER_HOST}'; GRANT ALL ON ${DATABASE}.* TO ${USER}@'${USER_HOST}';"
37+
log "Preparing privilege statements for ${USER_IDENTIFIER} on database \`${DATABASE}\` (MySQL ${MYSQL_VERSION})."
38+
39+
case "${MYSQL_VERSION}" in
40+
MYSQL_5_7*)
41+
SQL_COMMANDS="REVOKE ALL PRIVILEGES, GRANT OPTION FROM ${USER_IDENTIFIER}; GRANT ALL PRIVILEGES ON ${DATABASE_IDENTIFIER} TO ${USER_IDENTIFIER};"
42+
;;
43+
MYSQL_8_0*|MYSQL_8_4*)
44+
SQL_COMMANDS="REVOKE cloudsqlsuperuser FROM ${USER_IDENTIFIER}; SET DEFAULT ROLE NONE TO ${USER_IDENTIFIER}; GRANT ALL PRIVILEGES ON ${DATABASE_IDENTIFIER} TO ${USER_IDENTIFIER};"
45+
;;
46+
*)
47+
log "ERROR: Unsupported MySQL version ${MYSQL_VERSION}." >&2
48+
exit 1
49+
;;
50+
esac
51+
52+
printf '[sql-grant] Executing SQL statements:\n%s\n' "${SQL_COMMANDS}"
53+
54+
if ! MYSQL_PWD="${CLOUDSQL_PRIVILEGED_USER_PASSWORD}" mysql --host="${CLOUDSQL_PROXY_HOST}" --port="${CLOUDSQL_PROXY_PORT}" --user="${CLOUDSQL_PRIVILEGED_USER_NAME}" --execute="${SQL_COMMANDS}"; then
55+
log "ERROR: Failed to apply privileges for ${USER_IDENTIFIER} on ${DATABASE}." >&2
56+
exit 1
2957
fi
3058

59+
log "Successfully applied privileges for ${USER_IDENTIFIER}."
60+
3161
exit 0
3262
else
33-
echo "ERROR: cannot connect to the CloudSQL Auth Proxy at ${CLOUDSQL_PROXY_HOST}, please check your settings."
63+
log "ERROR: cannot connect to the CloudSQL Auth Proxy at ${CLOUDSQL_PROXY_HOST}:${CLOUDSQL_PROXY_PORT}, please check your settings." >&2
3464
exit 1
3565
fi

scripts/kill_cloud_sql_proxy.sh

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
#!/usr/bin/env sh
22

3-
SERVICE="cloud_sql_proxy"
3+
set -eu
44

5-
if pgrep -x "$SERVICE" >/dev/null; then
6-
# It's better to take some time and to wait for the other tasks to finish
7-
# before killing the proxy; do not entering a sleep time, can lead to a
8-
# race condition error when simultaneously creating and destroying resources.
5+
# shellcheck disable=SC3040
6+
if (set -o pipefail 2>/dev/null); then
7+
set -o pipefail
8+
fi
9+
10+
log() {
11+
printf '[sql-proxy] %s\n' "${1}"
12+
}
13+
14+
PROXY_BIN="cloud_sql_proxy"
15+
if pgrep -x "$PROXY_BIN" >/dev/null; then
16+
log "Detected running ${PROXY_BIN}; waiting 5 seconds before shutdown to avoid race conditions."
917
sleep 5s
10-
PID_CLOUD_SQL_PROXY=$(pgrep -x ${SERVICE})
11-
kill "$PID_CLOUD_SQL_PROXY" || true
18+
# Obtain the PID of the running Cloud SQL Auth Proxy and terminate gently.
19+
PID="$(pgrep -x "$PROXY_BIN")"
20+
log "Stopping ${PROXY_BIN} (PID(s): ${PID})."
21+
22+
kill "${PID}" || true
1223
fi

variables.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ variable "region" {
1010

1111
variable "cloudsql_instance_name" {
1212
type = string
13-
description = "The name of the existing Google CloudSQL Instance name. Actually only a MySQL 5.7 or 8 instance is supported."
13+
description = "The name of the existing Google CloudSQL Instance name. MySQL 5.7, 8.0 and 8.4 are supported."
1414
}
1515

1616
variable "terraform_start_cloud_sql_proxy" {

versions.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,3 @@ terraform {
1616
}
1717
}
1818
}
19-

0 commit comments

Comments
 (0)