コード例 #1
0
ファイル: views.py プロジェクト: virtengine/ve-waldur-v2
class VirtualMachineViewSet(structure_views.ResourceViewSet):
    queryset = models.VirtualMachine.objects.all().order_by('name')
    filterset_class = filters.VirtualMachineFilter
    serializer_class = serializers.VirtualMachineSerializer
    create_executor = executors.VirtualMachineCreateExecutor
    delete_executor = executors.VirtualMachineDeleteExecutor
    pull_executor = executors.VirtualMachinePullExecutor

    @decorators.action(detail=True, methods=['post'])
    def start(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineStartExecutor().execute(virtual_machine)
        return response.Response({'status': _('start was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    start_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('stopped'),
    ]
    start_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def stop(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineStopExecutor().execute(virtual_machine)
        return response.Response({'status': _('stop was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    stop_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('running'),
    ]
    stop_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def restart(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineRestartExecutor().execute(virtual_machine)
        return response.Response({'status': _('restart was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    restart_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('running'),
    ]
    restart_serializer_class = rf_serializers.Serializer
コード例 #2
0
ファイル: views.py プロジェクト: andromedia/waldur-mastermind
 def _can_destroy_volume(volume):
     if volume.state == models.Volume.States.ERRED:
         return
     if volume.state != models.Volume.States.OK:
         raise core_exceptions.IncorrectStateException(
             _('Volume should be in OK state.'))
     core_validators.RuntimeStateValidator('available', 'error',
                                           'error_restoring',
                                           'error_extending', '')(volume)
コード例 #3
0
ファイル: views.py プロジェクト: andromedia/waldur-mastermind
class InstanceViewSet(structure_views.ImportableResourceViewSet):
    """
    OpenStack instance permissions
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    - Staff members can list all available VM instances in any service.
    - Customer owners can list all VM instances in all the services that belong to any of the customers they own.
    - Project administrators can list all VM instances, create new instances and start/stop/restart instances in all the
      services that are connected to any of the projects they are administrators in.
    - Project managers can list all VM instances in all the services that are connected to any of the projects they are
      managers in.
    """

    queryset = models.Instance.objects.all()
    serializer_class = serializers.InstanceSerializer
    filterset_class = filters.InstanceFilter
    filter_backends = structure_views.ResourceViewSet.filter_backends + (
        structure_filters.StartTimeFilter, )
    pull_executor = executors.InstancePullExecutor
    pull_serializer_class = rf_serializers.Serializer

    update_executor = executors.InstanceUpdateExecutor
    update_validators = partial_update_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]

    def perform_create(self, serializer):
        instance = serializer.save()
        executors.InstanceCreateExecutor.execute(
            instance,
            ssh_key=serializer.validated_data.get('ssh_public_key'),
            flavor=serializer.validated_data['flavor'],
            is_heavy_task=True,
        )

    def _has_backups(instance):
        if instance.backups.exists():
            raise core_exceptions.IncorrectStateException(
                _('Cannot delete instance that has backups.'))

    def _can_destroy_instance(instance):
        if instance.state == models.Instance.States.ERRED:
            return
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.SHUTOFF):
            return
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.ACTIVE):
            raise core_exceptions.IncorrectStateException(
                _('Please stop the instance before its removal.'))
        raise core_exceptions.IncorrectStateException(
            _('Instance should be shutoff and OK or erred. '
              'Please contact support.'))

    def destroy(self, request, uuid=None):
        """
        Deletion of an instance is done through sending a **DELETE** request to the instance URI.
        Valid request example (token is user specific):

        .. code-block:: http

            DELETE /api/openstacktenant-instances/abceed63b8e844afacd63daeac855474/ HTTP/1.1
            Authorization: Token c84d653b9ec92c6cbac41c706593e66f567a7fa4
            Host: example.com

        Only stopped instances or instances in ERRED state can be deleted.

        By default when instance is destroyed, all data volumes
        attached to it are destroyed too. In order to preserve data
        volumes use query parameter ?delete_volumes=false
        In this case data volumes are detached from the instance and
        then instance is destroyed. Note that system volume is deleted anyway.
        For example:

        .. code-block:: http

            DELETE /api/openstacktenant-instances/abceed63b8e844afacd63daeac855474/?delete_volumes=false HTTP/1.1
            Authorization: Token c84d653b9ec92c6cbac41c706593e66f567a7fa4
            Host: example.com

        """
        serializer = self.get_serializer(data=request.query_params,
                                         instance=self.get_object())
        serializer.is_valid(raise_exception=True)
        delete_volumes = serializer.validated_data['delete_volumes']
        release_floating_ips = serializer.validated_data[
            'release_floating_ips']

        resource = self.get_object()
        force = resource.state == models.Instance.States.ERRED
        executors.InstanceDeleteExecutor.execute(
            resource,
            force=force,
            delete_volumes=delete_volumes,
            release_floating_ips=release_floating_ips,
            is_async=self.async_executor,
        )

        return response.Response({'status': _('destroy was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    destroy_validators = [_can_destroy_instance, _has_backups]
    destroy_serializer_class = serializers.InstanceDeleteSerializer

    @decorators.action(detail=True, methods=['post'])
    def change_flavor(self, request, uuid=None):
        instance = self.get_object()
        old_flavor_name = instance.flavor_name
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        flavor = serializer.validated_data.get('flavor')
        executors.InstanceFlavorChangeExecutor().execute(
            instance, flavor=flavor, old_flavor_name=old_flavor_name)
        return response.Response(
            {'status': _('change_flavor was scheduled')},
            status=status.HTTP_202_ACCEPTED,
        )

    def _can_change_flavor(instance):
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.ACTIVE):
            raise core_exceptions.IncorrectStateException(
                _('Please stop the instance before changing its flavor.'))

    change_flavor_serializer_class = serializers.InstanceFlavorChangeSerializer
    change_flavor_validators = [
        _can_change_flavor,
        core_validators.StateValidator(models.Instance.States.OK),
        core_validators.RuntimeStateValidator(
            models.Instance.RuntimeStates.SHUTOFF),
    ]

    @decorators.action(detail=True, methods=['post'])
    def start(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceStartExecutor().execute(instance)
        return response.Response({'status': _('start was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    def _can_start_instance(instance):
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.ACTIVE):
            raise core_exceptions.IncorrectStateException(
                _('Instance is already active.'))

    start_validators = [
        _can_start_instance,
        core_validators.StateValidator(models.Instance.States.OK),
        core_validators.RuntimeStateValidator(
            models.Instance.RuntimeStates.SHUTOFF),
    ]
    start_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def stop(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceStopExecutor().execute(instance)
        return response.Response({'status': _('stop was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    def _can_stop_instance(instance):
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.SHUTOFF):
            raise core_exceptions.IncorrectStateException(
                _('Instance is already stopped.'))

    stop_validators = [
        _can_stop_instance,
        core_validators.StateValidator(models.Instance.States.OK),
        core_validators.RuntimeStateValidator(
            models.Instance.RuntimeStates.ACTIVE),
    ]
    stop_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def restart(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceRestartExecutor().execute(instance)
        return response.Response({'status': _('restart was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    def _can_restart_instance(instance):
        if (instance.state == models.Instance.States.OK
                and instance.runtime_state
                == models.Instance.RuntimeStates.SHUTOFF):
            raise core_exceptions.IncorrectStateException(
                _('Please start instance first.'))

    restart_validators = [
        _can_restart_instance,
        core_validators.StateValidator(models.Instance.States.OK),
        core_validators.RuntimeStateValidator(
            models.Instance.RuntimeStates.ACTIVE),
    ]
    restart_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def update_security_groups(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        executors.InstanceUpdateSecurityGroupsExecutor().execute(instance)
        return response.Response(
            {'status': _('security groups update was scheduled')},
            status=status.HTTP_202_ACCEPTED,
        )

    update_security_groups_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]
    update_security_groups_serializer_class = (
        serializers.InstanceSecurityGroupsUpdateSerializer)

    @decorators.action(detail=True, methods=['post'])
    def backup(self, request, uuid=None):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        backup = serializer.save()

        executors.BackupCreateExecutor().execute(backup)
        return response.Response(serializer.data,
                                 status=status.HTTP_201_CREATED)

    backup_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]
    backup_serializer_class = serializers.BackupSerializer

    @decorators.action(detail=True, methods=['post'])
    def create_backup_schedule(self, request, uuid=None):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return response.Response(serializer.data,
                                 status=status.HTTP_201_CREATED)

    create_backup_schedule_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]
    create_backup_schedule_serializer_class = serializers.BackupScheduleSerializer

    @decorators.action(detail=True, methods=['post'])
    def update_internal_ips_set(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        executors.InstanceInternalIPsSetUpdateExecutor().execute(instance)
        return response.Response(
            {'status': _('internal ips update was scheduled')},
            status=status.HTTP_202_ACCEPTED,
        )

    update_internal_ips_set_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]
    update_internal_ips_set_serializer_class = (
        serializers.InstanceInternalIPsSetUpdateSerializer)

    @decorators.action(detail=True, methods=['get'])
    def internal_ips_set(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(instance.internal_ips_set.all(),
                                         many=True)
        return response.Response(serializer.data, status=status.HTTP_200_OK)

    internal_ips_set_serializer_class = serializers.NestedInternalIPSerializer

    @decorators.action(detail=True, methods=['post'])
    def update_floating_ips(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        executors.InstanceFloatingIPsUpdateExecutor().execute(instance)
        return response.Response(
            {'status': _('floating ips update was scheduled')},
            status=status.HTTP_202_ACCEPTED,
        )

    update_floating_ips_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]
    update_floating_ips_serializer_class = (
        serializers.InstanceFloatingIPsUpdateSerializer)

    @decorators.action(detail=True, methods=['get'])
    def floating_ips(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(
            instance=instance.floating_ips.all(),
            queryset=models.FloatingIP.objects.all(),
            many=True,
        )
        return response.Response(serializer.data, status=status.HTTP_200_OK)

    floating_ips_serializer_class = serializers.NestedFloatingIPSerializer

    importable_resources_backend_method = 'get_instances_for_import'
    importable_resources_serializer_class = serializers.InstanceImportableSerializer
    import_resource_serializer_class = serializers.InstanceImportSerializer
    import_resource_executor = executors.InstancePullExecutor

    @decorators.action(detail=True, methods=['get'])
    def console(self, request, uuid=None):
        instance = self.get_object()
        backend = instance.get_backend()
        try:
            url = backend.get_console_url(instance)
        except OpenStackBackendError as e:
            raise exceptions.ValidationError(str(e))

        return response.Response({'url': url}, status=status.HTTP_200_OK)

    console_validators = [
        core_validators.StateValidator(models.Instance.States.OK)
    ]

    def check_permissions_for_console(request, view, instance=None):
        if not instance:
            return

        if request.user.is_staff:
            return

        if settings.WALDUR_OPENSTACK_TENANT[
                'ALLOW_CUSTOMER_USERS_OPENSTACK_CONSOLE_ACCESS']:
            structure_permissions.is_administrator(request, view, instance)
        else:
            raise exceptions.PermissionDenied()

    console_permissions = [check_permissions_for_console]

    @decorators.action(detail=True, methods=['get'])
    def console_log(self, request, uuid=None):
        instance = self.get_object()
        backend = instance.get_backend()
        serializer = self.get_serializer(data=request.query_params)
        serializer.is_valid(raise_exception=True)
        length = serializer.validated_data.get('length')

        try:
            log = backend.get_console_output(instance, length)
        except OpenStackBackendError as e:
            raise exceptions.ValidationError(str(e))

        return response.Response(log, status=status.HTTP_200_OK)

    console_log_serializer_class = serializers.ConsoleLogSerializer
    console_log_permissions = [structure_permissions.is_administrator]

    @decorators.action(detail=True, methods=['delete'])
    def force_destroy(self, request, uuid=None):
        """This action completely repeats 'destroy', with the exclusion of validators.
           Destroy's validators require stopped VM. This requirement has expired.
           But for compatibility with old documentation, it must be left.
        """
        return self.destroy(request, uuid)

    force_destroy_validators = [
        _has_backups,
        core_validators.StateValidator(models.Instance.States.OK,
                                       models.Instance.States.ERRED),
    ]
    force_destroy_serializer_class = destroy_serializer_class
コード例 #4
0
ファイル: views.py プロジェクト: andromedia/waldur-mastermind
class VolumeViewSet(structure_views.ImportableResourceViewSet):
    queryset = models.Volume.objects.all()
    serializer_class = serializers.VolumeSerializer
    filterset_class = filters.VolumeFilter

    create_executor = executors.VolumeCreateExecutor
    update_executor = executors.VolumeUpdateExecutor
    pull_executor = executors.VolumePullExecutor

    def _can_destroy_volume(volume):
        if volume.state == models.Volume.States.ERRED:
            return
        if volume.state != models.Volume.States.OK:
            raise core_exceptions.IncorrectStateException(
                _('Volume should be in OK state.'))
        core_validators.RuntimeStateValidator('available', 'error',
                                              'error_restoring',
                                              'error_extending', '')(volume)

    def _volume_snapshots_exist(volume):
        if volume.snapshots.exists():
            raise core_exceptions.IncorrectStateException(
                _('Volume has dependent snapshots.'))

    delete_executor = executors.VolumeDeleteExecutor
    destroy_validators = [
        _can_destroy_volume,
        _volume_snapshots_exist,
    ]

    def _is_volume_bootable(volume):
        if volume.bootable:
            raise core_exceptions.IncorrectStateException(
                _('Volume cannot be bootable.'))

    def _is_volume_instance_shutoff(volume):
        if (volume.instance and volume.instance.runtime_state !=
                models.Instance.RuntimeStates.SHUTOFF):
            raise core_exceptions.IncorrectStateException(
                _('Volume instance should be in shutoff state.'))

    def _is_volume_instance_ok(volume):
        if volume.instance and volume.instance.state != models.Instance.States.OK:
            raise core_exceptions.IncorrectStateException(
                _('Volume instance should be in OK state.'))

    @decorators.action(detail=True, methods=['post'])
    def extend(self, request, uuid=None):
        """ Increase volume size """
        volume = self.get_object()
        old_size = volume.size
        serializer = self.get_serializer(volume, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        volume.refresh_from_db()
        executors.VolumeExtendExecutor().execute(volume,
                                                 old_size=old_size,
                                                 new_size=volume.size)

        return response.Response({'status': _('extend was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    extend_validators = [
        _is_volume_bootable,
        _is_volume_instance_ok,
        _is_volume_instance_shutoff,
        core_validators.StateValidator(models.Volume.States.OK),
    ]
    extend_serializer_class = serializers.VolumeExtendSerializer

    @decorators.action(detail=True, methods=['post'])
    def snapshot(self, request, uuid=None):
        """ Create snapshot from volume """
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        snapshot = serializer.save()

        executors.SnapshotCreateExecutor().execute(snapshot)
        return response.Response(serializer.data,
                                 status=status.HTTP_201_CREATED)

    snapshot_serializer_class = serializers.SnapshotSerializer

    @decorators.action(detail=True, methods=['post'])
    def create_snapshot_schedule(self, request, uuid=None):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return response.Response(serializer.data,
                                 status=status.HTTP_201_CREATED)

    create_snapshot_schedule_validators = [
        core_validators.StateValidator(models.Volume.States.OK)
    ]
    create_snapshot_schedule_serializer_class = serializers.SnapshotScheduleSerializer

    @decorators.action(detail=True, methods=['post'])
    def attach(self, request, uuid=None):
        """ Attach volume to instance """
        volume = self.get_object()
        serializer = self.get_serializer(volume, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        executors.VolumeAttachExecutor().execute(volume)
        return response.Response({'status': _('attach was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    attach_validators = [
        core_validators.RuntimeStateValidator('available'),
        core_validators.StateValidator(models.Volume.States.OK),
    ]
    attach_serializer_class = serializers.VolumeAttachSerializer

    @decorators.action(detail=True, methods=['post'])
    def detach(self, request, uuid=None):
        """ Detach instance from volume """
        volume = self.get_object()
        executors.VolumeDetachExecutor().execute(volume)
        return response.Response({'status': _('detach was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    detach_validators = [
        _is_volume_bootable,
        core_validators.RuntimeStateValidator('in-use'),
        core_validators.StateValidator(models.Volume.States.OK),
    ]

    @decorators.action(detail=True, methods=['post'])
    def retype(self, request, uuid=None):
        """ Retype detached volume """
        volume = self.get_object()
        serializer = self.get_serializer(volume, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        executors.VolumeRetypeExecutor().execute(volume)
        return response.Response({'status': _('retype was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    retype_validators = [
        core_validators.RuntimeStateValidator('available'),
        core_validators.StateValidator(models.Volume.States.OK),
    ]

    retype_serializer_class = serializers.VolumeRetypeSerializer

    importable_resources_backend_method = 'get_volumes_for_import'
    importable_resources_serializer_class = serializers.VolumeImportableSerializer
    import_resource_serializer_class = serializers.VolumeImportSerializer
コード例 #5
0
class VirtualMachineViewSet(structure_views.BaseResourceViewSet):
    queryset = models.VirtualMachine.objects.all()
    serializer_class = serializers.VirtualMachineSerializer
    delete_executor = executors.VirtualMachineDeleteExecutor

    @decorators.detail_route()
    def rdp(self, request, uuid=None):
        vm = self.get_object()

        try:
            rdp_endpoint = vm.endpoints.get(
                name=models.InstanceEndpoint.Name.RDP)
        except models.InstanceEndpoint.DoesNotExist:
            raise exceptions.NotFound(
                "This virtual machine doesn't run remote desktop")

        response = HttpResponse(content_type='application/x-rdp')
        response[
            'Content-Disposition'] = 'attachment; filename="{}.rdp"'.format(
                vm.name)
        response.write("full address:s:%s.cloudapp.net:%s\n"
                       "prompt for credentials:i:1\n\n" %
                       (vm.service_project_link.cloud_service_name,
                        rdp_endpoint.public_port))

        return response

    rdp_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('running')
    ]

    @decorators.detail_route(methods=['post'])
    def start(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineStartExecutor().execute(virtual_machine)
        return response.Response({'status': _('start was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    start_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('stopped')
    ]
    start_serializer_class = rf_serializers.Serializer

    @decorators.detail_route(methods=['post'])
    def stop(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineStopExecutor().execute(virtual_machine)
        return response.Response({'status': _('stop was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    stop_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('running')
    ]
    stop_serializer_class = rf_serializers.Serializer

    @decorators.detail_route(methods=['post'])
    def restart(self, request, uuid=None):
        virtual_machine = self.get_object()
        executors.VirtualMachineRestartExecutor().execute(virtual_machine)
        return response.Response({'status': _('restart was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    restart_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator('running')
    ]
    restart_serializer_class = rf_serializers.Serializer

    def perform_create(self, serializer):
        instance = serializer.save()
        executors.VirtualMachineCreateExecutor.execute(
            instance,
            backend_image_id=serializer.validated_data['image'].backend_id,
            backend_size_id=serializer.validated_data['size'].pk,
        )
コード例 #6
0
ファイル: views.py プロジェクト: puunukk/waldur-mastermind
class VirtualMachineViewSet(structure_views.BaseResourceViewSet):
    queryset = models.VirtualMachine.objects.all()
    serializer_class = serializers.VirtualMachineSerializer
    filterset_class = filters.VirtualMachineFilter
    pull_executor = executors.VirtualMachinePullExecutor
    create_executor = executors.VirtualMachineCreateExecutor
    delete_executor = executors.VirtualMachineDeleteExecutor
    update_executor = executors.VirtualMachineUpdateExecutor
    update_validators = partial_update_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(models.VirtualMachine.RuntimeStates.POWERED_OFF),
    ]

    destroy_validators = structure_views.BaseResourceViewSet.destroy_validators + [
        core_validators.RuntimeStateValidator(models.VirtualMachine.RuntimeStates.POWERED_OFF)
    ]

    @action(detail=True, methods=['post'])
    def start(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineStartExecutor().execute(instance)
        return Response({'status': _('start was scheduled')}, status=status.HTTP_202_ACCEPTED)

    start_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(
            models.VirtualMachine.RuntimeStates.POWERED_OFF,
            models.VirtualMachine.RuntimeStates.SUSPENDED,
        ),
    ]
    start_serializer_class = rf_serializers.Serializer

    @action(detail=True, methods=['post'])
    def stop(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineStopExecutor().execute(instance)
        return Response({'status': _('stop was scheduled')}, status=status.HTTP_202_ACCEPTED)

    stop_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(
            models.VirtualMachine.RuntimeStates.POWERED_ON,
            models.VirtualMachine.RuntimeStates.SUSPENDED,
        ),
    ]
    stop_serializer_class = rf_serializers.Serializer

    @action(detail=True, methods=['post'])
    def reset(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineResetExecutor().execute(instance)
        return Response({'status': _('reset was scheduled')}, status=status.HTTP_202_ACCEPTED)

    reset_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(
            models.VirtualMachine.RuntimeStates.POWERED_ON,
        ),
    ]
    reset_serializer_class = rf_serializers.Serializer

    @action(detail=True, methods=['post'])
    def suspend(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineSuspendExecutor().execute(instance)
        return Response({'status': _('suspend was scheduled')}, status=status.HTTP_202_ACCEPTED)

    suspend_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(
            models.VirtualMachine.RuntimeStates.POWERED_ON,
        ),
    ]
    suspend_serializer_class = rf_serializers.Serializer

    def vm_tools_are_running(vm):
        if vm.tools_state != models.VirtualMachine.ToolsStates.RUNNING:
            raise rf_serializers.ValidationError('VMware Tools are not running.')

    @action(detail=True, methods=['post'])
    def shutdown_guest(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineShutdownGuestExecutor().execute(instance)
        return Response({'status': _('shutdown was scheduled')}, status=status.HTTP_202_ACCEPTED)

    shutdown_guest_validators = reboot_guest_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(
            models.VirtualMachine.RuntimeStates.POWERED_ON,
        ),
        vm_tools_are_running,
    ]
    shutdown_guest_serializer_class = rf_serializers.Serializer

    @action(detail=True, methods=['post'])
    def reboot_guest(self, request, uuid=None):
        instance = self.get_object()
        executors.VirtualMachineRebootGuestExecutor().execute(instance)
        return Response({'status': _('reboot was scheduled')}, status=status.HTTP_202_ACCEPTED)

    reboot_guest_serializer_class = rf_serializers.Serializer

    @action(detail=True, methods=['post'])
    def create_port(self, request, uuid=None):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        port = serializer.save()

        transaction.on_commit(lambda: executors.PortCreateExecutor().execute(port))
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def check_number_of_ports(vm):
        # Limit of the network adapter per VM is 10 in vSphere 6.7, 6.5 and 6.0
        if vm.port_set.count() >= 10:
            raise rf_serializers.ValidationError('Virtual machine can have at most 10 network adapters.')

    create_port_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        check_number_of_ports,
    ]
    create_port_serializer_class = serializers.PortSerializer

    @action(detail=True, methods=['post'])
    def create_disk(self, request, uuid=None):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        disk = serializer.save()

        transaction.on_commit(lambda: executors.DiskCreateExecutor().execute(disk))
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def validate_total_size(vm):
        max_disk_total = serializers.get_int_or_none(vm.service_settings.options, 'max_disk_total')

        if max_disk_total:
            remaining_quota = max_disk_total - vm.total_disk
            if remaining_quota < 1024:
                raise rf_serializers.ValidationError('Storage quota has been reached.')

    create_disk_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        validate_total_size,
    ]
    create_disk_serializer_class = serializers.DiskSerializer

    @action(detail=True, methods=['get'])
    def console(self, request, uuid=None):
        """
        This endpoint provides access to Virtual Machine Remote Console aka VMRC.
        """
        instance = self.get_object()
        backend = instance.get_backend()
        try:
            url = backend.get_console_url(instance)
        except Exception:
            logger.exception('Unable to get console URL.')
            raise rf_serializers.ValidationError('Unable to get console URL.')
        return Response({'url': url}, status=status.HTTP_200_OK)

    console_validators = [core_validators.StateValidator(models.VirtualMachine.States.OK)]

    @action(detail=True, methods=['get'])
    def web_console(self, request, uuid=None):
        """
        This endpoint provides access to HTML Console aka WMKS.
        """
        instance = self.get_object()
        backend = instance.get_backend()
        try:
            url = backend.get_web_console_url(instance)
        except Exception:
            logger.exception('Unable to get web console URL.')
            raise rf_serializers.ValidationError('Unable to get web console URL.')
        return Response({'url': url}, status=status.HTTP_200_OK)

    web_console_validators = [
        core_validators.StateValidator(models.VirtualMachine.States.OK),
        core_validators.RuntimeStateValidator(models.VirtualMachine.RuntimeStates.POWERED_ON)
    ]
コード例 #7
0
class DropletViewSet(structure_views.ResourceViewSet):
    queryset = models.Droplet.objects.all()
    serializer_class = serializers.DropletSerializer
    filter_class = filters.DropletFilter
    create_executor = executors.DropletCreateExecutor
    update_executor = core_executors.EmptyExecutor
    delete_executor = executors.DropletDeleteExecutor
    destroy_validators = [
        core_validators.StateValidator(models.Droplet.States.OK,
                                       models.Droplet.States.ERRED)
    ]

    def perform_create(self, serializer):
        region = serializer.validated_data['region']
        image = serializer.validated_data['image']
        size = serializer.validated_data['size']
        ssh_key = serializer.validated_data.get('ssh_public_key')

        droplet = serializer.save(cores=size.cores,
                                  ram=size.ram,
                                  disk=size.disk,
                                  transfer=size.transfer)

        # XXX: We do not operate with backend_id`s in views.
        #      View should pass objects to executor.
        self.create_executor.execute(
            droplet,
            async=self.async_executor,
            backend_region_id=region.backend_id,
            backend_image_id=image.backend_id,
            backend_size_id=size.backend_id,
            ssh_key_uuid=ssh_key.uuid.hex if ssh_key else None)

    @decorators.detail_route(methods=['post'])
    def start(self, request, uuid=None):
        instance = self.get_object()
        executors.DropletStartExecutor().execute(instance)
        return response.Response({'status': _('start was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    start_validators = [
        core_validators.StateValidator(models.Droplet.States.OK),
        core_validators.RuntimeStateValidator(
            models.Droplet.RuntimeStates.OFFLINE)
    ]
    start_serializer_class = rf_serializers.Serializer

    @decorators.detail_route(methods=['post'])
    def stop(self, request, uuid=None):
        instance = self.get_object()
        executors.DropletStopExecutor().execute(instance)
        return response.Response({'status': _('stop was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    stop_validators = [
        core_validators.StateValidator(models.Droplet.States.OK),
        core_validators.RuntimeStateValidator(
            models.Droplet.RuntimeStates.ONLINE)
    ]
    stop_serializer_class = rf_serializers.Serializer

    @decorators.detail_route(methods=['post'])
    def restart(self, request, uuid=None):
        instance = self.get_object()
        executors.DropletRestartExecutor().execute(instance)
        return response.Response({'status': _('restart was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    restart_validators = [
        core_validators.StateValidator(models.Droplet.States.OK),
        core_validators.RuntimeStateValidator(
            models.Droplet.RuntimeStates.ONLINE)
    ]
    restart_serializer_class = rf_serializers.Serializer

    @decorators.detail_route(methods=['post'])
    def resize(self, request, uuid=None):
        """
        To resize droplet, submit a **POST** request to the instance URL, specifying URI of a target size.

        Pass {'disk': true} along with target size in order to perform permanent resizing,
        which allows you to resize your disk space as well as CPU and RAM.
        After increasing the disk size, you will not be able to decrease it.

        Pass {'disk': false} along with target size in order to perform flexible resizing,
        which only upgrades your CPU and RAM. This option is reversible.

        Note that instance must be OFFLINE. Example of a valid request:

        .. code-block:: http

            POST /api/digitalocean-droplets/6c9b01c251c24174a6691a1f894fae31/resize/ HTTP/1.1
            Content-Type: application/json
            Accept: application/json
            Authorization: Token c84d653b9ec92c6cbac41c706593e66f567a7fa4
            Host: example.com

            {
                "size": "http://example.com/api/digitalocean-sizes/1ee385bc043249498cfeb8c7e3e079f0/"
            }
        """
        droplet = self.get_object()
        serializer = self.get_serializer(droplet, data=request.data)
        serializer.is_valid(raise_exception=True)

        size = serializer.validated_data['size']
        disk = serializer.validated_data['disk']

        executors.DropletResizeExecutor.execute(droplet,
                                                disk=disk,
                                                size=size,
                                                updated_fields=None,
                                                async=self.async_executor)

        message = _('Droplet {droplet_name} has been scheduled to %s resize.') % \
            (disk and _('permanent') or _('flexible'))
        log.event_logger.droplet_resize.info(
            message,
            event_type='droplet_resize_scheduled',
            event_context={
                'droplet': droplet,
                'size': size
            })

        cores_increment = size.cores - droplet.cores
        ram_increment = size.ram - droplet.ram
        disk_increment = None

        droplet.cores = size.cores
        droplet.ram = size.ram

        if disk:
            disk_increment = size.disk - droplet.disk
            droplet.disk = size.disk

        droplet.save()

        spl = droplet.service_project_link

        if disk_increment:
            spl.add_quota_usage(spl.Quotas.storage,
                                disk_increment,
                                validate=True)
        spl.add_quota_usage(spl.Quotas.ram, ram_increment, validate=True)
        spl.add_quota_usage(spl.Quotas.vcpu, cores_increment, validate=True)

        return response.Response({'detail': _('resizing was scheduled')},
                                 status=status.HTTP_202_ACCEPTED)

    resize_validators = [
        core_validators.StateValidator(models.Droplet.States.OK)
    ]
    resize_serializer_class = serializers.DropletResizeSerializer
コード例 #8
0
class InstanceViewSet(structure_views.ResourceViewSet):
    queryset = models.Instance.objects.all()
    filterset_class = filters.InstanceFilter
    serializer_class = serializers.InstanceSerializer
    create_executor = executors.InstanceCreateExecutor

    delete_executor = executors.InstanceDeleteExecutor
    destroy_validators = [core_validators.StateValidator(models.Instance.States.OK, models.Instance.States.ERRED)]

    def perform_create(self, serializer):
        instance = serializer.save()
        volume = instance.volume_set.first()

        self.create_executor.execute(
            instance,
            image=serializer.validated_data.get('image'),
            size=serializer.validated_data.get('size'),
            ssh_key=serializer.validated_data.get('ssh_public_key'),
            volume=volume
        )

    @decorators.action(detail=True, methods=['post'])
    def start(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceStartExecutor().execute(instance)
        return response.Response({'status': _('start was scheduled')}, status=status.HTTP_202_ACCEPTED)

    start_validators = [core_validators.StateValidator(models.Instance.States.OK),
                        core_validators.RuntimeStateValidator('stopped')]
    start_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def stop(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceStopExecutor().execute(instance)
        return response.Response({'status': _('stop was scheduled')}, status=status.HTTP_202_ACCEPTED)

    stop_validators = [core_validators.StateValidator(models.Instance.States.OK),
                       core_validators.RuntimeStateValidator('running')]
    stop_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def restart(self, request, uuid=None):
        instance = self.get_object()
        executors.InstanceRestartExecutor().execute(instance)
        return response.Response({'status': _('restart was scheduled')}, status=status.HTTP_202_ACCEPTED)

    restart_validators = [core_validators.StateValidator(models.Instance.States.OK),
                          core_validators.RuntimeStateValidator('running')]
    restart_serializer_class = rf_serializers.Serializer

    @decorators.action(detail=True, methods=['post'])
    def resize(self, request, uuid=None):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        new_size = serializer.validated_data.get('size')
        executors.InstanceResizeExecutor().execute(instance, size=new_size)
        return response.Response({'status': _('resize was scheduled')}, status=status.HTTP_202_ACCEPTED)

    resize_validators = [core_validators.StateValidator(models.Instance.States.OK)]
    resize_serializer_class = serializers.InstanceResizeSerializer