#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Gonéri Le Bouder <goneri.lebouder@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import glob
import augeas
import yaml
import subprocess
import os
import sys
import shutil
import argparse

def start_bridge():
    subprocess.call(['brctl', 'addbr', conf['network']['bridge'] ])
    subprocess.call(['ifconfig', conf['network']['bridge'], conf['network']['gateway'] ])

def stop_bridge():
    subprocess.call(['ifconfig', conf['network']['bridge'], 'down' ])
    subprocess.call(['brctl', 'delbr', conf['network']['bridge'] ])

def setup_ssh_key(conf, host):
    if not 'ssh_key' in conf['general']:
            return

    ssh_dir = '/var/lib/lxc/%s/rootfs/root/.ssh/' % host['name']
    os.makedirs(ssh_dir)
    shutil.copyfile(conf['general']['ssh_key'], ssh_dir + '/authorized_keys')


def stop():
    print "stopping"
    for host in conf['hosts']:

        aufs_rw_dir = "/tmp/base_aufs/%s" % host['name']
        lxc_dir = "/var/lib/lxc/%s" % host['name']
        try:
            subprocess.call(['lxc-kill', '-n', host['name'] ])
            subprocess.call(['lxc-stop', '-n', host['name'] ])
        except:
            print "foo"# nothing

        if os.path.exists(lxc_dir):
            print("[%s]" % host['name'])
            try:
                subprocess.call(['umount', lxc_dir ])
            except:
                print("Failed to umount %s" % lxc_dir)
            shutil.rmtree(lxc_dir)

            if os.path.exists(aufs_rw_dir):
                shutil.rmtree(aufs_rw_dir)

    stop_bridge()

