-
Notifications
You must be signed in to change notification settings - Fork 3
/
hooks.py
executable file
·164 lines (131 loc) · 5.42 KB
/
hooks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python
from charmhelpers.core import hookenv
from charmhelpers.core import unitdata
from charmhelpers.core import templating
from charmhelpers.core import host
from charmhelpers import fetch
from os import environ
from path import path
import string
import random
import shlex
from subprocess import check_output, check_call
import sys
hooks = hookenv.Hooks()
hook_data = unitdata.HookData()
db = unitdata.kv()
private_address = hookenv.unit_get('private-address')
public_address = hookenv.unit_get('private-address')
unit_name = environ['JUJU_UNIT_NAME'].replace('/', '')
try:
leader_status = hookenv.is_leader()
except NotImplementedError:
hookenv.log('This charm requires Leader Election. Juju >= 1.23.2.'
' Leader election binary not found, Panic and exit!',
'CRITICAL')
sys.exit(1)
@hooks.hook('config-changed')
def config_changed():
if not db.get('installed') or hookenv.config().changed('source-sum'):
install_etcd()
if leader_status:
print "I am the leader, configuring single node"
cluster_data = {'token': cluster_token()}
cluster_data['cluster_state'] = 'new'
cluster_data['cluster'] = cluster_string()
main(cluster_data)
@hooks.hook('cluster-relation-changed')
def cluster_relation_changed():
cluster_data = {}
# Useful when doing runtime based configuration. (units added after cluster
# bootstrap) see docs:
# https://github.com/coreos/etcd/blob/master/Documentation/runtime-configuration.md
if leader_status:
token = cluster_token()
print 'Initializing cluster with {}'.format(token)
hookenv.relation_set(hookenv.relation_id(),
{'leader-address': private_address,
'cluster-state': 'existing',
'cluster-token': token,
'cluster': cluster_string()})
cluster_data['cluster'] = cluster_string()
if not leader_status:
# A token is only generated once on a cluster.
token = hookenv.relation_get('cluster-token')
cluster_data['cluster'] = hookenv.relation_get('cluster')
if not token:
print "No token available on relationship - exiting"
return
cluster_data['token'] = token
main(cluster_data)
@hooks.hook('proxy-relation-changed')
def proxy_relation_changed():
hookenv.relation_set(hookenv.relation_id(),
{'cluster': cluster_string()})
def main(cluster_data={}):
# Grab the boilerplate config entries
cluster_data['unit_name'] = environ['JUJU_UNIT_NAME'].replace('/', '')
cluster_data['private_address'] = private_address
cluster_data['public_address'] = public_address
cluster_data['cluster_state'] = 'new'
if not leader_status:
cluster_data['cluster_state'] = hookenv.relation_get('cluster-state')
leader_address = hookenv.relation_get('leader-address')
# do self registration
if not db.get('registered'):
cmd = "/opt/etcd/etcdctl -C http://{}:4001 member add {}" \
" http://{}:7001".format(leader_address,
cluster_data['unit_name'],
private_address)
print(cmd)
check_call(shlex.split(cmd))
db.set('registered', True)
# introspect the cluster, and form the cluster string.
# https://github.com/coreos/etcd/blob/master/Documentation/configuration.md#-initial-cluster
templating.render('etcd.conf.jinja2', '/etc/init/etcd.conf',
cluster_data, owner='root', group='root')
host.service('restart', 'etcd')
def cluster_string():
cluster = ""
cluster_rels = hook_data.rels['cluster'][1].keys()
# introspect the cluster, and form the cluster string.
# https://github.com/coreos/etcd/blob/master/Documentation/configuration.md#-initial-cluster
if hook_data.rels['cluster'][1]:
reldata = hook_data.rels['cluster'][1][cluster_rels[0]]
for unit in reldata:
private = reldata[unit]['private-address']
cluster = '{}{}=http://{}:7001,'.format(cluster,
unit.replace('/', ''),
private)
else:
cluster = "{}=http://{}:7001".format(unit_name, private_address)
return cluster.rstrip(',')
def cluster_token():
if not db.get('cluster-token'):
token = id_generator()
db.set('cluster-token', token)
return token
return db.get('cluster-token')
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def install_etcd():
source = hookenv.config('bin-source')
sha = hookenv.config('source-sum')
unpack = fetch.install_remote(source, 'fetched', sha)
# Copy the payload into place on the system
etcd_dir = path('/opt/etcd')
unpack_dir = path(unpack)
for d in unpack_dir.dirs():
d = path(d)
for f in d.files():
f.copy(etcd_dir)
for executable in "etcd", "etcdctl":
origin = etcd_dir / executable
target = path('/usr/local/bin/%s' % executable)
target.exists() and target.remove()
origin.symlink(target)
hookenv.open_port(4001)
db.set('installed', True)
if __name__ == '__main__':
with hook_data():
hooks.execute(sys.argv)