コード例 #1
0
ファイル: test_exceptions.py プロジェクト: cloudbase/maas
 def test_MAASAPIException_produces_http_response(self):
     error = factory.getRandomString()
     exception = MAASAPIBadRequest(error)
     response = exception.make_http_response()
     self.assertEqual(
         (httplib.BAD_REQUEST, error),
         (response.status_code, response.content))
コード例 #2
0
def store_node_power_parameters(node, request):
    """Store power parameters in request.

    The parameters should be JSON, passed with key `power_parameters`.
    """
    power_type = request.POST.get("power_type", None)
    if power_type is None:
        return

    power_types = get_driver_types(ignore_errors=True)
    if len(power_types) == 0:
        raise ClusterUnavailable(
            "No rack controllers connected to validate the power_type.")

    if power_type in power_types or power_type == UNKNOWN_POWER_TYPE:
        node.power_type = power_type
    else:
        raise MAASAPIBadRequest("Bad power_type '%s'" % power_type)

    power_parameters = request.POST.get("power_parameters", None)
    if power_parameters and not power_parameters.isspace():
        try:
            node.power_parameters = json.loads(power_parameters)
        except ValueError:
            raise MAASAPIBadRequest("Failed to parse JSON power_parameters")

    node.save()
コード例 #3
0
 def unformat(self, request, system_id, device_id, id):
     """Unformat a partition."""
     device = BlockDevice.objects.get_block_device_or_404(
         system_id, device_id, request.user, NODE_PERMISSION.EDIT)
     partition_table = get_object_or_404(PartitionTable,
                                         block_device=device)
     partition = get_partition_by_id_or_name__or_404(id, partition_table)
     node = device.get_node()
     raise_error_for_invalid_state_on_allocated_operations(
         node, request.user, "unformat")
     filesystem = partition.get_effective_filesystem()
     if filesystem is None:
         raise MAASAPIBadRequest("Partition is not formatted.")
     if filesystem.is_mounted:
         raise MAASAPIBadRequest(
             "Filesystem is mounted and cannot be unformatted. Unmount the "
             "filesystem before unformatting the partition.")
     if filesystem.filesystem_group is not None:
         nice_name = filesystem.filesystem_group.get_nice_name()
         raise MAASAPIBadRequest(
             "Filesystem is part of a %s, and cannot be "
             "unformatted. Remove partition from %s "
             "before unformatting the partition." % (nice_name, nice_name))
     filesystem.delete()
     return partition
コード例 #4
0
    def unmount(self, request, system_id, device_id, id):
        """Unmount the filesystem on partition.

        Returns 400 if the partition is not formatted or not currently \
            mounted.
        Returns 403 when the user doesn't have the ability to unmount the \
            partition.
        Returns 404 if the node, block device, or partition is not found.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, device_id, request.user, NODE_PERMISSION.EDIT)
        partition_table = get_object_or_404(PartitionTable,
                                            block_device=device)
        partition = get_partition_by_id_or_name__or_404(id, partition_table)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unmount")
        filesystem = partition.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Partition is not formatted.")
        if not filesystem.is_mounted:
            raise MAASAPIBadRequest("Filesystem is already unmounted.")
        filesystem.mount_point = None
        filesystem.mount_options = None
        filesystem.save()
        return partition
コード例 #5
0
    def import_ssh_keys(self, request):
        """Import the requesting user's SSH keys.

        Import SSH keys for a given protocol and authorization ID in
        protocol:auth_id format.
        """
        keysource = request.data.get('keysource', None)
        if keysource is not None:
            if ':' in keysource:
                protocol, auth_id = keysource.split(':', 1)
            else:
                protocol = KEYS_PROTOCOL_TYPE.LP
                auth_id = keysource
            try:
                keysource = KeySource.objects.save_keys_for_user(
                    user=request.user, protocol=protocol, auth_id=auth_id)
                create_audit_event(EVENT_TYPES.AUTHORISATION,
                                   ENDPOINT.API,
                                   request,
                                   None,
                                   description="Imported SSH keys.")
                return keysource
            except (ImportSSHKeysError, RequestException) as e:
                raise MAASAPIBadRequest(e.args[0])
        else:
            raise MAASAPIBadRequest(
                "Importing SSH keys failed. "
                "Input needs to be in protocol:auth_id or auth_id format.")
コード例 #6
0
    def unformat(self, request, system_id, id):
        """Unformat block device with filesystem.

        Returns 400 if the block device is not formatted, currently mounted, \
            or part of a filesystem group.
        Returns 403 when the user doesn't have the ability to unformat the \
            block device.
        Returns 404 if the machine or block device is not found.
        Returns 409 if the machine is not Ready or Allocated.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NODE_PERMISSION.EDIT)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unformat")
        filesystem = device.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Block device is not formatted.")
        if filesystem.is_mounted:
            raise MAASAPIBadRequest(
                "Filesystem is mounted and cannot be unformatted. Unmount the "
                "filesystem before unformatting the block device.")
        if filesystem.filesystem_group is not None:
            nice_name = filesystem.filesystem_group.get_nice_name()
            raise MAASAPIBadRequest(
                "Filesystem is part of a %s, and cannot be "
                "unformatted. Remove block device from %s "
                "before unformatting the block device." %
                (nice_name, nice_name))
        filesystem.delete()
        return device
