X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=snaps%2Fopenstack%2Fcreate_instance.py;h=d5917a8608b3c9ea81d8a358d5c00c3129759705;hb=0c8b35023a0216315dbd93d3f4dcf7322b0ef1dd;hp=991aca5482394fdec48faccef96b874db5ce9249;hpb=2e0e2c683e2329084f3e7eea6ed5d9ab5ed56661;p=snaps.git diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py index 991aca5..d5917a8 100644 --- a/snaps/openstack/create_instance.py +++ b/snaps/openstack/create_instance.py @@ -102,12 +102,13 @@ class OpenStackVmInstance: logger.info( 'Found existing machine with name - %s', self.instance_settings.name) - fips = self.__nova.floating_ips.list() + fips = neutron_utils.get_floating_ips(self.__neutron) for fip in fips: - if fip.instance_id == server.id: - self.__floating_ips.append(fip) - # TODO - Determine a means to associate to the FIP - # configuration and add to FIP map + for subnet_name, ips in server.networks.items(): + if fip.ip in ips: + self.__floating_ips.append(fip) + # TODO - Determine a means to associate to the FIP + # configuration and add to FIP map def __create_vm(self, block=False): """ @@ -116,61 +117,26 @@ class OpenStackVmInstance: active, error, or timeout waiting. Floating IPs will be assigned after active when block=True """ - nics = [] - for key, port in self.__ports: - kv = dict() - kv['port-id'] = port['port']['id'] - nics.append(kv) - - logger.info('Creating VM with name - ' + self.instance_settings.name) - keypair_name = None - if self.keypair_settings: - keypair_name = self.keypair_settings.name - - flavor = nova_utils.get_flavor_by_name(self.__nova, - self.instance_settings.flavor) - if not flavor: - raise Exception( - 'Flavor not found with name - %s', - self.instance_settings.flavor) - - image = glance_utils.get_image( - glance_utils.glance_client(self.__os_creds), - self.image_settings.name) - if image: - self.__vm = self.__nova.servers.create( - name=self.instance_settings.name, - flavor=flavor, - image=image, - nics=nics, - key_name=keypair_name, - security_groups=self.instance_settings.security_group_names, - userdata=self.instance_settings.userdata, - availability_zone=self.instance_settings.availability_zone) - - else: - raise Exception( - 'Cannot create instance, image cannot be located with name %s', - self.image_settings.name) - - logger.info( - 'Created instance with name - %s', self.instance_settings.name) + glance = glance_utils.glance_client(self.__os_creds) + self.__vm = nova_utils.create_server( + self.__nova, self.__neutron, glance, self.instance_settings, + self.image_settings, self.keypair_settings) + logger.info('Created instance with name - %s', + self.instance_settings.name) if block: if not self.vm_active(block=True): - raise Exception( + raise VmInstanceCreationError( 'Fatal error, VM did not become ACTIVE within the alloted ' 'time') - # TODO - the call above should add security groups. The return object - # shows they exist but the association had never been made by - # OpenStack. This call is here to ensure they have been added + # Create server should do this but found it needed to occur here for sec_grp_name in self.instance_settings.security_group_names: if self.vm_active(block=True): nova_utils.add_security_group(self.__nova, self.__vm, sec_grp_name) else: - raise Exception( + raise VmInstanceCreationError( 'Cannot applying security group with name ' + sec_grp_name + ' to VM that did not activate with name - ' + @@ -191,7 +157,7 @@ class OpenStackVmInstance: port = port_dict.get(floating_ip_setting.port_name) if not port: - raise Exception( + raise VmInstanceCreationError( 'Cannot find port object with name - ' + floating_ip_setting.port_name) @@ -202,8 +168,8 @@ class OpenStackVmInstance: if ext_gateway: subnet = neutron_utils.get_subnet_by_name( self.__neutron, floating_ip_setting.subnet_name) - floating_ip = nova_utils.create_floating_ip(self.__nova, - ext_gateway) + floating_ip = neutron_utils.create_floating_ip( + self.__neutron, ext_gateway) self.__floating_ips.append(floating_ip) self.__floating_ip_dict[floating_ip_setting.name] = floating_ip @@ -212,9 +178,9 @@ class OpenStackVmInstance: floating_ip_setting.router_name) self.__add_floating_ip(floating_ip, port, subnet) else: - raise Exception('Unable to add floating IP to port,' - ' cannot locate router with an external ' - 'gateway ') + raise VmInstanceCreationError( + 'Unable to add floating IP to port, cannot locate router ' + 'with an external gateway ') def __ext_gateway_by_router(self, router_name): """ @@ -224,12 +190,12 @@ class OpenStackVmInstance: :return: the external network name or None """ router = neutron_utils.get_router_by_name(self.__neutron, router_name) - if router and router['router'].get('external_gateway_info'): + if router and router.external_gateway_info: network = neutron_utils.get_network_by_id( self.__neutron, - router['router']['external_gateway_info']['network_id']) + router.external_gateway_info['network_id']) if network: - return network['network']['name'] + return network.name return None def clean(self): @@ -241,7 +207,7 @@ class OpenStackVmInstance: for floating_ip in self.__floating_ips: try: logger.info('Deleting Floating IP - ' + floating_ip.ip) - nova_utils.delete_floating_ip(self.__nova, floating_ip) + neutron_utils.delete_floating_ip(self.__neutron, floating_ip) except Exception as e: logger.error('Error deleting Floating IP - ' + str(e)) self.__floating_ips = list() @@ -297,27 +263,16 @@ class OpenStackVmInstance: ports = list() for port_setting in port_settings: - # First check to see if network already has this port - # TODO/FIXME - this could potentially cause problems if another - # port with the same name exists - # VM has the same network/port name pair - found = False - - # TODO/FIXME - should we not be iterating on ports for the specific - # network in question as unique port names - # seem to only be important by network - existing_ports = self.__neutron.list_ports()['ports'] - for existing_port in existing_ports: - if existing_port['name'] == port_setting.name: - ports.append((port_setting.name, {'port': existing_port})) - found = True - break - - if not found and not cleanup: - ports.append((port_setting.name, - neutron_utils.create_port(self.__neutron, - self.__os_creds, - port_setting))) + port = neutron_utils.get_port_by_name(self.__neutron, + port_setting.name) + if port: + ports.append((port_setting.name, {'port': port})) + elif not cleanup: + # Exception will be raised when port with same name already + # exists + ports.append( + (port_setting.name, neutron_utils.create_port( + self.__neutron, self.__os_creds, port_setting))) return ports @@ -332,20 +287,21 @@ class OpenStackVmInstance: if subnet: # Take IP of subnet if there is one configured on which to place # the floating IP - for fixed_ip in port['port']['fixed_ips']: + for fixed_ip in port.fixed_ips: if fixed_ip['subnet_id'] == subnet['subnet']['id']: ip = fixed_ip['ip_address'] break else: # Simply take the first - ip = port['port']['fixed_ips'][0]['ip_address'] + ip = port.ips[0]['ip_address'] if ip: count = timeout / poll_interval while count > 0: logger.debug('Attempting to add floating IP to instance') try: - self.__vm.add_floating_ip(floating_ip, ip) + nova_utils.add_floating_ip_to_server( + self.__nova, self.__vm, floating_ip, ip) logger.info( 'Added floating IP %s to port IP %s on instance %s', floating_ip.ip, ip, self.instance_settings.name) @@ -358,11 +314,12 @@ class OpenStackVmInstance: count -= 1 pass else: - raise Exception( + raise VmInstanceCreationError( 'Unable find IP address on which to place the floating IP') logger.error('Timeout attempting to add the floating IP to instance.') - raise Exception('Timeout while attempting add floating IP to instance') + raise VmInstanceCreationError( + 'Timeout while attempting add floating IP to instance') def get_os_creds(self): """ @@ -376,7 +333,14 @@ class OpenStackVmInstance: Returns the latest version of this server object from OpenStack :return: Server object """ - return nova_utils.get_latest_server_object(self.__nova, self.__vm) + return self.__vm + + def get_console_output(self): + """ + Returns the vm console object for parsing logs + :return: the console output object + """ + return nova_utils.get_server_console_output(self.__nova, self.__vm) def get_port_ip(self, port_name, subnet_name=None): """ @@ -389,7 +353,6 @@ class OpenStackVmInstance: """ port = self.get_port_by_name(port_name) if port: - port_dict = port['port'] if subnet_name: subnet = neutron_utils.get_subnet_by_name(self.__neutron, subnet_name) @@ -398,13 +361,12 @@ class OpenStackVmInstance: 'not be located with name - %s', subnet_name) return None - for fixed_ip in port_dict['fixed_ips']: - if fixed_ip['subnet_id'] == subnet['subnet']['id']: + for fixed_ip in port.ips: + if fixed_ip['subnet_id'] == subnet.id: return fixed_ip['ip_address'] else: - fixed_ips = port_dict['fixed_ips'] - if fixed_ips and len(fixed_ips) > 0: - return fixed_ips[0]['ip_address'] + if port.ips and len(port.ips) > 0: + return port.ips[0]['ip_address'] return None def get_port_mac(self, port_name): @@ -418,8 +380,7 @@ class OpenStackVmInstance: """ port = self.get_port_by_name(port_name) if port: - port_dict = port['port'] - return port_dict['mac_address'] + return port.mac_address return None def get_port_by_name(self, port_name): @@ -434,11 +395,18 @@ class OpenStackVmInstance: logger.warning('Cannot find port with name - ' + port_name) return None + def get_vm_info(self): + """ + Returns a dictionary of a VMs info as returned by OpenStack + :return: a dict() + """ + return nova_utils.get_server_info(self.__nova, self.__vm) + def config_nics(self): """ Responsible for configuring NICs on RPM systems where the instance has more than one configured port - :return: None + :return: the value returned by ansible_utils.apply_ansible_playbook() """ if len(self.__ports) > 1 and len(self.__floating_ips) > 0: if self.vm_active(block=True) and self.vm_ssh_active(block=True): @@ -446,11 +414,12 @@ class OpenStackVmInstance: port_index = self.__ports.index((key, port)) if port_index > 0: nic_name = 'eth' + repr(port_index) - self.__config_nic( + retval = self.__config_nic( nic_name, port, self.__get_first_provisioning_floating_ip().ip) logger.info('Configured NIC - %s on VM - %s', nic_name, self.instance_settings.name) + return retval def __get_first_provisioning_floating_ip(self): """ @@ -466,21 +435,21 @@ class OpenStackVmInstance: elif len(self.__floating_ips) > 0: return self.__floating_ips[0] - def __config_nic(self, nic_name, port, floating_ip): + def __config_nic(self, nic_name, port, ip): """ Although ports/NICs can contain multiple IPs, this code currently only supports the first. :param nic_name: Name of the interface :param port: The port information containing the expected IP values. - :param floating_ip: The floating IP on which to apply the playbook. + :param ip: The IP on which to apply the playbook. :return: the return value from ansible """ - ip = port['port']['fixed_ips'][0]['ip_address'] + port_ip = port.ips[0]['ip_address'] variables = { - 'floating_ip': floating_ip, + 'floating_ip': ip, 'nic_name': nic_name, - 'nic_ip': ip + 'nic_ip': port_ip } if self.image_settings.nic_config_pb_loc and self.keypair_settings: @@ -594,17 +563,18 @@ class OpenStackVmInstance: if not self.__vm: return False - instance = self.__nova.servers.get(self.__vm.id) - if not instance: + status = nova_utils.get_server_status(self.__nova, self.__vm) + if not status: logger.warning('Cannot find instance with id - ' + self.__vm.id) return False - if instance.status == 'ERROR': - raise Exception('Instance had an error during deployment') + if status == 'ERROR': + raise VmInstanceCreationError( + 'Instance had an error during deployment') logger.debug( 'Instance status [%s] is - %s', self.instance_settings.name, - instance.status) - return instance.status == expected_status_code + status) + return status == expected_status_code def vm_ssh_active(self, block=False, poll_interval=POLL_INTERVAL): """ @@ -685,7 +655,7 @@ class OpenStackVmInstance: def add_security_group(self, security_group): """ Adds a security group to this VM. Call will block until VM is active. - :param security_group: the OpenStack security group object + :param security_group: the SNAPS SecurityGroup domain object :return True if successful else False """ self.vm_active(block=True) @@ -696,8 +666,7 @@ class OpenStackVmInstance: try: nova_utils.add_security_group(self.__nova, self.get_vm_inst(), - security_group['security_group'][ - 'name']) + security_group.name) return True except NotFound as e: logger.warning('Security group not added - ' + str(e)) @@ -770,13 +739,13 @@ class VmInstanceSettings: if kwargs.get('security_group_names'): if isinstance(kwargs['security_group_names'], list): - self.security_group_names = kwargs['security_group_names'] + self.security_group_names = kwargs['security_group_names'] elif isinstance(kwargs['security_group_names'], set): self.security_group_names = kwargs['security_group_names'] elif isinstance(kwargs['security_group_names'], str): self.security_group_names = [kwargs['security_group_names']] else: - raise Exception( + raise VmInstanceSettingsError( 'Invalid data type for security_group_names attribute') else: self.security_group_names = set() @@ -814,11 +783,11 @@ class VmInstanceSettings: self.availability_zone = None if not self.name or not self.flavor: - raise Exception( + raise VmInstanceSettingsError( 'Instance configuration requires the attributes: name, flavor') if len(self.port_settings) == 0: - raise Exception( + raise VmInstanceSettingsError( 'Instance configuration requires port settings (aka. NICS)') @@ -855,6 +824,24 @@ class FloatingIpSettings: self.provisioning = True if not self.name or not self.port_name or not self.router_name: - raise Exception( + raise FloatingIpSettingsError( 'The attributes name, port_name and router_name are required ' 'for FloatingIPSettings') + + +class VmInstanceSettingsError(Exception): + """ + Exception to be thrown when an VM instance settings are incorrect + """ + + +class FloatingIpSettingsError(Exception): + """ + Exception to be thrown when an VM instance settings are incorrect + """ + + +class VmInstanceCreationError(Exception): + """ + Exception to be thrown when an VM instance cannot be created + """