Skip to content

Commit 4c4d7d4

Browse files
wowi42Fizzadar
authored andcommitted
operations/postgres: enable modifying existing postgres databases (#1319)
1 parent e1b4089 commit 4c4d7d4

File tree

5 files changed

+80
-15
lines changed

5 files changed

+80
-15
lines changed

pyinfra/facts/postgres.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class PostgresDatabases(PostgresFactBase):
144144
"""
145145

146146
default = dict
147-
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database"
147+
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), *, pg_catalog.pg_get_userbyid(datdba) AS owner FROM pg_catalog.pg_database" # noqa: E501
148148

149149
@override
150150
def process(self, output):
@@ -161,7 +161,7 @@ def process(self, output):
161161

162162
for details in rows:
163163
details["encoding"] = details.pop("pg_encoding_to_char")
164-
164+
details["owner"] = details.pop("owner")
165165
for key, value in list(details.items()):
166166
if key.endswith("id") or key in (
167167
"dba",

pyinfra/operations/postgres.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,8 @@ def database(
199199
+ psql_*: global module arguments, see above
200200
201201
Updates:
202-
pyinfra will not attempt to change existing databases - it will either
203-
create or drop databases, but not alter them (if the db exists this
204-
operation will make no changes).
202+
pyinfra will change existing databases - but some parameters are not
203+
changeable (template, encoding, lc_collate and lc_ctype).
205204
206205
**Example:**
207206
@@ -212,7 +211,7 @@ def database(
212211
database="pyinfra_stuff",
213212
owner="pyinfra",
214213
encoding="UTF8",
215-
sudo_user="postgres",
214+
_sudo_user="postgres",
216215
)
217216
218217
"""
@@ -267,7 +266,51 @@ def database(
267266
database=psql_database,
268267
)
269268
else:
270-
host.noop("postgresql database {0} exists".format(database))
269+
current_db = current_databases[database]
270+
271+
for key, value, current_value in (
272+
("TEMPLATE", template, current_db.get("istemplate")),
273+
("ENCODING", encoding, current_db.get("encoding")),
274+
("LC_COLLATE", lc_collate, None),
275+
("LC_CTYPE", lc_ctype, None),
276+
):
277+
if value and (current_value is None or current_value != value):
278+
host.noop(
279+
"postgresql database {0} already exists, skipping {1}".format(database, key)
280+
)
281+
282+
sql_bits = []
283+
284+
if owner and "owner" in current_db and current_db["owner"] != owner:
285+
sql_bits.append('ALTER DATABASE "{0}" OWNER TO "{1}";'.format(database, owner))
286+
287+
if tablespace and "tablespace" in current_db and current_db["tablespace"] != tablespace:
288+
sql_bits.append(
289+
'ALTER DATABASE "{0}" SET TABLESPACE "{1}";'.format(database, tablespace)
290+
)
291+
292+
if (
293+
connection_limit
294+
and "connlimit" in current_db
295+
and current_db["connlimit"] != connection_limit
296+
):
297+
sql_bits.append(
298+
'ALTER DATABASE "{0}" CONNECTION LIMIT {1};'.format(database, connection_limit)
299+
)
300+
301+
if len(sql_bits) > 0:
302+
yield make_execute_psql_command(
303+
StringCommand(*sql_bits),
304+
user=psql_user,
305+
password=psql_password,
306+
host=psql_host,
307+
port=psql_port,
308+
database=psql_database,
309+
)
310+
else:
311+
host.noop(
312+
"postgresql database {0} already exists with the same parameters".format(database)
313+
)
271314

272315

273316
@operation(is_idempotent=False)

tests/facts/postgresql.PostgresqlDatabases/multiple.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"command": "psql -Ac 'SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database'",
2+
"command": "psql -Ac 'SELECT pg_catalog.pg_encoding_to_char(encoding), *, pg_catalog.pg_get_userbyid(datdba) AS owner FROM pg_catalog.pg_database'",
33
"requires_command": "psql",
44
"output": [
5-
"pg_encoding_to_char|datname|datdba|encoding|datcollate|datctype|datistemplate|datallowconn|datconnlimit|datlastsysoid|datfrozenxid|datminmxid|dattablespace|datacl",
6-
"UTF8|postgres|10|6|en_US.UTF-8|en_US.UTF-8|f|t|-1|13052|548|1|1663|",
7-
"UTF8|pyinfra_stuff|16384|6|en_US.UTF-8|en_US.UTF-8|f|t|-1|13052|548|1|1663|",
5+
"pg_encoding_to_char|datname|datdba|encoding|datcollate|datctype|datistemplate|datallowconn|datconnlimit|datlastsysoid|datfrozenxid|datminmxid|dattablespace|datacl|owner",
6+
"UTF8|postgres|10|6|en_US.UTF-8|en_US.UTF-8|f|t|-1|13052|548|1|1663||postgres",
7+
"UTF8|pyinfra_stuff|16384|6|en_US.UTF-8|en_US.UTF-8|f|t|-1|13052|548|1|1663||pyinfra",
88
"(4 rows)"
99
],
1010
"fact": {
@@ -20,7 +20,8 @@
2020
"frozenxid": 548,
2121
"minmxid": 1,
2222
"tablespace": 1663,
23-
"acl": null
23+
"acl": null,
24+
"owner": "postgres"
2425
},
2526
"pyinfra_stuff": {
2627
"dba": 16384,
@@ -34,7 +35,8 @@
3435
"frozenxid": 548,
3536
"minmxid": 1,
3637
"tablespace": 1663,
37-
"acl": null
38+
"acl": null,
39+
"owner": "pyinfra"
3840
}
3941
}
4042
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"args": ["somedb"],
3+
"kwargs": {
4+
"owner": "someowner",
5+
"tablespace": "someothertablespace"
6+
},
7+
"facts" :{
8+
"postgres.PostgresDatabases": {
9+
"psql_database=None, psql_host=None, psql_password=None, psql_port=None, psql_user=None": {
10+
"somedb": { "owner": "someotherowner", "tablespace": "sometablespace" }
11+
}
12+
}
13+
},
14+
"commands": [
15+
"psql -Ac 'ALTER DATABASE \"somedb\" OWNER TO \"someowner\"; ALTER DATABASE \"somedb\" SET TABLESPACE \"someothertablespace\";'"
16+
]
17+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
{
22
"args": ["somedb"],
3+
"kwargs": {
4+
"owner": "someowner"
5+
},
36
"facts" :{
47
"postgres.PostgresDatabases": {
58
"psql_database=None, psql_host=None, psql_password=None, psql_port=None, psql_user=None": {
6-
"somedb": {}
9+
"somedb": { "owner": "someowner" }
710
}
811
}
912
},
1013
"commands": [],
11-
"noop_description": "postgresql database somedb exists"
14+
"noop_description": "postgresql database somedb already exists with the same parameters"
1215
}

0 commit comments

Comments
 (0)