def test_attach_wait_for_sync(self, mrapi): """Test wait_for_sync when attaching volume to instance. """ volume = mfactory.VolumeFactory() vm = volume.machine # Test Started VM vm.operstate = "STARTED" vm.save() mrapi().ModifyInstance.return_value = 1 for sync in [True, False]: with override_settings(settings, GANETI_DISKS_WAIT_FOR_SYNC=sync): jobid = backend.attach_volume(vm, volume) self.assertEqual(jobid, 1) name, args, kwargs = mrapi().ModifyInstance.mock_calls[-1] self.assertEqual(kwargs['wait_for_sync'], sync) # Test Stopped VM. We do not pass wait_for_sync. vm.operstate = "STOPPED" vm.save() mrapi().ModifyInstance.return_value = 1 for sync in [True, False]: with override_settings(settings, GANETI_DISKS_WAIT_FOR_SYNC=sync): jobid = backend.attach_volume(vm, volume) self.assertEqual(jobid, 1) name, args, kwargs = mrapi().ModifyInstance.mock_calls[-1] self.assertFalse('wait_for_sync' in kwargs)
def test_attach_volume_type_specs(self, mrapi): """Test volume type spces propagation when attaching a volume to an instance """ vlmt = mfactory.VolumeTypeFactory(disk_template='ext_archipelago') # Generate 4 specs. 2 prefixed with GNT_EXTP_VOLTYPESPEC_PREFIX # and 2 with an other prefix that should be omitted volume_type_specs = [ mfactory.VolumeTypeSpecsFactory(volume_type=vlmt, key='%sbar' % GNT_EXTP_VOLTYPESPEC_PREFIX), mfactory.VolumeTypeSpecsFactory(volume_type=vlmt, key='%sfoo' % GNT_EXTP_VOLTYPESPEC_PREFIX), mfactory.VolumeTypeSpecsFactory(volume_type=vlmt, key='other-prefx-baz'), mfactory.VolumeTypeSpecsFactory(volume_type=vlmt, key='another-prefix-biz'), ] gnt_prefixed_specs = filter( lambda s: s.key.startswith(GNT_EXTP_VOLTYPESPEC_PREFIX), volume_type_specs) volume = mfactory.VolumeFactory(volume_type=vlmt, size=1) vm = volume.machine osettings = { "GANETI_DISK_PROVIDER_KWARGS": { "archipelago": { "foo": "mpaz", "lala": "lolo" } } } with override_settings(settings, **osettings): mrapi().ModifyInstance.return_value = 1 jobid = backend.attach_volume(vm, volume) self.assertEqual(jobid, 1) name, args, kwargs = mrapi().ModifyInstance.mock_calls[-1] disk_kwargs = { "provider": "archipelago", "name": vm.volumes.all()[0].backend_volume_uuid, "reuse_data": 'False', "foo": "mpaz", "lala": "lolo", "size": 1024 } disk_kwargs.update({ spec.key[len(GNT_EXTP_VOLTYPESPEC_PREFIX):]: spec.value for spec in gnt_prefixed_specs }) # Should be "disks": [('add', '-1', {disk_kwargs}), ] disk = kwargs["disks"][0] self.assertEqual(disk[0], 'add') self.assertEqual(disk[1], '-1') self.assertEqual(disk[2], disk_kwargs)
def test_attach_volume_type_specs(self, mrapi): """Test volume type spces propagation when attaching a volume to an instance """ vlmt = mfactory.VolumeTypeFactory(disk_template='ext_archipelago') # Generate 4 specs. 2 prefixed with GNT_EXTP_VOLTYPESPEC_PREFIX # and 2 with an other prefix that should be omitted volume_type_specs = [ mfactory.VolumeTypeSpecsFactory( volume_type=vlmt, key='%sbar' % GNT_EXTP_VOLTYPESPEC_PREFIX), mfactory.VolumeTypeSpecsFactory( volume_type=vlmt, key='%sfoo' % GNT_EXTP_VOLTYPESPEC_PREFIX), mfactory.VolumeTypeSpecsFactory( volume_type=vlmt, key='other-prefx-baz'), mfactory.VolumeTypeSpecsFactory( volume_type=vlmt, key='another-prefix-biz'), ] gnt_prefixed_specs = filter(lambda s: s.key.startswith( GNT_EXTP_VOLTYPESPEC_PREFIX), volume_type_specs) volume = mfactory.VolumeFactory(volume_type=vlmt, size=1) vm = volume.machine osettings = { "GANETI_DISK_PROVIDER_KWARGS": { "archipelago": { "foo": "mpaz", "lala": "lolo" } } } with override_settings(settings, **osettings): mrapi().ModifyInstance.return_value = 1 jobid = backend.attach_volume(vm, volume) self.assertEqual(jobid, 1) name, args, kwargs = mrapi().ModifyInstance.mock_calls[-1] disk_kwargs = {"provider": "archipelago", "name": vm.volumes.all()[0].backend_volume_uuid, "reuse_data": 'False', "foo": "mpaz", "lala": "lolo", "size": 1024} disk_kwargs.update({spec.key[len(GNT_EXTP_VOLTYPESPEC_PREFIX):]: spec.value for spec in gnt_prefixed_specs}) # Should be "disks": [('add', '-1', {disk_kwargs}), ] disk = kwargs["disks"][0] self.assertEqual(disk[0], 'add') self.assertEqual(disk[1], '-1') self.assertEqual(disk[2], disk_kwargs)
def _attach_volume(vm, volume): """Attach a Volume to a VM and update the Volume's status.""" jobid = backend.attach_volume(vm, volume) log.info("Attached volume '%s' to server '%s'. JobID: '%s'", volume.id, volume.machine_id, jobid) volume.backendjobid = jobid volume.machine = vm if volume.status == "AVAILABLE": volume.status = "ATTACHING" else: volume.status = "CREATING" volume.save() return jobid
def attach_volume(vm, volume, atomic_context): """Attach a volume to a server. The volume must be in 'AVAILABLE' status in order to be attached. Also, number of the volumes that are attached to the server must remain less than 'GANETI_MAX_DISKS_PER_INSTANCE' setting. This function will send the corresponding job to Ganeti backend and update the status of the volume to 'ATTACHING'. """ # Check volume state if volume.status not in ["AVAILABLE", "CREATING"]: raise faults.BadRequest("Cannot attach volume while volume is in" " '%s' status." % volume.status) elif volume.status == "AVAILABLE": util.assert_detachable_volume_type(volume.volume_type) # Check that disk templates are the same if volume.volume_type.template != vm.flavor.volume_type.template: msg = ("Volume and server must have the same volume template. Volume" " has volume template'%s' while server has '%s'" % (volume.volume_type.template, vm.flavor.volume_type.template)) raise faults.BadRequest(msg) # Check maximum disk per instance hard limit vm_volumes_num = vm.volumes.filter(deleted=False).count() if vm_volumes_num == settings.GANETI_MAX_DISKS_PER_INSTANCE: raise faults.BadRequest("Maximum volumes per server limit reached") if volume.status == "CREATING": action_fields = {"disks": [("add", volume, {})]} else: action_fields = None with commands.ServerCommand("ATTACH_VOLUME", vm, atomic_context=atomic_context, action_fields=action_fields): util.assign_volume_to_server(vm, volume) jobid = backend.attach_volume(vm, volume) vm.record_job(jobid) log.info("Attached volume '%s' to server '%s'. JobID: '%s'", volume.id, volume.machine_id, jobid) volume.backendjobid = jobid volume.machine = vm if volume.status == "AVAILABLE": volume.status = "ATTACHING" else: volume.status = "CREATING" volume.save()