summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Doan <andy.doan@linaro.org>2016-04-20 15:02:48 -0500
committerAndy Doan <andy.doan@linaro.org>2016-04-20 15:06:14 -0500
commitdd45d54ab74c265513805d309041235c167114fe (patch)
tree233082748ff9764cc23ee1dd52a61d2852d86712
parent8cc18c6814ad0ab8489c9b85f280003bee3bba8e (diff)
colo: create a simple tool for the devcloud
This creates a simple command members of dev-cloud-admins can use to manage the devcloud Change-Id: I002f9b39a7a36a8eca307c2d2ae738c3b735d880
-rw-r--r--aus-colo-servers.yml3
-rwxr-xr-xroles/devcloud-admin/files/devcloud-admin.sh11
-rwxr-xr-xroles/devcloud-admin/files/devcloud.py140
-rw-r--r--roles/devcloud-admin/files/sudoers2
-rw-r--r--roles/devcloud-admin/tasks/main.yml14
-rw-r--r--roles/devcloud-admin/templates/devcloud-novarc10
6 files changed, 179 insertions, 1 deletions
diff --git a/aus-colo-servers.yml b/aus-colo-servers.yml
index ea30759a..31446ad5 100644
--- a/aus-colo-servers.yml
+++ b/aus-colo-servers.yml
@@ -2,12 +2,13 @@
---
- name: Configure firewall/router
hosts: aus-colo.linaro.org
+ become: yes
vars_files:
- "{{secrets_dir}}/host_vars/{{inventory_hostname}}"
- "reservations.yml"
roles:
- role: colo-router
- become: yes
+ - {role: devcloud-admin, tags: [devcloud]}
- name: Configure our x86-1 top-of-rack servers
hosts:
diff --git a/roles/devcloud-admin/files/devcloud-admin.sh b/roles/devcloud-admin/files/devcloud-admin.sh
new file mode 100755
index 00000000..895244d4
--- /dev/null
+++ b/roles/devcloud-admin/files/devcloud-admin.sh
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+if [ `id -u` -ne 0 ] ; then
+ # This has to be exectuted as root
+ exec sudo $0 $*
+fi
+
+. /srv/devcloud/novarc
+. /srv/devcloud/bin/activate
+
+/srv/devcloud/devcloud.py $*
diff --git a/roles/devcloud-admin/files/devcloud.py b/roles/devcloud-admin/files/devcloud.py
new file mode 100755
index 00000000..3b86a04c
--- /dev/null
+++ b/roles/devcloud-admin/files/devcloud.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python3
+
+import argparse
+import configparser
+import json
+import logging
+import os
+import re
+import subprocess
+import tempfile
+import time
+
+IP_CONF = '/etc/iptables.conf'
+
+logging.basicConfig(level=logging.WARN)
+log = logging.getLogger()
+
+
+def _find_colo_ip(server):
+ out = subprocess.check_output(
+ ['openstack', 'server', 'show', '-f', 'json', server])
+ props = json.loads(out.decode()).get('properties')
+ m = re.match('COLO_IP=\'(\S+)\'', props)
+ if m:
+ return m.groups()[0]
+ return None
+
+
+def _assign_public_ip(server, ip):
+ log.debug('Finding public IP for instance')
+ cp = configparser.ConfigParser()
+ cp.read([IP_CONF])
+ mappings = cp['public/private mappings']
+ for pub, priv in mappings.items():
+ priv = priv.split('#')[0].strip()
+ if not priv:
+ log.info('Mapping %s -> %s', ip, pub)
+ mappings[pub] = '%s # devcloud - %s' % (ip, server)
+ with open(IP_CONF, 'w') as f:
+ cp.write(f, True)
+ subprocess.check_call(
+ ['/usr/local/bin/manage_iptables.py', 'sync'])
+ return pub
+
+
+def _unmap_ip(public_ip):
+ log.info('Removing public ip mapping for: %s', public_ip)
+ cp = configparser.ConfigParser()
+ cp.read([IP_CONF])
+ cp['public/private mappings'][public_ip] = ' '
+ with open(IP_CONF, 'w') as f:
+ cp.write(f, True)
+ subprocess.check_call(['/usr/local/bin/manage_iptables.py', 'sync'])
+
+
+def _start_instance(server, flavor, image, sshkey):
+ log.info('Starting openstack instance: %s %s %s', server, flavor, image)
+ with tempfile.NamedTemporaryFile('w', delete=False) as f:
+ f.write('#!/bin/sh -ex\n')
+ f.write('echo "%s" >> /home/admin/.ssh/authorized_keys\n' % sshkey)
+ f.write('systemctl enable systemd-timesyncd\n')
+ f.write('systemctl start systemd-timesyncd\n')
+
+ try:
+ subprocess.check_call(
+ ['openstack', 'server', 'create', '--user-data', f.name,
+ '--key-name', 'andy', '--image', image,
+ '--flavor', flavor, server])
+ finally:
+ os.unlink(f.name)
+
+
+def _wait_for_ip(server):
+ for _ in range(5):
+ out = subprocess.check_output(
+ ['openstack', 'server', 'show', '-f', 'json', server])
+ addresses = json.loads(out.decode()).get('addresses')
+ if addresses:
+ for x in addresses.split(','):
+ if x.startswith('public='):
+ return x[7:]
+ log.info('Waiting for openstack instance IP...')
+ time.sleep(4)
+ raise RuntimeError('Unable to find IP for instance')
+
+
+def create(args):
+ if os.path.exists(args.sshkey):
+ args.sshkey = open(args.sshkey).read()
+
+ _start_instance(args.name, args.flavor, args.image, args.sshkey)
+ try:
+ ip = _wait_for_ip(args.name)
+ log.debug('internal ip: %s', ip)
+ ip = _assign_public_ip(args.name, ip)
+ if not ip:
+ raise RuntimeError('Unable to find available public IP')
+ subprocess.check_call(['openstack', 'server', 'set', '--property',
+ 'COLO_IP=%s' % ip, args.name])
+ except:
+ delete(args)
+
+
+def delete(args):
+ ip = _find_colo_ip(args.name)
+ if ip:
+ _unmap_ip(ip)
+ else:
+ log.warn('No public IP address found?')
+ log.info('Deleting openstack instance')
+ subprocess.check_call(['openstack', 'server', 'delete', args.name])
+
+
+if __name__ == '__main__':
+ images = ('rp-debian-jessie', 'rp-centos7')
+ flavors = ('m1.small', 'm1.medium', 'm1.large', 'm1.xlarge')
+
+ parser = argparse.ArgumentParser(description='Manage devcloud instances')
+ parser.add_argument('--log', default='INFO',
+ choices=('WARN', 'INFO', 'DEBUG'),
+ help='Logging level to use. Default=%(default)s')
+
+ cmds = parser.add_subparsers(title='Commands')
+ p = cmds.add_parser('create-instance')
+ p.set_defaults(func=create)
+ p.add_argument('--name', '-n', required=True)
+ p.add_argument('--image', '-i', required=True, choices=images)
+ p.add_argument('--flavor', '-f', required=True, choices=flavors)
+ p.add_argument('--sshkey', '-k', required=True,
+ help='Users ssh key(s) can be file or string')
+
+ p = cmds.add_parser('delete-instance')
+ p.set_defaults(func=delete)
+ p.add_argument('--name', '-n', required=True)
+
+ args = parser.parse_args()
+ log.setLevel(getattr(logging, args.log))
+
+ if getattr(args, 'func', None):
+ args.func(args)
diff --git a/roles/devcloud-admin/files/sudoers b/roles/devcloud-admin/files/sudoers
new file mode 100644
index 00000000..f4053e95
--- /dev/null
+++ b/roles/devcloud-admin/files/sudoers
@@ -0,0 +1,2 @@
+# DO NOT EDIT! MANAGED BY ANSIBLE
+%dev-cloud-admins ALL=(ALL:ALL) /usr/local/bin/devcloud-admin
diff --git a/roles/devcloud-admin/tasks/main.yml b/roles/devcloud-admin/tasks/main.yml
new file mode 100644
index 00000000..cf84d4ea
--- /dev/null
+++ b/roles/devcloud-admin/tasks/main.yml
@@ -0,0 +1,14 @@
+- name: Install openstack command line into virtualenv
+ pip: name=python-openstackclient virtualenv=/srv/devcloud
+
+- name: Install devcloud.py script
+ copy: src=devcloud.py dest=/srv/devcloud/ mode=0500
+
+- name: Install devcloud novarc
+ template: src=devcloud-novarc dest=/srv/devcloud/novarc mode=0500
+
+- name: Install devcloud wrapper
+ copy: src=devcloud-admin.sh dest=/usr/local/bin/devcloud-admin mode=0555
+
+- name: Install sudoers rule
+ copy: src=sudoers dest=/etc/sudoers.d/devcloud mode=0440
diff --git a/roles/devcloud-admin/templates/devcloud-novarc b/roles/devcloud-admin/templates/devcloud-novarc
new file mode 100644
index 00000000..77eefb1a
--- /dev/null
+++ b/roles/devcloud-admin/templates/devcloud-novarc
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+export OS_AUTH_URL=http://r3-m1-c4:5000/v2.0
+
+export OS_TENANT_ID={{devcloud_tenant_id}}
+export OS_TENANT_NAME="{{devcloud_tenant_name}}"
+export OS_PROJECT_NAME="{{devcloud_tenant_name}}"
+export OS_USERNAME="admin"
+
+export OS_PASSWORD="{{devcloud_os_password}}"