def run(self, *args, **kwargs): operation_params = json.loads(self.db_operation.params) region = operation_params.get('region') if not region: return self.abort_operation() nc = nova_client( api_session=IdentityAdminApi(request_session=AUTH_CACHE).session, region_name=region) try: instance = nc.servers.get( server={'id': self.db_operation.primary_object_id}) except (Exception, NotFound): instance = None if not instance: resource_usage_log = ResourceUsageLog.objects.filter( resource_uuid=self.db_operation.primary_object_id).order_by( 'start').last() if not resource_usage_log: return self.abort_operation() if not resource_usage_log.end: timestamp = utcnow().isoformat() LOG.info( 'Instance delete operation successfully set the resource usage log end date' ) resource_usage_log.end = timestamp resource_usage_log.save() return self.mark_as_completed() else: LOG.info( 'Instance related resource usage log was already ended by OS messages' ) return self.mark_as_completed()
def delete_project_security_groups(api_session, project_id, region=None, instances_list: Optional[List] = None): neutron_cl = neutron_client(api_session, region_name=region) nova_c = nova_client(api_session=api_session, region_name=region) # wait for all instances to be gone first if instances_list: for instance_id in instances_list: wait_for_instance_deleted(device_id=instance_id, nova_c=nova_c) try: security_groups = neutron_cl.list_security_groups( fields=['id', 'name'], tenant_id=project_id).get('security_groups', []) for security_group in security_groups: if security_group['name'] != 'default': try: neutron_cl.delete_security_group(security_group['id']) except Conflict as e: LOG.exception( e ) # should not get here because we waited for instances to disappear above except Exception as e: LOG.exception(e)
def compute_api(self): """ :rtype: novaclient.v2.client.Client """ assert self.api_session is not None, 'Unable to use compute_api without a Keystoneauth session' return nova_client(api_session=self.api_session, region_name=self.region_name)
def nova_api(self): """ :rtype: novaclient.v2.client.Client """ assert self.api_session is not None, 'Unable to use nova_api without an api_session!' # TODO(Marius): refactor this class, the way it uses the nova client return nova_client(api_session=self.api_session, region_name=self.db_flavor.region.id)
def create(self, name, image, flavor, admin_pass, nics, region_name, user_data, key_name=None, key_content=None, block_device_mapping=None, block_device_mapping_v2=None): """ :type name: str or unicode, the instance name :type image: str or unicode, the flavor id :type flavor: str or unicode :type admin_pass: str or unicode, the root/admin password for the instance :type nics: dict, network interfaces for the instance :type key_name: str or unicode, the ssh keypair name :type region_name: str or unicode :type key_content: str or unicode :type block_device_mapping: dict :type block_device_mapping_v2: list of dicts :rtype: :class:`novaclient.v2.servers.Server` """ # Create the ssh keypair in Nova if needed if key_name and key_content: kp = Keypairs(api_session=self.api_session, region_name=region_name) nova_key_name = kp.create_if_missing(name=key_name, public_key=key_content) else: nova_key_name = None # Create the default security group if Needed # TODO(tomo): Try to deal with the default security group in another way sgid = create_security_group_if_missing(api_session=self.api_session, region=region_name) nc = nova_client(api_session=self.api_session, region_name=region_name) params = dict(name=name, image=image, flavor=flavor, nics=nics, security_groups=[sgid], key_name=nova_key_name, block_device_mapping=block_device_mapping, block_device_mapping_v2=block_device_mapping_v2) if plugin_settings.force_config_drive_for_instance_creation: params['config_drive'] = True if admin_pass: params['admin_pass'] = admin_pass if user_data: params['userdata'] = user_data return nc.servers.create(**params)
def admin_api(self): """ :rtype: novaclient.v2.client.Client """ admin_session = self._get_admin_session() assert admin_session is not None, 'Unable to use admin_api without a Keystoneauth session' return nova_client(api_session=admin_session, region_name=self.instance.region, extensions=True)
def nova_admin_api(self): """ :rtype: novaclient.v2.client.Client """ assert self.admin_session is not None, 'Unable to use admin_api without a Keystoneauth session' return nova_client(api_session=self.admin_session, region_name=self.region, endpoint_type=self.interface, extensions=True)
def _get_hypervisor_host_name(self, instance_id: str, region: str) -> Optional[str]: """gets host name from 'OS-EXT-SRV-ATTR:host' attribute found on instances""" nc = nova_client(api_session=self.admin_api_session, region_name=region) try: nc_instance = nc.servers.get(instance_id) except Exception as e: LOG.error(str(e)) return None return getattr(nc_instance, 'OS-EXT-SRV-ATTR:host', None)
def sync_instances(region_id=None): ih = InstanceSyncHandler() nc = nova_client(api_session=get_keystone_admin().session, region_name=region_id) try: for instance in nc.servers.list(detailed=True, search_opts={'all_tenants': '1'}): ih.create_or_update(instance, region=region_id, timestamp=timestamp) except EndpointNotFound as e: LOG.error(str(e)) return version = ih.get_version(timestamp) delete_filter = {'{}__lt'.format(ih.version_field): version, 'region': region_id} ih.model_class.objects.filter(**delete_filter).delete()
def get_hypervisors(self, region=None): """ :param region: Openstack region name :return: """ try: nc = nova_client(api_session=self.api_session, region_name=region) hypervisors = nc.hypervisors.list() except EndpointNotFound: return [] else: return hypervisors
def perform_create(self, serializer): os_api = self.get_os_api( request=self.request) # type: [OSApi, OSAdminApi] serialized_data = copy.deepcopy(serializer.validated_data) cluster_template_id = serialized_data.get('cluster_template_id') keypair_name = serialized_data.pop('keypair') keypair = PublicKey.objects.filter(user=self.request.user, name=keypair_name).first() if not keypair: if self.request.user.is_staff: msg = _('Provided keypair was not found or you do not own it.') else: msg = _('Provided keypair was not found.') raise APIBadRequest(msg) keypair_name_formatted = '{}_{}'.format( keypair_name, self.get_project_id(request=self.request)) if not cluster_template_id: raise APIBadRequest(_('You need to provide a cluster template')) cluster_template = ClusterTemplate.objects.filter( id=cluster_template_id).first() if not cluster_template: raise APIBadRequest( _('Provided cluster template cannot be found anymore')) nc = nova_client(api_session=identity.IdentityAdminApi().session, region_name=cluster_template.region) try: nc.keypairs.create(name=keypair_name_formatted, public_key=newlines_substract( keypair.public_key)) except Conflict: # Key was created before, use it try: return os_api.clusters.create( region_id=cluster_template.region, keypair=keypair_name_formatted, **serialized_data, ) except Exception as e: raise APIBadRequest(str(e)) except Exception as e: raise APIBadRequest(str(e)) try: return os_api.clusters.create( region_id=cluster_template.region, keypair=keypair_name_formatted, **serialized_data, ) except Exception as e: raise APIBadRequest(str(e))
def delete_openstack_instance(self, instance_id, region, project_id, user_id: Optional[int] = None): del self # unused project = Project.with_admin_session(project_id, cache=AUTH_CACHE) nc = nova_client(api_session=project.api_session, region_name=region, extensions=True) try: user = AppUser.objects.filter(id=user_id).first() db_instance = ModelInstance.objects.filter(id=instance_id).first() nc.servers.delete(server=instance_id) if user and db_instance: if user.is_staff: staff_signals.staff_delete_instance.send( sender=__name__, user=user, user_id=user.id, instance_name=db_instance.name, instance_id=instance_id, username=user.username) else: user_signals.user_delete_instance.send( sender=__name__, user=user, user_id=user.id, instance_name=db_instance.name, instance_id=instance_id, username=user.username) except nova_exceptions.NotFound: ModelInstance.objects.filter(id=instance_id).delete() else: Operation.objects.create(operation_type=InstanceDeletion.name, primary_object_id=instance_id, params=json.dumps({ 'region': region, }))
def get_current_cores(): if 'fleio.openstack' not in settings.INSTALLED_APPS: return 0 from fleio.openstack.api.identity import IdentityAdminApi from fleio.openstack.api.nova import nova_client from fleio.openstack.models import OpenstackRegion physical_cores = 0 for region in OpenstackRegion.objects.all(): try: client = nova_client(api_session=IdentityAdminApi().session, region_name=region.id) for virtual_node in client.hypervisors.list(): cpu_info = virtual_node.cpu_info if isinstance(cpu_info, str): cpu_info = json.loads(cpu_info) physical_cores += int(cpu_info['topology']['cores']) except (ClientException, ConnectTimeout, Unauthorized, ConnectFailure, TypeError, JSONDecodeError, DiscoveryFailure): raise exceptions.APIException() except EndpointNotFound: # region not available LOG.error( 'Region not found when attempting to get number of cores for region {}, ignoring' .format(region.id), ) except ConfigException: # configuration error LOG.exception( 'Invalid configuration when attempting to get number of cores for region {}, ignoring' .format(region.id), ) # region not available except Exception as e: del e # unused LOG.exception( 'Exception when attempting to get number of cores for region {}, ignoring' .format(region.id), ) return physical_cores
def create(self, name, ram, vcpus, disk, flavorid, ephemeral=0, swap=0, rxtx_factor=1.0, is_public=True, region=None): novaclient = nova_client(api_session=self.api_session, region_name=region) return novaclient.flavors.create(name, ram, vcpus, disk, flavorid=flavorid, ephemeral=ephemeral, swap=swap, rxtx_factor=rxtx_factor, is_public=is_public)
def sync_flavors(region_id=None): def _get_int_or_zero(value): """Convert to int or return 0 if unable to convert.""" try: int_value = int(value) except ValueError: int_value = 0 return int_value def _update_flavor(dbf, openstack_flavor): dbf.name = openstack_flavor.name dbf.vcpus = openstack_flavor.vcpus dbf.root_gb = _get_int_or_zero(openstack_flavor.disk) dbf.memory_mb = _get_int_or_zero(openstack_flavor.ram) dbf.swap = _get_int_or_zero(openstack_flavor.swap) dbf.is_public = openstack_flavor.is_public dbf.region_id = region_id dbf.disabled = getattr(openstack_flavor, 'OS-FLV-DISABLED:disabled', False) dbf.ephemeral_gb = _get_int_or_zero(openstack_flavor.ephemeral) dbf.deleted = False properties = openstack_flavor.get_keys() dbf.properties = json.dumps(properties) if not dbf.description: dbf.description = openstack_flavor.name dbf.save() # Get flavors from API try: api_flavors = nova_client(api_session=get_keystone_admin().session, region_name=region_id).\ flavors.list(is_public=None) except EndpointNotFound as e: LOG.error(str(e)) return existing_flavors = [] for f in api_flavors: try: db_flv = OpenstackInstanceFlavor.objects.get(id=f.id) existing_flavors.append(db_flv.id) except OpenstackInstanceFlavor.DoesNotExist: LOG.info('Attempting to create missing flavor: %s ' % f.name) # Get the region object in DB try: db_flv = OpenstackInstanceFlavor.objects.create(id=f.id, name=f.name, memory_mb=_get_int_or_zero(f.ram), vcpus=f.vcpus, swap=_get_int_or_zero(f.swap), root_gb=f.disk, ephemeral_gb=_get_int_or_zero(f.ephemeral), is_public=f.is_public, disabled=getattr(f, 'OS-FLV-DISABLED:disabled', False), region_id=region_id, show_in_fleio=True, description=f.name, properties=json.dumps(f.get_keys())) existing_flavors.append(db_flv.id) except Exception as e: LOG.error('Unable to create flavor %s: %s' % (f.name, e)) # Go to the next flavor if not found. continue # If found, update it's records: _update_flavor(db_flv, f) # Remove missing flavors from region OpenstackInstanceFlavor.objects.exclude(id__in=existing_flavors).filter(region__id=region_id).delete()
def run_backup(time_to_execute): # TODO(MARIUS): implement command line arguments (recognisable flags like --force/-f) # TODO(MARIUS): don't backup schedules from db that have already been executed (they pass the filter condition now) # TODO(MARIUS): check backup types and execute the backups based on that, for accuracy """ :param time_to_execute: The time at which the procedure will be executed. Scenario 1 (auto-run): - an external automatic process (cron for linux, windows task scheduler for windows) will be set to execute this script, in which :param time_to_execute: will be the time that the external process was set to run e.g (5:00 AM, daily / weekly / etc.) Scenario 2 (manual-run): - script is run manually, in which case :param time_to_execute: will be the time at which the script is executed All backups that are scheduled BEFORE the :param time_to_execute: are going to be executed. """ # default_session = admin_session() backups_to_execute = OpenStackBackupSchedule.objects.filter( run_at__lt=time_to_execute) total_backups = len(backups_to_execute) backups_executed = 0 backups_failed = [] session_map = dict( # stores sessions based on project_id ) for backup in backups_to_execute: instance_region = backup.instance.region project_id = backup.instance.project_id # use the session related to the instance project_id new_session = session_map.get(project_id, None) if not new_session: new_session = custom_session(project_id=project_id) session_map[ project_id] = new_session # store the session in case we need it later gc = glance_client(api_session=new_session, region_name=instance_region) nc = nova_client(api_session=new_session, region_name=instance_region) nc.servers.backup(server=backup.instance.id, backup_name=backup.backup_name, backup_type=backup.backup_type, rotation=backup.rotation) if len(list(gc.images.list(filters={'name': backup.backup_name}))) > 0: backups_executed += 1 else: backups_failed.append(backup.instance.id) logger.error(e) logger.info( 'Cannot perform backup on instance {}, instance currently under a task state.' .format(backup.instance.id)) time_to_execute = time_to_execute.strftime('%Y-%m-%d %H:%M:%S') if not backups_failed: msg = _( '{executed} out of {total} backups were created successfully before {time_to_execute}' ).format(executed=backups_executed, total=total_backups, time_to_execute=time_to_execute) else: msg = _('Could not backup the following virtual machines: {failed}\n' ).format(backups_failed) msg += _( 'Backed up {executed} out of {total} virtual machines').format( executed=backups_executed, total=total_backups) OpenStackBackupLog.objects.create() return msg