コード例 #7
0
    def create(self, request):
        """Add a new file to the file storage.

        :param filename: The file name to use in the storage.
        :type filename: string
        :param file: Actual file data with content type
            application/octet-stream

        Returns 400 if any of these conditions apply:
         - The filename is missing from the parameters
         - The file data is missing
         - More than one file is supplied
        """
        filename = request.data.get("filename", None)
        if not filename:
            raise MAASAPIBadRequest("Filename not supplied")
        files = request.FILES
        if not files:
            raise MAASAPIBadRequest("File not supplied")
        if len(files) != 1:
            raise MAASAPIBadRequest("Exactly one file must be supplied")
        uploaded_file = files['file']

        # As per the comment in FileStorage, this ought to deal in
        # chunks instead of reading the file into memory, but large
        # files are not expected.
        FileStorage.objects.save_file(filename, uploaded_file, request.user)
        return HttpResponse('', status=int(http.client.CREATED))
コード例 #8
0
ファイル: files.py プロジェクト: shawnallen85/maas
    def create(self, request):
        """@description-title Add a new file
        @description Add a new file to the file storage.

        @param (string) "filename" [required=true] The file name to use in
        storage.

        @param (string) "file" [required=true] File data. Content type must be
        ``application/octet-stream``.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing the new file.
        @success-example "success-json" [exkey=files-placeholder] placeholder
        text

        @error (http-status-code) "400" 400
        @error (content) "arg-prob" The filename is missing, the file data is
        missing or more than one file is supplied.
        """
        filename = request.data.get("filename", None)
        if not filename:
            raise MAASAPIBadRequest("Filename not supplied")
        files = request.FILES
        if not files:
            raise MAASAPIBadRequest("File not supplied")
        if len(files) != 1:
            raise MAASAPIBadRequest("Exactly one file must be supplied")
        uploaded_file = files["file"]

        # As per the comment in FileStorage, this ought to deal in
        # chunks instead of reading the file into memory, but large
        # files are not expected.
        FileStorage.objects.save_file(filename, uploaded_file, request.user)
        return HttpResponse("", status=int(http.client.CREATED))
