예제 #1
0
def uninhibit_default_cluster_creation():
    '''Undo inhibit_default_cluster_creation() so manual creation works.'''
    hookenv.log('Removing inhibitions')
    path = postgresql.postgresql_conf_path()
    with open(path, 'r') as f:
        assert f.read() == '# Inhibited', 'Default cluster inhibition failed'
    os.unlink(postgresql.postgresql_conf_path())
    reactive.remove_state('postgresql.cluster.inhibited')
예제 #2
0
def create_cluster():
    '''Sets the postgresql.cluster.created state.'''
    assert not os.path.exists(postgresql.postgresql_conf_path()), \
        'inhibit_default_cluster_creation() failed'
    assert not os.path.exists(postgresql.data_dir())
    postgresql.create_cluster()
    reactive.set_state('postgresql.cluster.created')
예제 #3
0
def main():
    if not (reactive.is_state("postgresql.cluster.created") or reactive.is_state("postgresql.cluster.initial-check")):
        # We need to check for existance of an existing database,
        # before the main PostgreSQL package has been installed.
        # If there is one, abort rather than risk destroying data.
        # We need to do this here, as the apt layer may pull in
        # the main PostgreSQL package through dependencies, per
        # lp:1749284
        if os.path.exists(postgresql.postgresql_conf_path()):
            hookenv.status_set(
                "blocked",
                "PostgreSQL config from previous install found at {}".format(postgresql.postgresql_conf_path()),
            )
        elif os.path.exists(postgresql.data_dir()):
            hookenv.status_set(
                "blocked",
                "PostgreSQL database from previous install found at {}".format(postgresql.postgresql.data_dir()),
            )
        else:
            hookenv.log("No pre-existing PostgreSQL database found")
            reactive.set_state("postgresql.cluster.initial-check")

    # Don't trust this state from the last hook. Daemons may have
    # crashed and servers rebooted since then.
    if reactive.is_state("postgresql.cluster.created"):
        try:
            reactive.toggle_state("postgresql.cluster.is_running", postgresql.is_running())
        except subprocess.CalledProcessError as x:
            if not reactive.is_state("workloadstatus.blocked"):
                status_set(
                    "blocked",
                    "Local PostgreSQL cluster is corrupt: {}".format(x.stderr),
                )

    # Reconfigure PostgreSQL. While we don't strictly speaking need
    # to do this every hook, we do need to do this almost every hook,
    # since even things like the number of peers or number of clients
    # can affect minimum viable configuration settings.
    reactive.remove_state("postgresql.cluster.configured")

    log_states()  # Debug noise.
예제 #4
0
 def test_simple_paths(self, version):
     # We have a pile of trivial helpers to get directory and file
     # paths. We use these for consistency and ease of mocking.
     version.return_value = "9.9"
     self.assertEqual(postgresql.config_dir(), "/etc/postgresql/9.9/main")
     self.assertEqual(postgresql.data_dir(), "/var/lib/postgresql/9.9/main")
     self.assertEqual(postgresql.postgresql_conf_path(), "/etc/postgresql/9.9/main/postgresql.conf")
     self.assertEqual(postgresql.pg_hba_conf_path(), "/etc/postgresql/9.9/main/pg_hba.conf")
     self.assertEqual(postgresql.pg_ident_conf_path(), "/etc/postgresql/9.9/main/pg_ident.conf")
     self.assertEqual(postgresql.recovery_conf_path(), "/var/lib/postgresql/9.9/main/recovery.conf")
     self.assertEqual(postgresql.pg_ctl_path(), "/usr/lib/postgresql/9.9/bin/pg_ctl")
     self.assertEqual(postgresql.postgres_path(), "/usr/lib/postgresql/9.9/bin/postgres")
예제 #5
0
def update_postgresql_conf():
    settings = assemble_postgresql_conf()
    path = postgresql.postgresql_conf_path()

    with open(path, "r") as f:
        pg_conf = f.read()

    start_mark = "### BEGIN JUJU SETTINGS ###"
    end_mark = "### END JUJU SETTINGS ###"

    # Strip the existing settings section, including the markers.
    pg_conf = re.sub(
        r"^\s*{}.*^\s*{}\s*$".format(re.escape(start_mark), re.escape(end_mark)),
        "",
        pg_conf,
        flags=re.I | re.M | re.DOTALL,
    )

    for k in settings:
        # Comment out conflicting options. We could just allow later
        # options to override earlier ones, but this is less surprising.
        pg_conf = re.sub(
            r"^\s*({}[\s=].*)$".format(re.escape(k)),
            r"# juju # \1",
            pg_conf,
            flags=re.M | re.I,
        )

    # Store the updated charm options. This is compared with the
    # live config to detect if a restart is required.
    store = unitdata.kv()
    current_prefix = "postgresql.cluster.pgconf.current."
    store.unsetrange(prefix=current_prefix)
    store.update(settings, prefix=current_prefix)

    # Generate the charm config section, adding it to the end of the
    # config file.
    simple_re = re.compile(r"^[-.\w]+$")
    override_section = [start_mark]
    for k, v in settings.items():
        v = str(v)
        assert "\n" not in v, "Invalid config value {!r}".format(v)
        if simple_re.search(v) is None:
            v = "'{}'".format(v.replace("'", "''"))
        override_section.append("{} = {}".format(k, v))
    if postgresql.has_version("12"):
        override_section.append("include_if_exists '{}'".format(postgresql.hot_standby_conf_path()))
    override_section.append(end_mark)
    pg_conf += "\n" + "\n".join(override_section)

    helpers.rewrite(path, pg_conf)
