Initial openvim v0.4.6 upload
[osm/openvim.git] / charm / openvim / layer-openvim / reactive / openvim.py
diff --git a/charm/openvim/layer-openvim/reactive/openvim.py b/charm/openvim/layer-openvim/reactive/openvim.py
new file mode 100644 (file)
index 0000000..d31a9f2
--- /dev/null
@@ -0,0 +1,273 @@
+import os
+import json
+import time
+import subprocess
+from git import Repo as gitrepo
+from shutil import rmtree
+
+from charms.reactive import when, when_not, set_state
+from charmhelpers.core.templating import render
+from charmhelpers.core.hookenv import (
+    status_set,
+    leader_set,
+    leader_get,
+    unit_public_ip,
+)
+from charmhelpers.core.unitdata import kv
+from charmhelpers.core.host import (
+    symlink,
+    mkdir,
+    chownr,
+    service_start,
+)
+from charmhelpers.contrib.unison import (
+    create_private_key,
+    create_public_key,
+    ensure_user,
+)
+
+
+def sh(cmd):
+    return subprocess.check_output(cmd, shell=True)
+
+
+def sh_as_openvim(cmd):
+    return sh('sudo -iu openvim ' + cmd)
+
+
+def create_openvim_user():
+    status_set("maintenance", "Creating OpenVIM user")
+    ensure_user('openvim')
+
+
+def initialize_openvim_database(db):
+    status_set("maintenance", "Initializing OpenVIM database")
+    sh_as_openvim("/opt/openmano/openvim/database_utils/init_vim_db.sh -u %s -p %s -d %s -h %s" % (
+        db.user(),
+        db.password(),
+        db.database(),
+        db.host()
+    ))
+
+
+def generate_ssh_key():
+    status_set("maintenance", "Generating ssh key")
+    user = "openvim"
+    folder = "/home/%s/.ssh" % user
+    mkdir(folder, owner=user, group=user, perms=0o775)
+    private_path = "%s/id_rsa" % folder
+    public_path = "%s.pub" % private_path
+    create_private_key(user, private_path)
+    create_public_key(user, private_path, public_path)
+
+
+def add_openvim_to_path():
+    status_set("maintenance", "Adding OpenVIM to path")
+    symlink(
+        '/opt/openmano/scripts/service-openmano.sh',
+        '/usr/bin/service-openmano')
+    symlink('/opt/openmano/openvim/openvim', '/usr/bin/openvim')
+
+
+def download_openvim():
+    status_set("maintenance", "Downloading OpenVIM")
+    if os.path.isdir("/opt/openmano"):
+        rmtree("/opt/openmano")
+    gitrepo.clone_from('https://github.com/tvansteenburgh/openmano.git', '/opt/openmano')
+    chownr('/opt/openmano', owner='openvim', group='openvim', follow_links=False, chowntopdir=True)
+
+
+def configure_openvim(db):
+    status_set("maintenance", "Configuring OpenVIM")
+    render(
+        source="openvimd.cfg",
+        target="/opt/openmano/openvim/openvimd.cfg",
+        owner="openvim",
+        perms=0o664,
+        context={"db": db}
+    )
+
+
+# TODO: possibly combine all of these create functions?
+def create_tenant():
+    status_set("maintenance", "Creating tenant")
+    render(source="tenant.yaml", target="/tmp/tenant.yaml", owner="openvim", perms=0o664, context={})
+    cmd = 'openvim tenant-create /tmp/tenant.yaml'
+    tenant_uuid = sh_as_openvim(cmd).split()[0]
+    tenant_uuid = str(tenant_uuid, 'utf-8')
+    leader_set({'tenant': tenant_uuid})
+    return tenant_uuid
+
+
+def create_image():
+    status_set("maintenance", "Creating image")
+    render(source="image.yaml", target="/tmp/image.yaml", owner="openvim", perms=0o664, context={})
+    cmd = 'openvim image-create /tmp/image.yaml'
+    image_uuid = sh_as_openvim(cmd).split()[0]
+    image_uuid = str(image_uuid, 'utf-8')
+    return image_uuid
+
+
+def create_flavor():
+    status_set("maintenance", "Creating flavor")
+    render(source="flavor.yaml", target="/tmp/flavor.yaml", owner="openvim", perms=0o664, context={})
+    cmd = 'openvim flavor-create /tmp/flavor.yaml'
+    flavor_uuid = sh_as_openvim(cmd).split()[0]
+    flavor_uuid = str(flavor_uuid, 'utf-8')
+    return flavor_uuid
+
+
+# TODO: especially combine these stupid network functions
+def create_default_network():
+    status_set("maintenance", "Creating default network")
+    render(source="net-default.yaml", target="/tmp/net-default.yaml", owner="openvim", perms=0o664, context={})
+    cmd = 'openvim net-create /tmp/net-default.yaml'
+    net_default_uuid = sh_as_openvim(cmd).split()[0]
+    net_default_uuid = str(net_default_uuid, 'utf-8')
+    return net_default_uuid
+
+
+def create_virbr_network():
+    status_set("maintenance", "Creating virbr0 network")
+    render(source="net-virbr0.yaml", target="/tmp/net-virbr0.yaml", owner="openvim", perms=0o664, context={})
+    cmd = 'openvim net-create /tmp/net-virbr0.yaml'
+    net_virbr0_uuid = sh_as_openvim(cmd).split()[0]
+    net_virbr0_uuid = str(net_virbr0_uuid, 'utf-8')
+    return net_virbr0_uuid
+
+
+def create_vm_yaml(image_uuid, flavor_uuid, net_default_uuid, net_virbr0_uuid):
+    status_set("maintenance", "Creating default VM yaml file")
+    render(
+        source="server.yaml",
+        target="/tmp/server.yaml",
+        owner="openvim",
+        perms=0o664,
+        context={
+            "image_uuid": image_uuid,
+            "flavor_uuid": flavor_uuid,
+            "net_default_uuid": net_default_uuid,
+            "net_virbr0_uuid": net_virbr0_uuid
+        }
+    )
+
+
+def create_sane_defaults():
+    tenant_uuid = create_tenant()
+    add_openvim_tenant_env_var(tenant_uuid)
+    image_uuid = create_image()
+    flavor_uuid = create_flavor()
+    net_default_uuid = create_default_network()
+    net_virbr0_uuid = create_virbr_network()
+    create_vm_yaml(
+        image_uuid=image_uuid,
+        flavor_uuid=flavor_uuid,
+        net_default_uuid=net_default_uuid,
+        net_virbr0_uuid=net_virbr0_uuid
+    )
+
+
+def install_openvim_service():
+    status_set("maintenance", "Installing OpenVIM service")
+    if not os.path.exists('/etc/systemd/system'):
+        os.makedirs('/etc/systemd/system')
+    render(
+        source="openvim.service",
+        target="/etc/systemd/system/openvim.service",
+        owner="root",
+        perms=0o644,
+        context={}
+    )
+
+
+def add_openvim_tenant_env_var(tenant_uuid):
+    status_set("maintenance", "Adding OPENVIM_TENANT environment variable")
+    env_line = 'export OPENVIM_TENANT=%s\n' % tenant_uuid
+    with open('/home/openvim/.profile', 'w+') as f:
+        lines = f.readlines()
+        for line in lines:
+            if env_line == line:
+                return
+        f.seek(0)
+        f.truncate()
+        for line in lines:
+            f.write(line)
+        f.write(env_line)
+
+
+def openvim_running():
+    try:
+        sh_as_openvim('openvim tenant-list')
+        return True
+    except:
+        return False
+
+
+def start_openvim():
+    status_set("maintenance", "Starting OpenVIM")
+    service_start('openvim')
+    t0 = time.time()
+    while not openvim_running():
+        if time.time() - t0 > 60:
+            raise Exception('Failed to start openvim.')
+        time.sleep(0.25)
+
+
+@when_not('db.available')
+def not_ready():
+    status_set('waiting', 'MySQL database required')
+
+
+@when('db.available')
+@when_not('openvim-controller.installed')
+def install_openvim_controller(mysql):
+    create_openvim_user()
+    download_openvim()
+    add_openvim_to_path()
+    configure_openvim(mysql)
+    initialize_openvim_database(mysql)
+    generate_ssh_key()
+    install_openvim_service()
+    start_openvim()
+    create_sane_defaults()
+    status_set(
+        'active',
+        'Up on {host}:{port}'.format(
+            host=unit_public_ip(),
+            port='9080'))
+    set_state('openvim-controller.installed')
+
+
+@when('compute.connected', 'openvim-controller.installed')
+def send_ssh_key(compute):
+    with open('/home/openvim/.ssh/id_rsa.pub', 'r') as f:
+        key = f.read().strip()
+    compute.send_ssh_key(key)
+
+
+@when('compute.available', 'openvim-controller.installed')
+def host_add(compute):
+    cache = kv()
+    for node in compute.authorized_nodes():
+        if cache.get("compute:" + node['address']):
+            continue
+        cmd = "ssh -n -o 'StrictHostKeyChecking no' %s@%s"
+        sh_as_openvim(cmd % (node['user'], node['address']))
+        data = {
+            'host': {
+                'name': 'compute-0',
+                'user': node['user'],
+                'ip_name': node['address'],
+                'description': 'compute-0'
+            }
+        }
+        with open('/tmp/compute-0.json', 'w') as f:
+            json.dump(data, f, indent=4, sort_keys=True)
+        # TODO: openvim run function!
+        sh_as_openvim('openvim host-add /tmp/compute-0.json')
+        cache.set('compute:' + node['address'], True)
+
+
+@when('openvim-controller.available')
+def openvim_available(openvim):
+    openvim.configure(port=9080, user=leader_get('tenant'))