Merge lp:~jjo/charms/precise/postgresql/support-no-explicit-version_and_trusty-pg93 into lp:charms/postgresql

Proposed by JuanJo Ciarlante
Status: Merged
Merged at revision: 80
Proposed branch: lp:~jjo/charms/precise/postgresql/support-no-explicit-version_and_trusty-pg93
Merge into: lp:charms/postgresql
Diff against target: 247 lines (+73/-22)
3 files modified
config.yaml (+1/-1)
hooks/hooks.py (+68/-21)
templates/postgresql.conf.tmpl (+4/-0)
To merge this branch: bzr merge lp:~jjo/charms/precise/postgresql/support-no-explicit-version_and_trusty-pg93
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
James Troup (community) Approve
Review via email: mp+202076@code.launchpad.net

Commit message

- support deploying with version unset in config.yaml (new default)
- add pg_version(): if no explicit version set, find it from apt.Cache() install-able candidate, save it in local_state later usage.
- add support for postgresql>=9.3 (trusty): deprecated unix_socket_directory in favor of unix_socket_directories (list)
- move ssl cert symlinking into create_ssl_cert()

To post a comment you must log in.
81. By JuanJo Ciarlante

add some logging

Revision history for this message
James Troup (elmo) wrote :

Trivial: 'canditate' should be 'candidate' throughout.

pg_version() makes several assumptions (e.g. that a postgresql package
exists and that it's version matches a specific regex (which won't be
the case if, e.g. the package grows an epoch) that are probably fine,
but it caught my eye.

| + # expensive operation, save it

What operation does this refer to? The function as a whole?

82. By JuanJo Ciarlante

s/canditate/candidate/, clarify apt.Cache being the expensive op

Revision history for this message
JuanJo Ciarlante (jjo) wrote :

> Trivial: 'canditate' should be 'candidate' throughout.

thanks for spotting, fixed.

>
> pg_version() makes several assumptions (e.g. that a postgresql package
> exists and that it's version matches a specific regex (which won't be
> the case if, e.g. the package grows an epoch) that are probably fine,
> but it caught my eye.

I found this the less painful way to find out which "short-version"
($major.$minor) is available.

>
> | + # expensive operation, save it
>
> What operation does this refer to? The function as a whole?

apt.Cache(), I clarified the comment there.

Revision history for this message
James Troup (elmo) wrote :

+1

review: Approve
Revision history for this message
Stuart Bishop (stub) wrote :

I don't think allowing an unspecified PostgreSQL version is a good idea. It means charm deployment is not repeatable, as which version is deployed depends on the state of the archive. I don't want 9.4 (or worse, 9.4 beta) being installed when my apps are tested with 9.3 just because a newer version is available in the archive. This would also break replication, as a unit does not know what version the other units in the service are using until after the install hook is run and the unit attempt's to join the service's peer relation. Archives will not always be under user control, in particular apt.postgresql.org for official Debian and Ubuntu backports.

If we really need this so the default version under trusty is 9.3, and the default version under precise is 9.1, I think we just want to check 'lsb_release -sc' and hard code the default version to the codename. This may still cause surprises, but would be repeatable.

If we keep the 'apt' import, do we need to add python-apt to the default list of packages to install?

review: Needs Fixing
Revision history for this message
JuanJo Ciarlante (jjo) wrote :

> I don't think allowing an unspecified PostgreSQL version is a good idea. It
> means charm deployment is not repeatable, as which version is deployed depends
> on the state of the archive. I don't want 9.4 (or worse, 9.4 beta) being
> installed when my apps are tested with 9.3 just because a newer version is
> available in the archive. This would also break replication, as a unit does
> not know what version the other units in the service are using until after the
> install hook is run and the unit attempt's to join the service's peer
> relation. Archives will not always be under user control, in particular
> apt.postgresql.org for official Debian and Ubuntu backports.
>
> If we really need this so the default version under trusty is 9.3, and the
> default version under precise is 9.1, I think we just want to check
> 'lsb_release -sc' and hard code the default version to the codename. This may
> still cause surprises, but would be repeatable.

I'm fine with hardcoding it, as far as we have a single charm that can be
deployed to either precise,trusty without requiring the user to overload
the config with a version that's already well-known/mapped for this distro
release.

>
> If we keep the 'apt' import, do we need to add python-apt to the default list
> of packages to install?

Good point, fwiw afaicT both precise,trusty it was already installed there.

83. By JuanJo Ciarlante

hardcode pg_version map by (LTS) distro release

Revision history for this message
JuanJo Ciarlante (jjo) wrote :

Thanks stub for the review, PTAL (CID testing case against precise,trusty running atm, will let you know once it finishes, ETA: ~+1.5hr).

Revision history for this message
Stuart Bishop (stub) wrote :