def start():
    start_bridge()


    roles = []
    
    for host in conf['hosts']:
        if host['role'] not in roles:
            roles.append(host['role'])

    for role in roles:
        rootfs = '/var/lib/lxc/%s/rootfs' % role
        if not os.path.exists(rootfs):
            os.makedirs(rootfs)
        subprocess.call(['rsync', '-av', '--delete', '--numeric-ids', '%s/%s/' % (conf['edeploy']['dir'], role), rootfs])
        subprocess.call(['tar', 'xf', '/usr/share/debootstrap/devices.tar.gz'], cwd=rootfs)

        if not os.path.exists(rootfs + '/dev/pts'):
            os.makedirs(rootfs + '/dev/pts')

        # work around for LXC bug, rmmod module on the host system
        shutil.copyfile(rootfs + '/bin/true', rootfs + '/bin/kmod')

    for host in conf['hosts']:
        print("[%s]" % host['name'])

        aufs_rw_dir = "/tmp/base_aufs/%s" % host['name']
        lxc_dir = "/var/lib/lxc/%s" % host['name']
        if os.path.exists(lxc_dir):
            try:
                print "foo"
                subprocess.call(['lxc-kill', '-n', host['name'] ])
                subprocess.call(['lxc-stop', '-n', host['name'] ])
            except:
                print "foo"# nothing
        else:
            os.makedirs(lxc_dir)
            os.makedirs(aufs_rw_dir)

        subprocess.call(['mount', '-t', 'aufs', '-o', 'br=%s:%s' % (aufs_rw_dir, '/var/lib/lxc/%s' % host['role']), 'none', lxc_dir ])
        #mount -t aufs -o br=/tmp/base_aufs/os-ci-test4:/var/lib/lxc/basesys none /var/lib/lxc/os-ci-test4

        try:
            fh = open('/var/lib/lxc/%s.config' % host['name'], 'r')
            addons = fh.read()
            fh.close()
        except (IOError, OSError) as e:
            addons = ""

        lxcConfFd = open('/var/lib/lxc/%s/config' % host['name'], 'w')
        lxcConfFd.write("lxc.network.type = veth\n" +
            "lxc.network.flags = up\n" +
            "lxc.network.link = %s\n" % conf['network']['bridge'] +
            "lxc.rootfs = /var/lib/lxc/%s/rootfs\n" % host['name'] +
            "lxc.tty = 4\n" +
            "lxc.pts = 1024\n" +
            "lxc.utsname = %s\n" % host['name'] +
            "lxc.cgroup.devices.deny = a\n" +
            "lxc.cgroup.devices.allow = c 1:3 rwm\n" +
            "lxc.cgroup.devices.allow = c 1:5 rwm\n" +
            "lxc.cgroup.devices.allow = c 5:1 rwm\n" +
            "lxc.cgroup.devices.allow = c 5:0 rwm\n" +
            "lxc.cgroup.devices.allow = c 1:9 rwm\n" +
            "lxc.cgroup.devices.allow = c 1:8 rwm\n" +
            "lxc.cgroup.devices.allow = c 136:* rwm\n" +
            "lxc.cgroup.devices.allow = c 5:2 rwm\n" +
            "lxc.cgroup.devices.allow = c 254:0 rwm\n" +
            "lxc.cgroup.devices.allow = b 7:* rwm # /dev/loop\n" +
            "lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0\n" +
            "lxc.mount.entry = sysfs sys sysfs defaults  0 0\n" +
            "lxc.cgroup.memory.limit_in_bytes = 536870912\n")
        lxcConfFd.write(addons)
        lxcConfFd.close()

        debian_interfaces = '/var/lib/lxc/%s/rootfs/etc/network/interfaces' % host['name']
        if os.path.exists(debian_interfaces):
            netFd = open(debian_interfaces, 'w')
            netFd.write("auto lo\n" +
                "iface lo inet loopback\n" +
                "auto eth0\n" +
                "iface eth0 inet static\n" +
                "    address %s\n" % host['address'] +
                "    netmask 255.255.255.0\n" +
                "    gateway %s\n" % conf['network']['gateway'])
            netFd.close()
        else:
            fd = open('/var/lib/lxc/%s/rootfs/etc/init/lxc-sysinit.conf' % host['name'], 'w')
            fd.write("start on startup\n" +
                "env container\n" +
                "pre-start script\n" +
                "if [ \"x$container\" != \"xlxc\" -a \"x$container\" != \"xlibvirt\" ]; then\n" +
                "stop;\n" +
                "fi\n" +
                "initctl start tty TTY=console\n" +
                "rm -f /var/lock/subsys/*\n" +
                "rm -f /var/run/*.pid\n" +
                "telinit 3\n" +
                "exit 0;\n" +
                "end script\n"
            )
            fd.close()

            fd = open('/var/lib/lxc/%s/rootfs/etc/sysconfig/network-scripts/ifcfg-eth0' % host['name'], 'w')
            fd.write(
                "DEVICE=eth0\n" +
                "ONBOOT=yes\n" +
                "BOOTPROTO=static\n" +
                "IPADDR=%s\n" % host['address'] +
                "NETMASK=255.255.255.0\n" +
                "GATEWAY=%s\n" % conf['network']['gateway']
            )
            fd.close()
            fd = open('/var/lib/lxc/%s/rootfs/etc/sysconfig/network' % host['name'], 'w')
            fd.write(
                "NETWORKING=yes\n" +
                "HOSTNAME=%s.%s\n" % (host['name'], conf['network']['domain'])
            )
            fd.close()

        hostFd = open('/var/lib/lxc/%s/rootfs/etc/hosts' % host['name'], 'w')
        hostFd.write(
            "127.0.0.1 %s.%s %s localhost\n" % (host['name'], conf['network']['domain'], host['name']) +
            "::1     localhost ip6-localhost ip6-loopback\n" +
            "ff02::1 ip6-allnodes\n" +
            "ff02::2 ip6-allrouters\n"
        )
        for h in conf['hosts']:
            hostFd.write("%s %s.%s %s\n" % (h['address'], h['name'], conf['network']['domain'], h['name']))

        hostFd.close()

        a = augeas.Augeas(root="/var/lib/lxc/%s/rootfs" % host['name'])
        a.set("/files/etc/hostname/hostname", "%s" % host['name'])
        a.save()

        setup_ssh_key(conf, host)

        if 'cloudinit' in host:
            cloudinit_name = os.path.basename(host['cloudinit']).replace('.cloudinit', '')
            print("    setting cloudinit flat file datasource")
            nocloud_dir = '/var/lib/lxc/%s/rootfs/var/lib/cloud/seed/nocloud' % host['name']
            if not os.path.exists(nocloud_dir):
                os.makedirs(nocloud_dir)
            open(os.path.join(nocloud_dir, 'user-data'), 'w').write(open(host['cloudinit']).read())
            open(os.path.join(nocloud_dir, 'meta-data'), 'w').write('local-hostname: %s' % host['name'])
            open('/var/lib/lxc/%s/rootfs/etc/cloud/cloud.cfg.d/90_dpkg.cfg' % (
                    host['name'], ), 'w').write('''
dsmod: local

datasource_list: [ NoCloud ]
''')
        print("    launching")
        subprocess.call(['lxc-start', '-d', '-L', '/tmp/lxc-%s.log' % host['name'], '-n', host['name'] ])

parser = argparse.ArgumentParser()
parser.add_argument('action', help='action', choices=['stop', 'start', 'restart'])
parser.add_argument('--config', help='configuration file', required=True)

args = parser.parse_args()

stream = file(args.config, 'r')
conf=yaml.load(stream)

if args.action == 'start':
    start()
elif args.action == 'stop':
    stop()
elif args.action == 'restart':
    stop()
    start()