コード例 #9
0
    def create(self, request):
        """Create a dnsresourcerecord.

        :param fqdn: Hostname (with domain) for the dnsresource.  Either fqdn
            or (name, domain) must be specified.  Fqdn is ignored if either
            name or domain is given.
        :param name: Hostname (without domain)
        :param domain: Domain (name or id)
        :param rrtype: resource type to create
        :param rrdata: resource data (everything to the right of
            resource type.)
        """
        data = request.data.copy()
        domain = None
        fqdn = data.get('fqdn', None)
        name = data.get('name', None)
        domainname = data.get('domain', None)
        rrtype = data.get('rrtype', None)
        rrdata = data.get('rrdata', None)
        if rrtype is None:
            raise MAASAPIBadRequest("rrtype must be provided.")
        if rrdata is None:
            raise MAASAPIBadRequest("rrdata must be provided.")
        # If the user gave us fqdn and did not give us name/domain, expand
        # fqdn.
        if domainname is None and name is None and fqdn is not None:
            # We need a type for resource separation.  If the user didn't give
            # us a rrtype, then assume it's an address of some sort.
            rrtype = data.get('rrtype', None)
            (name, domainname) = separate_fqdn(fqdn, rrtype)
            data['domain'] = domainname
            data['name'] = name
        # If the domain is a name, make it an id.
        if domainname is not None:
            if domainname.isdigit():
                domain = Domain.objects.get_domain_or_404(
                    domainname, user=request.user, perm=NODE_PERMISSION.VIEW)
            else:
                domain = Domain.objects.get_domain_or_404(
                    "name:%s" % domainname, user=request.user,
                    perm=NODE_PERMISSION.VIEW)
            data['domain'] = domain.id
        if domain is None or name is None:
            raise MAASAPIValidationError(
                "Either name and domain (or fqdn) must be specified")
        # Do we already have a DNSResource for this fqdn?
        dnsrr = DNSResource.objects.filter(name=name, domain__id=domain.id)
        if not dnsrr.exists():
            form = DNSResourceForm(data=data, request=request)
            if form.is_valid():
                form.save()
            else:
                raise MAASAPIValidationError(form.errors)
            dnsrr = DNSResource.objects.filter(name=name, domain__id=domain.id)
        data['dnsresource'] = dnsrr
        form = DNSDataForm(data=data)
        if form.is_valid():
            return form.save()
        else:
            raise MAASAPIValidationError(form.errors)
コード例 #10
0
def store_node_power_parameters(node, request):
    """Store power parameters in request.

    The parameters should be JSON, passed with key `power_parameters`.
    """
    power_type = request.POST.get("power_type", None)
    if power_type is None:
        return
    # Don't overwrite redfish power type with ipmi.
    if node.power_type == "redfish":
        power_type = node.power_type

    power_types = list(get_driver_types(ignore_errors=True))
    if not power_types:
        raise ClusterUnavailable(
            "No rack controllers connected to validate the power_type.")

    if power_type not in power_types + [UNKNOWN_POWER_TYPE]:
        raise MAASAPIBadRequest("Bad power_type '%s'" % power_type)

    power_parameters = request.POST.get("power_parameters", None)
    if power_parameters:
        try:
            power_parameters = json.loads(power_parameters)
        except ValueError:
            raise MAASAPIBadRequest("Failed to parse JSON power_parameters")
    else:
        power_parameters = node.power_parameters
    if power_type == "redfish":
        power_parameters = {
            **node.instance_power_parameters,
            **power_parameters,
        }
    node.set_power_config(power_type, power_parameters)
    node.save()
コード例 #11
0
ファイル: test_exceptions.py プロジェクト: zhangrb/maas
 def test_MAASAPIException_produces_http_response(self):
     error = factory.make_string()
     exception = MAASAPIBadRequest(error)
     response = exception.make_http_response()
     self.assertEqual(
         (http.client.BAD_REQUEST, error),
         (response.status_code,
          response.content.decode(settings.DEFAULT_CHARSET)))
