def perform_destroy(self, client): activity_helper.add_current_activity_params(client_name=client.name) if client.billing_settings.suspend_instead_of_terminate or reseller_suspend_instead_of_terminate( client=client): return self.suspend(self.request, client.pk) client.status = ClientStatus.deleting client.save() delete_all_resources = (self.request.query_params.get( 'delete_cloud_resources', None) in ('true', 'True', '1') or self.request.data.get( 'delete_cloud_resources', None) in ('true', 'True', '1')) user = self.request.user core_tasks.terminate_client.delay( client_id=client.id, user_id=user.id, delete_all_resources=delete_all_resources, ) reseller_delete_client.send(sender=__name__, user=user, user_id=user.id, client_name=client.name, client_id=client.id, username=user.username, request=self.request) return Response({'detail': _('Client delete scheduled')}, status=rest_status.HTTP_202_ACCEPTED)
def create_instance_task(self, volume_id, project_id, project_domain_id, region_name, name, image, flavor, nics, block_device_mapping_v2, block_device_mapping, user_data=None, user_id=None, admin_pass=None, key_name=None, key_content=None): os_api = OSApi(project=project_id, domain=project_domain_id) boot_device = None if block_device_mapping_v2: for block_device in block_device_mapping_v2: if block_device.get('boot_index') == '0': boot_device = block_device if boot_device and volume_id: # NOTE(tomo): Boot from volume with a volume type specified boot_device['source_type'] = 'volume' boot_device['uuid'] = volume_id try: server = os_api.instances.create( name=name, image=image, flavor=flavor, admin_pass=admin_pass, nics=nics, region_name=region_name, key_name=key_name, key_content=key_content, user_data=user_data, block_device_mapping=block_device_mapping, block_device_mapping_v2=block_device_mapping_v2) except Exception as e: openstack_error.send( sender='create_instance_task', event_type='fleio_instance_create', payload=dict(exception=str(e)), region=region_name, ) raise e if user_id: user = AppUser.objects.filter(id=user_id).first() if user: instance_create.send(sender=__name__, user=user, username=user.username, instance_id=server.id, request=None) activity_helper.add_current_activity_params(object_id=server.id) return server.id
def add_payment_to_invoice(self, request, pk): del pk # unused self.get_object() serializer = StaffAddInvoicePaymentSerializer(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) serializer.save() activity_helper.add_current_activity_params( amount=serializer.validated_data['amount'], currency_code=serializer.validated_data['currency'].code, ) return Response({'detail': _('Payment added')})
def _finalize_response_wrapper(self, request: Request, response: Response, *args, **kwargs): if activity_helper.has_current_activity(): if response.status_code >= 200 and response.status_code < 300: action = getattr(self, 'action', None) if action == 'create': response_data = getattr(response, 'data', None) if response_data and hasattr(response_data, 'get'): object_id = response_data.get('id', None) if object_id: activity_helper.add_current_activity_params(object_id=object_id) activity_helper.end_activity() else: activity_helper.end_activity(failed=True) return self._original_finalize_response(request=request, response=response, *args, **kwargs)
def perform_create(self, serializer: StaffVolumeBackupCreateSerializer): if not validate_cloud_objects_limit(): raise APIBadRequest( _('Licence cloud objects limit reached. Please check your license.' )) volume_id = serializer.validated_data.get('volume_id') volume = Volume.objects.filter(id=volume_id).first() if volume: if serializer.validated_data.pop('for_client'): try: volume_related_project = volume.project except Project.DoesNotExist: raise APIBadRequest( _('Cannot create volume backup for client because related volume has not ' 'client project associated')) else: project_id_used = volume_related_project.project_id os_api = OSApi.from_project_id( project_id=volume_related_project.project_id) else: project_id_used = plugin_settings.USER_PROJECT_ID os_api = OSAdminApi() if serializer.validated_data.get('incremental') is True: if not has_full_backup_for_incremental_backup( project_id=project_id_used, related_volume=volume): # for incremental backups check if a full backup related to the volume exists in the same project # - openstack doesn't validate this at specific project level raise APIBadRequest(detail=_( 'Cannot create incremental backup without having a full backup first ' 'in your os project')) try: volume_backup = os_api.volume_backups.create( region_id=volume.region, **serializer.validated_data, ) activity_helper.add_current_activity_params( object_id=volume_backup.id) except Exception as e: LOG.error(e) handle(self.request, message=_('Unable to create volume backup')) return Response( {'detail': _('Volume backup creation in progress')}) else: raise APIBadRequest( _('Cannot create volume backup as related volume does not exist' ))
def resume(self, request, pk): del request, pk # unused client = self.get_object() activity_helper.add_current_activity_params(client_name=client.name) if client.status == ClientStatus.active: return Response({'detail': _('Client is not suspended')}) resume_service_tasks = list() for service in client.services.suspended(): resume_service_tasks.append( service_tasks.resume_service.s(service.id)) celery.group(resume_service_tasks).apply_async() client.status = ClientStatus.active client.save() return Response({'detail': _('Resume scheduled')})
def perform_create(self, serializer: VolumeBackupCreateSerializer): if not validate_cloud_objects_limit(): raise APIBadRequest( _('Licence cloud objects limit reached. Please check your license.' )) volume_id = serializer.validated_data.get('volume_id') volume = Volume.objects.filter(id=volume_id).first() if volume: if serializer.validated_data.get('incremental') is True: client = self.request.user.clients.first() try: project = client.first_project.project_id except (AttributeError, TypeError): raise APIBadRequest( detail=_('No client with an OpenStack project found')) if not has_full_backup_for_incremental_backup( project_id=project, related_volume=volume): # for incremental backups check if a full backup related to the volume exists in the same project # - openstack doesn't validate this at specific project level raise APIBadRequest(detail=_( 'Cannot create incremental backup without having a full backup first' )) os_api = OSApi.from_request(request=self.request) try: volume_backup = os_api.volume_backups.create( region_id=volume.region, **serializer.validated_data, ) activity_helper.add_current_activity_params( object_id=volume_backup.id) except Exception as e: del e # unused handle( self.request, message=self.format_exception( default_message=_('Unable to create volume backup'))) return Response( {'detail': _('Volume backup creation in progress')}) else: raise APIBadRequest( _('Cannot create volume backup as related volume does not exist' ))
def suspend(self, request, pk): del request, pk # unused client = self.get_object() activity_helper.add_current_activity_params(client_name=client.name) if client.status == ClientStatus.suspended: return Response({'detail': _('Client already suspended')}) suspend_service_tasks = list() for service in client.services.active(): # TODO - #1015: seems like reason is not sent to this method, passing empty reason suspend_service_tasks.append( service_tasks.suspend_service.s(service.id, '')) celery.group(suspend_service_tasks).apply_async() client.status = ClientStatus.suspended client.save() return Response({'detail': _('Suspend scheduled')})
def perform_create(self, serializer): serializer.is_valid(raise_exception=True) port_admin_api = Ports(api_session=self.openstack_admin_session) try: port = port_admin_api.create( kwargs=serializer.validated_data)['port'] activity_helper.add_current_activity_params(object_id=port['id']) user = self.request.user instance_attach_ips.send( sender=__name__, user=user, user_id=user.id, port_id=port['id'], instance_id=serializer.validated_data['device_id'], ips=', '.join( [f_ip['ip_address'] for f_ip in port['fixed_ips']]), network_id=port['network_id'], username=user.username, request=self.request) except Exception as e: LOG.error(e) handle(self.request, message=_('Unable to create port'))
def perform_create(self, serializer: StaffVolumeSnapshotCreateSerializer): if not validate_cloud_objects_limit(): raise APIBadRequest( _('Licence cloud objects limit reached. Please check your license.' )) volume_id = serializer.validated_data.get('volume_id') for_client = serializer.validated_data.pop('for_client', False) volume = Volume.objects.filter(id=volume_id).first() if volume: try: if for_client: if not volume.project: raise APIBadRequest( _('Cannot create snapshot for client as volume does not have a related ' 'project in the database.')) if volume.project.project_id == plugin_settings.user_project_id: raise APIBadRequest( _('The volume is in the admin project. No client found.' )) os_api = OSApi.from_project_id( project_id=volume.project.project_id) else: os_api = OSAdminApi() volume_snapshot = os_api.volume_snapshots.create( region_name=volume.region, **serializer.validated_data, ) activity_helper.add_current_activity_params( object_id=volume_snapshot.id) except Exception as e: handle(self.request, message=str(e)) return Response( {'detail': _('Volume snapshot creation in progress')}) else: raise APIBadRequest( _('Cannot create volume snapshot as related volume does not exist' ))
def perform_create(self, serializer: VolumeSnapshotCreateSerializer): if not validate_cloud_objects_limit(): raise APIBadRequest( _('Licence cloud objects limit reached. Please check your license.' )) volume_id = serializer.validated_data.get('volume_id') volume = Volume.objects.filter(id=volume_id).first() if volume: os_api = OSApi.from_request(request=self.request) try: volume_snapshot = os_api.volume_snapshots.create( region_name=volume.region, **serializer.validated_data, ) activity_helper.add_current_activity_params( object_id=volume_snapshot.id) except Exception as e: handle(self.request, message=str(e)) return Response( {'detail': _('Volume snapshot creation in progress')}) else: raise APIBadRequest( _('Cannot create volume snapshot as related volume does not exist' ))
def perform_create(self, serializer): if not validate_cloud_objects_limit(): raise APIBadRequest(_('Licence cloud objects limit reached. Please check your license.')) project = serializer.validated_data['project'] region = serializer.validated_data.get('region') nics = serializer.validated_data['nics'] flavor = serializer.validated_data['flavor'] user_supplied_user_data = serializer.validated_data.get('user_data', None) user = serializer.validated_data.get('user', 'root') password = serializer.validated_data.get('root_password') user_data_passwd_template = None if password: password = crypt.crypt(password, crypt.mksalt( method=getattr(settings, 'INSTANCE_PASSWORD_HASH_METHOD', crypt.METHOD_SHA512) )) if user == 'root': user_data_passwd_template = getattr( settings, 'INSTANCE_CLOUD_INIT_ROOT_PASSWORD_SET', '' ).format(root_password=password) else: user_data_passwd_template = getattr( settings, 'INSTANCE_CLOUD_INIT_NEW_USER_AND_PASSWORD_SET', '' ).format(new_user_name=user, new_user_password=password) ssh_keys_set_template = getattr( settings, 'INSTANCE_CLOUD_INIT_SSH_KEYS_SET', '' ).format(user=user) ssh_keys = serializer.validated_data.get('ssh_keys', None) try: final_user_data = parse_user_data_mime( user_data_passwd_template=user_data_passwd_template, user_supplied_user_data=user_supplied_user_data, ssh_keys_set_template=ssh_keys_set_template, keys_content=ssh_keys, additional_userdata=getattr(settings, 'STAFF_INSTANCE_ADDITIONAL_CLOUD_INIT_USERDATA', None), ) except Exception as e: raise APIBadRequest(str(e)) dev_mapping_v1 = serializer.validated_data['boot_source'].get('dev_mapping_v1') dev_mapping_v2 = serializer.validated_data['boot_source'].get('dev_mapping_v2') volume_type = serializer.validated_data['boot_source'].get('volume_type') boot_image = serializer.validated_data['boot_source'].get('image') first_boot_device = serializer.validated_data['boot_source'].get('boot_device') boot_image_id = boot_image.id if boot_image else None create_args = dict(project_id=project.project_id, project_domain_id=project.project_domain_id, region_name=region.id) user_id = self.request.user.id if dev_mapping_v2 and first_boot_device and volume_type: # NOTE(tomo): Volume type was requested, we need to create the volume first # since nova does not support this directly chain = (create_instance_volume.s(source_type=first_boot_device['source_type'], source_id=first_boot_device['uuid'], volume_type=volume_type, volume_size=first_boot_device['volume_size'], **create_args) | wait_for_volume_status.s(status='available', **create_args) | create_instance_task.s(name=serializer.validated_data.get('name'), image=boot_image_id, flavor=flavor.id, nics=nics, user_data=final_user_data, block_device_mapping_v2=dev_mapping_v2, block_device_mapping=dev_mapping_v1, user_id=user_id, **create_args)) chain() else: # TODO(tomo): This create instance task is ran in sync so we can catch the exception below # however, we need to unify this with the above, mainly run the create async and deal with errors # in another way try: boot_from_iso = False if boot_image_id: # wait for image wait_for(lambda: Image.objects.filter(id=boot_image_id).count() > 0, 600) boot_image_model = Image.objects.get(id=boot_image_id) boot_from_iso = boot_image_model.disk_format == 'iso' if boot_from_iso: create_instance_from_iso_task.delay( volume_id=None, name=serializer.validated_data.get('name'), image=boot_image_id, flavor=flavor.id, nics=nics, user_data=final_user_data, block_device_mapping_v2=dev_mapping_v2, block_device_mapping=dev_mapping_v1, **create_args, ) else: instance_id = create_instance_task( volume_id=None, name=serializer.validated_data.get('name'), image=boot_image_id, flavor=flavor.id, nics=nics, user_data=final_user_data, block_device_mapping_v2=dev_mapping_v2, block_device_mapping=dev_mapping_v1, user_id=user_id, **create_args, ) activity_helper.add_current_activity_params(object_id=instance_id) except Unauthorized as e: LOG.error(e) raise exceptions.OpenstackAuthError( _('Project id for client does not exist, or does not have the permission for the operation')) except Exception as e: LOG.error(e) exceptions.handle(self.request, message=e)
def create_instance_from_iso_task(volume_id, project_id, project_domain_id, region_name, name, image, flavor, nics, block_device_mapping_v2, block_device_mapping, user_data, admin_pass=None, key_name=None, key_content=None, **create_args): boot_image_id = image identity_admin_api = IdentityAdminApi() # wait for image if not wait_for( lambda: Image.objects.filter(id=boot_image_id).first().status == OpenStackImageStatus.ACTIVE, 600): raise InstanceTaskException(_('Upload image failed ')) region = OpenstackRegion.objects.get(id=region_name) boot_image_model = Image.objects.get(id=boot_image_id) unique_name = '{}'.format(uuid4()) os_image_api = Images(api_session=identity_admin_api.session) # copy properties starting with hw_ to new image extra_properties = {} prefixes = getattr(settings, 'OPENSTACK_CREATE_FROM_ISO_PROPERTY_PREFIXES', []) for property_name in boot_image_model.properties: # type: str for prefix in prefixes: if property_name.startswith(prefix): extra_properties[property_name] = boot_image_model.properties[ property_name] owner = project_id if project_id else identity_admin_api.project_id disk_format = getattr(settings, 'OPENSTACK_CREATE_FROM_ISO_IMAGE_TYPE', 'raw') try: new_image = os_image_api.create( owner=owner, name=unique_name, min_disk=1, min_ram=1, container_format='bare', disk_format=disk_format, visibility='community', protected=False, architecture=boot_image_model.architecture, os_distro=boot_image_model.os_distro, os_version=boot_image_model.os_version, region=region, hypervisor_type=boot_image_model.hypervisor_type, file=None, url=None, source=None, properties=extra_properties, ) except Exception as e: del e # unused LOG.exception( 'Create instance failed. (owner: {}, disk_format: {}, extra_properties: {}' .format(owner, disk_format, extra_properties)) return None else: try: if disk_format == 'qcow2': upload_empty_qcow2_image(new_image.id, region_name=region_name, disk_size_in_bytes=1) else: upload_zero_filled_image(new_image.id, region_name=region_name, length_in_bytes=1) except Exception as e: LOG.exception( 'Failed to create temporary image when booting from iso: {}'. format(e)) try: db_image = Image.objects.get(id=new_image.id) os_image_api.get(image=db_image).delete() except Exception as e: LOG.exception('Failed to delete image: {}'.format(e)) return None instance_id = create_instance_task( volume_id=volume_id, project_id=project_id, project_domain_id=project_domain_id, region_name=region_name, name=name, image=new_image.id, flavor=flavor, admin_pass=admin_pass, nics=nics, key_name=key_name, key_content=key_content, block_device_mapping_v2=block_device_mapping_v2, user_data=user_data, block_device_mapping=block_device_mapping, **create_args, ) activity_helper.add_current_activity_params(object_id=instance_id) if not wait_for( lambda: ModelInstance.objects.filter(id=instance_id).first(), max_time=300): raise InstanceTaskException(_('Failed to create instance')) if not wait_for(lambda: ModelInstance.objects.filter(id=instance_id). first().status == 'active', max_time=300): raise InstanceTaskException(_('Failed to create instance')) if not wait_for(lambda: not ModelInstance.objects.filter( id=instance_id).first().task_state, max_time=300): raise InstanceTaskException(_('Failed to create instance')) try: db_image = Image.objects.get(id=new_image.id) os_image_api.get(image=db_image).delete() except Exception as e: LOG.exception('Failed to delete image: {}'.format(e)) instance_model = ModelInstance.objects.get(id=instance_id) instance_model.booted_from_iso = True instance_model.save() instance_api = Instance.with_admin_session(instance=instance_model) instance_api.rescue(image=boot_image_id) signal_boot_from_iso.delay(instance_id=instance_id, is_new_instance=True) return instance_id