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