コード例 #12
0
ファイル: blockdevices.py プロジェクト: th3architect/maas
    def unformat(self, request, system_id, id):
        """@description-title Unformat a block device
        @description Unformat a previously formatted block device.

        @param (string) "{system_id}" [required=true] The machine system_id.
        @param (string) "{id}" [required=true] The block device's id.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing
        the updated block device.
        @success-example "success-json" [exkey=block-devs-unformat] placeholder
        text

        @error (http-status-code) "400" 400
        @error (content) "problem" The block device is not formatted, currently
        mounted, or part of a filesystem group.

        @error (http-status-code) "403" 403
        @error (content) "no-perms" The user does not have permissions to
        unformat the block device.

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine or block device is
        not found.
        @error-example "not-found"
            Not Found

        @error (http-status-code) "409" 409
        @error (content) "not-ready" The requested machine is not ready.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NodePermission.edit)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unformat")
        filesystem = device.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Block device is not formatted.")
        if filesystem.is_mounted:
            raise MAASAPIBadRequest(
                "Filesystem is mounted and cannot be unformatted. Unmount the "
                "filesystem before unformatting the block device.")
        if filesystem.filesystem_group is not None:
            nice_name = filesystem.filesystem_group.get_nice_name()
            raise MAASAPIBadRequest(
                "Filesystem is part of a %s, and cannot be "
                "unformatted. Remove block device from %s "
                "before unformatting the block device." %
                (nice_name, nice_name))
        filesystem.delete()
        return device
コード例 #13
0
ファイル: ssh_keys.py プロジェクト: ocni-dtu/maas
    def import_ssh_keys(self, request):
        """@description-title Import SSH keys
        @description Import the requesting user's SSH keys for a given protocol
        and authorization ID in protocol:auth_id format.

        @param (string) "keysource" [required=true,formatting=true] The source
        of the keys to import should be provided in the request payload as form
        data:

        E.g.

            source:user

        - ``source``: lp (Launchpad), gh (GitHub)
        - ``user``: User login

        @success (http-status-code) "200" 200
        @success (json) "success-json" A JSON object containing a list of
        imported keys.
        @success-example "success-json" [exkey=ssh-keys-import] placeholder
        text
        """
        keysource = request.data.get("keysource", None)
        if keysource is not None:
            if ":" in keysource:
                protocol, auth_id = keysource.split(":", 1)
            else:
                protocol = KEYS_PROTOCOL_TYPE.LP
                auth_id = keysource
            try:
                keysource = KeySource.objects.save_keys_for_user(
                    user=request.user, protocol=protocol, auth_id=auth_id
                )
                create_audit_event(
                    EVENT_TYPES.AUTHORISATION,
                    ENDPOINT.API,
                    request,
                    None,
                    description="Imported SSH keys.",
                )
                return keysource
            except (ImportSSHKeysError, RequestException) as e:
                raise MAASAPIBadRequest(e.args[0])
        else:
            raise MAASAPIBadRequest(
                "Importing SSH keys failed. "
                "Input needs to be in protocol:auth_id or auth_id format."
            )
コード例 #14
0
ファイル: spaces.py プロジェクト: ocni-dtu/maas
    def update(self, request, id):
        """@description-title Update space
        @description Updates a space with the given ID.

        @param (int) "{id}" [required=true] The space's ID.
        @param (string) "name" [required=true] The name of the new space.
        @param (string) "description" [required=false] A description of the new
        space.

        @success (http-status-code) "200" 200
        @success (json) "success-json" A JSON object containing information
        about the updated space.
        @success-example "success-json" [exkey=update-a-space] placeholder text

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested space is not found.
        @error-example "not-found"
            Not Found
        """
        if id == "-1" or id == Space.UNDEFINED:
            raise MAASAPIBadRequest("Space cannot be modified: %s" %
                                    Space.UNDEFINED)
        space = Space.objects.get_space_or_404(id, request.user,
                                               NodePermission.admin)
        form = SpaceForm(instance=space, data=request.data)
        if form.is_valid():
            return form.save()
        else:
            raise MAASAPIValidationError(form.errors)
コード例 #15
0
    def read(self, request):
        """@description-title List boot resources
        @description List all boot resources

        @param (string) "type" [required=false] Type of boot resources to list.
        If not provided, returns all types.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing a list of boot
        resource objects.
        @success-example "success-json" [exkey=boot-res-read] placeholder text
        """
        if 'type' not in request.GET:
            rtype = 'all'
        else:
            rtype = request.GET['type']

        if rtype == 'all':
            resources = BootResource.objects.all().order_by(
                'rtype', 'name', 'architecture')
        elif rtype in TYPE_MAPPING:
            resources = BootResource.objects.filter(
                rtype=TYPE_MAPPING[rtype]).order_by('name', 'architecture')
        else:
            raise MAASAPIBadRequest(
                "'%s' is not a valid boot resource type. Available "
                "types: %s" % (rtype, list(TYPE_MAPPING.keys())))

        resource_list = [
            boot_resource_to_dict(resource) for resource in resources
        ]
        stream = json_object(resource_list, request)
        return HttpResponse(stream,
                            content_type='application/json; charset=utf-8',
                            status=int(http.client.OK))
コード例 #16
0
ファイル: bcache_cacheset.py プロジェクト: zhangrb/maas
    def delete(self, request, system_id, id):
        """@description-title Delete a bcache set
        @description Delete bcache cache set on a machine.

        @param (string) "{system_id}" [required=true] A machine system_id.
        @param (string) "{id}" [required=true] A cache_set_id.

        @success (http-status-code) "server-success" 204

        @error (http-status-code) "400" 400
        @error (content) "not-ready" The cache set is in use.

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine is not found.
        @error-example "not-found"
            Not Found

        @error (http-status-code) "409" 409
        @error (content) "not-ready" The requested machine is not ready.
        """
        cache_set = CacheSet.objects.get_cache_set_or_404(
            system_id, id, request.user, NodePermission.admin)
        node = cache_set.get_node()
        if node.status != NODE_STATUS.READY:
            raise NodeStateViolation(
                "Cannot delete cache set because the machine is not Ready.")
        if cache_set.filesystemgroup_set.exists():
            raise MAASAPIBadRequest(
                "Cannot delete cache set; it's currently in use.")
        else:
            cache_set.delete()
            create_audit_event(EVENT_TYPES.NODE, ENDPOINT.API, request,
                               system_id, "Deleted bcache cache set.")
            return rc.DELETED
コード例 #17
0
ファイル: partitions.py プロジェクト: zhangrb/maas
    def unmount(self, request, system_id, device_id, id):
        """@description-title Unmount a filesystem
        @description Unmount a filesystem on machine system_id, device
        device_id and partition id.

        @param (string) "{system_id}" [required=true] The system_id.
        @param (int) "{device_id}" [required=true] The block device_id.
        @param (int) "{id}" [required=true] The partition id.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing the updated
        partition object.
        @success-example "success-json" [exkey=partitions-unmount] placeholder
        text

        @error (http-status-code) "400" 400
        @error (content) "part-prob" The partition is not formatted or not
        currently mounted.

        @error (http-status-code) "403" 403
        @error (content) "no-perms" The user does not have permissions to
        unmount the filesystem.

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine, device or partition
        is not found.
        @error-example "not-found"
            Not Found
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, device_id, request.user, NodePermission.edit)
        partition_table = get_object_or_404(PartitionTable,
                                            block_device=device)
        partition = get_partition_by_id_or_name__or_404(id, partition_table)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unmount")
        filesystem = partition.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Partition is not formatted.")
        if not filesystem.is_mounted:
            raise MAASAPIBadRequest("Filesystem is already unmounted.")
        filesystem.mount_point = None
        filesystem.mount_options = None
        filesystem.save()
        return partition