예제 #6
0
 def test_simple_paths(self, version):
     # We have a pile of trivial helpers to get directory and file
     # paths. We use these for consistency and ease of mocking.
     version.return_value = '9.9'
     self.assertEqual(postgresql.config_dir(), '/etc/postgresql/9.9/main')
     self.assertEqual(postgresql.data_dir(), '/var/lib/postgresql/9.9/main')
     self.assertEqual(postgresql.postgresql_conf_path(),
                      '/etc/postgresql/9.9/main/postgresql.conf')
     self.assertEqual(postgresql.pg_hba_conf_path(),
                      '/etc/postgresql/9.9/main/pg_hba.conf')
     self.assertEqual(postgresql.pg_ident_conf_path(),
                      '/etc/postgresql/9.9/main/pg_ident.conf')
     self.assertEqual(postgresql.recovery_conf_path(),
                      '/var/lib/postgresql/9.9/main/recovery.conf')
     self.assertEqual(postgresql.pg_ctl_path(),
                      '/usr/lib/postgresql/9.9/bin/pg_ctl')
     self.assertEqual(postgresql.postgres_path(),
                      '/usr/lib/postgresql/9.9/bin/postgres')
예제 #7
0
def update_postgresql_conf():
    settings = assemble_postgresql_conf()
    path = postgresql.postgresql_conf_path()

    with open(path, 'r') as f:
        pg_conf = f.read()

    start_mark = '### BEGIN JUJU SETTINGS ###'
    end_mark = '### END JUJU SETTINGS ###'

    # Strip the existing settings section, including the markers.
    pg_conf = re.sub(r'^\s*{}.*^\s*{}\s*$'.format(re.escape(start_mark),
                                                  re.escape(end_mark)),
                     '', pg_conf, flags=re.I | re.M | re.DOTALL)

    for k in settings:
        # Comment out conflicting options. We could just allow later
        # options to override earlier ones, but this is less surprising.
        pg_conf = re.sub(r'^\s*({}[\s=].*)$'.format(re.escape(k)),
                         r'# juju # \1', pg_conf, flags=re.M | re.I)

    # Store the updated charm options. This is compared with the
    # live config to detect if a restart is required.
    store = unitdata.kv()
    current_prefix = 'postgresql.cluster.pgconf.current.'
    store.unsetrange(prefix=current_prefix)
    store.update(settings, prefix=current_prefix)

    # Generate the charm config section, adding it to the end of the
    # config file.
    simple_re = re.compile(r'^[-.\w]+$')
    override_section = [start_mark]
    for k, v in settings.items():
        v = str(v)
        assert '\n' not in v, "Invalid config value {!r}".format(v)
        if simple_re.search(v) is None:
            v = "'{}'".format(v.replace("'", "''"))
        override_section.append('{} = {}'.format(k, v))
    override_section.append(end_mark)
    pg_conf += '\n' + '\n'.join(override_section)

    helpers.rewrite(path, pg_conf)
예제 #8
0
def inhibit_default_cluster_creation():
    '''Stop the PostgreSQL packages from creating the default cluster.

    We can't use the default cluster as it is likely created with an
    incorrect locale and without options such as data checksumming.
    We could just delete it, but then we need to be able to tell between
    an existing cluster whose data should be preserved and a freshly
    created empty cluster. And why waste time creating it in the first
    place?
    '''
    hookenv.log('Inhibiting PostgreSQL packages from creating default cluster')
    path = postgresql.postgresql_conf_path()
    if os.path.exists(path) and open(path, 'r').read():
        status_set('blocked', 'postgresql.conf already exists')
    else:
        hookenv.log('Inhibiting', DEBUG)
        os.makedirs(os.path.dirname(path), mode=0o755, exist_ok=True)
        with open(path, 'w') as f:
            f.write('# Inhibited')
        reactive.set_state('postgresql.cluster.inhibited')