root / snf-deploy / snfdeploy / components.py @ caf065e1
History | View | Annotate | Download (33.2 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 |
"mkdir -p /srv/archip/blocks",
|
377 |
"mkdir -p /srv/archip/maps",
|
378 |
"archipelago restart"]
|
379 |
|
380 |
|
381 |
class Master(SynnefoComponent): |
382 |
def add_rapi_user(self): |
383 |
user = self.env.env.synnefo_user
|
384 |
passwd = self.env.env.synnefo_rapi_passwd
|
385 |
x = "%s:Ganeti Remote API:%s" % (user, passwd)
|
386 |
|
387 |
cmd = """
|
388 |
cat >> /var/lib/ganeti/rapi/users <<EOF
|
389 |
%s {HA1}$(echo -n %s | openssl md5 | sed 's/^.* //') write
|
390 |
EOF
|
391 |
""" % (self.env.env.synnefo_user, x) |
392 |
|
393 |
return [cmd] + self.restart() |
394 |
|
395 |
def add_node(self, node_info): |
396 |
commands = [ |
397 |
"gnt-node add --no-ssh-key-check --master-capable=yes " +
|
398 |
"--vm-capable=yes " + node_info.fqdn,
|
399 |
] |
400 |
return commands
|
401 |
|
402 |
def try_use_vg(self): |
403 |
vg = self.env.env.vg
|
404 |
return [
|
405 |
"gnt-cluster modify --vg-name=%s || true" % vg,
|
406 |
"gnt-cluster modify --disk-parameters=drbd:metavg=%s" % vg,
|
407 |
"gnt-group modify --disk-parameters=drbd:metavg=%s default" % vg,
|
408 |
] |
409 |
|
410 |
def initialize(self): |
411 |
cmd = """
|
412 |
gnt-cluster init --enabled-hypervisors=kvm \
|
413 |
--no-lvm-storage --no-drbd-storage \
|
414 |
--nic-parameters link={0},mode=bridged \
|
415 |
--master-netdev {1} \
|
416 |
--specs-nic-count min=0,max=8 \
|
417 |
--default-iallocator hail \
|
418 |
--hypervisor-parameters kvm:kernel_path=,vnc_bind_address=0.0.0.0 \
|
419 |
--no-ssh-init --no-etc-hosts \
|
420 |
--enabled-disk-templates file,plain,ext,drbd \
|
421 |
{2}
|
422 |
""".format(self.env.env.common_bridge, |
423 |
self.env.env.cluster_netdev, self.env.env.cluster.fqdn) |
424 |
|
425 |
return [cmd] + self.try_use_vg() + self.add_rapi_user() |
426 |
|
427 |
def restart(self): |
428 |
return ["/etc/init.d/ganeti restart"] |
429 |
|
430 |
|
431 |
class Image(SynnefoComponent): |
432 |
REQUIRED_PACKAGES = [ |
433 |
"snf-image",
|
434 |
] |
435 |
|
436 |
def check(self): |
437 |
return ["mkdir -p %s" % self.env.env.image_dir] |
438 |
|
439 |
def configure(self): |
440 |
tmpl = "/etc/default/snf-image"
|
441 |
replace = { |
442 |
"synnefo_user": self.env.env.synnefo_user, |
443 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
444 |
"pithos_dir": self.env.env.pithos_dir, |
445 |
"db_node": self.env.env.db.ip, |
446 |
"image_dir": self.env.env.image_dir, |
447 |
} |
448 |
return [(tmpl, replace, {})]
|
449 |
|
450 |
def initialize(self): |
451 |
return ["snf-image-update-helper -y"] |
452 |
|
453 |
|
454 |
class GTools(SynnefoComponent): |
455 |
REQUIRED_PACKAGES = [ |
456 |
"snf-cyclades-gtools",
|
457 |
] |
458 |
|
459 |
def check(self): |
460 |
return ["ping -c1 %s" % self.env.env.mq.ip] |
461 |
|
462 |
def configure(self): |
463 |
tmpl = "/etc/synnefo/gtools.conf"
|
464 |
replace = { |
465 |
"synnefo_user": self.env.env.synnefo_user, |
466 |
"synnefo_rabbitmq_passwd": self.env.env.synnefo_rabbitmq_passwd, |
467 |
"mq_node": self.env.env.mq.ip, |
468 |
} |
469 |
return [(tmpl, replace, {})]
|
470 |
|
471 |
def initialize(self): |
472 |
return [
|
473 |
"sed -i 's/false/true/' /etc/default/snf-ganeti-eventd",
|
474 |
"/etc/init.d/snf-ganeti-eventd start",
|
475 |
] |
476 |
|
477 |
def restart(self): |
478 |
return ["/etc/init.d/snf-ganeti-eventd restart"] |
479 |
|
480 |
|
481 |
class Network(SynnefoComponent): |
482 |
REQUIRED_PACKAGES = [ |
483 |
"python-nfqueue",
|
484 |
"snf-network",
|
485 |
"nfdhcpd",
|
486 |
] |
487 |
|
488 |
def configure(self): |
489 |
r1 = { |
490 |
"ns_node_ip": self.env.env.ns.ip |
491 |
} |
492 |
r2 = { |
493 |
"common_bridge": self.env.env.common_bridge, |
494 |
"public_iface": self.env.env.public_iface, |
495 |
"subnet": self.env.env.synnefo_public_network_subnet, |
496 |
"gateway": self.env.env.synnefo_public_network_gateway, |
497 |
"router_ip": self.env.env.router.ip, |
498 |
"node_ip": self.node_info.ip, |
499 |
} |
500 |
r3 = { |
501 |
"domain": self.env.env.domain, |
502 |
"server": self.env.env.ns.ip, |
503 |
"keyfile": self.env.env.ddns_private_key, |
504 |
} |
505 |
|
506 |
return [
|
507 |
("/etc/nfdhcpd/nfdhcpd.conf", r1, {}),
|
508 |
("/etc/rc.local", r2, {"mode": 0755}), |
509 |
("/etc/default/snf-network", r3, {}),
|
510 |
] |
511 |
|
512 |
def initialize(self): |
513 |
return ["/etc/init.d/rc.local start"] |
514 |
|
515 |
def restart(self): |
516 |
return ["/etc/init.d/nfdhcpd restart"] |
517 |
|
518 |
|
519 |
class Apache(SynnefoComponent): |
520 |
REQUIRED_PACKAGES = [ |
521 |
"apache2",
|
522 |
] |
523 |
|
524 |
def prepare(self): |
525 |
return [
|
526 |
"a2enmod ssl", "a2enmod rewrite", "a2dissite default", |
527 |
"a2enmod headers",
|
528 |
"a2enmod proxy_http", "a2dismod autoindex", |
529 |
] |
530 |
|
531 |
def configure(self): |
532 |
r1 = {"HOST": self.node_info.fqdn} |
533 |
return [
|
534 |
("/etc/apache2/sites-available/synnefo", r1, {}),
|
535 |
("/etc/apache2/sites-available/synnefo-ssl", r1, {}),
|
536 |
] |
537 |
|
538 |
def initialize(self): |
539 |
return [
|
540 |
"a2ensite synnefo", "a2ensite synnefo-ssl", |
541 |
] |
542 |
|
543 |
def restart(self): |
544 |
return [
|
545 |
"/etc/init.d/apache2 restart",
|
546 |
] |
547 |
|
548 |
|
549 |
class Gunicorn(SynnefoComponent): |
550 |
REQUIRED_PACKAGES = [ |
551 |
"gunicorn",
|
552 |
] |
553 |
|
554 |
def prepare(self): |
555 |
return [
|
556 |
"chown root.www-data /var/log/gunicorn",
|
557 |
] |
558 |
|
559 |
def configure(self): |
560 |
r1 = {"HOST": self.node_info.fqdn} |
561 |
return [
|
562 |
("/etc/gunicorn.d/synnefo", r1, {}),
|
563 |
] |
564 |
|
565 |
def restart(self): |
566 |
return [
|
567 |
"/etc/init.d/gunicorn restart",
|
568 |
] |
569 |
|
570 |
|
571 |
class Common(SynnefoComponent): |
572 |
REQUIRED_PACKAGES = [ |
573 |
# snf-common
|
574 |
"python-objpool",
|
575 |
"snf-common",
|
576 |
"python-astakosclient",
|
577 |
"snf-django-lib",
|
578 |
"snf-branding",
|
579 |
] |
580 |
|
581 |
def configure(self): |
582 |
r1 = { |
583 |
"EMAIL_SUBJECT_PREFIX": self.node_info.hostname, |
584 |
"domain": self.env.env.domain, |
585 |
"HOST": self.node_info.fqdn, |
586 |
"MAIL_DIR": self.env.env.mail_dir, |
587 |
} |
588 |
return [
|
589 |
("/etc/synnefo/common.conf", r1, {}),
|
590 |
] |
591 |
|
592 |
def initialize(self): |
593 |
return ["mkdir -p {0}; chmod 777 {0}".format(self.env.env.mail_dir)] |
594 |
|
595 |
def restart(self): |
596 |
return [
|
597 |
"/etc/init.d/gunicorn restart",
|
598 |
] |
599 |
|
600 |
|
601 |
class WEB(SynnefoComponent): |
602 |
REQUIRED_PACKAGES = [ |
603 |
"snf-webproject",
|
604 |
"python-psycopg2",
|
605 |
"python-gevent",
|
606 |
"python-django",
|
607 |
] |
608 |
|
609 |
def check(self): |
610 |
return ["ping -c1 %s" % self.env.env.db.fqdn] |
611 |
|
612 |
def configure(self): |
613 |
r1 = { |
614 |
"synnefo_user": self.env.env.synnefo_user, |
615 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
616 |
"db_node": self.env.env.db.fqdn, |
617 |
"domain": self.env.env.domain, |
618 |
} |
619 |
return [
|
620 |
("/etc/synnefo/webproject.conf", r1, {}),
|
621 |
] |
622 |
|
623 |
def restart(self): |
624 |
return [
|
625 |
"/etc/init.d/gunicorn restart",
|
626 |
] |
627 |
|
628 |
|
629 |
class Astakos(SynnefoComponent): |
630 |
REQUIRED_PACKAGES = [ |
631 |
"python-django-south",
|
632 |
"snf-astakos-app",
|
633 |
"kamaki",
|
634 |
] |
635 |
|
636 |
def export_service(self): |
637 |
f = self.env.jsonfile
|
638 |
return [
|
639 |
"snf-manage service-export-astakos > %s" % f
|
640 |
] |
641 |
|
642 |
def import_service(self): |
643 |
f = self.env.jsonfile
|
644 |
return [
|
645 |
"snf-manage service-import --json=%s" % f
|
646 |
] |
647 |
|
648 |
def set_default_quota(self): |
649 |
cmd = "snf-manage resource-modify --default-quota"
|
650 |
return [
|
651 |
"%s 40G pithos.diskspace" % cmd,
|
652 |
"%s 2 astakos.pending_app" % cmd,
|
653 |
"%s 4 cyclades.vm" % cmd,
|
654 |
"%s 40G cyclades.disk" % cmd,
|
655 |
"%s 16G cyclades.total_ram" % cmd,
|
656 |
"%s 8G cyclades.ram" % cmd,
|
657 |
"%s 32 cyclades.total_cpu" % cmd,
|
658 |
"%s 16 cyclades.cpu" % cmd,
|
659 |
"%s 4 cyclades.network.private" % cmd,
|
660 |
"%s 4 cyclades.floating_ip" % cmd,
|
661 |
] |
662 |
|
663 |
def modify_all_quota(self): |
664 |
cmd = "snf-manage user-modify -f --all --base-quota"
|
665 |
return [
|
666 |
"%s pithos.diskspace 40G" % cmd,
|
667 |
"%s astakos.pending_app 2" % cmd,
|
668 |
"%s cyclades.vm 4" % cmd,
|
669 |
"%s cyclades.disk 40G" % cmd,
|
670 |
"%s cyclades.total_ram 16G" % cmd,
|
671 |
"%s cyclades.ram 8G" % cmd,
|
672 |
"%s cyclades.total_cpu 32" % cmd,
|
673 |
"%s cyclades.cpu 16" % cmd,
|
674 |
"%s cyclades.network.private 4" % cmd,
|
675 |
"%s cyclades.floating_ip 4" % cmd,
|
676 |
] |
677 |
|
678 |
def get_services(self): |
679 |
return [
|
680 |
"snf-manage component-list -o id,name,token"
|
681 |
] |
682 |
|
683 |
def configure(self): |
684 |
r1 = { |
685 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
686 |
"domain": self.env.env.domain, |
687 |
"CYCLADES": self.env.env.cyclades.fqdn, |
688 |
"PITHOS": self.env.env.pithos.fqdn, |
689 |
} |
690 |
return [
|
691 |
("/etc/synnefo/astakos.conf", r1, {})
|
692 |
] |
693 |
|
694 |
def initialize(self): |
695 |
secret = self.env.env.oa2_secret
|
696 |
view = "https://%s/pithos/ui/view" % self.env.env.pithos.fqdn |
697 |
oa2 = "snf-manage oauth2-client-add pithos-view \
|
698 |
--secret=%s --is-trusted --url %s" % (secret, view)
|
699 |
|
700 |
return [
|
701 |
"snf-manage syncdb --noinput",
|
702 |
"snf-manage migrate im --delete-ghost-migrations",
|
703 |
"snf-manage migrate quotaholder_app",
|
704 |
"snf-manage migrate oa2",
|
705 |
"snf-manage loaddata groups",
|
706 |
oa2 |
707 |
] + self.astakos_register_components()
|
708 |
|
709 |
def astakos_register_components(self): |
710 |
# base urls
|
711 |
cbu = "https://%s/cyclades" % self.env.env.cyclades.fqdn |
712 |
pbu = "https://%s/pithos" % self.env.env.pithos.fqdn |
713 |
abu = "https://%s/astakos" % self.env.env.accounts.fqdn |
714 |
cmsurl = "https://%s/home" % self.env.env.cms.fqdn |
715 |
|
716 |
cmd = "snf-manage component-add"
|
717 |
h = "%s home --base-url %s --ui-url %s" % (cmd, cmsurl, cmsurl)
|
718 |
c = "%s cyclades --base-url %s --ui-url %s/ui" % (cmd, cbu, cbu)
|
719 |
p = "%s pithos --base-url %s --ui-url %s/ui" % (cmd, pbu, pbu)
|
720 |
a = "%s astakos --base-url %s --ui-url %s/ui" % (cmd, abu, abu)
|
721 |
|
722 |
return [h, c, p, a]
|
723 |
|
724 |
def add_user(self): |
725 |
info = ( |
726 |
self.env.env.user_passwd,
|
727 |
self.env.env.user_email,
|
728 |
self.env.env.user_name,
|
729 |
self.env.env.user_lastname,
|
730 |
) |
731 |
cmd = "snf-manage user-add --password %s %s %s %s" % info
|
732 |
return [cmd]
|
733 |
|
734 |
def activate_user(self): |
735 |
user_id = self.env.user_id
|
736 |
return [
|
737 |
"snf-manage user-modify --verify %s" % user_id,
|
738 |
"snf-manage user-modify --accept %s" % user_id,
|
739 |
] |
740 |
|
741 |
|
742 |
class CMS(SynnefoComponent): |
743 |
REQUIRED_PACKAGES = [ |
744 |
"snf-cloudcms"
|
745 |
] |
746 |
|
747 |
def configure(self): |
748 |
r1 = { |
749 |
"ACCOUNTS": self.env.env.accounts.fqdn |
750 |
} |
751 |
r2 = { |
752 |
"DOMAIN": self.env.env.domain |
753 |
} |
754 |
return [
|
755 |
("/etc/synnefo/cms.conf", r1, {}),
|
756 |
("/tmp/sites.json", r2, {}),
|
757 |
("/tmp/page.json", {}, {}),
|
758 |
] |
759 |
|
760 |
def initialize(self): |
761 |
return [
|
762 |
"snf-manage syncdb",
|
763 |
"snf-manage migrate --delete-ghost-migrations",
|
764 |
"snf-manage loaddata /tmp/sites.json",
|
765 |
"snf-manage loaddata /tmp/page.json",
|
766 |
"snf-manage createsuperuser --username=admin \
|
767 |
--email=admin@%s --noinput" % self.env.env.domain, |
768 |
] |
769 |
|
770 |
def restart(self): |
771 |
return ["/etc/init.d/gunicorn restart"] |
772 |
|
773 |
|
774 |
class Mount(SynnefoComponent): |
775 |
REQUIRED_PACKAGES = [ |
776 |
"nfs-common"
|
777 |
] |
778 |
|
779 |
def prepare(self): |
780 |
ret = [] |
781 |
dirs = [self.env.env.pithos_dir, self.env.env.image_dir, "/srv/archip"] |
782 |
for d in dirs: |
783 |
ret.append("mkdir -p %s" % d)
|
784 |
cmd = """
|
785 |
cat >> /etc/fstab <<EOF
|
786 |
{0}:{1} {1} nfs defaults,rw,noatime,rsize=131072,wsize=131072 0 0
|
787 |
EOF
|
788 |
""".format(self.env.env.pithos.ip, d) |
789 |
ret.append(cmd) |
790 |
|
791 |
return ret
|
792 |
|
793 |
def initialize(self): |
794 |
ret = [] |
795 |
dirs = [self.env.env.pithos_dir, self.env.env.image_dir, "/srv/archip"] |
796 |
for d in dirs: |
797 |
ret.append("mount %s" % d)
|
798 |
return ret
|
799 |
|
800 |
|
801 |
class NFS(SynnefoComponent): |
802 |
REQUIRED_PACKAGES = [ |
803 |
"nfs-kernel-server"
|
804 |
] |
805 |
|
806 |
def prepare_image(self): |
807 |
url = self.env.env.debian_base_url
|
808 |
d = self.env.env.image_dir
|
809 |
image = "debian_base.diskdump"
|
810 |
return ["wget %s -O %s/%s" % (url, d, image)] |
811 |
|
812 |
def prepare(self): |
813 |
p = self.env.env.pithos_dir
|
814 |
return [
|
815 |
"mkdir -p %s" % self.env.env.image_dir, |
816 |
"mkdir -p %s/data" % p,
|
817 |
"mkdir -p /srv/archip/blocks",
|
818 |
"mkdir -p /srv/archip/maps",
|
819 |
"chown www-data.www-data %s/data" % p,
|
820 |
"chmod g+ws %s/data" % p,
|
821 |
] + self.prepare_image()
|
822 |
|
823 |
def update_exports(self, node_info): |
824 |
cmd = """
|
825 |
cat >> /etc/exports <<EOF
|
826 |
{0} {2}(rw,async,no_subtree_check,no_root_squash)
|
827 |
{1} {2}(rw,async,no_subtree_check,no_root_squash)
|
828 |
/srv/archip {2}(rw,async,no_subtree_check,no_root_squash)
|
829 |
EOF
|
830 |
""".format(self.env.env.pithos_dir, self.env.env.image_dir, node_info.ip) |
831 |
return [cmd] + self.restart() |
832 |
|
833 |
def restart(self): |
834 |
return ["exportfs -a"] |
835 |
|
836 |
|
837 |
class Pithos(SynnefoComponent): |
838 |
REQUIRED_PACKAGES = [ |
839 |
"kamaki",
|
840 |
"python-svipc",
|
841 |
"snf-pithos-app",
|
842 |
"snf-pithos-webclient",
|
843 |
] |
844 |
|
845 |
def export_service(self): |
846 |
f = self.env.jsonfile
|
847 |
return [
|
848 |
"snf-manage service-export-pithos > %s" % f
|
849 |
] |
850 |
|
851 |
def configure(self): |
852 |
r1 = { |
853 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
854 |
"PITHOS": self.env.env.pithos.fqdn, |
855 |
"db_node": self.env.env.db.ip, |
856 |
"synnefo_user": self.env.env.synnefo_user, |
857 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
858 |
"pithos_dir": self.env.env.pithos_dir, |
859 |
"PITHOS_SERVICE_TOKEN": self.env.service_token, |
860 |
"oa2_secret": self.env.env.oa2_secret, |
861 |
} |
862 |
r2 = { |
863 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
864 |
"PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE": self.env.service_id, |
865 |
} |
866 |
|
867 |
return [
|
868 |
("/etc/synnefo/pithos.conf", r1, {}),
|
869 |
("/etc/synnefo/webclient.conf", r2, {}),
|
870 |
] |
871 |
|
872 |
def initialize(self): |
873 |
return ["pithos-migrate stamp head"] |
874 |
|
875 |
|
876 |
class PithosBackend(SynnefoComponent): |
877 |
REQUIRED_PACKAGES = [ |
878 |
"snf-pithos-backend",
|
879 |
] |
880 |
|
881 |
def configure(self): |
882 |
r1 = { |
883 |
"db_node": self.env.env.db.ip, |
884 |
"synnefo_user": self.env.env.synnefo_user, |
885 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
886 |
"pithos_dir": self.env.env.pithos_dir, |
887 |
} |
888 |
|
889 |
return [
|
890 |
("/etc/synnefo/backend.conf", r1, {}),
|
891 |
] |
892 |
|
893 |
|
894 |
class Cyclades(SynnefoComponent): |
895 |
REQUIRED_PACKAGES = [ |
896 |
"memcached",
|
897 |
"python-memcache",
|
898 |
"kamaki",
|
899 |
"snf-cyclades-app",
|
900 |
"python-django-south",
|
901 |
] |
902 |
|
903 |
def add_network(self): |
904 |
subnet = self.env.env.synnefo_public_network_subnet
|
905 |
gw = self.env.env.synnefo_public_network_gateway
|
906 |
ntype = self.env.env.synnefo_public_network_type
|
907 |
link = self.env.env.common_bridge
|
908 |
|
909 |
cmd = """
|
910 |
snf-manage network-create --subnet={0} --gateway={1} --public \
|
911 |
--dhcp=True --flavor={2} --mode=bridged --link={3} --name=Internet \
|
912 |
--floating-ip-pool=True
|
913 |
""".format(subnet, gw, ntype, link)
|
914 |
|
915 |
return [cmd]
|
916 |
|
917 |
def add_network6(self): |
918 |
subnet = "babe::/64"
|
919 |
gw = "babe::1"
|
920 |
ntype = self.env.env.synnefo_public_network_type
|
921 |
link = self.env.env.common_bridge
|
922 |
|
923 |
cmd = """
|
924 |
snf-manage network-create --subnet6={0} \
|
925 |
--gateway6={1} --public --dhcp=True --flavor={2} --mode=bridged \
|
926 |
--link={3} --name=IPv6PublicNetwork
|
927 |
""".format(subnet, gw, ntype, link)
|
928 |
|
929 |
return [cmd]
|
930 |
|
931 |
def export_service(self): |
932 |
f = self.env.jsonfile
|
933 |
return [
|
934 |
"snf-manage service-export-cyclades > %s" % f
|
935 |
] |
936 |
|
937 |
def list_backends(self): |
938 |
return [
|
939 |
"snf-manage backend-list"
|
940 |
] |
941 |
|
942 |
def add_backend(self): |
943 |
cluster = self.env.env.cluster
|
944 |
user = self.env.env.synnefo_user
|
945 |
passwd = self.env.env.synnefo_rapi_passwd
|
946 |
return [
|
947 |
"snf-manage backend-add --clustername=%s --user=%s --pass=%s" %
|
948 |
(cluster.fqdn, user, passwd) |
949 |
] |
950 |
|
951 |
def undrain_backend(self): |
952 |
backend_id = self.env.backend_id
|
953 |
return [
|
954 |
"snf-manage backend-modify --drained=False %s" % str(backend_id) |
955 |
] |
956 |
|
957 |
def prepare(self): |
958 |
return ["sed -i 's/false/true/' /etc/default/snf-dispatcher"] |
959 |
|
960 |
def configure(self): |
961 |
r1 = { |
962 |
"ACCOUNTS": self.env.env.accounts.fqdn, |
963 |
"CYCLADES": self.env.env.cyclades.fqdn, |
964 |
"mq_node": self.env.env.mq.ip, |
965 |
"db_node": self.env.env.db.ip, |
966 |
"synnefo_user": self.env.env.synnefo_user, |
967 |
"synnefo_db_passwd": self.env.env.synnefo_db_passwd, |
968 |
"synnefo_rabbitmq_passwd": self.env.env.synnefo_rabbitmq_passwd, |
969 |
"pithos_dir": self.env.env.pithos_dir, |
970 |
"common_bridge": self.env.env.common_bridge, |
971 |
"HOST": self.env.env.cyclades.ip, |
972 |
"domain": self.env.env.domain, |
973 |
"CYCLADES_SERVICE_TOKEN": self.env.service_token, |
974 |
"STATS": self.env.env.stats.fqdn, |
975 |
"SYNNEFO_VNC_PASSWD": self.env.env.synnefo_vnc_passwd, |
976 |
"CYCLADES_NODE_IP": self.env.env.cyclades.ip |
977 |
} |
978 |
return [
|
979 |
("/etc/synnefo/cyclades.conf", r1, {})
|
980 |
] |
981 |
|
982 |
def initialize(self): |
983 |
cpu = self.env.env.flavor_cpu
|
984 |
ram = self.env.env.flavor_ram
|
985 |
disk = self.env.env.flavor_disk
|
986 |
storage = self.env.env.flavor_storage
|
987 |
return [
|
988 |
"snf-manage syncdb",
|
989 |
"snf-manage migrate --delete-ghost-migrations",
|
990 |
"snf-manage pool-create --type=mac-prefix \
|
991 |
--base=aa:00:0 --size=65536",
|
992 |
"snf-manage pool-create --type=bridge --base=prv --size=20",
|
993 |
"snf-manage flavor-create %s %s %s %s" % (cpu, ram, disk, storage),
|
994 |
] |
995 |
|
996 |
def restart(self): |
997 |
return [
|
998 |
"/etc/init.d/gunicorn restart",
|
999 |
"/etc/init.d/snf-dispatcher restart",
|
1000 |
] |
1001 |
|
1002 |
|
1003 |
class VNC(SynnefoComponent): |
1004 |
REQUIRED_PACKAGES = [ |
1005 |
"snf-vncauthproxy"
|
1006 |
] |
1007 |
|
1008 |
def prepare(self): |
1009 |
return ["mkdir -p /var/lib/vncauthproxy"] |
1010 |
|
1011 |
def configure(self): |
1012 |
return [
|
1013 |
("/var/lib/vncauthproxy/users", {}, {})
|
1014 |
] |
1015 |
|
1016 |
def initialize(self): |
1017 |
user = self.env.env.synnefo_user
|
1018 |
passwd = self.env.env.synnefo_vnc_passwd
|
1019 |
#TODO: run vncauthproxy-passwd
|
1020 |
return []
|
1021 |
|
1022 |
def restart(self): |
1023 |
return [
|
1024 |
"/etc/init.d/vncauthproxy restart"
|
1025 |
] |
1026 |
|
1027 |
|
1028 |
class Kamaki(SynnefoComponent): |
1029 |
REQUIRED_PACKAGES = [ |
1030 |
"python-progress",
|
1031 |
"kamaki",
|
1032 |
] |
1033 |
|
1034 |
def initialize(self): |
1035 |
url = "https://%s/astakos/identity/v2.0" % self.env.env.accounts.fqdn |
1036 |
token = self.env.user_auth_token
|
1037 |
return [
|
1038 |
"kamaki config set cloud.default.url %s" % url,
|
1039 |
"kamaki config set cloud.default.token %s" % token,
|
1040 |
"kamaki container create images",
|
1041 |
] |
1042 |
|
1043 |
def fetch_image(self): |
1044 |
url = self.env.env.debian_base_url
|
1045 |
image = "debian_base.diskdump"
|
1046 |
return [
|
1047 |
"wget %s -O /tmp/%s" % (url, image)
|
1048 |
] |
1049 |
|
1050 |
def upload_image(self): |
1051 |
image = "debian_base.diskdump"
|
1052 |
return [
|
1053 |
"kamaki file upload --container images /tmp/%s %s" % (image, image)
|
1054 |
] |
1055 |
|
1056 |
def register_image(self): |
1057 |
image = "debian_base.diskdump"
|
1058 |
image_location = "/images/%s" % image
|
1059 |
cmd = """
|
1060 |
kamaki image register --name "Debian Base" --location {0} \
|
1061 |
--public --disk-format=diskdump \
|
1062 |
--property OSFAMILY=linux --property ROOT_PARTITION=1 \
|
1063 |
--property description="Debian Squeeze Base System" \
|
1064 |
--property size=450M --property kernel=2.6.32 \
|
1065 |
--property GUI="No GUI" --property sortorder=1 \
|
1066 |
--property USERS=root --property OS=debian
|
1067 |
""".format(image_location)
|
1068 |
return [
|
1069 |
"sleep 5",
|
1070 |
cmd |
1071 |
] |
1072 |
|
1073 |
|
1074 |
class Burnin(SynnefoComponent): |
1075 |
REQUIRED_PACKAGES = [ |
1076 |
"kamaki",
|
1077 |
"snf-tools",
|
1078 |
] |
1079 |
|
1080 |
|
1081 |
class Collectd(SynnefoComponent): |
1082 |
REQUIRED_PACKAGES = [ |
1083 |
"collectd",
|
1084 |
] |
1085 |
|
1086 |
def configure(self): |
1087 |
return [
|
1088 |
("/etc/collectd/collectd.conf", {}, {}),
|
1089 |
] |
1090 |
|
1091 |
def restart(self): |
1092 |
return [
|
1093 |
"/etc/init.d/collectd restart",
|
1094 |
] |
1095 |
|
1096 |
|
1097 |
class Stats(SynnefoComponent): |
1098 |
REQUIRED_PACKAGES = [ |
1099 |
"snf-stats-app",
|
1100 |
] |
1101 |
|
1102 |
def prepare(self): |
1103 |
return [
|
1104 |
"mkdir -p /var/cache/snf-stats-app/",
|
1105 |
"chown www-data:www-data /var/cache/snf-stats-app/",
|
1106 |
] |
1107 |
|
1108 |
def configure(self): |
1109 |
r1 = { |
1110 |
"STATS": self.env.env.stats.fqdn, |
1111 |
} |
1112 |
return [
|
1113 |
("/etc/synnefo/stats.conf", r1, {}),
|
1114 |
("/etc/collectd/synnefo-stats.conf", r1, {}),
|
1115 |
] |
1116 |
|
1117 |
def restart(self): |
1118 |
return [
|
1119 |
"/etc/init.d/gunicorn restart",
|
1120 |
"/etc/init.d/apache2 restart",
|
1121 |
] |
1122 |
|
1123 |
|
1124 |
class GanetiCollectd(SynnefoComponent): |
1125 |
def configure(self): |
1126 |
r1 = { |
1127 |
"STATS": self.env.env.stats.fqdn, |
1128 |
} |
1129 |
return [
|
1130 |
("/etc/collectd/passwd", {}, {}),
|
1131 |
("/etc/collectd/synnefo-ganeti.conf", r1, {}),
|
1132 |
] |
1133 |
|
1134 |
|
1135 |
class Archip(SynnefoComponent): |
1136 |
REQUIRED_PACKAGES = [ |
1137 |
"librados2",
|
1138 |
"archipelago",
|
1139 |
"archipelago-dbg",
|
1140 |
"archipelago-modules-dkms",
|
1141 |
"archipelago-modules-source",
|
1142 |
"archipelago-rados",
|
1143 |
"archipelago-rados-dbg",
|
1144 |
"libxseg0",
|
1145 |
"libxseg0-dbg",
|
1146 |
"python-archipelago",
|
1147 |
"python-xseg",
|
1148 |
] |
1149 |
|
1150 |
def prepare(self): |
1151 |
return ["mkdir -p /etc/archip"] |
1152 |
|
1153 |
def configure(self): |
1154 |
return [
|
1155 |
("/etc/archip/pithos.conf.py", {}, {})
|
1156 |
] |
1157 |
|
1158 |
def restart(self): |
1159 |
return [
|
1160 |
"archipelago restart"
|
1161 |
] |
1162 |
|
1163 |
|
1164 |
class ArchipGaneti(SynnefoComponent): |
1165 |
REQUIRED_PACKAGES = [ |
1166 |
"archipelago-ganeti",
|
1167 |
] |