X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=rwcal%2Ftest%2Faws_resources.py;fp=rwcal%2Ftest%2Faws_resources.py;h=875de5658a6ed38e7b8680a11a6719d6e6cbdbe4;hb=6f07e6f33f751ab4ffe624f6037f887b243bece2;hp=0000000000000000000000000000000000000000;hpb=72a563886272088feb7cb52e4aafbe6d2c580ff9;p=osm%2FSO.git diff --git a/rwcal/test/aws_resources.py b/rwcal/test/aws_resources.py new file mode 100644 index 00000000..875de565 --- /dev/null +++ b/rwcal/test/aws_resources.py @@ -0,0 +1,370 @@ +#!/usr/bin/python3 + +# +# Copyright 2016 RIFT.IO Inc +# +# 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 os +import sys +import uuid +import rw_peas +from gi import require_version +require_version('RwCal', '1.0') + +from gi.repository import RwcalYang +from gi.repository.RwTypes import RwStatus +import argparse +import logging +import rwlogger +import boto3 +import botocore + +persistent_resources = { + 'vms' : [], + 'networks' : [], +} + +MISSION_CONTROL_NAME = 'mission-control' +LAUNCHPAD_NAME = 'launchpad' + +RIFT_IMAGE_AMI = 'ami-7070231a' + +logging.basicConfig(level=logging.ERROR) +logger = logging.getLogger('rift.cal.awsresources') +logger.setLevel(logging.INFO) + +def get_cal_plugin(): + """ + Load AWS cal plugin + """ + plugin = rw_peas.PeasPlugin('rwcal_aws', 'RwCal-1.0') + engine, info, extension = plugin() + cal = plugin.get_interface("Cloud") + rwloggerctx = rwlogger.RwLog.Ctx.new("Cal-Log") + try: + rc = cal.init(rwloggerctx) + assert rc == RwStatus.SUCCESS + except Exception as e: + logger.error("ERROR:Cal plugin instantiation failed with exception %s",repr(e)) + else: + logger.info("AWS Cal plugin successfully instantiated") + return cal + +def get_cal_account(**kwargs): + """ + Returns AWS cal account + """ + account = RwcalYang.CloudAccount() + account.account_type = "aws" + account.aws.key = kwargs['key'] + account.aws.secret = kwargs['secret'] + account.aws.region = kwargs['region'] + if 'ssh_key' in kwargs and kwargs['ssh_key'] is not None: + account.aws.ssh_key = kwargs['ssh_key'] + account.aws.availability_zone = kwargs['availability_zone'] + if 'vpcid' in kwargs and kwargs['vpcid'] is not None: + account.aws.vpcid = kwargs['vpcid'] + if 'default_subnet_id' in kwargs and kwargs['default_subnet_id'] is not None: + account.aws.default_subnet_id = kwargs['default_subnet_id'] + return account + +class AWSResources(object): + """ + Class with methods to manage AWS resources + """ + def __init__(self,**kwargs): + self._cal = get_cal_plugin() + self._acct = get_cal_account(**kwargs) + + def _destroy_vms(self): + """ + Destroy VMs + """ + logger.info("Initiating VM cleanup") + rc, rsp = self._cal.get_vdu_list(self._acct) + vdu_list = [vm for vm in rsp.vdu_info_list if vm.name not in persistent_resources['vms']] + logger.info("Deleting VMs : %s" %([x.name for x in vdu_list])) + + for vdu in vdu_list: + self._cal.delete_vdu(self._acct, vdu.vdu_id) + + logger.info("VM cleanup complete") + + def _destroy_networks(self): + """ + Destroy Networks + """ + logger.info("Initiating Network cleanup") + driver = self._cal._get_driver(self._acct) + subnets = driver.get_subnet_list() + subnet_list = [subnet for subnet in subnets if subnet.default_for_az is False] + + logger.info("Deleting Networks : %s" %([x.id for x in subnet_list])) + for subnet in subnet_list: + self._cal.delete_virtual_link(self._acct, subnet.subnet_id) + logger.info("Network cleanup complete") + + def destroy_resource(self): + """ + Destroy resources + """ + logger.info("Cleaning up AWS resources") + self._destroy_vms() + self._destroy_networks() + logger.info("Cleaning up AWS resources.......[Done]") + + def _destroy_mission_control(self): + """ + Destroy Mission Control VM + """ + logger.info("Initiating MC VM cleanup") + rc, rsp = self._cal.get_vdu_list(self._acct) + vdu_list = [vm for vm in rsp.vdu_info_list if vm.name == MISSION_CONTROL_NAME] + logger.info("Deleting VMs : %s" %([x.name for x in vdu_list])) + + for vdu in vdu_list: + self._cal.delete_vdu(self._acct, vdu.vdu_id) + logger.info("MC VM cleanup complete") + + def _destroy_launchpad(self): + """ + Destroy Launchpad VM + """ + logger.info("Initiating LP VM cleanup") + rc, rsp = self._cal.get_vdu_list(self._acct) + vdu_list = [vm for vm in rsp.vdu_info_list if vm.name == LAUNCHPAD_NAME] + logger.info("Deleting VMs : %s" %([x.name for x in vdu_list])) + + for vdu in vdu_list: + self._cal.delete_vdu(self._acct, vdu.vdu_id) + logger.info("LP VM cleanup complete") + + + def create_mission_control(self): + """ + Create Mission Control VM in AWS + """ + logger.info("Creating mission control VM") + vdu = RwcalYang.VDUInitParams() + vdu.name = MISSION_CONTROL_NAME + vdu.image_id = RIFT_IMAGE_AMI + vdu.flavor_id = 'c3.large' + vdu.allocate_public_address = True + vdu.vdu_init.userdata = "#cloud-config\n\nruncmd:\n - echo Sleeping for 5 seconds and attempting to start salt-master\n - sleep 5\n - /bin/systemctl restart salt-master.service\n" + + rc,rs=self._cal.create_vdu(self._acct,vdu) + assert rc == RwStatus.SUCCESS + self._mc_id = rs + + driver = self._cal._get_driver(self._acct) + inst=driver.get_instance(self._mc_id) + inst.wait_until_running() + + rc,rs =self._cal.get_vdu(self._acct,self._mc_id) + assert rc == RwStatus.SUCCESS + self._mc_public_ip = rs.public_ip + self._mc_private_ip = rs.management_ip + + logger.info("Started Mission Control VM with id %s and IP Address %s\n",self._mc_id, self._mc_public_ip) + + def create_launchpad_vm(self, salt_master = None): + """ + Create Launchpad VM in AWS + Arguments + salt_master (String): String with Salt master IP typically MC VM private IP + """ + logger.info("Creating launchpad VM") + USERDATA_FILENAME = os.path.join(os.environ['RIFT_INSTALL'], + 'etc/userdata-template') + + try: + fd = open(USERDATA_FILENAME, 'r') + except Exception as e: + sys.exit(-1) + else: + LP_USERDATA_FILE = fd.read() + # Run the enable lab script when the openstack vm comes up + LP_USERDATA_FILE += "runcmd:\n" + LP_USERDATA_FILE += " - echo Sleeping for 5 seconds and attempting to start elastic-network-interface\n" + LP_USERDATA_FILE += " - sleep 5\n" + LP_USERDATA_FILE += " - /bin/systemctl restart elastic-network-interfaces.service\n" + + if salt_master is None: + salt_master=self._mc_private_ip + node_id = str(uuid.uuid4()) + + vdu = RwcalYang.VDUInitParams() + vdu.name = LAUNCHPAD_NAME + vdu.image_id = RIFT_IMAGE_AMI + vdu.flavor_id = 'c3.xlarge' + vdu.allocate_public_address = True + vdu.vdu_init.userdata = LP_USERDATA_FILE.format(master_ip = salt_master, + lxcname = node_id) + vdu.node_id = node_id + + rc,rs=self._cal.create_vdu(self._acct,vdu) + assert rc == RwStatus.SUCCESS + self._lp_id = rs + + driver = self._cal._get_driver(self._acct) + inst=driver.get_instance(self._lp_id) + inst.wait_until_running() + + rc,rs =self._cal.get_vdu(self._acct,self._lp_id) + assert rc == RwStatus.SUCCESS + + self._lp_public_ip = rs.public_ip + self._lp_private_ip = rs.management_ip + logger.info("Started Launchpad VM with id %s and IP Address %s\n",self._lp_id, self._lp_public_ip) + + def upload_ssh_key_to_ec2(self): + """ + Upload SSH key to EC2 region + """ + driver = self._cal._get_driver(self._acct) + key_name = os.getlogin() + '-' + 'sshkey' + key_path = '%s/.ssh/id_rsa.pub' % (os.environ['HOME']) + if os.path.isfile(key_path): + logger.info("Uploading ssh public key file in path %s with keypair name %s", key_path,key_name) + with open(key_path) as fp: + driver.upload_ssh_key(key_name,fp.read()) + else: + logger.error("Valid Public key file %s not found", key_path) + + +def main(): + """ + Main routine + """ + parser = argparse.ArgumentParser(description='Script to manage AWS resources') + + parser.add_argument('--aws-key', + action = 'store', + dest = 'aws_key', + type = str, + help='AWS key') + + parser.add_argument('--aws-secret', + action = 'store', + dest = 'aws_secret', + type = str, + help='AWS secret') + + parser.add_argument('--aws-region', + action = 'store', + dest = 'aws_region', + type = str, + help='AWS region') + + parser.add_argument('--aws-az', + action = 'store', + dest = 'aws_az', + type = str, + help='AWS Availability zone') + + parser.add_argument('--aws-sshkey', + action = 'store', + dest = 'aws_sshkey', + type = str, + help='AWS SSH Key to login to instance') + + parser.add_argument('--aws-vpcid', + action = 'store', + dest = 'aws_vpcid', + type = str, + help='AWS VPC ID to use to indicate non default VPC') + + parser.add_argument('--aws-default-subnet', + action = 'store', + dest = 'aws_default_subnet', + type = str, + help='AWS Default subnet id in VPC to be used for mgmt network') + + parser.add_argument('--mission-control', + action = 'store_true', + dest = 'mission_control', + help='Create Mission Control VM') + + parser.add_argument('--launchpad', + action = 'store_true', + dest = 'launchpad', + help='Create LaunchPad VM') + + parser.add_argument('--salt-master', + action = 'store', + dest = 'salt_master', + type = str, + help='IP Address of salt controller. Required, if only launchpad VM is being created.') + + parser.add_argument('--cleanup', + action = 'store', + dest = 'cleanup', + nargs = '+', + type = str, + help = 'Perform resource cleanup for AWS installation. \n Possible options are {all, mc, lp, vms, networks }') + + parser.add_argument('--upload-ssh-key', + action = 'store_true', + dest = 'upload_ssh_key', + help = 'Upload users SSH public key ~/.ssh/id_rsa.pub') + + argument = parser.parse_args() + + if (argument.aws_key is None or argument.aws_secret is None or argument.aws_region is None or + argument.aws_az is None): + logger.error("Missing mandatory params. AWS Key, Secret, Region, AZ and SSH key are mandatory params") + sys.exit(-1) + + if (argument.cleanup is None and argument.mission_control is None and argument.launchpad is None + and argument.upload_ssh_key is None): + logger.error('Insufficient parameters') + sys.exit(-1) + + ### Start processing + logger.info("Instantiating cloud-abstraction-layer") + drv = AWSResources(key=argument.aws_key, secret=argument.aws_secret, region=argument.aws_region, availability_zone = argument.aws_az, + ssh_key = argument.aws_sshkey, vpcid = argument.aws_vpcid, default_subnet_id = argument.aws_default_subnet) + logger.info("Instantiating cloud-abstraction-layer.......[Done]") + + if argument.upload_ssh_key: + drv.upload_ssh_key_to_ec2() + + if argument.cleanup is not None: + for r_type in argument.cleanup: + if r_type == 'all': + drv.destroy_resource() + break + if r_type == 'vms': + drv._destroy_vms() + if r_type == 'networks': + drv._destroy_networks() + if r_type == 'mc': + drv._destroy_mission_control() + if r_type == 'lp': + drv._destroy_launchpad() + + if argument.mission_control == True: + drv.create_mission_control() + + if argument.launchpad == True: + if argument.salt_master is None and argument.mission_control is False: + logger.error('Salt Master IP address not provided to start Launchpad.') + sys.exit(-2) + + drv.create_launchpad_vm(argument.salt_master) + +if __name__ == '__main__': + main()