Merge lp:~sidnei/charms/precise/postgresql/trunk into lp:charms/postgresql

Proposed by Sidnei da Silva
Status: Merged
Merged at revision: 47
Proposed branch: lp:~sidnei/charms/precise/postgresql/trunk
Merge into: lp:charms/postgresql
Diff against target: 760 lines (+216/-137)
5 files modified
config.yaml (+4/-0)
hooks/hooks.py (+210/-136)
revision (+0/-1)
templates/pg_hba.conf.tmpl (+1/-0)
templates/postgres.cron.tmpl (+1/-0)
To merge this branch: bzr merge lp:~sidnei/charms/precise/postgresql/trunk
Reviewer Review Type Date Requested Status
Marco Ceppi (community) Approve
Review via email: mp+160531@code.launchpad.net

Commit message

Fix flake8 warnings
Fix a NameError
Use params instead of string interpolation

Description of the change

Fix flake8 warnings
Fix a NameError
Use params instead of string interpolation

To post a comment you must log in.
101. By Sidnei da Silva

- Quote identifiers.
- Generate username like in -joined if not set on relation by the time -changed gets called.

Revision history for this message
Marco Ceppi (marcoceppi) wrote :

LGTM, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2013-04-01 17:13:24 +0000
3+++ config.yaml 2013-04-24 03:09:24 +0000
4@@ -286,6 +286,10 @@
5 description: >
6 Block device for attached volumes as seen by the VM, will be "scanned"
7 for an unused device when "volume-map" is valid for the unit.
8+ backup_dir:
9+ default: "/var/lib/postgresql/backups"
10+ type: string
11+ description: Directory to place backups in
12 backup_schedule:
13 default: "13 4 * * *"
14 type: string
15
16=== modified file 'hooks/hooks.py'
17--- hooks/hooks.py 2013-04-10 15:14:18 +0000
18+++ hooks/hooks.py 2013-04-24 03:09:24 +0000
19@@ -66,7 +66,7 @@
20 """Publish relevant unit state to relations"""
21
22 def add(state_dict, key):
23- if self.has_key(key):
24+ if key in self:
25 state_dict[key] = self[key]
26
27 client_state = {}
28@@ -159,7 +159,7 @@
29 # shell helper
30 def volume_init_and_mount(volid):
31 command = ("scripts/volume-common.sh call " +
32- "volume_init_and_mount %s" % volid)
33+ "volume_init_and_mount %s" % volid)
34 output = run(command)
35 if output.find("ERROR") >= 0:
36 return False
37@@ -232,9 +232,8 @@
38 # install_dir: create a directory
39 #------------------------------------------------------------------------------
40 def install_dir(dirname, owner="root", group="root", mode=0700):
41- command = \
42- '/usr/bin/install -o {} -g {} -m {} -d {}'.format(owner, group, oct(mode),
43- dirname)
44+ command = '/usr/bin/install -o {} -g {} -m {} -d {}'.format(
45+ owner, group, oct(mode), dirname)
46 return run(command)
47
48
49@@ -296,7 +295,7 @@
50
51 # Store a copy of our known live configuration so
52 # postgresql_reload_or_restart() can make good choices.
53- if local_state.has_key('saved_config'):
54+ if 'saved_config' in local_state:
55 local_state['live_config'] = local_state['saved_config']
56 local_state.save()
57
58@@ -356,7 +355,7 @@
59 MSG_DEBUG, "PostgreSQL reload, config changes taking effect.")
60 rc = postgresql_reload() # No pending need to bounce, just reload.
61
62- if rc == 0 and local_state.has_key('saved_config'):
63+ if rc == 0 and 'saved_config' in local_state:
64 local_state['live_config'] = local_state['saved_config']
65 local_state.save()
66
67@@ -508,7 +507,7 @@
68 for unit in json.loads(json_units):
69 unit_data = \
70 json.loads(relation_json(relation_id=relid,
71- unit_name=unit))
72+ unit_name=unit))
73 for key in unit_data:
74 if key.endswith('-list'):
75 unit_data[key] = unit_data[key].split()
76@@ -553,9 +552,9 @@
77 conf_file = open("/etc/sysctl.d/50-postgresql.conf", "w")
78 conf_file.write("kernel.sem = 250 32000 100 1024\n")
79 conf_file.write("kernel.shmall = %s\n" %
80- ((int(total_ram) * 1024 * 1024) + 1024),)
81+ ((int(total_ram) * 1024 * 1024) + 1024),)
82 conf_file.write("kernel.shmmax = %s\n" %
83- ((int(total_ram) * 1024 * 1024) + 1024),)
84+ ((int(total_ram) * 1024 * 1024) + 1024),)
85 conf_file.close()
86 run("sysctl -p /etc/sysctl.d/50-postgresql.conf")
87
88@@ -578,7 +577,7 @@
89 # Send config data to the template
90 # Return it as pg_config
91 pg_config = Template(
92- open("templates/postgresql.conf.tmpl").read()).render(config_data)
93+ open("templates/postgresql.conf.tmpl").read()).render(config_data)
94 install_file(pg_config, postgresql_config)
95
96 local_state['saved_config'] = config_data
97@@ -600,7 +599,8 @@
98 #------------------------------------------------------------------------------
99 # generate_postgresql_hba: Creates the pg_hba.conf file
100 #------------------------------------------------------------------------------
101-def generate_postgresql_hba(postgresql_hba):
102+def generate_postgresql_hba(postgresql_hba, user=None,
103+ schema_user=None, database=None):
104
105 # Per Bug #1117542, when generating the postgresql_hba file we
106 # need to cope with private-address being either an IP address
107@@ -620,19 +620,26 @@
108 unit_name=os.environ['JUJU_UNIT_NAME'], relation_id=relid)
109 for unit in relation_list(relid):
110 relation = relation_get(unit_name=unit, relation_id=relid)
111- relation['relation-id'] = relid
112+ relation['relation-id'] = relid
113 relation['unit'] = unit
114
115 if relid.startswith('db-admin:'):
116 relation['user'] = 'all'
117 relation['database'] = 'all'
118 elif relid.startswith('db:'):
119- relation['user'] = local_relation['user']
120- relation['schema_user'] = local_relation['schema_user']
121- relation['database'] = local_relation['database']
122+ relation['user'] = local_relation.get('user', user)
123+ relation['schema_user'] = local_relation.get('schema_user',
124+ schema_user)
125+ relation['database'] = local_relation.get('database', database)
126+
127+ if ((relation['user'] is None
128+ or relation['schema_user'] is None
129+ or relation['database'] is None)):
130+ # Missing info in relation for this unit, so skip it.
131+ continue
132 else:
133 raise RuntimeError(
134- 'Unknown relation type {}'.format(repr(relation_id)))
135+ 'Unknown relation type {}'.format(repr(relid)))
136
137 relation['private-address'] = munge_address(
138 relation['private-address'])
139@@ -646,32 +653,31 @@
140 # database.
141 for relid in relation_ids(relation_types=replication_relation_types):
142 for unit in relation_list(relid):
143- replicated = True
144 relation = relation_get(unit_name=unit, relation_id=relid)
145 remote_addr = munge_address(relation['private-address'])
146- remote_replication = {
147- 'database': 'replication', 'user': 'juju_replication',
148- 'private-address': remote_addr,
149- 'relation-id': relid,
150- 'unit': unit,
151- }
152+ remote_replication = {'database': 'replication',
153+ 'user': 'juju_replication',
154+ 'private-address': remote_addr,
155+ 'relation-id': relid,
156+ 'unit': unit,
157+ }
158 relation_data.append(remote_replication)
159- remote_pgdb = {
160- 'database': 'postgres', 'user': 'juju_replication',
161- 'private-address': remote_addr,
162- 'relation-id': relid,
163- 'unit': unit,
164- }
165+ remote_pgdb = {'database': 'postgres',
166+ 'user': 'juju_replication',
167+ 'private-address': remote_addr,
168+ 'relation-id': relid,
169+ 'unit': unit,
170+ }
171 relation_data.append(remote_pgdb)
172
173 # Hooks need permissions too to setup replication.
174 for relid in relation_ids(relation_types=['replication']):
175- local_replication = {
176- 'database': 'postgres', 'user': 'juju_replication',
177- 'private-address': munge_address(get_unit_host()),
178- 'relation-id': relid,
179- 'unit': os.environ['JUJU_UNIT_NAME'],
180- }
181+ local_replication = {'database': 'postgres',
182+ 'user': 'juju_replication',
183+ 'private-address': munge_address(get_unit_host()),
184+ 'relation-id': relid,
185+ 'unit': os.environ['JUJU_UNIT_NAME'],
186+ }
187 relation_data.append(local_replication)
188
189 pg_hba_template = Template(
190@@ -682,7 +688,6 @@
191 postgresql_reload()
192
193
194-
195 #------------------------------------------------------------------------------
196 # install_postgresql_crontab: Creates the postgresql crontab file
197 #------------------------------------------------------------------------------
198@@ -718,7 +723,7 @@
199 if port is None:
200 return(None)
201 return(subprocess.call(['open-port', "%d/%s" %
202- (int(port), protocol)]))
203+ (int(port), protocol)]))
204
205
206 #------------------------------------------------------------------------------
207@@ -729,7 +734,7 @@
208 if port is None:
209 return(None)
210 return(subprocess.call(['close-port', "%d/%s" %
211- (int(port), protocol)]))
212+ (int(port), protocol)]))
213
214
215 #------------------------------------------------------------------------------
216@@ -754,9 +759,9 @@
217 if pwd_length is None:
218 pwd_length = random.choice(range(20, 30))
219 alphanumeric_chars = [l for l in (string.letters + string.digits)
220- if l not in 'Iil0oO1']
221+ if l not in 'Iil0oO1']
222 random_chars = [random.choice(alphanumeric_chars)
223- for i in range(pwd_length)]
224+ for i in range(pwd_length)]
225 return(''.join(random_chars))
226
227
228@@ -779,8 +784,8 @@
229 return None
230
231
232-def db_cursor(
233- autocommit=False, db='template1', user='postgres', host=None, timeout=120):
234+def db_cursor(autocommit=False, db='template1', user='postgres',
235+ host=None, timeout=120):
236 import psycopg2
237 if host:
238 conn_str = "dbname={} host={} user={}".format(db, host, user)
239@@ -844,34 +849,38 @@
240 if volid:
241 if volume_is_permanent(volid):
242 if not volume_init_and_mount(volid):
243- juju_log(MSG_ERROR, "volume_init_and_mount failed, " +
244- "not applying changes")
245+ juju_log(MSG_ERROR,
246+ "volume_init_and_mount failed, "
247+ "not applying changes")
248 return False
249
250 if not os.path.exists(data_directory_path):
251- juju_log(MSG_CRITICAL, ("postgresql data dir = %s not found, " +
252- "not applying changes.") % data_directory_path)
253+ juju_log(MSG_CRITICAL,
254+ "postgresql data dir = %s not found, "
255+ "not applying changes." % data_directory_path)
256 return False
257
258 mount_point = volume_mount_point_from_volid(volid)
259 new_pg_dir = os.path.join(mount_point, "postgresql")
260- new_pg_version_cluster_dir = os.path.join(new_pg_dir,
261- config_data["version"], config_data["cluster_name"])
262+ new_pg_version_cluster_dir = os.path.join(
263+ new_pg_dir, config_data["version"], config_data["cluster_name"])
264 if not mount_point:
265- juju_log(MSG_ERROR, "invalid mount point from volid = \"%s\", " +
266+ juju_log(MSG_ERROR,
267+ "invalid mount point from volid = \"%s\", "
268 "not applying changes." % mount_point)
269 return False
270
271- if (os.path.islink(data_directory_path) and
272- os.readlink(data_directory_path) == new_pg_version_cluster_dir and
273- os.path.isdir(new_pg_version_cluster_dir)):
274- juju_log(MSG_INFO,
275- "NOTICE: postgresql data dir '%s' already points to '%s', \
276- skipping storage changes." %
277- (data_directory_path, new_pg_version_cluster_dir))
278- juju_log(MSG_INFO,
279- "existing-symlink: to fix/avoid UID changes from previous "
280- "units, doing: chown -R postgres:postgres %s" % new_pg_dir)
281+ if ((os.path.islink(data_directory_path) and
282+ os.readlink(data_directory_path) == new_pg_version_cluster_dir and
283+ os.path.isdir(new_pg_version_cluster_dir))):
284+ juju_log(MSG_INFO,
285+ "NOTICE: postgresql data dir '%s' already points "
286+ "to '%s', skipping storage changes." %
287+ (data_directory_path, new_pg_version_cluster_dir))
288+ juju_log(MSG_INFO,
289+ "existing-symlink: to fix/avoid UID changes from "
290+ "previous units, doing: "
291+ "chown -R postgres:postgres %s" % new_pg_dir)
292 run("chown -R postgres:postgres %s" % new_pg_dir)
293 return True
294
295@@ -880,8 +889,8 @@
296 # /var/lib/postgresql/9.1/main
297 curr_dir_stat = os.stat(data_directory_path)
298 for new_dir in [new_pg_dir,
299- os.path.join(new_pg_dir, config_data["version"]),
300- new_pg_version_cluster_dir]:
301+ os.path.join(new_pg_dir, config_data["version"]),
302+ new_pg_version_cluster_dir]:
303 if not os.path.isdir(new_dir):
304 juju_log(MSG_INFO, "mkdir %s" % new_dir)
305 os.mkdir(new_dir)
306@@ -895,10 +904,10 @@
307 # main-$TIMESTAMP
308 if not postgresql_stop():
309 juju_log(MSG_ERROR,
310- "postgresql_stop() returned False - can't migrate data.")
311+ "postgresql_stop() returned False - can't migrate data.")
312 return False
313 if not os.path.exists(os.path.join(new_pg_version_cluster_dir,
314- "PG_VERSION")):
315+ "PG_VERSION")):
316 juju_log(MSG_WARNING, "migrating PG data %s/ -> %s/" % (
317 data_directory_path, new_pg_version_cluster_dir))
318 # void copying PID file to perm storage (shouldn't be any...)
319@@ -909,18 +918,19 @@
320 run(command)
321 try:
322 os.rename(data_directory_path, "%s-%d" % (
323- data_directory_path, int(time.time())))
324+ data_directory_path, int(time.time())))
325 juju_log(MSG_INFO, "NOTICE: symlinking %s -> %s" %
326- (new_pg_version_cluster_dir, data_directory_path))
327+ (new_pg_version_cluster_dir, data_directory_path))
328 os.symlink(new_pg_version_cluster_dir, data_directory_path)
329 juju_log(MSG_INFO,
330- "after-symlink: to fix/avoid UID changes from previous "
331- "units, doing: chown -R postgres:postgres %s" % new_pg_dir)
332+ "after-symlink: to fix/avoid UID changes from "
333+ "previous units, doing: "
334+ "chown -R postgres:postgres %s" % new_pg_dir)
335 run("chown -R postgres:postgres %s" % new_pg_dir)
336 return True
337 except OSError:
338 juju_log(MSG_CRITICAL, "failed to symlink \"%s\" -> \"%s\"" % (
339- data_directory_path, mount_point))
340+ data_directory_path, mount_point))
341 return False
342 else:
343 juju_log(MSG_ERROR, "ERROR: Invalid volume storage configuration, " +
344@@ -945,9 +955,9 @@
345 if mounts:
346 juju_log(MSG_INFO, "FYI current mounted volumes: %s" % mounts)
347 juju_log(MSG_ERROR,
348- "Disabled and stopped postgresql service, \
349- because of broken volume configuration - check \
350- 'volume-ephermeral-storage' and 'volume-map'")
351+ "Disabled and stopped postgresql service, "
352+ "because of broken volume configuration - check "
353+ "'volume-ephemeral-storage' and 'volume-map'")
354 sys.exit(1)
355
356 if volume_is_permanent(volid):
357@@ -963,8 +973,8 @@
358 if mounts:
359 juju_log(MSG_INFO, "FYI current mounted volumes: %s" % mounts)
360 juju_log(MSG_ERROR,
361- "Disabled and stopped postgresql service \
362- (config_changed_volume_apply failure)")
363+ "Disabled and stopped postgresql service "
364+ "(config_changed_volume_apply failure)")
365 sys.exit(1)
366 current_service_port = get_service_port(postgresql_config)
367 create_postgresql_config(postgresql_config)
368@@ -1000,7 +1010,7 @@
369 packages.extend(config_data["extra-packages"].split())
370 apt_get_install(packages)
371
372- if not local_state.has_key('state'):
373+ if not 'state' in local_state:
374 # Fresh installation. Because this function is invoked by both
375 # the install hook and the upgrade-charm hook, we need to guard
376 # any non-idempotent setup. We should probably fix this; it
377@@ -1028,9 +1038,9 @@
378 backup_job = Template(
379 open("templates/pg_backup_job.tmpl").read()).render(paths)
380 install_file(dump_script, '{}/dump-pg-db'.format(postgresql_scripts_dir),
381- mode=0755)
382+ mode=0755)
383 install_file(backup_job, '{}/pg_backup_job'.format(postgresql_scripts_dir),
384- mode=0755)
385+ mode=0755)
386 install_postgresql_crontab(postgresql_crontab)
387 open_port(5432)
388
389@@ -1043,7 +1053,7 @@
390 def upgrade_charm():
391 # Detect if we are upgrading from the old charm that used repmgr for
392 # replication.
393- from_repmgr = not local_state.has_key('juju_replication')
394+ from_repmgr = not 'juju_replication' in local_state
395
396 # Handle renaming of the repmgr user to juju_replication.
397 if from_repmgr and local_state['state'] == 'master':
398@@ -1073,16 +1083,61 @@
399 break
400
401
402+def quote_identifier(identifier):
403+ r'''Quote an identifier, such as a table or role name.
404+
405+ In SQL, identifiers are quoted using " rather than ' (which is reserved
406+ for strings).
407+
408+ >>> print(quote_identifier('hello'))
409+ "hello"
410+
411+ Quotes and Unicode are handled if you make use of them in your
412+ identifiers.
413+
414+ >>> print(quote_identifier("'"))
415+ "'"
416+ >>> print(quote_identifier('"'))
417+ """"
418+ >>> print(quote_identifier("\\"))
419+ "\"
420+ >>> print(quote_identifier('\\"'))
421+ "\"""
422+ >>> print(quote_identifier('\\ aargh \u0441\u043b\u043e\u043d'))
423+ U&"\\ aargh \0441\043b\043e\043d"
424+ '''
425+ try:
426+ return '"%s"' % identifier.encode('US-ASCII').replace('"', '""')
427+ except UnicodeEncodeError:
428+ escaped = []
429+ for c in identifier:
430+ if c == '\\':
431+ escaped.append('\\\\')
432+ elif c == '"':
433+ escaped.append('""')
434+ else:
435+ c = c.encode('US-ASCII', 'backslashreplace')
436+ # Note Python only supports 32 bit unicode, so we use
437+ # the 4 hexdigit PostgreSQL syntax (\1234) rather than
438+ # the 6 hexdigit format (\+123456).
439+ if c.startswith('\\u'):
440+ c = '\\' + c[2:]
441+ escaped.append(c)
442+ return 'U&"%s"' % ''.join(escaped)
443+
444+
445+def sanitize(s):
446+ s = s.replace(':', '_')
447+ s = s.replace('-', '_')
448+ s = s.replace('/', '_')
449+ s = s.replace('"', '_')
450+ s = s.replace("'", '_')
451+ return s
452+
453+
454 def user_name(relid, remote_unit, admin=False, schema=False):
455- def sanitize(s):
456- s = s.replace(':', '_')
457- s = s.replace('-', '_')
458- s = s.replace('/', '_')
459- s = s.replace('"', '_')
460- s = s.replace("'", '_')
461- return s
462 # Per Bug #1160530, don't append the remote unit number to the user name.
463- components = [sanitize(relid), sanitize(re.split("/",remote_unit)[0])]
464+ components = [sanitize(relid), sanitize(re.split("/", remote_unit)[0])]
465 if admin:
466 components.append("admin")
467 elif schema:
468@@ -1099,6 +1154,8 @@
469
470
471 def create_user(user, admin=False, replication=False):
472+ from psycopg2.extensions import AsIs
473+
474 password = get_password(user)
475 if password is None:
476 password = pwgen()
477@@ -1107,8 +1164,7 @@
478 action = ["ALTER ROLE"]
479 else:
480 action = ["CREATE ROLE"]
481- action.append('"{}"'.format(user))
482- action.append('WITH LOGIN')
483+ action.append('%s WITH LOGIN')
484 if admin:
485 action.append('SUPERUSER')
486 else:
487@@ -1119,11 +1175,13 @@
488 action.append('NOREPLICATION')
489 action.append('PASSWORD %s')
490 sql = ' '.join(action)
491- run_sql_as_postgres(sql, password)
492+ run_sql_as_postgres(sql, AsIs(quote_identifier(user)), password)
493 return password
494
495
496 def grant_roles(user, roles):
497+ from psycopg2.extensions import AsIs
498+
499 # Delete previous roles
500 sql = ("DELETE FROM pg_auth_members WHERE member IN ("
501 "SELECT oid FROM pg_roles WHERE rolname = %s)")
502@@ -1131,33 +1189,39 @@
503
504 for role in roles:
505 ensure_role(role)
506- sql = "GRANT {} to {}".format(role, user)
507- run_sql_as_postgres(sql)
508+ sql = "GRANT %s to %s"
509+ run_sql_as_postgres(sql, AsIs(quote_identifier(role)),
510+ AsIs(quote_identifier(user)))
511
512
513 def ensure_role(role):
514+ from psycopg2.extensions import AsIs
515+
516 sql = "SELECT oid FROM pg_roles WHERE rolname = %s"
517 if run_select_as_postgres(sql, role)[0] != 0:
518 # role already exists
519 pass
520 else:
521- sql = "CREATE ROLE {} INHERIT NOLOGIN".format(role)
522- run_sql_as_postgres(sql)
523+ sql = "CREATE ROLE %s INHERIT NOLOGIN"
524+ run_sql_as_postgres(sql, AsIs(quote_identifier(role)))
525
526
527 def ensure_database(user, schema_user, database):
528+ from psycopg2.extensions import AsIs
529+
530 sql = "SELECT datname FROM pg_database WHERE datname = %s"
531 if run_select_as_postgres(sql, database)[0] != 0:
532 # DB already exists
533 pass
534 else:
535- sql = "CREATE DATABASE {}".format(database)
536- run_sql_as_postgres(sql)
537- sql = "GRANT ALL PRIVILEGES ON DATABASE {} TO {}".format(database,
538- schema_user)
539- run_sql_as_postgres(sql)
540- sql = "GRANT CONNECT ON DATABASE {} TO {}".format(database, user)
541- run_sql_as_postgres(sql)
542+ sql = "CREATE DATABASE %s"
543+ run_sql_as_postgres(sql, AsIs(quote_identifier(database)))
544+ sql = "GRANT ALL PRIVILEGES ON DATABASE %s TO %s"
545+ run_sql_as_postgres(sql, AsIs(quote_identifier(database)),
546+ AsIs(quote_identifier(schema_user)))
547+ sql = "GRANT CONNECT ON DATABASE %s TO %s"
548+ run_sql_as_postgres(sql, AsIs(quote_identifier(database)),
549+ AsIs(quote_identifier(user)))
550
551
552 def get_relation_host():
553@@ -1189,7 +1253,9 @@
554 host = get_unit_host()
555 run("relation-set host='%s' database='%s' port='%s'" % (
556 host, database, config_data["listen_port"]))
557- generate_postgresql_hba(postgresql_hba)
558+ generate_postgresql_hba(postgresql_hba, user=user,
559+ schema_user=schema_user,
560+ database=database)
561
562
563 def db_admin_relation_joined_changed(user, database='all'):
564@@ -1204,15 +1270,20 @@
565
566
567 def db_relation_broken(user, database):
568- sql = "REVOKE ALL PRIVILEGES ON {} FROM {}".format(database, user)
569- run_sql_as_postgres(sql)
570- sql = "REVOKE ALL PRIVILEGES ON {} FROM {}_schema".format(database, user)
571- run_sql_as_postgres(sql)
572+ from psycopg2.extensions import AsIs
573+
574+ sql = "REVOKE ALL PRIVILEGES ON %s FROM %s"
575+ run_sql_as_postgres(sql, AsIs(quote_identifier(database)),
576+ AsIs(quote_identifier(user)))
577+ run_sql_as_postgres(sql, AsIs(quote_identifier(database)),
578+ AsIs(quote_identifier(user + "_schema")))
579
580
581 def db_admin_relation_broken(user):
582- sql = "ALTER USER {} NOSUPERUSER".format(user)
583- run_sql_as_postgres(sql)
584+ from psycopg2.extensions import AsIs
585+
586+ sql = "ALTER USER %s NOSUPERUSER"
587+ run_sql_as_postgres(sql, AsIs(quote_identifier(user)))
588 generate_postgresql_hba(postgresql_hba)
589
590
591@@ -1301,7 +1372,7 @@
592 if passwords:
593 pgpass = '\n'.join(
594 "*:*:*:{}:{}".format(username, password)
595- for username, password in passwords.items())
596+ for username, password in passwords.items())
597 install_file(
598 pgpass, charm_pgpass,
599 owner="postgres", group="postgres", mode=0o400)
600@@ -1528,8 +1599,8 @@
601
602 if remote_is_master and remote_has_authorized:
603 replication_password = relation['replication_password']
604- if local_state.get(
605- 'replication_password', None) != replication_password:
606+ if ((local_state.get('replication_password', None) !=
607+ replication_password)):
608 local_state['replication_password'] = replication_password
609 generate_pgpass()
610
611@@ -1601,12 +1672,10 @@
612 postgresql_stop()
613 juju_log(MSG_INFO, "Cloning master {}".format(master_unit))
614
615- cmd = [
616- 'sudo', '-E', '-u', 'postgres', # -E needed to locate pgpass file.
617- 'pg_basebackup', '-D', postgresql_cluster_dir,
618- '--xlog', '--checkpoint=fast', '--no-password',
619- '-h', master_host, '-p', '5432', '--username=juju_replication',
620- ]
621+ cmd = ['sudo', '-E', '-u', 'postgres', # -E needed to locate pgpass file.
622+ 'pg_basebackup', '-D', postgresql_cluster_dir,
623+ '--xlog', '--checkpoint=fast', '--no-password',
624+ '-h', master_host, '-p', '5432', '--username=juju_replication']
625 juju_log(MSG_DEBUG, ' '.join(cmd))
626 if os.path.isdir(postgresql_cluster_dir):
627 shutil.rmtree(postgresql_cluster_dir)
628@@ -1667,8 +1736,8 @@
629 os.path.join(postgresql_cluster_dir, 'backup_label'))
630
631
632-def postgresql_wal_received_offset(
633- host, db='postgres', user='juju_replication'):
634+def postgresql_wal_received_offset(host, db='postgres',
635+ user='juju_replication'):
636 cur = db_cursor(autocommit=True, db=db, user=user, host=host)
637 cur.execute('SELECT pg_is_in_recovery(), pg_last_xlog_receive_location()')
638 is_in_recovery, xlog_received = cur.fetchone()
639@@ -1713,8 +1782,8 @@
640 # --- exported service configuration file
641 from jinja2 import Environment, FileSystemLoader
642 template_env = Environment(
643- loader=FileSystemLoader(os.path.join(os.environ['CHARM_DIR'],
644- 'templates')))
645+ loader=FileSystemLoader(
646+ os.path.join(os.environ['CHARM_DIR'], 'templates')))
647 templ_vars = {
648 'nagios_hostname': nagios_hostname,
649 'nagios_servicegroup': config_data['nagios_context'],
650@@ -1730,11 +1799,11 @@
651 with open(nrpe_check_file, 'w') as nrpe_check_config:
652 nrpe_check_config.write("# check pgsql\n")
653 nrpe_check_config.write(
654- "command[check_pgsql]=/usr/lib/nagios/plugins/check_pgsql -p {}"
655+ "command[check_pgsql]=/usr/lib/nagios/plugins/check_pgsql -P {}"
656 .format(config_data['listen_port']))
657 # pgsql backups
658 nrpe_check_file = '/etc/nagios/nrpe.d/check_pgsql_backups.cfg'
659- backup_log = "%s/backups.log".format(postgresql_logs_dir)
660+ backup_log = "{}/backups.log".format(postgresql_logs_dir)
661 # XXX: these values _should_ be calculated from the backup schedule
662 # perhaps warn = backup_frequency * 1.5, crit = backup_frequency * 2
663 warn_age = 172800
664@@ -1765,12 +1834,15 @@
665 postgresql_crontab = "/etc/cron.d/postgresql"
666 postgresql_service_config_dir = "/var/run/postgresql"
667 postgresql_scripts_dir = os.path.join(postgresql_data_dir, 'scripts')
668-postgresql_backups_dir = os.path.join(postgresql_data_dir, 'backups')
669+postgresql_backups_dir = (
670+ config_data['backup_dir'].strip() or
671+ os.path.join(postgresql_data_dir, 'backups'))
672 postgresql_logs_dir = os.path.join(postgresql_data_dir, 'logs')
673 postgres_ssh_dir = os.path.expanduser('~postgres/.ssh')
674 postgres_ssh_public_key = os.path.join(postgres_ssh_dir, 'id_rsa.pub')
675 postgres_ssh_private_key = os.path.join(postgres_ssh_dir, 'id_rsa')
676-postgres_ssh_authorized_keys = os.path.join(postgres_ssh_dir, 'authorized_keys')
677+postgres_ssh_authorized_keys = os.path.join(postgres_ssh_dir,
678+ 'authorized_keys')
679 postgres_ssh_known_hosts = os.path.join(postgres_ssh_dir, 'known_hosts')
680 hook_name = os.path.basename(sys.argv[0])
681 replication_relation_types = ['master', 'slave', 'replication']
682@@ -1829,7 +1901,9 @@
683 database = relation_get('database', os.environ['JUJU_UNIT_NAME'])
684
685 user = relation_get('user', os.environ['JUJU_UNIT_NAME'])
686- assert user, 'user not set'
687+ if not user:
688+ user = user_name(
689+ os.environ['JUJU_RELATION_ID'], os.environ['JUJU_REMOTE_UNIT'])
690 db_relation_joined_changed(user, database, roles)
691
692 elif hook_name == "db-relation-broken":
693@@ -1838,31 +1912,31 @@
694 os.environ['JUJU_RELATION_ID'], os.environ['JUJU_REMOTE_UNIT'])
695 db_relation_broken(user, database)
696
697- elif hook_name in [
698- "db-admin-relation-joined", "db-admin-relation-changed"]:
699+ elif hook_name in ("db-admin-relation-joined",
700+ "db-admin-relation-changed"):
701 user = user_name(os.environ['JUJU_RELATION_ID'],
702- os.environ['JUJU_REMOTE_UNIT'], admin=True)
703+ os.environ['JUJU_REMOTE_UNIT'], admin=True)
704 db_admin_relation_joined_changed(user, 'all')
705
706 elif hook_name == "db-admin-relation-broken":
707 # XXX: Fix: relation is not set when it is already broken
708 # cannot determine the user name
709 user = user_name(os.environ['JUJU_RELATION_ID'],
710- os.environ['JUJU_REMOTE_UNIT'], admin=True)
711+ os.environ['JUJU_REMOTE_UNIT'], admin=True)
712 db_admin_relation_broken(user)
713
714 elif hook_name == "nrpe-external-master-relation-changed":
715 update_nrpe_checks()
716
717- elif hook_name in (
718- 'master-relation-joined', 'master-relation-changed',
719- 'slave-relation-joined', 'slave-relation-changed',
720- 'replication-relation-joined', 'replication-relation-changed'):
721+ elif hook_name in ('master-relation-joined', 'master-relation-changed',
722+ 'slave-relation-joined', 'slave-relation-changed',
723+ 'replication-relation-joined',
724+ 'replication-relation-changed'):
725 replication_relation_changed()
726
727- elif hook_name in (
728- 'master-relation-broken', 'slave-relation-broken',
729- 'replication-relation-broken', 'replication-relation-departed'):
730+ elif hook_name in ('master-relation-broken', 'slave-relation-broken',
731+ 'replication-relation-broken',
732+ 'replication-relation-departed'):
733 replication_relation_broken()
734
735 #-------- persistent-storage-relation-joined,
736
737=== removed file 'revision'
738--- revision 2013-04-15 11:50:30 +0000
739+++ revision 1970-01-01 00:00:00 +0000
740@@ -1,1 +0,0 @@
741-27
742
743=== modified file 'templates/pg_hba.conf.tmpl'
744--- templates/pg_hba.conf.tmpl 2013-02-22 12:02:45 +0000
745+++ templates/pg_hba.conf.tmpl 2013-04-24 03:09:24 +0000
746@@ -4,6 +4,7 @@
747
748 # Database administrative login by UNIX sockets
749 local all postgres ident map=superusers
750+local all nagios md5
751
752 {% if access_list is defined -%}
753 {% for unit in access_list -%}
754
755=== modified file 'templates/postgres.cron.tmpl'
756--- templates/postgres.cron.tmpl 2012-10-16 19:03:17 +0000
757+++ templates/postgres.cron.tmpl 2013-04-24 03:09:24 +0000
758@@ -1,1 +1,2 @@
759 {{backup_schedule}} postgres {{scripts_dir}}/pg_backup_job {{backup_days}}
760+

Subscribers

People subscribed via source and target branches