Initial import of charm layer to deploy and configure OpenMano
[osm/RO.git] / charms / layers / openmano / reactive / layer_openmano.py
1 from git import Repo as gitrepo
2 from shutil import rmtree
3
4 import os
5 import subprocess
6
7 from charmhelpers.core import host
8 from charmhelpers.core import hookenv
9 from charmhelpers.core import templating
10 from charmhelpers.core.unitdata import kv
11 from charmhelpers.core.hookenv import (
12 config,
13 log,
14 open_port,
15 status_set,
16 )
17
18 from charmhelpers.core.host import (
19 chownr,
20 )
21
22 from charms.reactive import (
23 when,
24 when_not,
25 set_state,
26 is_state,
27 )
28
29 kvdb = kv()
30
31 INSTALL_PATH = '/opt/openmano'
32 USER = 'openmanod'
33
34
35 @when('openmano.installed')
36 @when('openmano.available')
37 def openmano_available(openmano):
38 # TODO make this configurable via charm config
39 openmano.configure(port=9090)
40
41
42 @when('openmano.installed')
43 @when('db.available', 'db.installed')
44 @when('openvim-controller.available')
45 @when('openmano.running')
46 def openvim_available(openvim, db):
47 for service in openvim.services():
48 for endpoint in service['hosts']:
49 host = endpoint['hostname']
50 port = endpoint['port']
51 user = endpoint['user']
52
53 openvim_uri = '{}:{}'.format(host, port)
54 if kvdb.get('openvim_uri') == openvim_uri:
55 return
56
57 import pdb; pdb.set_trace()
58 # TODO: encapsulate the logic in create-datacenter.sh into python
59 try:
60 cmd = './scripts/create-datacenter.sh {} {} {} {}'.format(
61 host, port, user, kvdb.get('openmano-tenant'))
62 out, err = _run(cmd)
63 except subprocess.CalledProcessError as e:
64 # Ignore the error if the datacenter already exists.
65 if e.returncode != 153:
66 raise
67
68 kvdb.set('openvim_uri', openvim_uri)
69 if not is_state('db.available'):
70 status_set('waiting', 'Waiting for database')
71 break
72 break
73
74
75 @when('openmano.installed')
76 @when('db.available', 'db.installed')
77 @when('openvim-controller.available')
78 @when_not('openmano.running')
79 def start(*args):
80 # TODO: if the service fails to start, we should raise an error to the op
81 # Right now, it sets the state as running and the charm dies. Because
82 # service-openmano returns 0 when it fails.
83 cmd = "/home/{}/bin/service-openmano start".format(USER)
84 out, err = _run(cmd)
85
86 if not kvdb.get('openmano-tenant'):
87 out, err = _run('./scripts/create-tenant.sh')
88 kvdb.set('openmano-tenant', out.strip())
89
90 status_set(
91 'active',
92 'Up on {host}:{port}'.format(
93 host=hookenv.unit_public_ip(),
94 port='9090'))
95
96 set_state('openmano.running')
97
98
99 @when('openmano.installed')
100 @when('db.available')
101 @when_not('db.installed')
102 def setup_db(db):
103 """Setup the database
104
105 """
106 db_uri = 'mysql://{}:{}@{}:{}/{}'.format(
107 db.user(),
108 db.password(),
109 db.host(),
110 db.port(),
111 db.database(),
112 )
113
114 if kvdb.get('db_uri') == db_uri:
115 # We're already configured
116 return
117
118 status_set('maintenance', 'Initializing database')
119
120 try:
121 # HACK: use a packed version of init_mano_db until bug https://osm.etsi.org/bugzilla/show_bug.cgi?id=56 is fixed
122 # cmd = "{}/database_utils/init_mano_db.sh --createdb ".format(kvdb.get('repo'))
123 cmd = "./scripts//init_mano_db.sh --createdb "
124 cmd += "-u {} -p{} -h {} -d {} -P {}".format(
125 db.user(),
126 db.password(),
127 db.host(),
128 db.database(),
129 db.port(),
130 )
131 output, err = _run(cmd)
132 except subprocess.CalledProcessError:
133 # Eat this. init_mano_db.sh will return error code 1 on success
134 pass
135
136 context = {
137 'user': db.user(),
138 'password': db.password(),
139 'host': db.host(),
140 'database': db.database(),
141 'port': db.port(),
142 }
143 templating.render(
144 'openmanod.cfg',
145 os.path.join(kvdb.get('repo'), 'openmanod.cfg'),
146 context,
147 owner=USER,
148 group=USER,
149 )
150 kvdb.set('db_uri', db_uri)
151
152 status_set('active', 'Database installed.')
153 set_state('db.installed')
154
155 @when_not('openvim-controller.available')
156 def need_openvim():
157 status_set('waiting', 'Waiting for OpenVIM')
158
159
160 @when_not('db.available')
161 def need_db():
162 status_set('waiting', 'Waiting for database')
163
164
165 @when_not('db.available')
166 @when_not('openvim-controller.available')
167 def need_everything():
168 status_set('waiting', 'Waiting for database and OpenVIM')
169
170
171 @when_not('openmano.installed')
172 def install_layer_openmano():
173 status_set('maintenance', 'Installing')
174
175 cfg = config()
176
177 # TODO change user home
178 # XXX security issue!
179 host.adduser(USER, password=USER)
180
181 if os.path.isdir(INSTALL_PATH):
182 rmtree(INSTALL_PATH)
183
184 gitrepo.clone_from(
185 cfg['repository'],
186 INSTALL_PATH,
187 branch=cfg['branch'],
188 )
189
190 chownr(
191 INSTALL_PATH,
192 owner=USER,
193 group=USER,
194 follow_links=False,
195 chowntopdir=True
196 )
197
198 os.mkdir(os.path.join(INSTALL_PATH, 'logs'))
199 chownr(INSTALL_PATH, USER, USER)
200 kvdb.set('repo', INSTALL_PATH)
201
202 os.mkdir('/home/{}/bin'.format(USER))
203
204 os.symlink(
205 "{}/openmano".format(INSTALL_PATH),
206 "/home/{}/bin/openmano".format(USER))
207 os.symlink(
208 "{}/scripts/openmano-report.sh".format(INSTALL_PATH),
209 "/home/{}/bin/openmano-report.sh".format(USER))
210 os.symlink(
211 "{}/scripts/service-openmano.sh".format(INSTALL_PATH),
212 "/home/{}/bin/service-openmano".format(USER))
213
214 open_port(9090)
215 set_state('openmano.installed')
216
217
218 def _run(cmd, env=None):
219 if isinstance(cmd, str):
220 cmd = cmd.split() if ' ' in cmd else [cmd]
221
222 log(cmd)
223 p = subprocess.Popen(cmd,
224 env=env,
225 stdout=subprocess.PIPE,
226 stderr=subprocess.PIPE)
227 stdout, stderr = p.communicate()
228 retcode = p.poll()
229 if retcode > 0:
230 raise subprocess.CalledProcessError(
231 returncode=retcode,
232 cmd=cmd,
233 output=stderr.decode("utf-8").strip())
234 return (stdout.decode('utf-8'), stderr.decode('utf-8'))