コード例 #18
0
ファイル: support.py プロジェクト: Kryndex/maas
 def dispatch(self, request, *args, **kwargs):
     op = request.GET.get("op") or request.POST.get("op")
     signature = request.method.upper(), op
     function = self.exports.get(signature)
     if function is None:
         raise MAASAPIBadRequest("Unrecognised signature: method=%s op=%s" %
                                 signature)
     else:
         return function(self, request, *args, **kwargs)
コード例 #19
0
ファイル: boot_resources.py プロジェクト: th3architect/maas
    def update(self, request, id, file_id):
        """Upload piece of boot resource file."""
        resource = get_object_or_404(BootResource, id=id)
        rfile = get_object_or_404(BootResourceFile, id=file_id)
        size = int(request.META.get("CONTENT_LENGTH", "0"))
        data = request.body
        if size == 0:
            raise MAASAPIBadRequest("Missing data.")
        if size != len(data):
            raise MAASAPIBadRequest(
                "Content-Length doesn't equal size of recieved data."
            )
        if resource.rtype not in ALLOW_UPLOAD_RTYPES:
            raise MAASAPIForbidden(
                "Cannot upload to a resource of type: %s. " % resource.rtype
            )
        if rfile.largefile.complete:
            raise MAASAPIBadRequest("Cannot upload to a complete file.")

        with rfile.largefile.content.open("wb") as stream:
            stream.seek(0, os.SEEK_END)

            # Check that the uploading data will not make the file larger
            # than expected.
            current_size = stream.tell()
            if current_size + size > rfile.largefile.total_size:
                raise MAASAPIBadRequest("Too much data recieved.")

            stream.write(data)
            rfile.largefile.size = current_size + size
            rfile.largefile.save()

        if rfile.largefile.complete:
            if not rfile.largefile.valid:
                raise MAASAPIBadRequest(
                    "Saved content does not match given SHA256 value."
                )
            # Avoid circular import.
            from maasserver.clusterrpc.boot_images import (
                RackControllersImporter,
            )

            post_commit_do(RackControllersImporter.schedule)
        return rc.ALL_OK
