def create(self, request): """Create a Pod. :param type: Type of pod to create (rsd, virsh) (required). :type name: unicode :param power_address: Address for power control of the pod (required). :type power_address: unicode :param power_user: User for power control of the pod (required for rsd). :type power_user: unicode :param power_pass: Password for power control of the pod (required for rsd). :type power_pass: unicode :param name: Name for the pod (optional). :type name: unicode :param zone: Name of the zone for the pod (optional). :type zone: unicode :param tags: A tag or tags (separated by comma) for the pod (optional). :type tags: unicode Returns 503 if the pod could not be discovered. Returns 404 if the pod is not found. Returns 403 if the user does not have permission to create a pod. """ form = PodForm(data=request.data, request=request) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def update(self, request, id): """@description-title Update fabric @description Update a fabric with the given id. @param (int) "{id}" [required=true] A fabric id. @param (string) "name" [required=false] Name of the fabric. @param (string) "description" [required=false] Description of the fabric. @param (string) "class_type" [required=false] Class type of the fabric. @success (http-status-code) "server-success" 200 @success (json) "success-json" A JSON object containing the updated fabric object. @success-example "success-json" [exkey=fabrics-update] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" The requested fabric is not found. @error-example "not-found" Not Found """ fabric = Fabric.objects.get_fabric_or_404(id, request.user, NodePermission.admin) form = FabricForm(instance=fabric, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def delete(self, request, username): """Deletes a user""" if request.user.username == username: raise ValidationError("An administrator cannot self-delete.") form = DeleteUserForm(data=request.GET) if not form.is_valid(): raise MAASAPIValidationError(form.errors) user = get_one(User.objects.filter(username=username)) if user is not None: new_owner_username = form.cleaned_data['transfer_resources_to'] if new_owner_username: new_owner = get_object_or_404(User, username=new_owner_username) if new_owner is not None: user.userprofile.transfer_resources(new_owner) Consumer.objects.filter(user=user).delete() try: user.userprofile.delete() except CannotDeleteUserException as e: raise ValidationError(str(e)) return rc.DELETED
def update(self, request, system_id, id): """Update RAID on a machine. :param name: Name of the RAID. :param uuid: UUID of the RAID. :param add_block_devices: Block devices to add to the RAID. :param remove_block_devices: Block devices to remove from the RAID. :param add_spare_devices: Spare block devices to add to the RAID. :param remove_spare_devices: Spare block devices to remove from the RAID. :param add_partitions: Partitions to add to the RAID. :param remove_partitions: Partitions to remove from the RAID. :param add_spare_partitions: Spare partitions to add to the RAID. :param remove_spare_partitions: Spare partitions to remove from the RAID. Returns 404 if the machine or RAID is not found. Returns 409 if the machine is not Ready. """ raid = RAID.objects.get_object_or_404(system_id, id, request.user, NodePermission.admin) node = raid.get_node() if node.status != NODE_STATUS.READY: raise NodeStateViolation( "Cannot update RAID because the machine is not Ready.") form = UpdateRaidForm(raid, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def set_zone(self, request): """@description-title Assign nodes to a zone @description Assigns a given node to a given zone. @param (string) "zone" [required=true] The zone name. @param (string) "nodes" [required=true] The node to add. @success (http-status-code) "204" 204 @error (http-status-code) "403" 403 @error (content) "no-perms" The user does not have set the zone. @error-example "no-perms" This method is reserved for admin users. @error (http-status-code) "400" 400 @error (content) "bad-param" The given parameters were not correct. """ data = { "zone": request.data.get("zone"), "system_id": get_optional_list(request.data, "nodes"), } form = BulkNodeSetZoneForm(request.user, data=data) if not form.is_valid(): raise MAASAPIValidationError(form.errors) form.save()
def add_tag(self, request, id): """@description-title Add a tag to a VM host @description Adds a tag to a given VM host. @param (int) "{id}" [required=true] The VM host's ID. @param (string) "tag" [required=true] The tag to add. @success (http-status-code) "200" 200 @success (json) "success-json" A JSON object @success-example (json) "success-json" [exkey=add-tag] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" No VM host with that ID can be found. @error-example "not-found" Not Found @error (http-status-code) "403" 403 @error (content) "no-perms" The user does not have the permissions to delete the VM host. @error-example (content) "no-perms" This method is reserved for admin users. """ tag = get_mandatory_param(request.data, "tag", String) if "," in tag: raise MAASAPIValidationError('Tag may not contain a ",".') pod = Pod.objects.get_pod_or_404(id, request.user, PodPermission.edit) pod.add_tag(tag) pod.save() return pod
def update(self, request, id): """@description-title Update a domain @description Update a domain with the given id. @param (int) "{id}" [required=true] A domain id. @param (string) "name" [required=true] Name of the domain. @param (string) "authoritative" [required=false] True if we are authoritative for this domain. @param (string) "ttl" [required=false] The default TTL for this domain. @success (http-status-code) "server-success" 200 @success (json) "success-json" A JSON object containing information about the updated domain. @success-example "success-json" [exkey=domains-update] placeholder text @error (http-status-code) "403" 403 @error (content) "no-perms" The user does not have the permissions required to update the domain. @error (http-status-code) "404" 404 @error (content) "not-found" The requested domain name is not found. @error-example "not-found" Not Found """ domain = Domain.objects.get_domain_or_404(id, request.user, NodePermission.admin) form = DomainForm(instance=domain, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def create(self, request, system_id): """Creates a Bcache. :param name: Name of the Bcache. :param uuid: UUID of the Bcache. :param cache_set: Cache set. :param backing_device: Backing block device. :param backing_partition: Backing partition. :param cache_mode: Cache mode (WRITEBACK, WRITETHROUGH, WRITEAROUND). Specifying both a device and a partition for a given role (cache or backing) is not allowed. Returns 404 if the machine is not found. Returns 409 if the machine is not Ready. """ machine = Machine.objects.get_node_or_404(system_id, request.user, NODE_PERMISSION.ADMIN) if machine.status != NODE_STATUS.READY: raise NodeStateViolation( "Cannot create Bcache because the machine is not Ready.") form = CreateBcacheForm(machine, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def delete(self, request, name): """@description-title Delete a script @description Deletes a script with the given name. @param (string) "{name}" [required=true] The script's name. @success (http-status-code) "server-success" 204 @error (http-status-code) "404" 404 @error (content) "not-found" The requested script is not found. @error-example "not-found" Not Found """ if name.isdigit(): script = get_object_or_404(Script, id=int(name)) else: script = get_object_or_404(Script, name=name) if script.default: raise MAASAPIValidationError("Unable to delete default script") script.delete() create_audit_event( EVENT_TYPES.SETTINGS, ENDPOINT.API, request, None, description="Deleted script '%s'." % script.name, ) return rc.DELETED
def create(self, request): """@description-title Add a new SSL key @description Add a new SSL key to the requesting user's account. @param (string) "key" [required=true,formatting=true] An SSL key should be provided in the request payload as form data with the name 'key': key: "key data" - ``key data``: The contents of a pem file. @success (http-status-code) "201" 201 @success (json) "success-json" A JSON object containing the new key. @success-example "success-json" [exkey=ssl-keys-create] placeholder text """ form = SSLKeyForm(user=request.user, data=request.data) if form.is_valid(): sslkey = form.save(ENDPOINT.API, request) emitter = JSONEmitter(sslkey, typemapper, None, DISPLAY_SSLKEY_FIELDS) stream = emitter.render(request) return HttpResponse( stream, content_type="application/json; charset=utf-8", status=int(http.client.CREATED), ) else: raise MAASAPIValidationError(form.errors)
def set_default_gateway(self, request, system_id, id): """Set the node to use this interface as the default gateway. If this interface has more than one subnet with a gateway IP in the same IP address family then specifying the ID of the link on this interface is required. :param link_id: ID of the link on this interface to select the default gateway IP address from. Returns 400 if the interface has not AUTO or STATIC links. Returns 404 if the node or interface is not found. """ interface = Interface.objects.get_interface_or_404( system_id, id, request.user, NODE_PERMISSION.EDIT) node = interface.get_node() raise_error_if_controller(node, "link subnet") if node.node_type == NODE_TYPE.MACHINE: # This node needs to be in the correct state to modify # the interface. raise_error_for_invalid_state_on_allocated_operations( node, request.user, "set default gateway") form = InterfaceSetDefaultGatwayForm(instance=interface, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def create_vlan(self, request, system_id): """Create a VLAN interface on a machine. :param tags: Tags for the interface. :param vlan: Tagged VLAN the interface is connected to. :param parent: Parent interface for this VLAN interface. Following are extra parameters that can be set on the interface: :param mtu: Maximum transmission unit. :param accept_ra: Accept router advertisements. (IPv6 only) :param autoconf: Perform stateless autoconfiguration. (IPv6 only) Returns 404 if the node is not found. """ machine = Machine.objects.get_node_or_404(system_id, request.user, NODE_PERMISSION.ADMIN) raise_error_for_invalid_state_on_allocated_operations( machine, request.user, "create VLAN") # Cast parent to parents to make it easier on the user and to make it # work with the form. request.data = request.data.copy() if 'parent' in request.data: request.data['parents'] = request.data['parent'] form = VLANInterfaceForm(node=machine, data=request.data) if form.is_valid(): return form.save() else: # Replace parents with parent so it matches the API parameter. if 'parents' in form.errors: form.errors['parent'] = form.errors.pop('parents') raise MAASAPIValidationError(form.errors)
def mount(self, request, system_id, device_id, id): """Mount the filesystem on partition. :param mount_point: Path on the filesystem to mount. :param mount_options: Options to pass to mount(8). Returns 403 when the user doesn't have the ability to mount 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) raise_error_for_invalid_state_on_allocated_operations( device.get_node(), request.user, "mount") filesystem = partition.get_effective_filesystem() form = MountFilesystemForm(filesystem, data=request.data) if form.is_valid(): form.save() return partition else: raise MAASAPIValidationError(form.errors)
def format(self, request, system_id, device_id, id): """Format a partition. :param fstype: Type of filesystem. :param uuid: The UUID for the filesystem. :param label: The label for the filesystem. Returns 403 when the user doesn't have the ability to format 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, "format") form = FormatPartitionForm(partition, data=request.data) if not form.is_valid(): raise MAASAPIValidationError(form.errors) else: return form.save()
def create(self, request): """Define a license key. :param osystem: Operating system that the key belongs to. :param distro_series: OS release that the key belongs to. :param license_key: License key for osystem/distro_series combo. """ # If the user provides no parametes to the create command, then # django will make the request.data=None. This will cause the form # to be valid, not returning all the missing fields. if request.data is None: data = {} else: data = request.data.copy() if "distro_series" in data: # Preprocess distro_series if present. if "/" in data["distro_series"]: if "osystem" not in data: # Construct osystem value from distroseries. data["osystem"] = data["distro_series"].split("/", 1)[0] else: # If distro_series is not of the form "os/series", we combine # osystem with distro_series since that is what LicenseKeyForm # expects. if "osystem" in data: data["distro_series"] = "%s/%s" % (data["osystem"], data["distro_series"]) form = LicenseKeyForm(data=data) if not form.is_valid(): raise MAASAPIValidationError(form.errors) return form.save()
def update(self, request, system_id, id): """Delete bcache on a machine. :param name: Name of the Bcache. :param uuid: UUID of the Bcache. :param cache_set: Cache set to replace current one. :param backing_device: Backing block device to replace current one. :param backing_partition: Backing partition to replace current one. :param cache_mode: Cache mode (writeback, writethrough, writearound). Specifying both a device and a partition for a given role (cache or backing) is not allowed. Returns 404 if the machine or the bcache is not found. Returns 409 if the machine is not Ready. """ bcache = Bcache.objects.get_object_or_404(system_id, id, request.user, NODE_PERMISSION.ADMIN) node = bcache.get_node() if node.status != NODE_STATUS.READY: raise NodeStateViolation( "Cannot update Bcache because the machine is not Ready.") form = UpdateBcacheForm(bcache, data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def delete(self, request, id): """@description-title Deletes a VM host @description Deletes a VM host with the given ID. @param (int) "{id}" [required=true] The VM host's ID. @param (boolean) "decompose" [required=false] Whether to also also decompose all machines in the VM host on removal. If not provided, machines will not be removed. @success (http-status-code) "204" 204 @error (http-status-code) "404" 404 @error (content) "not-found" No VM host with that ID can be found. @error-example "not-found" Not Found @error (http-status-code) "403" 403 @error (content) "no-perms" The user does not have the permissions to delete the VM host. @error-example (content) "no-perms" This method is reserved for admin users. """ pod = Pod.objects.get_pod_or_404(id, request.user, PodPermission.edit) form = DeletePodForm(data=request.GET) if not form.is_valid(): raise MAASAPIValidationError(form.errors) pod.delete_and_wait(decompose=form.cleaned_data["decompose"]) return rc.DELETED
def add_tag(self, request, name): """Add a single tag to a script. :param tag: The tag being added. :type tag: unicode Returns 404 if the script is not found. """ tag = get_mandatory_param(request.data, 'tag', String) if ',' in tag: raise MAASAPIValidationError('Tag may not contain a ",".') if name.isdigit(): script = get_object_or_404(Script, id=int(name)) else: script = get_object_or_404(Script, name=name) script.add_tag(tag) script.save() create_audit_event( EVENT_TYPES.SETTINGS, ENDPOINT.API, request, None, description=("Script %s" % script.name + " had tag %s" % tag + " added for '%(username)s'.")) return script
def update(self, request, **kwargs): """@description-title Update VLAN @description Updates a given VLAN. @param (int) "{fabric_id}" [required=true] Fabric ID containing the VLAN. @param (int) "{vid}" [required=true] VLAN ID of the VLAN. @param (string) "name" [required=false] Name of the VLAN. @param (string) "description" [required=false] Description of the VLAN. @param (int) "mtu" [required=false] The MTU to use on the VLAN. @param (boolean) "dhcp_on" [required=false] Whether or not DHCP should be managed on the VLAN. @param (string) "primary_rack" [required=false] The primary rack controller managing the VLAN (system_id). @param (string) "secondary_rack" [required=false] The secondary rack controller managing the VLAN (system_id). @param (int) "relay_vlan" [required=false] Relay VLAN ID. Only set when this VLAN will be using a DHCP relay to forward DHCP requests to another VLAN that MAAS is managing. MAAS will not run the DHCP relay itself, it must be configured to proxy reqests to the primary and/or secondary rack controller interfaces for the VLAN specified in this field. @param (string) "space" [required=false] The space this VLAN should be placed in. Passing in an empty string (or the string 'undefined') will cause the VLAN to be placed in the 'undefined' space. @success (http-status-code) "200" 200 @success (json) "success-json" A JSON object containing information about the updated VLAN. @success-example "success-json" [exkey=vlan-update] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" The requested fabric_id or vid is not found. @error-example "not-found" Not Found """ vlan = self._get_vlan(request.user, NodePermission.admin, **kwargs) data = {} # If the user passed in a space, make the undefined space name a # synonym for the empty space. But the Django request data object is # immutable, so we must first copy its contents into our own dict. for k, v in request.data.items(): data[k] = v if 'space' in data and data['space'] == Space.UNDEFINED: data['space'] = '' form = VLANForm(instance=vlan, data=data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def set_config(self, request): """@description-title Set a configuration value @description Set a configuration value. @param (string) "value" [required=false] The value of the configuration item to be set. @param (string) "name" [required=true,formatting=true] The name of the configuration item to be set. %s @success (http-status-code) "server-success" 200 @success (content) "set-success" A plain-text string @success-example "set-success" OK """ name = get_mandatory_param(request.data, 'name', validators.String(min=1)) name = rewrite_config_name(name) value = get_mandatory_param(request.data, 'value') form = get_maas_form(name, value) if not form.is_valid(): raise MAASAPIValidationError(form.errors) form.save(ENDPOINT.API, request) return rc.ALL_OK
def create(self, request): """POST request. Create a new instance of the model.""" form = self.model_form(request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def create(self, request): """@description-title Create a static route @description Creates a static route. @param (string) "source" [required=true] Source subnet name for the route. @param (string) "destination" [required=true] Destination subnet name for the route. @param (string) "gateway_ip" [required=true] IP address of the gateway on the source subnet. @param (int) "metric" [required=false] Weight of the route on a deployed machine. @success (http-status-code) "200" 200 @success (json) "success-json" A JSON object containing information about the new static route object. @success-example "success-json" [exkey=static-routes-create] placeholder text """ form = StaticRouteForm(data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def create(Self, request): """@description-title Create a DHCP snippet @description Creates a DHCP snippet. @param (string) "name" [required=true] The name of the DHCP snippet. @param (string) "value" [required=true] The snippet of config inserted into dhcpd.conf. @param (string) "description" [required=false] A description of what the snippet does. @param (boolean) "enabled" [required=false] Whether or not the snippet is currently enabled. @param (string) "node" [required=false] The node this snippet applies to. Cannot be used with subnet or global_snippet. @param (string) "subnet" [required=false] The subnet this snippet applies to. Cannot be used with node or global_snippet. @param (boolean) "global_snippet" [required=false] Whether or not this snippet is to be applied globally. Cannot be used with node or subnet. @success (http-status-code) "server-success" 200 @success (json) "success-json" A JSON object containing the new DHCP snippet object. @success-example "success-json" [exkey=dhcp-snippets-create] placeholder text """ form = DHCPSnippetForm(data=request.data) if form.is_valid(): return form.save(ENDPOINT.API, request) else: raise MAASAPIValidationError(form.errors)
def create(Self, request): """Create a Package Repository. :param name: The name of the Package Repository. :type name: unicode :param url: The url of the Package Repository. :type url: unicode :param distributions: Which package distributions to include. :type distributions: unicode :param disabled_pockets: The list of pockets to disable. :param disabled_components: The list of components to disable. Only applicable to the default Ubuntu repositories. :param components: The list of components to enable. Only applicable to custom repositories. :param arches: The list of supported architectures. :param key: The authentication key to use with the repository. :type key: unicode :param enabled: Whether or not the repository is enabled. :type enabled: boolean """ form = PackageRepositoryForm(data=request.data) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def delete(self, request, username): """Deletes a user""" if request.user.username == username: raise ValidationError("An administrator cannot self-delete.") form = DeleteUserForm(data=request.GET) if not form.is_valid(): raise MAASAPIValidationError(form.errors) user = get_one(User.objects.filter(username=username)) if user is not None: new_owner_username = form.cleaned_data['transfer_resources_to'] if new_owner_username: new_owner = get_object_or_404(User, username=new_owner_username) if new_owner is not None: user.userprofile.transfer_resources(new_owner) Consumer.objects.filter(user=user).delete() try: user.userprofile.delete() create_audit_event( EVENT_TYPES.AUTHORISATION, ENDPOINT.API, request, None, description=( "%s %s" % ('Admin' if user.is_superuser else 'User', username) + " deleted by '%(username)s'.")) except CannotDeleteUserException as e: raise ValidationError(str(e)) return rc.DELETED
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)
def read(self, request, system_id, id): """View a specific set of results. id can either by the script set id, current-commissioning, current-testing, or current-installation. :param hardware_type: Only return scripts for the given hardware type. Can be node, cpu, memory, or storage. Defaults to all. :type script_type: unicode :param include_output: Include base64 encoded output from the script. :type include_output: bool :param filters: A comma seperated list to show only results that ran with a script name, tag, or id. :type filters: unicode """ script_set = self._get_script_set(request, system_id, id) include_output = get_optional_param(request.GET, 'include_output', False, Bool) filters = get_optional_param(request.GET, 'filters', None, String) if filters is not None: filters = filters.split(',') hardware_type = get_optional_param(request.GET, 'hardware_type') if hardware_type is not None: try: hardware_type = translate_hardware_type(hardware_type) except ValidationError as e: raise MAASAPIValidationError(e) script_set.include_output = include_output script_set.filters = filters script_set.hardware_type = hardware_type return script_set
def create(self, request): """@description-title Add a new SSH key @description Add a new SSH key to the requesting or supplied user's account. @param (string) "key" [required=true,formatting=true] A public SSH key should be provided in the request payload as form data with the name 'key': key: "key-type public-key-data" - ``key-type``: ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-dss, ssh-ed25519, ssh-rsa - ``public key data``: Base64-encoded key data. @success (http-status-code) "201" 201 @success (json) "success-json" A JSON object containing the new key. @success-example "success-json" [exkey=ssh-keys-create] placeholder text """ user = request.user username = get_optional_param(request.POST, 'user') if username is not None and request.user.is_superuser: supplied_user = get_one(User.objects.filter(username=username)) if supplied_user is not None: user = supplied_user else: # Raise an error so that the user can know that their # attempt at specifying a user did not work. raise MAASAPIValidationError( "Supplied username does not match any current users.") elif username is not None and not request.user.is_superuser: raise MAASAPIValidationError( "Only administrators can specify a user" " when creating an SSH key.") form = SSHKeyForm(user=user, data=request.data) if form.is_valid(): sshkey = form.save(ENDPOINT.API, request) emitter = JSONEmitter(sshkey, typemapper, None, DISPLAY_SSHKEY_FIELDS) stream = emitter.render(request) return HttpResponse(stream, content_type='application/json; charset=utf-8', status=int(http.client.CREATED)) else: raise MAASAPIValidationError(form.errors)
def update(self, request, system_id, id): """@description-title Update a bcache @description Update bcache on a machine. Specifying both a device and a partition for a given role (cache or backing) is not allowed. @param (string) "{system_id}" [required=true] The machine's system_id. @param (string) "{id}" [required=true] The bcache id. @param (string) "name" [required=false] Name of the Bcache. @param (string) "uuid" [required=false] UUID of the Bcache. @param (string) "cache_set" [required=false] Cache set to replace current one. @param (string) "backing_device" [required=false] Backing block device to replace current one. @param (string) "backing_partition" [required=false] Backing partition to replace current one. @param (string) "cache_mode" [required=false] Cache mode: ``WRITEBACK``, ``WRITETHROUGH``, ``WRITEAROUND``. @success (http-status-code) "server-success" 200 @success (json) "success-json" A JSON object containing the new bcache device. @success-example "success-json" [exkey=bcache-placeholder] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" The requested id or system_id 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. """ bcache = Bcache.objects.get_object_or_404(system_id, id, request.user, NodePermission.admin) node = bcache.get_node() if node.status != NODE_STATUS.READY: raise NodeStateViolation( "Cannot update Bcache because the machine is not Ready.") form = UpdateBcacheForm(bcache, data=request.data) if form.is_valid(): create_audit_event( EVENT_TYPES.NODE, ENDPOINT.API, request, system_id, "Updated bcache.", ) return form.save() else: raise MAASAPIValidationError(form.errors)
def revert(self, request, name): """@description-title Revert a script version @description Revert a script with the given name to an earlier version. @param (string) "{name}" [required=true] The name of the script. @param (int) "to" [required=false] What revision in the script's history to revert to. This can either be an ID or a negative number representing how far back to go. @success (http-status-code) "server-success" 200 @success (json) "success-json" A JSON object containing information about the reverted script. @success-example "success-json" [exkey=scripts-revert] placeholder text @error (http-status-code) "404" 404 @error (content) "not-found" The requested script is not found. @error-example "not-found" Not Found """ revert_to = get_mandatory_param(request.data, "to", Int) if name.isdigit(): script = get_object_or_404(Script, id=int(name)) else: script = get_object_or_404(Script, name=name) try: if script.default: raise MAASAPIValidationError("Unable to revert default script") def gc_hook(value): script.script = value script.save() script.script.revert(revert_to, gc_hook=gc_hook) create_audit_event( EVENT_TYPES.SETTINGS, ENDPOINT.API, request, None, description=("Reverted script '%s' to revision '%s'." % (script.name, revert_to)), ) return script except ValueError as e: raise MAASAPIValidationError(e.args[0])