def test_detach(self, mrapi): """Test the detach functionality.""" # Fail to detach a non-detachable volume vol = mf.VolumeFactory(volume_type=self.file_vt, machine=self.file_vm, userid=self.userid, status="IN_USE") message = "Volume type '{}' is not detachable".format( self.file_vt.disk_template) with self.assertRaisesMessage(faults.BadRequest, message): volumes.detach(vol.id, self.credentials) # Fail to detach a volume that has never been attached to any server vol = mf.VolumeFactory(userid=self.userid, volume_type=self.archip_vt, machine=None) message = "Volume is already detached" with self.assertRaisesMessage(faults.BadRequest, message): volumes.detach(vol.id, self.credentials) # Fail to detach a volume that is not in use vol = mf.VolumeFactory(userid=self.userid, volume_type=self.archip_vt) vol.machine = self.archip_vm vol.status = "CREATING" vol.save() message = "Cannot detach volume while volume is in '{}' status".format( vol.status) with self.assertRaisesMessage(faults.BadRequest, message): volumes.detach(vol.id, self.credentials) # Fail to detach the root volume of a vm vol.status = "IN_USE" vol.index = 0 vol.save() message = "Cannot detach the root volume of server {}.".format( self.archip_vm) with self.assertRaisesMessage(faults.BadRequest, message): volumes.detach(vol.id, self.credentials) # Detach a volume from a server vol.userid = self.userid vol.index = 1 vol.save() mrapi().ModifyInstance.return_value = 42 with mocked_quotaholder() as m: volumes.detach(vol.id, self.credentials) # Assert that the VM has just one volume, the volume has an appropriate # status and that no commission was sent. self.assertEqual(self.archip_vm.volumes.all().count(), 1) vol = Volume.objects.get(pk=vol.id) self.assertEqual(vol.status, "DETACHING") self.assertNoCommission(m) # Assert that Ganeti was instructed to keep the disks and that the # ModifyInstance command corresponds to the target volume and server. gnt_args = self.get_ganeti_args(mrapi) self.assertIn("keep_disks", gnt_args) disk_args = self.get_ganeti_disk_args(mrapi) self.assertEqual(disk_args[0], "remove") self.assertEqual(disk_args[1], vol.backend_volume_uuid) self.assertEqual(disk_args[2], {})
def handle(self, *args, **options): if not args: raise CommandError("Please provide a volume ID") force = options['force'] message = "volumes" if len(args) > 1 else "volume" self.confirm_detachment(force, message, args) for volume_id in args: self.stdout.write("\n") try: volume = volumes.detach(volume_id) wait = parse_bool(options["wait"]) if volume.machine is not None: volume.machine.task_job_id = volume.backendjobid common.wait_server_task(volume.machine, wait, stdout=self.stdout) else: self.stdout.write("Successfully detached volume %s\n" % volume) except CommandError as e: self.stdout.write("Error -- %s\n" % e.message)