コード例 #20
0
ファイル: partitions.py プロジェクト: zhangrb/maas
    def unformat(self, request, system_id, device_id, id):
        """@description-title Unformat a partition
        @description Unformat the partition on machine system_id and device
        device_id with the given partition id.

        @param (string) "{system_id}" [required=true] The system_id.
        @param (int) "{device_id}" [required=true] The block device_id.
        @param (int) "{id}" [required=true] The partition id.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing the updated
        partition object.
        @success-example "success-json" [exkey=partitions-unformat]
        placeholder text

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine, device or partition
        is not found.
        @error-example "not-found"
            Not Found
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, device_id, request.user, NodePermission.edit)
        partition_table = get_object_or_404(PartitionTable,
                                            block_device=device)
        partition = get_partition_by_id_or_name__or_404(id, partition_table)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unformat")
        filesystem = partition.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Partition is not formatted.")
        if filesystem.is_mounted:
            raise MAASAPIBadRequest(
                "Filesystem is mounted and cannot be unformatted. Unmount the "
                "filesystem before unformatting the partition.")
        if filesystem.filesystem_group is not None:
            nice_name = filesystem.filesystem_group.get_nice_name()
            raise MAASAPIBadRequest(
                "Filesystem is part of a %s, and cannot be "
                "unformatted. Remove partition from %s "
                "before unformatting the partition." % (nice_name, nice_name))
        filesystem.delete()
        return partition
コード例 #21
0
ファイル: blockdevices.py プロジェクト: th3architect/maas
    def unmount(self, request, system_id, id):
        """@description-title Unmount a filesystem
        @description Unmount the filesystem on block device.

        @param (string) "{system_id}" [required=true] The machine system_id.
        @param (string) "{id}" [required=true] The block device's id.

        @success (http-status-code) "server-success" 200
        @success (json) "success-json" A JSON object containing the updated
        block device.
        @success-example "success-json" [exkey=block-devs-unmount] placeholder
        text

        @error (http-status-code) "400" 400
        @error (content) "problem" The block device is not formatted or
        currently mounted.

        @error (http-status-code) "403" 403
        @error (content) "no-perms" The user does not have permissions to mount
        the filesystem.

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine or block device is
        not found.
        @error-example "not-found"
            Not Found

        @error (http-status-code) "409" 409
        @error (content) "not-ready" The requested machine is not ready.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NodePermission.edit)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unmount")
        filesystem = device.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Block device is not formatted.")
        if not filesystem.is_mounted:
            raise MAASAPIBadRequest("Filesystem is already unmounted.")
        filesystem.mount_point = None
        filesystem.mount_options = None
        filesystem.save()
        return device
コード例 #22
0
ファイル: api.py プロジェクト: cloudbase/maas
    def signal(self, request, version=None, mac=None):
        """Signal commissioning status.

        A commissioning node can call this to report progress of the
        commissioning process to the metadata server.

        Calling this from a node that is not Commissioning, Ready, or
        Failed Tests is an error.  Signaling completion more than once is not
        an error; all but the first successful call are ignored.

        :param status: A commissioning status code.  This can be "OK" (to
            signal that commissioning has completed successfully), or "FAILED"
            (to signal failure), or "WORKING" (for progress reports).
        :param script_result: If this call uploads files, this parameter must
            be provided and will be stored as the return value for the script
            which produced these files.
        :param error: An optional error string.  If given, this will be stored
            (overwriting any previous error string), and displayed in the MAAS
            UI.  If not given, any previous error string will be cleared.
        """
        node = get_queried_node(request, for_mac=mac)
        status = get_mandatory_param(request.POST, 'status')
        if node.status not in self.signalable_states:
            raise NodeStateViolation(
                "Node wasn't commissioning (status is %s)"
                % NODE_STATUS_CHOICES_DICT[node.status])

        if status not in self.signaling_statuses:
            raise MAASAPIBadRequest(
                "Unknown commissioning status: '%s'" % status)

        if node.status != NODE_STATUS.COMMISSIONING:
            # Already registered.  Nothing to be done.
            return rc.ALL_OK

        self._store_commissioning_results(node, request)
        store_node_power_parameters(node, request)

        target_status = self.signaling_statuses.get(status)
        if target_status in (None, node.status):
            # No status change.  Nothing to be done.
            return rc.ALL_OK

        node.status = target_status
        # When moving to a terminal state, remove the allocation.
        node.owner = None
        node.error = request.POST.get('error', '')

        # When moving to a successful terminal state, recalculate tags.
        populate_tags_for_single_node(Tag.objects.all(), node)

        # Done.
        node.save()
        return rc.ALL_OK
