Statistics
| Branch: | Tag: | Revision:

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