Skip to content

Commit a631fca

Browse files
authored
Merge pull request #4 from squidmin/gcs-batch-request-test
Set up & document CloudSQL / PostgreSQL
2 parents 007a95a + a620ade commit a631fca

File tree

8 files changed

+277
-2
lines changed

8 files changed

+277
-2
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Java CI with Maven (multi-job)
1+
name: CI
22

33
on:
44
workflow_dispatch:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Automate table creation using Terraform
2+
3+
### Example
4+
5+
```hcl
6+
# run after instance+db+user exist
7+
resource "null_resource" "init_table" {
8+
depends_on = [google_sql_database.db, google_sql_user.user]
9+
10+
provisioner "local-exec" {
11+
interpreter = ["/bin/bash", "-c"]
12+
command = <<-EOT
13+
set -euo pipefail
14+
# Start proxy
15+
cloud-sql-proxy ${google_sql_database_instance.pg.connection_name} --port 5432 &
16+
PID=$!
17+
# Wait for port
18+
for i in {1..30}; do nc -z 127.0.0.1 5432 && break; sleep 1; done
19+
# Apply DDL
20+
PGPASSWORD='${var.db_password}' psql -h 127.0.0.1 -p 5432 -U '${var.db_user}' -d '${var.db_name}' <<'SQL'
21+
CREATE TABLE IF NOT EXISTS widgets (
22+
id UUID PRIMARY KEY,
23+
name TEXT NOT NULL,
24+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
25+
meta JSONB
26+
);
27+
SQL
28+
kill $PID
29+
EOT
30+
}
31+
}
32+
```
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Cloud SQL Auth Proxy
2+
3+
### Set instance connection name
4+
5+
```bash
6+
export INSTANCE_CONNECTION_NAME="lofty-root-378503:us-central1:jm-pg-demo"
7+
```
8+
9+
### Run the CloudSQL auth proxy
10+
11+
Remove any old proxy container:
12+
13+
```bash
14+
docker rm -f csql-proxy 2>/dev/null || true
15+
```
16+
17+
Then use one of the below options:
18+
19+
#### Executable
20+
21+
```bash
22+
# CLI option
23+
# Download from: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
24+
./cloud-sql-proxy ${INSTANCE_CONNECTION_NAME} --port 5432 &
25+
PROXY_PID=$!
26+
```
27+
28+
#### Docker
29+
30+
```bash
31+
32+
export CREDENTIALS_PATH="/Users/admin/.config/gcloud/sa-private-key.json"
33+
docker run -d --name csql-proxy -p 127.0.0.1:5400:5432 \
34+
-v "$GOOGLE_APPLICATION_CREDENTIALS:/creds/key.json:ro" \
35+
gcr.io/cloud-sql-connectors/cloud-sql-proxy:2 \
36+
--address 0.0.0.0 --port 5432 \
37+
--credentials-file=/creds/key.json "$INSTANCE_CONNECTION_NAME"
38+
```
39+
40+
### Wait for proxy to listen
41+
42+
```bash
43+
for i in {1..30}; do nc -z 127.0.0.1 5433 && echo "proxy ready" && break; sleep 1; done
44+
```
45+
46+
### Check if proxy is running
47+
48+
```bash
49+
docker ps -a | grep csql-proxy || true
50+
```
51+
52+
### Verify proxy is running on a specific port
53+
54+
```bash
55+
nc -z 127.0.0.1 5400 && echo "proxy up" || echo "proxy not up"
56+
```
57+
58+
### Check proxy logs
59+
60+
```bash
61+
docker logs csql-proxy --tail=200 || true
62+
```
63+
64+
### Check if port is in use
65+
66+
```bash
67+
lsof -iTCP:5432 -sTCP:LISTEN || true
68+
```
69+
70+
### List available ports
71+
72+
#### Common Postgres ports
73+
74+
```bash
75+
for p in 5432 5433 5434 5435 5436; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) && echo "$p in use" || echo "$p free"; done
76+
```
77+
78+
#### Scan a wider port range
79+
80+
```bash
81+
for p in {5400..5450}; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) || echo "$p free"; done
82+
```
83+
84+
#### Pick the first available port
85+
86+
```bash
87+
for p in {5400..5450}; do (lsof -iTCP:$p -sTCP:LISTEN >/dev/null) || { echo "First free port: $p"; break; }; done
88+
```
89+
90+
### Test connection
91+
92+
```bash
93+
export TF_VAR_db_user=username
94+
export TF_VAR_db_password=password
95+
export TF_VAR_db_name=jm_demo_db
96+
```
97+
98+
Have the proxy running and healthy to `127.0.0.1:5432`.
99+
Make sure nothing else is using port `5432`.
100+
If it is, pick another port (e.g., 5433) and update your `psql` command.
101+
102+
Then run:
103+
104+
```bash
105+
PGPASSWORD="$TF_VAR_db_password" psql \
106+
-h 127.0.0.1 -p 5400 \
107+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
108+
-c "select 1;"
109+
```
110+
111+
### If the test is successful
112+
113+
Assuming the file `/src/test/resources/init.sql` exists:
114+
115+
```bash
116+
PGPASSWORD="$TF_VAR_db_password" psql \
117+
-h 127.0.0.1 -p 5400 \
118+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
119+
-f init.sql
120+
```
121+
122+
You can also create the table directly from the command line:
123+
124+
```bash
125+
cat > init.sql <<'SQL'
126+
PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5400 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" -v ON_ERROR_STOP=1 <<'SQL'
127+
CREATE TABLE IF NOT EXISTS widgets (
128+
id UUID PRIMARY KEY,
129+
name TEXT NOT NULL,
130+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
131+
meta JSONB
132+
);
133+
SQL
134+
```
135+
136+
### Single insert
137+
138+
```bash
139+
PGPASSWORD="$TF_VAR_db_password" psql \
140+
-h 127.0.0.1 -p 5400 \
141+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
142+
-c "INSERT INTO widgets (id, name, meta) VALUES (gen_random_uuid(), 'Test Widget', '{\"color\":\"red\",\"size\":10}');"
143+
```
144+
145+
### Multiple inserts
146+
147+
```bash
148+
PGPASSWORD="$TF_VAR_db_password" psql \
149+
-h 127.0.0.1 -p 5400 \
150+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
151+
-c "
152+
INSERT INTO widgets (id, name, meta) VALUES
153+
(gen_random_uuid(), 'Widget A', '{\"type\":\"alpha\"}'),
154+
(gen_random_uuid(), 'Widget B', '{\"type\":\"beta\"}'),
155+
(gen_random_uuid(), 'Widget C', '{\"type\":\"gamma\"}');
156+
"
157+
```
158+
159+
### Insert rows from a file
160+
161+
```bash
162+
cat > /tmp/insert_widgets.sql <<'SQL'
163+
INSERT INTO widgets (id, name, meta) VALUES
164+
(gen_random_uuid(), 'Widget X', '{"size":42}'),
165+
(gen_random_uuid(), 'Widget Y', '{"color":"blue"}');
166+
SQL
167+
168+
PGPASSWORD="$TF_VAR_db_password" psql \
169+
-h 127.0.0.1 -p 5400 \
170+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
171+
-f insert_widgets.sql
172+
```
173+
174+
### Read all rows in a table
175+
176+
```bash
177+
PGPASSWORD="$TF_VAR_db_password" psql \
178+
-h 127.0.0.1 -p 5400 \
179+
-U "$TF_VAR_db_user" -d "$TF_VAR_db_name" \
180+
-c "SELECT * FROM widgets;"
181+
```
182+
183+
### Open an interactive psql session
184+
185+
```bash
186+
PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5400 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name"
187+
```
188+
189+
```sql
190+
INSERT INTO widgets (id, name, meta) VALUES (gen_random_uuid(), 'Widget ABC', '{"shape":"sphere"}');
191+
SELECT * FROM widgets;
192+
```
193+
194+
### List tables
195+
196+
```psql
197+
\l
198+
```
199+
200+
### Drop tables
201+
202+
```bash
203+
DROP TABLE widgets;
204+
```
205+
206+
### Exit `psql`
207+
208+
```psql
209+
exit
210+
```
211+
212+
---
213+
214+
### Grant create/use to a user
215+
216+
```bash
217+
PGPASSWORD="$TF_VAR_db_password" psql -h 127.0.0.1 -p 5432 -U "$TF_VAR_db_user" -d "$TF_VAR_db_name" -c \
218+
"GRANT USAGE ON SCHEMA public TO $TF_VAR_db_user; GRANT CREATE ON SCHEMA public TO $TF_VAR_db_user;"
219+
```
220+
221+
Verify `roles/cloudsql.client` on the user's service account.
222+
223+
---
224+
225+
### Stop the CloudSQL auth proxy
226+
227+
```bash
228+
kill $PROXY_PID 2>/dev/null || true
229+
# or: docker rm -f csql-proxy
230+
```

google-cloud-sql/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<groupId>org.squidmin.java.spring.maven.cloudsql</groupId>
1414
<artifactId>google-cloud-sql</artifactId>
1515
<version>0.0.1-SNAPSHOT</version>
16+
1617
<name>google-cloud-sql</name>
1718
<description>google-cloud-sql</description>
1819
<url/>

google-cloud-sql/src/main/java/org/squidmin/java/spring/maven/cloudsql/controller/CloudSqlController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class CloudSqlController {
1313
public CloudSqlController() {}
1414

1515
@GetMapping(
16-
value = "/placeholder",
16+
value = "/insert-rows",
1717
consumes = MediaType.APPLICATION_JSON_VALUE,
1818
produces = MediaType.APPLICATION_JSON_VALUE
1919
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
spring:
2+
application:
3+
name: google-cloud-sql
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE IF NOT EXISTS widgets (
2+
id UUID PRIMARY KEY,
3+
name TEXT NOT NULL,
4+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
5+
meta JSONB
6+
);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
INSERT INTO widgets (id, name, meta)
2+
VALUES (gen_random_uuid(), 'Widget X', '{"size":42}'),
3+
(gen_random_uuid(), 'Widget Y', '{"color":"blue"}');

0 commit comments

Comments
 (0)