""" Create a new GNS3 Server Rackspace image with the provided options. """ import argparse import getpass import os import sys import uuid from fabric.api import env from fabric.contrib.files import exists from github import Github from novaclient.v1_1 import client from string import Template from time import sleep POLL_SEC = 20 GNS3_REPO = 'gns3/gns3-server' PLANC_REPO = 'planctechnologies/gns3-server' OS_AUTH_URL = 'https://identity.api.rackspacecloud.com/v2.0/' UBUNTU_BASE_ID = '5cc098a5-7286-4b96-b3a2-49f4c4f82537' def main(): """ Get the user options and perform the image creation. Creates a new instance, installs the required software, creates an image from the instance, and then deletes the instance. """ github = Github() args = get_cli_args() if args.username: username = args.username else: if 'OS_USERNAME' in os.environ: username = os.environ.get('OS_USERNAME') else: username = raw_input('Enter Rackspace username: ') if args.password: password = args.password else: if 'OS_PASSWORD' in os.environ: password = os.environ.get('OS_PASSWORD') else: password = getpass.getpass('Enter Rackspace password: ') if args.tenant: tenant = args.tenant else: if 'OS_TENANT_NAME' in os.environ: tenant = os.environ.get('OS_TENANT_NAME') else: tenant = raw_input('Enter Rackspace Tenant ID: ') if args.region: region = args.region else: if 'OS_REGION_NAME' in os.environ: region = os.environ.get('OS_REGION_NAME') else: region = raw_input('Enter Rackspace Region Name: ') if args.source == 'release': # get the list of releases, present them to the user, save the url repo = github.get_repo(GNS3_REPO) keyword = "tag" i = 1 branch_opts = {} for tag in repo.get_tags(): branch_opts[i] = tag.name i += 1 elif args.source == 'dev': # get the list of dev branches, present them to the user, save the url repo = github.get_repo(PLANC_REPO) keyword = "branch" i = 1 branch_opts = {} for branch in repo.get_branches(): branch_opts[i] = branch.name i += 1 prompt_text = "Select a %s" % keyword selected_branch = prompt_user_select(branch_opts, prompt_text) if args.image_name: image_name = args.image_name else: image_name = "gns3-%s-%s-%s" % (args.source, selected_branch, uuid.uuid4().hex[0:4]) if args.on_boot: on_boot = True else: on_boot = False startup_script = create_script(repo.svn_url, selected_branch, on_boot) server_name = uuid.uuid4().hex instance = create_instance(username, password, tenant, region, server_name, startup_script) passwd = uuid.uuid4().hex instance.change_password(passwd) # wait for the password change to be processed. Continuing while # a password change is processing will cause image creation to fail. sleep(POLL_SEC*6) env.host_string = str(instance.accessIPv4) env.user = "root" env.password = passwd sys.stdout.write("Installing software...") sys.stdout.flush() while True: if exists('/tmp/gns-install-complete'): break sleep(POLL_SEC) sys.stdout.write(".") sys.stdout.flush() print("Done.") image_id = create_image(username, password, tenant, region, instance, image_name) instance.delete() def prompt_user_select(opts, text="Please select"): """ Ask the user to select an option from the provided list. """ print("%s" % text) print("=" * len(text)) for o in opts: print("(%s)\t%s" % (o, opts[o])) while True: selected = raw_input("Select: ") try: return opts[int(selected)] except (KeyError, ValueError): print("Invalid selection. Try again") def create_instance(username, password, tenant, region, server_name, script, auth_url=OS_AUTH_URL): """ Create a new instance. """ sys.stdout.write("Creating instance...") sys.stdout.flush() nc = client.Client(username, password, tenant, auth_url, region_name=region) server = nc.servers.create(server_name, UBUNTU_BASE_ID, 2, config_drive=True, userdata=script) while True: server = nc.servers.get(server.id) if server.status == 'ACTIVE': break sleep(POLL_SEC) sys.stdout.write(".") sys.stdout.flush() print("Done.") return server def create_script(git_url, git_branch, on_boot): """ Create the start-up script. """ script_template = Template(open('script_template', 'r').read()) params = {'git_url': git_url, 'git_branch': git_branch, 'rc_local': ''} if on_boot: params['rc_local'] = "echo '/usr/local/bin/gns3-server' >> /etc/rc.local" return script_template.substitute(params) def create_image(username, password, tenant, region, server, image_name, auth_url=OS_AUTH_URL): """ Create a Rackspace image based on the server instance. """ nc = client.Client(username, password, tenant, auth_url, region_name=region) sys.stdout.write("Creating image %s..." % image_name) sys.stdout.flush() image_id = server.create_image(image_name) while True: server = nc.servers.get(server.id) if getattr(server, 'OS-EXT-STS:task_state') is None: break sleep(POLL_SEC) sys.stdout.write(".") sys.stdout.flush() print("Done.") return image_id def get_cli_args(): """ Parse the CLI input. """ parser = argparse.ArgumentParser( description='Create a new GNS3 image', formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '--rackspace_username', dest='username', action='store') parser.add_argument( '--rackspace_password', dest='password', action='store') parser.add_argument( '--rackspace_tenant', dest='tenant', action='store') parser.add_argument( '--rackspace_region', dest='region', action='store') parser.add_argument( '--source', dest='source', action='store', choices=['release', 'dev'], default='release', help='specify the gns3-server source location') parser.add_argument( '--branch', dest='branch', action='store', help='specify the branch/tag') parser.add_argument( '--start-on-boot', dest='on_boot', action='store_true', default=False, help='start the GNS3-server when the image boots') parser.add_argument( '--image-name', dest='image_name', action='store', help='the name of the image to be created') return parser.parse_args() if __name__ == "__main__": main()