This no longer worries me and looks good.

review: Approve
84. By JuanJo Ciarlante

need to: distro_release.rstrip()

85. By JuanJo Ciarlante

move rstrip above, let distro_release value "clean" from there

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2014-01-07 19:00:20 +0000
+++ config.yaml 2014-01-21 12:55:42 +0000
@@ -43,7 +43,7 @@
43 access details are updated, so disabling either doesn't mean PostgreSQL43 access details are updated, so disabling either doesn't mean PostgreSQL
44 will never be reloaded.44 will never be reloaded.
45 version:45 version:
46 default: "9.1"46 default: ""
47 type: string47 type: string
48 description: Version of PostgreSQL that we want to install48 description: Version of PostgreSQL that we want to install
49 cluster_name:49 cluster_name:
5050
=== modified file 'hooks/hooks.py'
--- hooks/hooks.py 2014-01-09 09:08:11 +0000
+++ hooks/hooks.py 2014-01-21 12:55:42 +0000
@@ -53,6 +53,39 @@
53 hookenv.log(msg, lvl)53 hookenv.log(msg, lvl)
5454
5555
56def pg_version():
57 '''Return pg_version to use.
58
59 Return "version" config item if set, else use version from "postgresql"
60 package candidate, saving it in local_state for later.
61 '''
62 config_data = hookenv.config()
63 if config_data['version']:
64 version = config_data['version']
65 elif 'pg_version' in local_state:
66 version = local_state['pg_version']
67 else:
68 log("map version from distro release ...")
69 distro_release = run("lsb_release -sc")
70 distro_release = distro_release.rstrip()
71 version_map = {'precise': '9.1',
72 'trusty': '9.3'}
73 version = version_map.get(distro_release)
74 if not version:
75 log("No PG version map for distro_release={}, "
76 "you'll need to explicitly set it".format(distro_release),
77 CRITICAL)
78 sys.exit(1)
79 log("version={} from distro_release='{}'".format(
80 version, distro_release))
81 # save it for later
82 local_state.setdefault('pg_version', version)
83 local_state.save()
84
85 assert version, "pg_version couldn't find a version to use"
86 return version
87
88
56class State(dict):89class State(dict):
57 """Encapsulate state common to the unit for republishing to relations."""90 """Encapsulate state common to the unit for republishing to relations."""
58 def __init__(self, state_file):91 def __init__(self, state_file):
@@ -230,7 +263,7 @@
230 if status != 0:263 if status != 0:
231 return False264 return False
232 # e.g. output: "Running clusters: 9.1/main"265 # e.g. output: "Running clusters: 9.1/main"
233 vc = "%s/%s" % (hookenv.config("version"), hookenv.config("cluster_name"))266 vc = "%s/%s" % (pg_version(), hookenv.config("cluster_name"))
234 return vc in output.decode('utf8').split()267 return vc in output.decode('utf8').split()
235268
236269
@@ -253,8 +286,9 @@
253 # 'service postgresql restart' fails; it only does a reload.286 # 'service postgresql restart' fails; it only does a reload.
254 # success = host.service_restart('postgresql')287 # success = host.service_restart('postgresql')
255 try:288 try:
256 run('pg_ctlcluster -force {version} {cluster_name} '289 run('pg_ctlcluster -force {} {} '
257 'restart'.format(**hookenv.config()))290 'restart'.format(pg_version(),
291 hookenv.config('cluster_name')))
258 success = True292 success = True
259 except subprocess.CalledProcessError:293 except subprocess.CalledProcessError:
260 success = False294 success = False
@@ -405,6 +439,8 @@
405 # Return it as pg_config439 # Return it as pg_config
406 charm_dir = hookenv.charm_dir()440 charm_dir = hookenv.charm_dir()
407 template_file = "{}/templates/postgresql.conf.tmpl".format(charm_dir)441 template_file = "{}/templates/postgresql.conf.tmpl".format(charm_dir)
442 if not config_data['version']:
443 config_data['version'] = pg_version()
408 pg_config = Template(444 pg_config = Template(
409 open(template_file).read()).render(config_data)445 open(template_file).read()).render(config_data)
410 host.write_file(446 host.write_file(
@@ -580,7 +616,7 @@
580616
581617
582def create_recovery_conf(master_host, restart_on_change=False):618def create_recovery_conf(master_host, restart_on_change=False):
583 version = hookenv.config('version')619 version = pg_version()
584 cluster_name = hookenv.config('cluster_name')620 cluster_name = hookenv.config('cluster_name')
585 postgresql_cluster_dir = os.path.join(621 postgresql_cluster_dir = os.path.join(
586 postgresql_data_dir, version, cluster_name)622 postgresql_data_dir, version, cluster_name)
@@ -632,6 +668,18 @@
632 hookenv.open_port(new_service_port)668 hookenv.open_port(new_service_port)
633669
634670
671def create_ssl_cert(cluster_dir):
672 # Debian by default expects SSL certificates in the datadir.
673 server_crt = os.path.join(cluster_dir, 'server.crt')
674 server_key = os.path.join(cluster_dir, 'server.key')
675 if not os.path.exists(server_crt):
676 os.symlink('/etc/ssl/certs/ssl-cert-snakeoil.pem',
677 server_crt)
678 if not os.path.exists(server_key):
679 os.symlink('/etc/ssl/private/ssl-cert-snakeoil.key',
680 server_key)
681
682
635def set_password(user, password):683def set_password(user, password):
636 if not os.path.isdir("passwords"):684 if not os.path.isdir("passwords"):
637 os.makedirs("passwords")685 os.makedirs("passwords")
@@ -711,7 +759,7 @@
711# - manipulate /var/lib/postgresql/VERSION/CLUSTER symlink759# - manipulate /var/lib/postgresql/VERSION/CLUSTER symlink
712#------------------------------------------------------------------------------760#------------------------------------------------------------------------------
713def config_changed_volume_apply():761def config_changed_volume_apply():
714 version = hookenv.config('version')762 version = pg_version()
715 cluster_name = hookenv.config('cluster_name')763 cluster_name = hookenv.config('cluster_name')
716 data_directory_path = os.path.join(764 data_directory_path = os.path.join(
717 postgresql_data_dir, version, cluster_name)765 postgresql_data_dir, version, cluster_name)
@@ -820,7 +868,7 @@
820@hooks.hook()868@hooks.hook()
821def config_changed(force_restart=False):869def config_changed(force_restart=False):
822 config_data = hookenv.config()870 config_data = hookenv.config()
823 update_repos_and_packages(config_data["version"])871 update_repos_and_packages()
824872
825 # Trigger volume initialization logic for permanent storage873 # Trigger volume initialization logic for permanent storage
826 volid = volume_get_volume_id()874 volid = volume_get_volume_id()
@@ -862,6 +910,8 @@
862 create_postgresql_config(postgresql_config)910 create_postgresql_config(postgresql_config)
863 generate_postgresql_hba(postgresql_hba)911 generate_postgresql_hba(postgresql_hba)
864 create_postgresql_ident(postgresql_ident)912 create_postgresql_ident(postgresql_ident)
913 create_ssl_cert(os.path.join(
914 postgresql_data_dir, pg_version(), config_data['cluster_name']))
865915
866 updated_service_port = config_data["listen_port"]916 updated_service_port = config_data["listen_port"]
867 update_service_port(current_service_port, updated_service_port)917 update_service_port(current_service_port, updated_service_port)
@@ -879,7 +929,7 @@
879 subprocess.check_call(['sh', '-c', f])929 subprocess.check_call(['sh', '-c', f])
880930
881 config_data = hookenv.config()931 config_data = hookenv.config()
882 update_repos_and_packages(config_data["version"])932 update_repos_and_packages()
883 if not 'state' in local_state:933 if not 'state' in local_state:
884 # Fresh installation. Because this function is invoked by both934 # Fresh installation. Because this function is invoked by both
885 # the install hook and the upgrade-charm hook, we need to guard935 # the install hook and the upgrade-charm hook, we need to guard
@@ -890,9 +940,10 @@
890940
891 # Drop the cluster created when the postgresql package was941 # Drop the cluster created when the postgresql package was
892 # installed, and rebuild it with the requested locale and encoding.942 # installed, and rebuild it with the requested locale and encoding.
893 run("pg_dropcluster --stop 9.1 main")943 version = pg_version()
894 run("pg_createcluster --locale='{}' --encoding='{}' 9.1 main".format(944 run("pg_dropcluster --stop {} main".format(version))
895 config_data['locale'], config_data['encoding']))945 run("pg_createcluster --locale='{}' --encoding='{}' {} main".format(
946 config_data['locale'], config_data['encoding'], version))
896947
897 postgresql_backups_dir = (948 postgresql_backups_dir = (
898 config_data['backup_dir'].strip() or949 config_data['backup_dir'].strip() or
@@ -1322,7 +1373,7 @@
1322 snapshot_relations()1373 snapshot_relations()
13231374
13241375
1325def update_repos_and_packages(version):1376def update_repos_and_packages():
1326 extra_repos = hookenv.config('extra_archives')1377 extra_repos = hookenv.config('extra_archives')
1327 extra_repos_added = local_state.setdefault('extra_repos_added', set())1378 extra_repos_added = local_state.setdefault('extra_repos_added', set())
1328 if extra_repos:1379 if extra_repos:
@@ -1336,6 +1387,7 @@
1336 fetch.apt_update(fatal=True)1387 fetch.apt_update(fatal=True)
1337 local_state.save()1388 local_state.save()
13381389
1390 version = pg_version()
1339 # It might have been better for debversion and plpython to only get1391 # It might have been better for debversion and plpython to only get
1340 # installed if they were listed in the extra-packages config item,1392 # installed if they were listed in the extra-packages config item,
1341 # but they predate this feature.1393 # but they predate this feature.
@@ -1409,7 +1461,7 @@
1409def promote_database():1461def promote_database():
1410 '''Take the database out of recovery mode.'''1462 '''Take the database out of recovery mode.'''
1411 config_data = hookenv.config()1463 config_data = hookenv.config()
1412 version = config_data['version']1464 version = pg_version()
1413 cluster_name = config_data['cluster_name']1465 cluster_name = config_data['cluster_name']
1414 postgresql_cluster_dir = os.path.join(1466 postgresql_cluster_dir = os.path.join(
1415 postgresql_data_dir, version, cluster_name)1467 postgresql_data_dir, version, cluster_name)
@@ -1814,7 +1866,7 @@
1814 log("Cloning master {}".format(master_unit))1866 log("Cloning master {}".format(master_unit))
18151867
1816 config_data = hookenv.config()1868 config_data = hookenv.config()
1817 version = config_data['version']1869 version = pg_version()
1818 cluster_name = config_data['cluster_name']1870 cluster_name = config_data['cluster_name']
1819 postgresql_cluster_dir = os.path.join(1871 postgresql_cluster_dir = os.path.join(
1820 postgresql_data_dir, version, cluster_name)1872 postgresql_data_dir, version, cluster_name)
@@ -1837,12 +1889,7 @@
1837 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)1889 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
1838 log(output, DEBUG)1890 log(output, DEBUG)
1839 # Debian by default expects SSL certificates in the datadir.1891 # Debian by default expects SSL certificates in the datadir.
1840 os.symlink(1892 create_ssl_cert(postgresql_cluster_dir)
1841 '/etc/ssl/certs/ssl-cert-snakeoil.pem',
1842 os.path.join(postgresql_cluster_dir, 'server.crt'))
1843 os.symlink(
1844 '/etc/ssl/private/ssl-cert-snakeoil.key',
1845 os.path.join(postgresql_cluster_dir, 'server.key'))
1846 create_recovery_conf(master_host)1893 create_recovery_conf(master_host)
1847 except subprocess.CalledProcessError as x:1894 except subprocess.CalledProcessError as x:
1848 # We failed, and this cluster is broken. Rebuild a1895 # We failed, and this cluster is broken. Rebuild a
@@ -1872,7 +1919,7 @@
18721919
18731920
1874def postgresql_is_in_backup_mode():1921def postgresql_is_in_backup_mode():
1875 version = hookenv.config('version')1922 version = pg_version()
1876 cluster_name = hookenv.config('cluster_name')1923 cluster_name = hookenv.config('cluster_name')
1877 postgresql_cluster_dir = os.path.join(1924 postgresql_cluster_dir = os.path.join(
1878 postgresql_data_dir, version, cluster_name)1925 postgresql_data_dir, version, cluster_name)
@@ -1998,7 +2045,7 @@
1998 """ Return the directory path of the postgresql configuration files. """2045 """ Return the directory path of the postgresql configuration files. """
1999 if config_data is None:2046 if config_data is None:
2000 config_data = hookenv.config()2047 config_data = hookenv.config()
2001 version = config_data['version']2048 version = pg_version()
2002 cluster_name = config_data['cluster_name']2049 cluster_name = config_data['cluster_name']
2003 return os.path.join("/etc/postgresql", version, cluster_name)2050 return os.path.join("/etc/postgresql", version, cluster_name)
20042051
20052052
=== modified file 'templates/postgresql.conf.tmpl'
--- templates/postgresql.conf.tmpl 2014-01-02 22:50:28 +0000
+++ templates/postgresql.conf.tmpl 2014-01-21 12:55:42 +0000
@@ -17,7 +17,11 @@
17# CONNECTIONS AND AUTHENTICATION17# CONNECTIONS AND AUTHENTICATION
18#------------------------------------------------------------------------------18#------------------------------------------------------------------------------
1919
20{% if version >= "9.3" -%}
21unix_socket_directories = '/var/run/postgresql'
22{% else -%}
20unix_socket_directory = '/var/run/postgresql'23unix_socket_directory = '/var/run/postgresql'
24{% endif -%}
2125
22{% if listen_ip != "" -%}26{% if listen_ip != "" -%}
23listen_addresses = '{{listen_ip}}'27listen_addresses = '{{listen_ip}}'

Subscribers

People subscribed via source and target branches