X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwcal%2Fplugins%2Fvala%2Frwcal_openstack%2Frift%2Frwcal%2Fopenstack%2Fprepare_vm.py;h=7f3800bad0fb840bfbe4cdf64ffc9ca822c338e4;hb=894c4682150a22e7b560622af0ad0a7b3ddd84cb;hp=7acf0fde5f9251c4fff224b6228765c7224d8f2b;hpb=255ff03a528a3090ce7f46f0a63b65da3e6f9bcf;p=osm%2FSO.git diff --git a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py index 7acf0fde..7f3800ba 100644 --- a/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py +++ b/rwcal/plugins/vala/rwcal_openstack/rift/rwcal/openstack/prepare_vm.py @@ -21,6 +21,10 @@ import logging import argparse import sys, os, time import rwlogger +import yaml +import random +import fcntl + logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() @@ -30,29 +34,93 @@ rwlog_handler = rwlogger.RwLogger(category="rw-cal-log", logger.addHandler(rwlog_handler) #logger.setLevel(logging.DEBUG) +class FileLock: + FILE_LOCK = '/tmp/_openstack_prepare_vm.lock' + def __init__(self): + # This will create it if it does not exist already + self.filename = FileLock.FILE_LOCK + self.handle = None + + # Bitwise OR fcntl.LOCK_NB if you need a non-blocking lock + def acquire(self): + logger.info(" Attempting to acquire log." %os.getpid()) + self.handle = open(self.filename, 'w') + fcntl.flock(self.handle, fcntl.LOCK_EX) + logger.info(" Lock successfully acquired." %os.getpid()) + + def release(self): + fcntl.flock(self.handle, fcntl.LOCK_UN) + self.handle.close() + logger.info(" Released lock." %os.getpid()) + + def __del__(self): + if self.handle and self.handle.closed == False: + self.handle.close() + + +def allocate_floating_ip(drv, argument): + #### Allocate a floating_ip + available_ip = [ ip for ip in drv.nova_floating_ip_list() if ip.instance_id == None ] + + if argument.pool_name: + ### Filter further based on IP address + available_ip = [ ip for ip in available_ip if ip.pool == argument.pool_name ] + + if not available_ip: + logger.info(" No free floating_ips available. Allocating fresh from pool: %s" %(os.getpid(), argument.pool_name)) + pool_name = argument.pool_name if argument.pool_name is not None else None + floating_ip = drv.nova_floating_ip_create(pool_name) + else: + floating_ip = random.choice(available_ip) + logger.info(" Selected floating_ip: %s from available free pool" %(os.getpid(), floating_ip)) + + return floating_ip + +def handle_floating_ip_assignment(drv, server, argument, management_ip): + lock = FileLock() + ### Try 3 time (<<>>) + RETRY = 3 + for attempt in range(RETRY): + try: + lock.acquire() + floating_ip = allocate_floating_ip(drv, argument) + logger.info("Assigning the floating_ip: %s to VM: %s" %(floating_ip, server['name'])) + drv.nova_floating_ip_assign(argument.server_id, + floating_ip, + management_ip) + logger.info("Assigned floating_ip: %s to management_ip: %s" %(floating_ip, management_ip)) + except Exception as e: + logger.error("Could not assign floating_ip: %s to VM: %s. Exception: %s" %(floating_ip, server['name'], str(e))) + lock.release() + if attempt == (RETRY -1): + logger.error("Max attempts %d reached for floating_ip allocation. Giving up" %attempt) + raise + else: + logger.error("Retrying floating ip allocation. Current retry count: %d" %attempt) + else: + lock.release() + return + + def assign_floating_ip_address(drv, argument): if not argument.floating_ip: return server = drv.nova_server_get(argument.server_id) - logger.info("Assigning the floating_ip: %s to VM: %s" %(argument.floating_ip, server['name'])) - + for i in range(120): server = drv.nova_server_get(argument.server_id) for network_name,network_info in server['addresses'].items(): - if network_info: - if network_name == argument.mgmt_network: - for n_info in network_info: - if 'OS-EXT-IPS:type' in n_info and n_info['OS-EXT-IPS:type'] == 'fixed': - management_ip = n_info['addr'] - drv.nova_floating_ip_assign(argument.server_id, - argument.floating_ip, - management_ip) - logger.info("Assigned floating_ip: %s to management_ip: %s" %(argument.floating_ip, management_ip)) + if network_info and network_name == argument.mgmt_network: + for n_info in network_info: + if 'OS-EXT-IPS:type' in n_info and n_info['OS-EXT-IPS:type'] == 'fixed': + management_ip = n_info['addr'] + handle_floating_ip_assignment(drv, server, argument, management_ip) return - logger.info("Waiting for management_ip to be assigned to server: %s" %(server['name'])) - time.sleep(1) + else: + logger.info("Waiting for management_ip to be assigned to server: %s" %(server['name'])) + time.sleep(1) else: logger.info("No management_ip IP available to associate floating_ip for server: %s" %(server['name'])) return @@ -90,15 +158,52 @@ def create_port_metadata(drv, argument): nvconn = drv.nova_drv._get_nova_connection() nvconn.servers.set_meta(argument.server_id, meta_data) + +def get_volume_id(server_vol_list, name): + if server_vol_list is None: + return + + for os_volume in server_vol_list: + try: + " Device name is of format /dev/vda" + vol_name = (os_volume['device']).split('/')[2] + except: + continue + if name == vol_name: + return os_volume['volumeId'] +def create_volume_metadata(drv, argument): + if argument.vol_metadata is None: + return + + yaml_vol_str = argument.vol_metadata.read() + yaml_vol_cfg = yaml.load(yaml_vol_str) + + srv_volume_list = drv.nova_volume_list(argument.server_id) + for volume in yaml_vol_cfg: + if 'custom_meta_data' not in volume: + continue + vmd = dict() + for vol_md_item in volume['custom_meta_data']: + if 'value' not in vol_md_item: + continue + vmd[vol_md_item['name']] = vol_md_item['value'] + + # Get volume id + vol_id = get_volume_id(srv_volume_list, volume['name']) + if vol_id is None: + logger.error("Server %s Could not find volume %s" %(argument.server_id, volume['name'])) + sys.exit(3) + drv.cinder_volume_set_metadata(vol_id, vmd) + def prepare_vm_after_boot(drv,argument): ### Important to call create_port_metadata before assign_floating_ip_address ### since assign_floating_ip_address can wait thus delaying port_metadata creation - ### Wait for 2 minute for server to come up -- Needs fine tuning - wait_time = 120 - sleep_time = 1 + ### Wait for a max of 5 minute for server to come up -- Needs fine tuning + wait_time = 500 + sleep_time = 2 for i in range(int(wait_time/sleep_time)): server = drv.nova_server_get(argument.server_id) if server['status'] == 'ACTIVE': @@ -115,6 +220,7 @@ def prepare_vm_after_boot(drv,argument): sys.exit(4) #create_port_metadata(drv, argument) + create_volume_metadata(drv, argument) assign_floating_ip_address(drv, argument) @@ -147,6 +253,27 @@ def main(): type = str, help = "Tenant name openstack installation") + parser.add_argument('--user_domain', + action = "store", + dest = "user_domain", + default = None, + type = str, + help = "User domain name for openstack installation") + + parser.add_argument('--project_domain', + action = "store", + dest = "project_domain", + default = None, + type = str, + help = "Project domain name for openstack installation") + + parser.add_argument('--region', + action = "store", + dest = "region", + default = "RegionOne", + type = str, + help = "Region name for openstack installation") + parser.add_argument('--mgmt_network', action = "store", dest = "mgmt_network", @@ -160,10 +287,17 @@ def main(): help = "Server ID on which boot operations needs to be performed") parser.add_argument('--floating_ip', - action = "store", + action = "store_true", dest = "floating_ip", + default = False, + help = "Floating IP assignment required") + + parser.add_argument('--pool_name', + action = "store", + dest = "pool_name", type = str, - help = "Floating IP to be assigned") + help = "Floating IP pool name") + parser.add_argument('--port_metadata', action = "store_true", @@ -171,6 +305,8 @@ def main(): default = False, help = "Create Port Metadata") + parser.add_argument("--vol_metadata", type=argparse.FileType('r')) + argument = parser.parse_args() if not argument.auth_url: @@ -209,7 +345,6 @@ def main(): else: logger.info("Using Server ID : %s" %(argument.server_id)) - try: pid = os.fork() if pid > 0: @@ -218,12 +353,18 @@ def main(): except OSError as e: logger.error("fork failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(2) - - drv = openstack_drv.OpenstackDriver(username = argument.username, - password = argument.password, - auth_url = argument.auth_url, - tenant_name = argument.tenant_name, - mgmt_network = argument.mgmt_network) + + kwargs = dict(username = argument.username, + password = argument.password, + auth_url = argument.auth_url, + project = argument.tenant_name, + mgmt_network = argument.mgmt_network, + cert_validate = False, + user_domain = argument.user_domain, + project_domain = argument.project_domain, + region = argument.region) + + drv = openstack_drv.OpenstackDriver(logger = logger, **kwargs) prepare_vm_after_boot(drv, argument) sys.exit(0)