7
from textwrap import dedent
9
from charmhelpers.core import hookenv, host
10
from charmhelpers.core.hookenv import log, DEBUG, INFO
11
from charmhelpers import fetch
14
CLIENT_RELATION_TYPES = frozenset(['db', 'db-admin'])
16
DATA_DIR = os.path.join(
17
'/var/lib/units', hookenv.local_unit().replace('/', '-'))
18
SCRIPT_DIR = os.path.join(DATA_DIR, 'bin')
19
PGPASS_DIR = os.path.join(DATA_DIR, 'pgpass')
22
def update_system_path():
23
org_lines = open('/etc/environment', 'rb').readlines()
26
for line in org_lines:
27
if line.startswith('PATH=') and SCRIPT_DIR not in line:
30
":{}\\1".format(SCRIPT_DIR),
32
env_lines.append(line)
34
if org_lines != env_lines:
35
content = '\n'.join(env_lines)
36
host.write_file('/etc/environment', content, perms=0o644)
39
def all_relations(relation_types=CLIENT_RELATION_TYPES):
40
for reltype in relation_types:
41
for relid in hookenv.relation_ids(reltype):
42
for unit in hookenv.related_units(relid):
43
yield reltype, relid, unit, hookenv.relation_get(
47
def rebuild_all_relations():
48
config = hookenv.config()
50
# Clear out old scripts and pgpass files
51
if os.path.exists(SCRIPT_DIR):
52
shutil.rmtree(SCRIPT_DIR)
53
if os.path.exists(PGPASS_DIR):
54
shutil.rmtree(PGPASS_DIR)
55
host.mkdir(DATA_DIR, perms=0o755)
56
host.mkdir(SCRIPT_DIR, perms=0o755)
57
host.mkdir(PGPASS_DIR, group='ubuntu', perms=0o750)
59
for _, relid, unit, relation in all_relations(relation_types=['db']):
60
log("{} {} {!r}".format(relid, unit, relation), DEBUG)
63
if config['database'] != relation.get('database', ''):
64
log("Switching from database {} to {}".format(
65
relation.get('database', '') or def_str,
66
config['database'] or def_str), INFO)
68
if config['roles'] != relation.get('roles', ''):
69
log("Updating granted roles from {} to {}".format(
70
relation.get('roles', '') or def_str,
71
config['roles'] or def_str))
74
relid, database=config['database'], roles=config['roles'])
76
if 'user' in relation:
77
rebuild_relation(relid, unit, relation)
79
for _, relid, unit, relation in all_relations(relation_types=['db-admin']):
80
log("{} {} {!r}".format(relid, unit, relation), DEBUG)
81
if 'user' in relation:
82
rebuild_relation(relid, unit, relation)
85
def rebuild_relation(relid, unit, relation):
86
relname = relid.split(':')[0]
87
unitname = unit.replace('/', '-')
88
this_unit = hookenv.local_unit()
90
allowed_units = relation.get('allowed-units', '')
91
if this_unit not in allowed_units.split():
92
log("Not yet authorized on {}".format(relid), INFO)
95
script_name = 'psql-{}-{}'.format(relname, unitname)
96
build_script(script_name, relation)
97
state = relation.get('state', None)
98
if state in ('master', 'hot standby'):
99
script_name = 'psql-{}-{}'.format(relname, state.replace(' ', '-'))
100
build_script(script_name, relation)
103
def build_script(script_name, relation):
104
# Install a wrapper to psql that connects it to the desired database
105
# by default. One wrapper per unit per relation.
106
script_path = os.path.abspath(os.path.join(SCRIPT_DIR, script_name))
107
pgpass_path = os.path.abspath(os.path.join(PGPASS_DIR, script_name))
111
PGHOST={host} PGPORT={port} PGDATABASE={database} \\
112
PGUSER={user} PGPASSFILE={pgpass} \\
115
host=relation['host'],
116
port=relation['port'],
117
database=relation.get('database', ''), # db-admin has no database
118
user=relation['user'],
120
log("Generating wrapper {}".format(script_path), INFO)
122
script_path, script, owner="ubuntu", group="ubuntu", perms=0o700)
124
# The wrapper requires access to the password, stored in a .pgpass
125
# file so it isn't exposed in an environment variable or on the
127
pgpass = "*:*:*:{user}:{password}".format(
128
user=relation['user'], password=relation['password'])
130
pgpass_path, pgpass, owner="ubuntu", group="ubuntu", perms=0o400)
133
hooks = hookenv.Hooks()
139
['language-pack-en', 'postgresql-client', 'python-psycopg2'],
146
# Per Bug #1205286, we can't store scripts and passwords in the
148
if os.path.exists('bin'):
150
if os.path.exists('pgpass'):
151
shutil.rmtree('pgpass')
153
return rebuild_all_relations()
157
'config-changed', 'db-admin-relation-broken',
158
'db-admin-relation-changed', 'db-admin-relation-joined',
159
'db-relation-broken', 'db-relation-changed', 'db-relation-joined')
161
return rebuild_all_relations()
164
if __name__ == '__main__':
165
hooks.execute(sys.argv)