def update_disk(self, params): """Update disk information.""" # Only admin users can perform delete. if not reload_object(self.user).is_superuser: raise HandlerPermissionError() node = self.get_object(params) device = BlockDevice.objects.get(id=params['block_id'], node=node).actual_instance if device.type == 'physical': form = UpdatePhysicalBlockDeviceForm(instance=device, data=params) elif device.type == 'virtual': form = UpdateVirtualBlockDeviceForm(instance=device, data=params) else: raise HandlerError('Cannot update block device of type %s' % device.type) if not form.is_valid(): raise HandlerError(form.errors) else: disk_obj = form.save() self._update_obj_tags(disk_obj, params) if 'fstype' in params: self.update_blockdevice_filesystem( disk_obj, params['fstype'], params.get('mount_point', ''), params.get('mount_options', ''))
def update_disk(self, params): """Update disk information.""" node = self._get_node_or_permission_error( params, permission=self._meta.edit_permission) device = BlockDevice.objects.get( id=params['block_id'], node=node).actual_instance if device.type == 'physical': form = UpdatePhysicalBlockDeviceForm( instance=device, data=params) elif device.type == 'virtual': form = UpdateVirtualBlockDeviceForm( instance=device, data=params) else: raise HandlerError( 'Cannot update block device of type %s' % device.type) if not form.is_valid(): raise HandlerError(form.errors) else: disk_obj = form.save() self._update_obj_tags(disk_obj, params) if 'fstype' in params: self.update_blockdevice_filesystem( disk_obj, params['fstype'], params.get('mount_point', ''), params.get('mount_options', ''))
def test_updates_physical_block_device(self): block_device = factory.make_PhysicalBlockDevice() name = factory.make_name("sd") model = factory.make_name("model") serial = factory.make_name("serial") id_path = factory.make_absolute_path() size = random.randint( MIN_BLOCK_DEVICE_SIZE, MIN_BLOCK_DEVICE_SIZE * 10) block_size = 4096 form = UpdatePhysicalBlockDeviceForm(instance=block_device, data={ 'name': name, 'model': model, 'serial': serial, 'id_path': id_path, 'size': size, 'block_size': block_size, }) self.assertTrue(form.is_valid(), form.errors) block_device = form.save() self.assertThat(block_device, MatchesStructure.byEquality( name=name, model=model, serial=serial, id_path=id_path, size=size, block_size=block_size, ))
def test_update_no_numa_node_change(self): node = factory.make_Node() numa_node = factory.make_NUMANode(node=node) # associate with a node different from the default one block_device = factory.make_PhysicalBlockDevice(numa_node=numa_node) form = UpdatePhysicalBlockDeviceForm(instance=block_device, data={}) self.assertTrue(form.is_valid(), form.errors) block_device = form.save() self.assertEqual(block_device.numa_node, numa_node)
def test_udpate_partitiontable_type_no_table(self): block_device = factory.make_PhysicalBlockDevice() self.assertIsNone(block_device.get_partitiontable()) form = UpdatePhysicalBlockDeviceForm( instance=block_device, data={"partition_table_type": PARTITION_TABLE_TYPE.MBR}, ) self.assertFalse(form.is_valid()) self.assertEqual( form.errors["partition_table_type"], ["Block device has no partition table"], )
def test_udpate_partitiontable_type(self): block_device = factory.make_PhysicalBlockDevice() factory.make_PartitionTable(table_type=PARTITION_TABLE_TYPE.GPT, block_device=block_device) form = UpdatePhysicalBlockDeviceForm( instance=block_device, data={"partition_table_type": PARTITION_TABLE_TYPE.MBR}, ) self.assertTrue(form.is_valid(), form.errors) block_device = form.save() self.assertEqual( block_device.get_partitiontable().table_type, PARTITION_TABLE_TYPE.MBR, )
def update(self, request, system_id, id): """Update block device on a machine. Machines must have a status of Ready to have access to all options. Machines with Deployed status can only have the name, model, serial, and/or id_path updated for a block device. This is intented to allow a bad block device to be replaced while the machine remains deployed. Fields for physical block device: :param name: Name of the block device. :param model: Model of the block device. :param serial: Serial number of the block device. :param id_path: (optional) Only used if model and serial cannot be \ provided. This should be a path that is fixed and doesn't change \ depending on the boot order or kernel version. :param size: Size of the block device. :param block_size: Block size of the block device. Fields for virtual block device: :param name: Name of the block device. :param uuid: UUID of the block device. :param size: Size of the block device. (Only allowed for logical \ volumes.) 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. """ device = BlockDevice.objects.get_block_device_or_404( system_id, id, request.user, NODE_PERMISSION.ADMIN) node = device.get_node() if node.status not in [NODE_STATUS.READY, NODE_STATUS.DEPLOYED]: raise NodeStateViolation( "Cannot update block device because the machine is not Ready.") if node.status == NODE_STATUS.DEPLOYED: if device.type == 'physical': form = UpdateDeployedPhysicalBlockDeviceForm(instance=device, data=request.data) else: raise NodeStateViolation( "Cannot update virtual block device because the machine " "is Deployed.") else: if device.type == 'physical': form = UpdatePhysicalBlockDeviceForm(instance=device, data=request.data) elif device.type == 'virtual': form = UpdateVirtualBlockDeviceForm(instance=device, data=request.data) else: raise ValueError('Cannot update block device of type %s' % device.type) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def test_updates_physical_block_device(self): block_device = factory.make_PhysicalBlockDevice() node = block_device.node numa_node = factory.make_NUMANode(node=node) name = factory.make_name("sd") model = factory.make_name("model") serial = factory.make_name("serial") id_path = factory.make_absolute_path() size = random.randint(MIN_BLOCK_DEVICE_SIZE, MIN_BLOCK_DEVICE_SIZE * 10) block_size = 4096 form = UpdatePhysicalBlockDeviceForm( instance=block_device, data={ "name": name, "model": model, "serial": serial, "id_path": id_path, "size": size, "block_size": block_size, "numa_node": numa_node.index, }, ) self.assertTrue(form.is_valid(), form.errors) block_device = form.save() self.assertThat( block_device, MatchesStructure.byEquality( name=name, model=model, serial=serial, id_path=id_path, size=size, block_size=block_size, numa_node=numa_node, ), )
def update(self, request, system_id, id): """@description-title Update a block device @description Update block device on a given machine. Machines must have a status of Ready to have access to all options. Machines with Deployed status can only have the name, model, serial, and/or id_path updated for a block device. This is intented to allow a bad block device to be replaced while the machine remains deployed. @param (string) "{system_id}" [required=true] The machine system_id. @param (string) "{id}" [required=true] The block device's id. @param (string) "name" [required=false] (Physical devices) Name of the block device. @param (string) "model" [required=false] (Physical devices) Model of the block device. @param (string) "serial" [required=false] (Physical devices) Serial number of the block device. @param (string) "id_path" [required=false] (Physical devices) Only used if model and serial cannot be provided. This should be a path that is fixed and doesn't change depending on the boot order or kernel version. @param (string) "size" [required=false] (Physical devices) Size of the block device. @param (string) "block_size" [required=false] (Physical devices) Block size of the block device. @param (string) "name" [required=false] (Virtual devices) Name of the block device. @param (string) "uuid" [required=false] (Virtual devices) UUID of the block device. @param (string) "size" [required=false] (Virtual devices) Size of the block device. (Only allowed for logical volumes.) @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-update] placeholder text @error (http-status-code) "403" 403 @error (content) "no-perms" The user does not have permissions to update 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.admin) node = device.get_node() if node.status not in [NODE_STATUS.READY, NODE_STATUS.DEPLOYED]: raise NodeStateViolation( "Cannot update block device because the machine is not Ready.") if node.status == NODE_STATUS.DEPLOYED: if device.type == "physical": form = UpdateDeployedPhysicalBlockDeviceForm(instance=device, data=request.data) else: raise NodeStateViolation( "Cannot update virtual block device because the machine " "is Deployed.") else: if device.type == "physical": form = UpdatePhysicalBlockDeviceForm(instance=device, data=request.data) elif device.type == "virtual": form = UpdateVirtualBlockDeviceForm(instance=device, data=request.data) else: raise ValueError("Cannot update block device of type %s" % device.type) if form.is_valid(): return form.save() else: raise MAASAPIValidationError(form.errors)
def test_update_invalid_numa_node(self): block_device = factory.make_PhysicalBlockDevice() form = UpdatePhysicalBlockDeviceForm(instance=block_device, data={"numa_node": 3}) self.assertFalse(form.is_valid()) self.assertEqual({"numa_node": ["Invalid NUMA node"]}, form.errors)
def test_requires_no_fields(self): block_device = factory.make_PhysicalBlockDevice() form = UpdatePhysicalBlockDeviceForm(instance=block_device, data={}) self.assertTrue(form.is_valid(), form.errors) self.assertItemsEqual([], form.errors.keys())