Example #1
0
    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)
Example #2
0
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
Example #3
0
 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')})
Example #4
0
    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)
Example #5
0
 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'
               ))
Example #6
0
    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')})
Example #7
0
 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'
               ))
Example #8
0
    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')})
Example #9
0
 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'))
Example #10
0
 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'
               ))
Example #11
0
 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'
               ))
Example #12
0
    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)
Example #13
0
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