root / snf-deploy / snfdeploy / components.py @ de1dcc91
History | View | Annotate | Download (31.8 kB)
1 |
# Copyright (C) 2010, 2011, 2012, 2013 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or
|
4 |
# without modification, are permitted provided that the following
|
5 |
# conditions are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above
|
8 |
# copyright notice, this list of conditions and the following
|
9 |
# disclaimer.
|
10 |
#
|
11 |
# 2. Redistributions in binary form must reproduce the above
|
12 |
# copyright notice, this list of conditions and the following
|
13 |
# disclaimer in the documentation and/or other materials
|
14 |
# provided with the distribution.
|
15 |
#
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A. OR
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
# POSSIBILITY OF SUCH DAMAGE.
|
28 |
#
|
29 |
# The views and conclusions contained in the software and
|
30 |
# documentation are those of the authors and should not be
|
31 |
# interpreted as representing official policies, either expressed
|
32 |
# or implied, of GRNET S.A.
|
33 |
|
34 |
import datetime |
35 |
from snfdeploy.utils import debug |
36 |
|
37 |
|
38 |
class SynnefoComponent(object): |
39 |
|
40 |
REQUIRED_PACKAGES = [] |
41 |
|
42 |
def debug(self, msg, info=""): |
43 |
debug(self.__class__.__name__, msg, info)
|
44 |
|
45 |
def __init__(self, node_info, env, *args, **kwargs): |
46 |
""" Take a node_info and env as argument and initialize local vars """
|
47 |
self.node_info = node_info
|
48 |
self.env = env
|
49 |
|
50 |
def check(self): |
51 |
""" Returns a list of bash commands that check prerequisites """
|
52 |
return []
|
53 |
|
54 |
def install(self): |
55 |
""" Returns a list of debian packages to install """
|
56 |
return self.REQUIRED_PACKAGES |
57 |
|
58 |
def prepare(self): |
59 |
""" Returs a list of bash commands that prepares the component """
|
60 |
return []
|
61 |
|
62 |
def configure(self): |
63 |
""" Must return a list of tuples (tmpl_path, replace_dict, mode) """
|
64 |
return []
|
65 |
|
66 |
def initialize(self): |
67 |
""" Returs a list of bash commands that initialize the component """
|
68 |
return []
|
69 |
|
70 |
def test(self): |
71 |
""" Returs a list of bash commands that test existing installation """
|
72 |
return []
|
73 |
|
74 |
def restart(self): |
75 |
return []
|
76 |
|
77 |
#TODO: add cleanup method for each component
|
78 |
def clean(self): |
79 |
return []
|
80 |
|
81 |
|
82 |
class HW(SynnefoComponent): |
83 |
def test(self): |
84 |
return [
|
85 |
"ping -c 1 %s" % self.node_info.ip, |
86 |
"ping -c 1 www.google.com",
|
87 |
"apt-get update",
|
88 |
] |
89 |
|
90 |
|
91 |
class SSH(SynnefoComponent): |
92 |
def prepare(self): |
93 |
return [
|
94 |
"mkdir -p /root/.ssh",
|
95 |
"for f in $(ls /root/.ssh/*); do cp $f $f.bak ; done",
|
96 |
"echo StrictHostKeyChecking no >> /etc/ssh/ssh_config",
|
97 |
] |
98 |
|
99 |
def configure(self): |
100 |
files = [ |
101 |
"authorized_keys", "id_dsa", "id_dsa.pub", "id_rsa", "id_rsa.pub" |
102 |
] |
103 |
ssh = [("/root/.ssh/%s" % f, {}, {"mode": 0600}) for f in files] |
104 |
return ssh
|
105 |
|
106 |
def initialize(self): |
107 |
f = "/root/.ssh/authorized_keys"
|
108 |
return [
|
109 |
"test -e {0}.bak && cat {0}.bak >> {0}".format(f)
|
110 |
] |
111 |
|
112 |
def test(self): |
113 |
return ["ssh %s date" % self.node_info.ip] |
114 |
|
115 |
|
116 |
class DNS(SynnefoComponent): |
117 |
def prepare(self): |
118 |
return [
|
119 |
"chattr -i /etc/resolv.conf",
|
120 |
"sed -i 's/^127.*$/127.0.0.1 localhost/g' /etc/hosts",
|
121 |
] |
122 |
|
123 |
def configure(self): |
124 |
r1 = { |
125 |
"date": str(datetime.datetime.today()), |
126 |
"domain": self.env.env.domain, |
127 |
"ns_node_ip": self.env.env.ns.ip, |
128 |
} |
129 |
resolv = [ |
130 |
("/etc/resolv.conf", r1, {})
|
131 |
] |
132 |
return resolv
|
133 |
|
134 |
def initialize(self): |
135 |
return ["chattr +i /etc/resolv.conf"] |
136 |
|
137 |
|
138 |
class DDNS(SynnefoComponent): |
139 |
REQUIRED_PACKAGES = [ |
140 |
"dnsutils",
|
141 |
] |
142 |
|
143 |
def prepare(self): |
144 |
return [
|
145 |
"mkdir -p /root/ddns/"
|
146 |
] |
147 |
|
148 |
def configure(self): |
149 |
return [
|
150 |
("/root/ddns/" + k, {}, {}) for k in self.env.env.ddns_keys |
151 |
] |
152 |
|
153 |
|
154 |
class NS(SynnefoComponent): |
155 |
REQUIRED_PACKAGES = [ |
156 |
"bind9",
|
157 |
] |
158 |
|
159 |
def nsupdate(self, cmd): |
160 |
ret = """
|
161 |
nsupdate -k {0} > /dev/null <<EOF || true
|
162 |
server {1}
|
163 |
{2}
|
164 |
send
|
165 |
EOF
|
166 |
""".format(self.env.env.ddns_private_key, self.node_info.ip, cmd) |
167 |
return ret
|
168 |
|
169 |
def prepare(self): |
170 |
return [
|
171 |
"mkdir -p /etc/bind/zones",
|
172 |
"chmod g+w /etc/bind/zones",
|
173 |
"mkdir -p /etc/bind/rev",
|
174 |
"chmod g+w /etc/bind/rev",
|
175 |
] |
176 |
|
177 |
def configure(self): |
178 |
d = self.env.env.domain
|
179 |
ip = self.node_info.ip
|
180 |
return [
|
181 |
("/etc/bind/named.conf.local", {"domain": d}, {}), |
182 |
("/etc/bind/zones/example.com",
|
183 |
{"domain": d, "ns_node_ip": ip}, |
184 |
{"remote": "/etc/bind/zones/%s" % d}), |
185 |
("/etc/bind/zones/vm.example.com",
|
186 |
{"domain": d, "ns_node_ip": ip}, |
187 |
{"remote": "/etc/bind/zones/vm.%s" % d}), |
188 |
("/etc/bind/rev/synnefo.in-addr.arpa.zone", {"domain": d}, {}), |
189 |
("/etc/bind/rev/synnefo.ip6.arpa.zone", {"domain": d}, {}), |
190 |
("/etc/bind/named.conf.options",
|
191 |
{"node_ips": ";".join(self.env.env.ips)}, {}), |
192 |
("/root/ddns/ddns.key", {}, {"remote": "/etc/bind/ddns.key"}), |
193 |
] |
194 |
|
195 |
def update_cnamerecord(self, node_info): |
196 |
return self.nsupdate("update add %s" % node_info.cnamerecord) |
197 |
|
198 |
def update_arecord(self, node_info): |
199 |
return self.nsupdate("update add %s" % node_info.arecord) |
200 |
|
201 |
def update_ptrrecord(self, node_info): |
202 |
return self.nsupdate("update add %s" % node_info.ptrrecord) |
203 |
|
204 |
def update_ns_for_node(self, node_info): |
205 |
return [
|
206 |
self.update_arecord(node_info),
|
207 |
self.update_cnamerecord(node_info),
|
208 |
self.update_ptrrecord(node_info)
|
209 |
] |
210 |
|
211 |
def initialize(self): |
212 |
a = [self.update_arecord(n)
|
213 |
for n in self.env.env.nodes_info.values()] |
214 |
ptr = [self.update_ptrrecord(n)
|
215 |
for n in self.env.env.nodes_info.values()] |
216 |
cnames = [self.update_cnamerecord(n)
|
217 |
for n in self.env.env.roles_info.values()] |
218 |
|
219 |
return a + ptr + cnames
|
220 |
|
221 |
def restart(self): |
222 |
return ["/etc/init.d/bind9 restart"] |
223 |
|
224 |
def test(self): |
225 |
n = ["host %s localhost" % i.fqdn
|
226 |
for i in self.env.env.nodes_info.values()] |
227 |
a = ["host %s localhost" % i.fqdn
|
228 |
for i in self.env.env.roles_info.values()] |
229 |
return n + a
|
230 |
|
231 |
|
232 |
class APT(SynnefoComponent): |
233 |
""" Setup apt repos and check fqdns """
|
234 |
REQUIRED_PACKAGES = ["curl"]
|
235 |
|
236 |
def prepare(self): |
237 |
return [
|
238 |
"echo 'APT::Install-Suggests \"false\";' >> /etc/apt/apt.conf",
|
239 |
"curl -k https://dev.grnet.gr/files/apt-grnetdev.pub | \
|
240 |
apt-key add -",
|
241 |
] |
242 |
|
243 |
def configure(self): |
244 |
return [
|
245 |
("/etc/apt/sources.list.d/synnefo.wheezy.list", {}, {})
|
246 |
] |
247 |
|
248 |
def initialize(self): |
249 |
return [
|
250 |
"apt-get update",
|
251 |
] |
252 |
|
253 |
|
254 |
class MQ(SynnefoComponent): |
255 |
REQUIRED_PACKAGES = ["rabbitmq-server"]
|
256 |
|
257 |
def check(self): |
258 |
return ["ping -c 1 mq.%s" % self.env.env.domain] |
259 |
|
260 |
def initialize(self): |
261 |
u = self.env.env.synnefo_user
|
262 |
p = self.env.env.synnefo_rabbitmq_passwd
|
263 |
return [
|
264 |
"rabbitmqctl add_user %s %s" % (u, p),
|
265 |
"rabbitmqctl set_permissions %s \".*\" \".*\" \".*\"" % u,
|
266 |
"rabbitmqctl delete_user guest",
|
267 |
"rabbitmqctl set_user_tags %s administrator" % u,
|
268 |
] |
269 |
|
270 |
|
271 |
class DB(SynnefoComponent): |
272 |
REQUIRED_PACKAGES = ["postgresql"]
|
273 |
|
274 |
def check(self): |
275 |
return ["ping -c 1 db.%s" % self.env.env.domain] |
276 |
|
277 |
def get_user_info_from_db(self): |
278 |
cmd = """
|
279 |
cat > /tmp/psqlcmd <<EOF
|
280 |
select id, auth_token, uuid, email from auth_user, im_astakosuser \
|
281 |
where auth_user.id = im_astakosuser.user_ptr_id and auth_user.email = '{0}';
|
282 |
EOF
|
283 |
|
284 |
su - postgres -c "psql -w -d snf_apps -f /tmp/psqlcmd"
|
285 |
""".format(self.env.env.user_email) |
286 |
|
287 |
return [cmd]
|
288 |
|
289 |
def allow_access_in_db(self, node_info, user="all", method="md5"): |
290 |
f = "/etc/postgresql/*/main/pg_hba.conf"
|
291 |
cmd1 = "echo host all %s %s/32 %s >> %s" % \
|
292 |
(user, node_info.ip, method, f) |
293 |
cmd2 = "sed -i 's/\(host.*127.0.0.1.*\)md5/\\1trust/' %s" % f
|
294 |
return [cmd1, cmd2] + self.restart() |
295 |
|
296 |
def configure(self): |
297 |
u = self.env.env.synnefo_user
|
298 |
p = self.env.env.synnefo_db_passwd
|
299 |
replace = {"synnefo_user": u, "synnefo_db_passwd": p} |
300 |
return [
|
301 |
("/tmp/db-init.psql", replace, {}),
|
302 |
] |
303 |
|
304 |
def make_db_fast(self): |
305 |
f = "/etc/postgresql/*/main/postgresql.conf"
|
306 |
opts = "fsync=off\nsynchronous_commit=off\nfull_page_writes=off\n"
|
307 |
return ["""echo -e "%s" >> %s""" % (opts, f)] |
308 |
|
309 |
def prepare(self): |
310 |
f = "/etc/postgresql/*/main/postgresql.conf"
|
311 |
return [
|
312 |
"""echo "listen_addresses = '*'" >> %s""" % f,
|
313 |
] |
314 |
|
315 |
def initialize(self): |
316 |
script = "/tmp/db-init.psql"
|
317 |
cmd = "su - postgres -c \"psql -w -f %s\" " % script
|
318 |
return [cmd]
|
319 |
|
320 |
def restart(self): |
321 |
return ["/etc/init.d/postgresql restart"] |
322 |
|
323 |
def destroy_db(self): |
324 |
return [
|
325 |
"""su - postgres -c ' psql -w -c "drop database snf_apps" '""",
|
326 |
"""su - postgres -c ' psql -w -c "drop database snf_pithos" '"""
|
327 |
] |
328 |
|
329 |
|
330 |
class Ganeti(SynnefoComponent): |
331 |
|
332 |
REQUIRED_PACKAGES = [ |
333 |
"qemu-kvm",
|
334 |
"python-bitarray",
|
335 |
"ganeti-htools",
|
336 |
"ganeti-haskell",
|
337 |
"snf-ganeti",
|
338 |
"ganeti2",
|
339 |
"bridge-utils",
|
340 |
"lvm2",
|
341 |
"drbd8-utils",
|
342 |
] |
343 |
|
344 |
def check(self): |
345 |
commands = [ |
346 |
"getent hosts %s | grep -v ^127" % self.node_info.hostname, |
347 |
"hostname -f | grep %s" % self.node_info.fqdn, |
348 |
] |
349 |
return commands
|
350 |
|
351 |
def configure(self): |
352 |
return [
|
353 |
("/etc/ganeti/file-storage-paths", {}, {}),
|
354 |
] |
355 |
|
356 |
def prepare_lvm(self): |
357 |
return [
|
358 |
"pvcreate %s" % self.env.env.extra_disk, |
359 |
"vgcreate %s %s" % (self.env.env.extra_disk, self.env.env.vg) |
360 |
] |
361 |
|
362 |
def prepare_net_infra(self): |
363 |
br = self.env.env.common_bridge
|
364 |
return [
|
365 |
"brctl addbr {0}; ip link set {0} up".format(br)
|
366 |
] |
367 |
|
368 |
def prepare(self): |
369 |
return [
|
370 |
"mkdir -p /srv/ganeti/file-storage/",
|
371 |
"sed -i 's/^127.*$/127.0.0.1 localhost/g' /etc/hosts"
|
372 |
] + self.prepare_net_infra()
|
373 |
|
374 |
def restart(self): |
375 |
return ["/etc/init.d/ganeti restart"] |
376 |
|
377 |
|
378 |
class Master(SynnefoComponent): |
379 |
def add_rapi_user(self): |
380 |
user = self.env.env.synnefo_user
|
381 |
passwd = self.env.env.synnefo_rapi_passwd
|
382 |
x = "%s:Ganeti Remote API:%s" % (user, passwd)
|
383 |
|
384 |
cmd = """
|
385 |
cat >> /var/lib/ganeti/rapi/users <<EOF
|
386 |
%s {HA1}$(echo -n %s | openssl md5 | sed 's/^.* //') write
|
387 |
EOF
|
388 |
""" % (self.env.env.synnefo_user, x) |
389 |
|
390 |
return [cmd] + self.restart() |
391 |
|
392 |
def add_node(self, node_info): |
393 |
commands = [ |
394 |
"gnt-node add --no-ssh-key-check --master-capable=yes " +
|
395 |
"--vm-capable=yes " + node_info.fqdn,
|
396 |
] |
397 |
return commands
|
398 |
|
399 |
def try_use_vg(self): |
400 |
vg = self.env.env.vg
|
401 |
return [
|
402 |
"gnt-cluster modify --vg-name=%s || true" % vg,
|
403 |
"gnt-cluster modify --disk-parameters=drbd:metavg=%s" % vg,
|
404 |
"gnt-group modify --disk-parameters=drbd:metavg=%s default" % vg,
|
405 |
] |
406 |
|
407 |
def initialize(self): |
408 |
cmd = """
|
409 |
gnt-cluster init --enabled-hypervisors=kvm \
|
410 |
--no-lvm-storage --no-drbd-storage \
|
411 |
--nic-parameters link={0},mode=bridged \
|
412 |
--master-netdev {1} \
|
413 |
--specs-nic-count min=0,max=8 \
|
414 |
--default-iallocator hail \
|
415 |
--hypervisor-parameters kvm:kernel_path=,vnc_bind_address=0.0.0.0 \
|
416 |
--no-ssh-init --no-etc-hosts \
|
417 |
--enabled-disk-templates file,plain,ext,drbd \
|
418 |
{2}
|
419 |
""".format(self.env.env.common_bridge, |
420 |
self.env.env.cluster_netdev, self.env.env.cluster.fqdn) |
421 |
|
422 |
return [cmd] + self.try_use_vg() + self.add_rapi_user() |
423 |
|
424 |
def restart(self): |
425 |
return ["/etc/init.d/ganeti restart"] |
426 |
|
427 |
|
428 |
class Image(SynnefoComponent): |
429 |
REQUIRED_PACKAGES = [ |
430 |
"snf-pithos-backend",
|
431 |
"snf-image",
|
432 |
] |
433 |
|
434 |
def check(self): |
435 |
return ["mkdir -p %s" % self.env.env.image_dir] |
436 |
|
437 |
def configure(self): |
438 |
tmpl = "/etc/default/snf-image"
|
439 |
replace = { |
440 |
"synnefo_user": self.env.env.synnefo_user, |
441 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
442 |
"pithos_dir": self.env.env.pithos_dir, |
443 |
"db_node": self.env.env.db.ip, |
444 |
"image_dir": self.env.env.image_dir, |
445 |
} |
446 |
return [(tmpl, replace, {})]
|
447 |
|
448 |
def initialize(self): |
449 |
return ["snf-image-update-helper -y"] |
450 |
|
451 |
|
452 |
class GTools(SynnefoComponent): |
453 |
REQUIRED_PACKAGES = [ |
454 |
"snf-cyclades-gtools",
|
455 |
] |
456 |
|
457 |
def check(self): |
458 |
return ["ping -c1 %s" % self.env.env.mq.ip] |
459 |
|
460 |
def configure(self): |
461 |
tmpl = "/etc/synnefo/gtools.conf"
|
462 |
replace = { |
463 |
"synnefo_user": self.env.env.synnefo_user, |
464 |
"synnefo_rabbitmq_passwd": self.env.env.synnefo_rabbitmq_passwd, |
465 |
"mq_node": self.env.env.mq.ip, |
466 |
} |
467 |
return [(tmpl, replace, {})]
|
468 |
|
469 |
def initialize(self): |
470 |
return [
|
471 |
"sed -i 's/false/true/' /etc/default/snf-ganeti-eventd",
|
472 |
"/etc/init.d/snf-ganeti-eventd start",
|
473 |
] |
474 |
|
475 |
def restart(self): |
476 |
return ["/etc/init.d/snf-ganeti-eventd restart"] |
477 |
|
478 |
|
479 |
class Network(SynnefoComponent): |
480 |
REQUIRED_PACKAGES = [ |
481 |
"python-nfqueue",
|
482 |
"snf-network",
|
483 |
"nfdhcpd",
|
484 |
] |
485 |
|
486 |
def configure(self): |
487 |
r1 = { |
488 |
"ns_node_ip": self.env.env.ns.ip |
489 |
} |
490 |
r2 = { |
491 |
"common_bridge": self.env.env.common_bridge, |
492 |
"public_iface": self.env.env.public_iface, |
493 |
"subnet": self.env.env.synnefo_public_network_subnet, |
494 |
"gateway": self.env.env.synnefo_public_network_gateway, |
495 |
"router_ip": self.env.env.router.ip, |
496 |
"node_ip": self.node_info.ip, |
497 |
} |
498 |
r3 = { |
499 |
"domain": self.env.env.domain, |
500 |
"server": self.env.env.ns.ip, |
501 |
"keyfile": self.env.env.ddns_private_key, |
502 |
} |
503 |
|
504 |
return [
|
505 |
("/etc/nfdhcpd/nfdhcpd.conf", r1, {}),
|
506 |
("/etc/rc.local", r2, {"mode": 0755}), |
507 |
("/etc/default/snf-network", r3, {}),
|
508 |
] |
509 |
|
510 |
def initialize(self): |
511 |
return ["/etc/init.d/rc.local start"] |
512 |
|
513 |
def restart(self): |
514 |
return ["/etc/init.d/nfdhcpd restart"] |
515 |
|
516 |
|
517 |
class Apache(SynnefoComponent): |
518 |
REQUIRED_PACKAGES = [ |
519 |
"apache2",
|
520 |
] |
521 |
|
522 |
def prepare(self): |
523 |
return [
|
524 |
"a2enmod ssl", "a2enmod rewrite", "a2dissite default", |
525 |
"a2enmod headers",
|
526 |
"a2enmod proxy_http", "a2dismod autoindex", |
527 |
] |
528 |
|
529 |
def configure(self): |
530 |
r1 = {"HOST": self.node_info.fqdn} |
531 |
return [
|
532 |
("/etc/apache2/sites-available/synnefo", r1, {}),
|
533 |
("/etc/apache2/sites-available/synnefo-ssl", r1, {}),
|
534 |
] |
535 |
|
536 |
def initialize(self): |
537 |
return [
|
538 |
"a2ensite synnefo", "a2ensite synnefo-ssl", |
539 |
] |
540 |
|
541 |
def restart(self): |
542 |
return [
|
543 |
"/etc/init.d/apache2 restart",
|
544 |
] |
545 |
|
546 |
|
547 |
class Gunicorn(SynnefoComponent): |
548 |
REQUIRED_PACKAGES = [ |
549 |
"gunicorn",
|
550 |
] |
551 |
|
552 |
def prepare(self): |
553 |
return [
|
554 |
"chown root.www-data /var/log/gunicorn",
|
555 |
] |
556 |
|
557 |
def configure(self): |
558 |
r1 = {"HOST": self.node_info.fqdn} |
559 |
return [
|
560 |
("/etc/gunicorn.d/synnefo", r1, {}),
|
561 |
] |
562 |
|
563 |
def restart(self): |
564 |
return [
|
565 |
"/etc/init.d/gunicorn restart",
|
566 |
] |
567 |
|
568 |
|
569 |
class Common(SynnefoComponent): |
570 |
REQUIRED_PACKAGES = [ |
571 |
# snf-common
|
572 |
"python-objpool",
|
573 |
"snf-common",
|
574 |
"python-astakosclient",
|
575 |
"snf-django-lib",
|
576 |
"snf-branding",
|
577 |
] |
578 |
|
579 |
def configure(self): |
580 |
r1 = { |
581 |
"EMAIL_SUBJECT_PREFIX": self.node_info.hostname, |
582 |
"domain": self.env.env.domain, |
583 |
"HOST": self.node_info.fqdn, |
584 |
"MAIL_DIR": self.env.env.mail_dir, |
585 |
} |
586 |
return [
|
587 |
("/etc/synnefo/common.conf", r1, {}),
|
588 |
] |
589 |
|
590 |
def initialize(self): |
591 |
return ["mkdir -p {0}; chmod 777 {0}".format(self.env.env.mail_dir)] |
592 |
|
593 |
def restart(self): |
594 |
return [
|
595 |
"/etc/init.d/gunicorn restart",
|
596 |
] |
597 |
|
598 |
|
599 |
class WEB(SynnefoComponent): |
600 |
REQUIRED_PACKAGES = [ |
601 |
"snf-webproject",
|
602 |
"python-psycopg2",
|
603 |
"python-gevent",
|
604 |
"python-django",
|
605 |
] |
606 |
|
607 |
def check(self): |
608 |
return ["ping -c1 %s" % self.env.env.db.fqdn] |
609 |
|
610 |
def configure(self): |
611 |
r1 = { |
612 |
"synnefo_user": self.env.env.synnefo_user, |
613 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
614 |
"db_node": self.env.env.db.fqdn, |
615 |
"domain": self.env.env.domain, |
616 |
} |
617 |
return [
|
618 |
("/etc/synnefo/webproject.conf", r1, {}),
|
619 |
] |
620 |
|
621 |
def restart(self): |
622 |
return [
|
623 |
"/etc/init.d/gunicorn restart",
|
624 |
] |
625 |
|
626 |
|
627 |
class Astakos(SynnefoComponent): |
628 |
REQUIRED_PACKAGES = [ |
629 |
"python-django-south",
|
630 |
"snf-astakos-app",
|
631 |
"kamaki",
|
632 |
] |
633 |
|
634 |
def export_service(self): |
635 |
f = self.env.jsonfile
|
636 |
return [
|
637 |
"snf-manage service-export-astakos > %s" % f
|
638 |
] |
639 |
|
640 |
def import_service(self): |
641 |
f = self.env.jsonfile
|
642 |
return [
|
643 |
"snf-manage service-import --json=%s" % f
|
644 |
] |
645 |
|
646 |
def set_default_quota(self): |
647 |
cmd = "snf-manage resource-modify --default-quota"
|
648 |
return [
|
649 |
"%s 40G pithos.diskspace" % cmd,
|
650 |
"%s 2 astakos.pending_app" % cmd,
|
651 |
"%s 4 cyclades.vm" % cmd,
|
652 |
"%s 40G cyclades.disk" % cmd,
|
653 |
"%s 16G cyclades.total_ram" % cmd,
|
654 |
"%s 8G cyclades.ram" % cmd,
|
655 |
"%s 32 cyclades.total_cpu" % cmd,
|
656 |
"%s 16 cyclades.cpu" % cmd,
|
657 |
"%s 4 cyclades.network.private" % cmd,
|
658 |
"%s 4 cyclades.floating_ip" % cmd,
|
659 |
] |
660 |
|
661 |
def modify_all_quota(self): |
662 |
cmd = "snf-manage user-modify -f --all --base-quota"
|
663 |
return [
|
664 |
"%s pithos.diskspace 40G" % cmd,
|
665 |
"%s astakos.pending_app 2" % cmd,
|
666 |
"%s cyclades.vm 4" % cmd,
|
667 |
"%s cyclades.disk 40G" % cmd,
|
668 |
"%s cyclades.total_ram 16G" % cmd,
|
669 |
"%s cyclades.ram 8G" % cmd,
|
670 |
"%s cyclades.total_cpu 32" % cmd,
|
671 |
"%s cyclades.cpu 16" % cmd,
|
672 |
"%s cyclades.network.private 4" % cmd,
|
673 |
"%s cyclades.floating_ip 4" % cmd,
|
674 |
] |
675 |
|
676 |
def get_services(self): |
677 |
return [
|
678 |
"snf-manage component-list -o id,name,token"
|
679 |
] |
680 |
|
681 |
def configure(self): |
682 |
r1 = { |
683 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
684 |
"domain": self.env.env.domain, |
685 |
"CYCLADES": self.env.env.cyclades.fqdn, |
686 |
"PITHOS": self.env.env.pithos.fqdn, |
687 |
} |
688 |
return [
|
689 |
("/etc/synnefo/astakos.conf", r1, {})
|
690 |
] |
691 |
|
692 |
def initialize(self): |
693 |
secret = self.env.env.oa2_secret
|
694 |
view = "https://%s/pithos/ui/view" % self.env.env.pithos.fqdn |
695 |
oa2 = "snf-manage oauth2-client-add pithos-view \
|
696 |
--secret=%s --is-trusted --url %s" % (secret, view)
|
697 |
|
698 |
return [
|
699 |
"snf-manage syncdb --noinput",
|
700 |
"snf-manage migrate im --delete-ghost-migrations",
|
701 |
"snf-manage migrate quotaholder_app",
|
702 |
"snf-manage migrate oa2",
|
703 |
"snf-manage loaddata groups",
|
704 |
oa2 |
705 |
] + self.astakos_register_components()
|
706 |
|
707 |
def astakos_register_components(self): |
708 |
# base urls
|
709 |
cbu = "https://%s/cyclades" % self.env.env.cyclades.fqdn |
710 |
pbu = "https://%s/pithos" % self.env.env.pithos.fqdn |
711 |
abu = "https://%s/astakos" % self.env.env.accounts.fqdn |
712 |
cmsurl = "https://%s/home" % self.env.env.cms.fqdn |
713 |
|
714 |
cmd = "snf-manage component-add"
|
715 |
h = "%s home --base-url %s --ui-url %s" % (cmd, cmsurl, cmsurl)
|
716 |
c = "%s cyclades --base-url %s --ui-url %s/ui" % (cmd, cbu, cbu)
|
717 |
p = "%s pithos --base-url %s --ui-url %s/ui" % (cmd, pbu, pbu)
|
718 |
a = "%s astakos --base-url %s --ui-url %s/ui" % (cmd, abu, abu)
|
719 |
|
720 |
return [h, c, p, a]
|
721 |
|
722 |
def add_user(self): |
723 |
info = ( |
724 |
self.env.env.user_passwd,
|
725 |
self.env.env.user_email,
|
726 |
self.env.env.user_name,
|
727 |
self.env.env.user_lastname,
|
728 |
) |
729 |
cmd = "snf-manage user-add --password %s %s %s %s" % info
|
730 |
return [cmd]
|
731 |
|
732 |
def activate_user(self): |
733 |
user_id = self.env.user_id
|
734 |
return [
|
735 |
"snf-manage user-modify --verify %s" % user_id,
|
736 |
"snf-manage user-modify --accept %s" % user_id,
|
737 |
] |
738 |
|
739 |
|
740 |
class CMS(SynnefoComponent): |
741 |
REQUIRED_PACKAGES = [ |
742 |
"snf-cloudcms"
|
743 |
] |
744 |
|
745 |
def configure(self): |
746 |
r1 = { |
747 |
"ACCOUNTS": self.env.env.accounts.fqdn |
748 |
} |
749 |
r2 = { |
750 |
"DOMAIN": self.env.env.domain |
751 |
} |
752 |
return [
|
753 |
("/etc/synnefo/cms.conf", r1, {}),
|
754 |
("/tmp/sites.json", r2, {}),
|
755 |
("/tmp/page.json", {}, {}),
|
756 |
] |
757 |
|
758 |
def initialize(self): |
759 |
return [
|
760 |
"snf-manage syncdb",
|
761 |
"snf-manage migrate --delete-ghost-migrations",
|
762 |
"snf-manage loaddata /tmp/sites.json",
|
763 |
"snf-manage loaddata /tmp/page.json",
|
764 |
"snf-manage createsuperuser --username=admin \
|
765 |
--email=admin@%s --noinput" % self.env.env.domain, |
766 |
] |
767 |
|
768 |
def restart(self): |
769 |
return ["/etc/init.d/gunicorn restart"] |
770 |
|
771 |
|
772 |
class Mount(SynnefoComponent): |
773 |
REQUIRED_PACKAGES = [ |
774 |
"nfs-common"
|
775 |
] |
776 |
|
777 |
def prepare(self): |
778 |
ret = [] |
779 |
for d in [self.env.env.pithos_dir, self.env.env.image_dir]: |
780 |
ret.append("mkdir -p %s" % d)
|
781 |
cmd = """
|
782 |
cat >> /etc/fstab <<EOF
|
783 |
{0}:{1} {1} nfs defaults,rw,noatime,rsize=131072,wsize=131072 0 0
|
784 |
EOF
|
785 |
""".format(self.env.env.pithos.ip, d) |
786 |
ret.append(cmd) |
787 |
|
788 |
return ret
|
789 |
|
790 |
def initialize(self): |
791 |
ret = [] |
792 |
for d in [self.env.env.pithos_dir, self.env.env.image_dir]: |
793 |
ret.append("mount %s" % d)
|
794 |
return ret
|
795 |
|
796 |
|
797 |
class NFS(SynnefoComponent): |
798 |
REQUIRED_PACKAGES = [ |
799 |
"nfs-kernel-server"
|
800 |
] |
801 |
|
802 |
def prepare_image(self): |
803 |
url = self.env.env.debian_base_url
|
804 |
d = self.env.env.image_dir
|
805 |
image = "debian_base.diskdump"
|
806 |
return ["wget %s -O %s/%s" % (url, d, image)] |
807 |
|
808 |
def prepare(self): |
809 |
p = self.env.env.pithos_dir
|
810 |
return [
|
811 |
"mkdir -p %s" % self.env.env.image_dir, |
812 |
"mkdir -p %s/data" % p,
|
813 |
"chown www-data.www-data %s/data" % p,
|
814 |
"chmod g+ws %s/data" % p,
|
815 |
] + self.prepare_image()
|
816 |
|
817 |
def update_exports(self, node_info): |
818 |
cmd = """
|
819 |
cat >> /etc/exports <<EOF
|
820 |
{0} {2}(rw,async,no_subtree_check,no_root_squash)
|
821 |
{1} {2}(rw,async,no_subtree_check,no_root_squash)
|
822 |
EOF
|
823 |
""".format(self.env.env.pithos_dir, self.env.env.image_dir, node_info.ip) |
824 |
return [cmd] + self.restart() |
825 |
|
826 |
def restart(self): |
827 |
return ["exportfs -a"] |
828 |
|
829 |
|
830 |
class Pithos(SynnefoComponent): |
831 |
REQUIRED_PACKAGES = [ |
832 |
"kamaki",
|
833 |
"snf-pithos-backend",
|
834 |
"snf-pithos-app",
|
835 |
"snf-pithos-webclient",
|
836 |
] |
837 |
|
838 |
def export_service(self): |
839 |
f = self.env.jsonfile
|
840 |
return [
|
841 |
"snf-manage service-export-pithos > %s" % f
|
842 |
] |
843 |
|
844 |
def configure(self): |
845 |
r1 = { |
846 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
847 |
"PITHOS": self.env.env.pithos.fqdn, |
848 |
"db_node": self.env.env.db.ip, |
849 |
"synnefo_user": self.env.env.synnefo_user, |
850 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
851 |
"pithos_dir": self.env.env.pithos_dir, |
852 |
"PITHOS_SERVICE_TOKEN": self.env.service_token, |
853 |
"oa2_secret": self.env.env.oa2_secret, |
854 |
} |
855 |
r2 = { |
856 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
857 |
"PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE": self.env.service_id, |
858 |
} |
859 |
|
860 |
return [
|
861 |
("/etc/synnefo/pithos.conf", r1, {}),
|
862 |
("/etc/synnefo/webclient.conf", r2, {}),
|
863 |
] |
864 |
|
865 |
def initialize(self): |
866 |
return ["pithos-migrate stamp head"] |
867 |
|
868 |
|
869 |
class Cyclades(SynnefoComponent): |
870 |
REQUIRED_PACKAGES = [ |
871 |
"memcached",
|
872 |
"python-memcache",
|
873 |
"snf-pithos-backend",
|
874 |
"kamaki",
|
875 |
"snf-cyclades-app",
|
876 |
"python-django-south",
|
877 |
] |
878 |
|
879 |
def add_network(self): |
880 |
subnet = self.env.env.synnefo_public_network_subnet
|
881 |
gw = self.env.env.synnefo_public_network_gateway
|
882 |
ntype = self.env.env.synnefo_public_network_type
|
883 |
link = self.env.env.common_bridge
|
884 |
|
885 |
cmd = """
|
886 |
snf-manage network-create --subnet={0} --gateway={1} --public \
|
887 |
--dhcp=True --flavor={2} --mode=bridged --link={3} --name=Internet \
|
888 |
--floating-ip-pool=True
|
889 |
""".format(subnet, gw, ntype, link)
|
890 |
|
891 |
return [cmd]
|
892 |
|
893 |
def add_network6(self): |
894 |
subnet = "babe::/64"
|
895 |
gw = "babe::1"
|
896 |
ntype = self.env.env.synnefo_public_network_type
|
897 |
link = self.env.env.common_bridge
|
898 |
|
899 |
cmd = """
|
900 |
snf-manage network-create --subnet6={0} \
|
901 |
--gateway6={1} --public --dhcp=True --flavor={2} --mode=bridged \
|
902 |
--link={3} --name=IPv6PublicNetwork
|
903 |
""".format(subnet, gw, ntype, link)
|
904 |
|
905 |
return [cmd]
|
906 |
|
907 |
def export_service(self): |
908 |
f = self.env.jsonfile
|
909 |
return [
|
910 |
"snf-manage service-export-cyclades > %s" % f
|
911 |
] |
912 |
|
913 |
def list_backends(self): |
914 |
return [
|
915 |
"snf-manage backend-list"
|
916 |
] |
917 |
|
918 |
def add_backend(self): |
919 |
cluster = self.env.env.cluster
|
920 |
user = self.env.env.synnefo_user
|
921 |
passwd = self.env.env.synnefo_rapi_passwd
|
922 |
return [
|
923 |
"snf-manage backend-add --clustername=%s --user=%s --pass=%s" %
|
924 |
(cluster.fqdn, user, passwd) |
925 |
] |
926 |
|
927 |
def undrain_backend(self): |
928 |
backend_id = self.env.backend_id
|
929 |
return [
|
930 |
"snf-manage backend-modify --drained=False %s" % str(backend_id) |
931 |
] |
932 |
|
933 |
def prepare(self): |
934 |
return ["sed -i 's/false/true/' /etc/default/snf-dispatcher"] |
935 |
|
936 |
def configure(self): |
937 |
r1 = { |
938 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
939 |
"CYCLADES": self.env.env.cyclades.fqdn, |
940 |
"mq_node": self.env.env.mq.ip, |
941 |
"db_node": self.env.env.db.ip, |
942 |
"synnefo_user": self.env.env.synnefo_user, |
943 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
944 |
"synnefo_rabbitmq_passwd": self.env.env.synnefo_rabbitmq_passwd, |
945 |
"pithos_dir": self.env.env.pithos_dir, |
946 |
"common_bridge": self.env.env.common_bridge, |
947 |
"HOST": self.env.env.cyclades.ip, |
948 |
"domain": self.env.env.domain, |
949 |
"CYCLADES_SERVICE_TOKEN": self.env.service_token, |
950 |
"STATS": self.env.env.stats.fqdn, |
951 |
"SYNNEFO_VNC_PASSWD": self.env.env.synnefo_vnc_passwd, |
952 |
"CYCLADES_NODE_IP": self.env.env.cyclades.ip |
953 |
} |
954 |
return [
|
955 |
("/etc/synnefo/cyclades.conf", r1, {})
|
956 |
] |
957 |
|
958 |
def initialize(self): |
959 |
cpu = self.env.env.flavor_cpu
|
960 |
ram = self.env.env.flavor_ram
|
961 |
disk = self.env.env.flavor_disk
|
962 |
storage = self.env.env.flavor_storage
|
963 |
return [
|
964 |
"snf-manage syncdb",
|
965 |
"snf-manage migrate --delete-ghost-migrations",
|
966 |
"snf-manage pool-create --type=mac-prefix \
|
967 |
--base=aa:00:0 --size=65536",
|
968 |
"snf-manage pool-create --type=bridge --base=prv --size=20",
|
969 |
"snf-manage flavor-create %s %s %s %s" % (cpu, ram, disk, storage),
|
970 |
] |
971 |
|
972 |
def restart(self): |
973 |
return [
|
974 |
"/etc/init.d/gunicorn restart",
|
975 |
"/etc/init.d/snf-dispatcher restart",
|
976 |
] |
977 |
|
978 |
|
979 |
class VNC(SynnefoComponent): |
980 |
REQUIRED_PACKAGES = [ |
981 |
"snf-vncauthproxy"
|
982 |
] |
983 |
|
984 |
def prepare(self): |
985 |
return ["mkdir -p /var/lib/vncauthproxy"] |
986 |
|
987 |
def configure(self): |
988 |
return [
|
989 |
("/var/lib/vncauthproxy/users", {}, {})
|
990 |
] |
991 |
|
992 |
def initialize(self): |
993 |
user = self.env.env.synnefo_user
|
994 |
passwd = self.env.env.synnefo_vnc_passwd
|
995 |
#TODO: run vncauthproxy-passwd
|
996 |
return []
|
997 |
|
998 |
def restart(self): |
999 |
return [
|
1000 |
"/etc/init.d/vncauthproxy restart"
|
1001 |
] |
1002 |
|
1003 |
|
1004 |
class Kamaki(SynnefoComponent): |
1005 |
REQUIRED_PACKAGES = [ |
1006 |
"python-progress",
|
1007 |
"kamaki",
|
1008 |
] |
1009 |
|
1010 |
def initialize(self): |
1011 |
url = "https://%s/astakos/identity/v2.0" % self.env.env.accounts.fqdn |
1012 |
token = self.env.user_auth_token
|
1013 |
return [
|
1014 |
"kamaki config set cloud.default.url %s" % url,
|
1015 |
"kamaki config set cloud.default.token %s" % token,
|
1016 |
"kamaki container create images",
|
1017 |
] |
1018 |
|
1019 |
def fetch_image(self): |
1020 |
url = self.env.env.debian_base_url
|
1021 |
image = "debian_base.diskdump"
|
1022 |
return [
|
1023 |
"wget %s -O /tmp/%s" % (url, image)
|
1024 |
] |
1025 |
|
1026 |
def upload_image(self): |
1027 |
image = "debian_base.diskdump"
|
1028 |
return [
|
1029 |
"kamaki file upload --container images /tmp/%s %s" % (image, image)
|
1030 |
] |
1031 |
|
1032 |
def register_image(self): |
1033 |
image = "debian_base.diskdump"
|
1034 |
image_location = "/images/%s" % image
|
1035 |
cmd = """
|
1036 |
kamaki image register --name "Debian Base" --location {0} \
|
1037 |
--public --disk-format=diskdump \
|
1038 |
--property OSFAMILY=linux --property ROOT_PARTITION=1 \
|
1039 |
--property description="Debian Squeeze Base System" \
|
1040 |
--property size=450M --property kernel=2.6.32 \
|
1041 |
--property GUI="No GUI" --property sortorder=1 \
|
1042 |
--property USERS=root --property OS=debian
|
1043 |
""".format(image_location)
|
1044 |
return [
|
1045 |
"sleep 5",
|
1046 |
cmd |
1047 |
] |
1048 |
|
1049 |
|
1050 |
class Burnin(SynnefoComponent): |
1051 |
REQUIRED_PACKAGES = [ |
1052 |
"kamaki",
|
1053 |
"snf-tools",
|
1054 |
] |
1055 |
|
1056 |
|
1057 |
class Collectd(SynnefoComponent): |
1058 |
REQUIRED_PACKAGES = [ |
1059 |
"collectd",
|
1060 |
] |
1061 |
|
1062 |
def configure(self): |
1063 |
return [
|
1064 |
("/etc/collectd/collectd.conf", {}, {}),
|
1065 |
] |
1066 |
|
1067 |
def restart(self): |
1068 |
return [
|
1069 |
"/etc/init.d/collectd restart",
|
1070 |
] |
1071 |
|
1072 |
|
1073 |
class Stats(SynnefoComponent): |
1074 |
REQUIRED_PACKAGES = [ |
1075 |
"snf-stats-app",
|
1076 |
] |
1077 |
|
1078 |
def prepare(self): |
1079 |
return [
|
1080 |
"mkdir -p /var/cache/snf-stats-app/",
|
1081 |
"chown www-data:www-data /var/cache/snf-stats-app/",
|
1082 |
] |
1083 |
|
1084 |
def configure(self): |
1085 |
r1 = { |
1086 |
"STATS": self.env.env.stats.fqdn, |
1087 |
} |
1088 |
return [
|
1089 |
("/etc/synnefo/stats.conf", r1, {}),
|
1090 |
("/etc/collectd/synnefo-stats.conf", r1, {}),
|
1091 |
] |
1092 |
|
1093 |
def restart(self): |
1094 |
return [
|
1095 |
"/etc/init.d/gunicorn restart",
|
1096 |
"/etc/init.d/apache2 restart",
|
1097 |
] |
1098 |
|
1099 |
|
1100 |
class GanetiCollectd(SynnefoComponent): |
1101 |
def configure(self): |
1102 |
r1 = { |
1103 |
"STATS": self.env.env.stats.fqdn, |
1104 |
} |
1105 |
return [
|
1106 |
("/etc/collectd/passwd", {}, {}),
|
1107 |
("/etc/collectd/synnefo-ganeti.conf", r1, {}),
|
1108 |
] |