13
from Cheetah.Template import Template
16
###############################################################################
17
# Supporting functions
18
###############################################################################
21
#------------------------------------------------------------------------------
22
# config_get: Returns a dictionary containing all of the config information
23
# Optional parameter: scope
24
# scope: limits the scope of the returned configuration to the
25
# desired config item.
26
#------------------------------------------------------------------------------
27
def config_get(scope=None):
29
config_cmd_line = ['config-get']
31
config_cmd_line.append(scope)
32
config_cmd_line.append('--format=json')
33
config_data = json.loads(subprocess.check_output(config_cmd_line))
40
#------------------------------------------------------------------------------
41
# get_service_port: Convenience function that scans the existing postgresql
42
# configuration file and returns a the existing port
43
# being used. This is necessary to know which port(s)
44
# to open and close when exposing/unexposing a service
45
#------------------------------------------------------------------------------
46
def get_service_port(postgresql_config_file="/etc/postgresql/9.1/main/postgresql.conf"):
47
postgresql_config = load_postgresql_config(postgresql_config_file)
48
if postgresql_config is None:
50
return(re.findall("port.*=(.*)", haproxy_config))
53
#------------------------------------------------------------------------------
54
# relation_get: Returns a dictionary containing the relation information
55
# Optional parameters: scope, relation_id
56
# scope: limits the scope of the returned data to the
58
# unit_name: limits the data ( and optionally the scope )
59
# to the specified unit
60
#------------------------------------------------------------------------------
61
def relation_get(scope=None, unit_name=None):
63
relation_cmd_line = ['relation-get', '--format=json']
65
relation_cmd_line.append(scope)
67
relation_cmd_line.append('')
68
if unit_name is not None:
69
relation_cmd_line.append(unit_name)
70
relation_data = json.loads(subprocess.check_output(relation_cmd_line))
77
#------------------------------------------------------------------------------
78
# apt_get_install( package ): Installs a package
79
#------------------------------------------------------------------------------
80
def apt_get_install(packages=None):
83
cmd_line = ['apt-get', '-y', 'install', '-qq']
84
cmd_line.append(packages)
85
return(subprocess.call(cmd_line))
88
#------------------------------------------------------------------------------
89
# create_postgresql_config: Creates the postgresql.conf file
90
#------------------------------------------------------------------------------
91
def create_postgresql_config():
92
# Send config data to the template
93
# Return it as pg_config
94
pg_config = Template(open("templates/postgresql.conf.tmp").read(), config_data)
95
with open(postgresql_config, 'w') as postgres_config:
96
postgres_config.write(pg_config)
99
#------------------------------------------------------------------------------
100
# load_postgresql_config: Convenience function that loads (as a string) the
101
# current postgresql configuration file.
102
# Returns a string containing the postgresql config or
104
#------------------------------------------------------------------------------
105
def load_postgresql_config():
106
if os.path.isfile(postgresql_config):
107
return(open(postgresql_config).read())
112
#------------------------------------------------------------------------------
113
# open_port: Convenience function to open a port in juju to
115
#------------------------------------------------------------------------------
116
def open_port(port=None, protocol="TCP"):
119
return(subprocess.call(['/usr/bin/open-port', "%d/%s" % \
120
(int(port), protocol)]))
123
#------------------------------------------------------------------------------
124
# close_port: Convenience function to close a port in juju to
126
#------------------------------------------------------------------------------
127
def close_port(port=None, protocol="TCP"):
130
return(subprocess.call(['/usr/bin/close-port', "%d/%s" % \
131
(int(port), protocol)]))
134
#------------------------------------------------------------------------------
135
# update_service_ports: Convenience function that evaluate the old and new
136
# service ports to decide which ports need to be
137
# opened and which to close
138
#------------------------------------------------------------------------------
139
def update_service_ports(old_service_ports=None, new_service_ports=None):
140
if old_service_ports is None or new_service_ports is None:
142
for port in old_service_ports:
143
if port not in new_service_ports:
145
for port in new_service_ports:
146
if port not in old_service_ports:
150
#------------------------------------------------------------------------------
151
# pwgen: Generates a random password
152
# pwd_length: Defines the length of the password to generate
154
#------------------------------------------------------------------------------
155
def pwgen(pwd_length=20):
156
alphanumeric_chars = [l for l in (string.letters + string.digits) \
157
if l not in 'Iil0oO1']
158
random_chars = [random.choice(alphanumeric_chars) \
159
for i in range(pwd_length)]
160
return(''.join(random_chars))
163
#------------------------------------------------------------------------------
164
# construct_haproxy_config: Convenience function to write haproxy.cfg
165
# haproxy_globals, haproxy_defaults,
166
# haproxy_monitoring, haproxy_services
167
# are all strings that will be written without
169
# haproxy_monitoring and haproxy_services are
171
#------------------------------------------------------------------------------
172
def construct_haproxy_config(haproxy_globals=None,
173
haproxy_defaults=None,
174
haproxy_monitoring=None,
175
haproxy_services=None):
176
if haproxy_globals is None or \
177
haproxy_defaults is None:
179
with open(default_haproxy_config, 'w') as haproxy_config:
180
haproxy_config.write(haproxy_globals)
181
haproxy_config.write("\n")
182
haproxy_config.write("\n")
183
haproxy_config.write(haproxy_defaults)
184
haproxy_config.write("\n")
185
haproxy_config.write("\n")
186
if haproxy_monitoring is not None:
187
haproxy_config.write(haproxy_monitoring)
188
haproxy_config.write("\n")
189
haproxy_config.write("\n")
190
if haproxy_services is not None:
191
haproxy_config.write(haproxy_services)
192
haproxy_config.write("\n")
193
haproxy_config.write("\n")
196
#------------------------------------------------------------------------------
197
# service_haproxy: Convenience function to start/stop/restart/reload
198
# the haproxy service
199
#------------------------------------------------------------------------------
200
def service_haproxy(action=None, haproxy_config=default_haproxy_config):
201
if action is None or haproxy_config is None:
203
elif action == "check":
204
retVal = subprocess.call(\
205
['/usr/sbin/haproxy', '-f', haproxy_config, '-c'])
213
retVal = subprocess.call(['service', 'haproxy', action])
220
###############################################################################
222
###############################################################################
224
return (apt_get_install("postgresql-%s" % version) == True)
227
def config_changed():
228
current_service_port = get_service_port()
229
create_postgresql_config()
230
updated_service_port = config_data["listen_port"]
231
update_service_port(current_service_port, updated_service_port)
232
service_postgresql("reload")
236
if service_postgresql("status"):
237
return(service_postgresql("restart"))
239
return(service_postgresql("start"))
243
if service_postgresql("status"):
244
return(service_postgresql("stop"))
247
def reverseproxy_interface(hook_name=None):
248
if hook_name is None:
250
if hook_name == "changed":
254
def website_interface(hook_name=None):
255
if hook_name is None:
257
my_fqdn = socket.getfqdn(socket.gethostname())
259
relation_data = relation_get()
260
if hook_name == "joined":
261
subprocess.call(['relation-set', 'port=%d' % \
262
default_port, 'hostname=%s' % my_fqdn])
263
elif hook_name == "changed":
264
if 'is-proxy' in relation_data:
265
service_name = "%s__%d" % \
266
(relation_data['hostname'], relation_data['port'])
267
open("%s/%s.is.proxy" % \
268
(default_haproxy_service_config_dir, service_name), 'a').close()
271
###############################################################################
273
###############################################################################
274
config_data = config_get()
275
version = config_data['version']
276
cluster_name = config_data['cluster_name']
277
postgresql_config_dir = "/etc/postgresql"
278
postgresql_config = "%s/%s/%s/postgresql.conf" % (version, cluster_name, postgreql_config_dir)
279
postgresql_service_config_dir = "/var/run/postgresql"
280
hook_name = os.path.basename(sys.argv[0])
282
###############################################################################
284
###############################################################################
285
if hook_name == "install":
287
elif hook_name == "config-changed":
289
elif hook_name == "start":
291
elif hook_name == "stop":
293
elif hook_name == "reverseproxy-relation-broken":
295
elif hook_name == "reverseproxy-relation-changed":
296
reverseproxy_interface("changed")
297
elif hook_name == "website-relation-joined":
298
website_interface("joined")
299
elif hook_name == "website-relation-changed":
300
website_interface("changed")