コード例 #23
0
ファイル: spaces.py プロジェクト: jamal-fuma/maas
    def delete(self, request, id):
        """Delete space.

        Returns 404 if the space is not found.
        """
        if id == "-1" or id == Space.UNDEFINED:
            raise MAASAPIBadRequest("Space cannot be deleted: %s" %
                                    Space.UNDEFINED)
        space = Space.objects.get_space_or_404(id, request.user,
                                               NodePermission.admin)
        space.delete()
        return rc.DELETED
コード例 #24
0
    def import_ssh_keys(self, request):
        """Import the requesting user's SSH keys.

        Import SSH keys for a given protocol and authorization ID in
        protocol:auth_id format.
        """
        keysource = request.data.get('keysource', None)
        if keysource is not None:
            if ':' in keysource:
                protocol, auth_id = keysource.split(':', 1)
            else:
                protocol = KEYS_PROTOCOL_TYPE.LP
                auth_id = keysource
            try:
                return KeySource.objects.save_keys_for_user(user=request.user,
                                                            protocol=protocol,
                                                            auth_id=auth_id)
            except (ImportSSHKeysError, RequestException) as e:
                raise MAASAPIBadRequest(e.args[0])
        else:
            raise MAASAPIBadRequest(
                "Importing SSH keys failed. "
                "Input needs to be in protocol:auth_id or auth_id format.")
コード例 #25
0
    def unmount(self, request, system_id, id):
        """Unmount the filesystem on block device.

        Returns 400 if the block device is not formatted or not currently \
            mounted.
        Returns 403 when the user doesn't have the ability to unmount the \
            block device.
        Returns 404 if the machine or block device is not found.
        Returns 409 if the machine is not Ready or Allocated.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NODE_PERMISSION.EDIT)
        node = device.get_node()
        raise_error_for_invalid_state_on_allocated_operations(
            node, request.user, "unmount")
        filesystem = device.get_effective_filesystem()
        if filesystem is None:
            raise MAASAPIBadRequest("Block device is not formatted.")
        if not filesystem.is_mounted:
            raise MAASAPIBadRequest("Filesystem is already unmounted.")
        filesystem.mount_point = None
        filesystem.mount_options = None
        filesystem.save()
        return device
コード例 #26
0
ファイル: spaces.py プロジェクト: jamal-fuma/maas
    def update(self, request, id):
        """Update space.

        :param name: Name of the space.
        :param description: Description of the space.

        Returns 404 if the space is not found.
        """
        if id == "-1" or id == Space.UNDEFINED:
            raise MAASAPIBadRequest("Space cannot be modified: %s" %
                                    Space.UNDEFINED)
        space = Space.objects.get_space_or_404(id, request.user,
                                               NodePermission.admin)
        form = SpaceForm(instance=space, data=request.data)
        if form.is_valid():
            return form.save()
        else:
            raise MAASAPIValidationError(form.errors)
コード例 #27
0
    def delete(self, request, system_id, id):
        """Delete cache set on a machine.

        Returns 400 if the cache set is in use.
        Returns 404 if the machine or cache set is not found.
        Returns 409 if the machine is not Ready.
        """
        cache_set = CacheSet.objects.get_cache_set_or_404(
            system_id, id, request.user, NODE_PERMISSION.ADMIN)
        node = cache_set.get_node()
        if node.status != NODE_STATUS.READY:
            raise NodeStateViolation(
                "Cannot delete cache set because the machine is not Ready.")
        if cache_set.filesystemgroup_set.exists():
            raise MAASAPIBadRequest(
                "Cannot delete cache set; it's currently in use.")
        else:
            cache_set.delete()
            return rc.DELETED
コード例 #28
0
ファイル: spaces.py プロジェクト: ocni-dtu/maas
    def delete(self, request, id):
        """@description-title Delete a space
        @description Deletes a space with the given ID.

        @param (int) "{id}" [required=true] The space's ID.

        @success (http-status-code) "204" 204

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested space is not found.
        @error-example "not-found"
            Not Found
        """
        if id == "-1" or id == Space.UNDEFINED:
            raise MAASAPIBadRequest("Space cannot be deleted: %s" %
                                    Space.UNDEFINED)
        space = Space.objects.get_space_or_404(id, request.user,
                                               NodePermission.admin)
        space.delete()
        return rc.DELETED
コード例 #29
0
    def set_boot_disk(self, request, system_id, id):
        """Set this block device as the boot disk for the machine.

        Returns 400 if the block device is a virtual block device.
        Returns 404 if the machine or block device is not found.
        Returns 403 if the user is not allowed to update the block device.
        Returns 409 if the machine is not Ready or Allocated.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NODE_PERMISSION.ADMIN)
        node = device.get_node()
        if node.status != NODE_STATUS.READY:
            raise NodeStateViolation(
                "Cannot set as boot disk because the machine is not Ready.")
        if not isinstance(device, PhysicalBlockDevice):
            raise MAASAPIBadRequest(
                "Cannot set a %s block device as the boot disk." % device.type)
        device.node.boot_disk = device
        device.node.save()
        return rc.ALL_OK
コード例 #30
0
ファイル: bcache_cacheset.py プロジェクト: jamal-fuma/maas
    def delete(self, request, system_id, id):
        """Delete bcache cache set on a machine.

        Returns 400 if the cache set is in use.
        Returns 404 if the machine or cache set is not found.
        Returns 409 if the machine is not Ready.
        """
        cache_set = CacheSet.objects.get_cache_set_or_404(
            system_id, id, request.user, NodePermission.admin)
        node = cache_set.get_node()
        if node.status != NODE_STATUS.READY:
            raise NodeStateViolation(
                "Cannot delete cache set because the machine is not Ready.")
        if cache_set.filesystemgroup_set.exists():
            raise MAASAPIBadRequest(
                "Cannot delete cache set; it's currently in use.")
        else:
            cache_set.delete()
            create_audit_event(EVENT_TYPES.NODE, ENDPOINT.API, request,
                               system_id, "Deleted bcache cache set.")
            return rc.DELETED
コード例 #31
0
ファイル: blockdevices.py プロジェクト: th3architect/maas
    def set_boot_disk(self, request, system_id, id):
        """@description-title Set boot disk
        @description Set a block device as the boot disk for the machine.

        @param (string) "{system_id}" [required=true] The machine system_id.
        @param (string) "{id}" [required=true] The block device's id.

        @success (http-status-code) "server-success" 200
        @success (content) "success-content" Boot disk set.
        @success-example "success-content"
            OK

        @error (http-status-code) "400" 400
        @error (content) "problem" The block device is a virtual block device.

        @error (http-status-code) "403" 403
        @error (content) "no-perms" The user does not have permissions to set
        the boot disk.

        @error (http-status-code) "404" 404
        @error (content) "not-found" The requested machine or block device is
        not found.
        @error-example "not-found"
            Not Found

        @error (http-status-code) "409" 409
        @error (content) "not-ready" The requested machine is not ready.
        """
        device = BlockDevice.objects.get_block_device_or_404(
            system_id, id, request.user, NodePermission.admin)
        node = device.get_node()
        if node.status != NODE_STATUS.READY:
            raise NodeStateViolation(
                "Cannot set as boot disk because the machine is not Ready.")
        if not isinstance(device, PhysicalBlockDevice):
            raise MAASAPIBadRequest(
                "Cannot set a %s block device as the boot disk." % device.type)
        device.node.boot_disk = device
        device.node.save()
        return rc.ALL_OK