def test_create_volume_from_image_invalid_size(self): usage_limit = {'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': 6} image = self.images.first() formData = { 'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 1, 'image_source': image.id } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) api.glance.image_get(IsA(http.HttpRequest), str(image.id)).AndReturn(image) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post("?".join([url, "image_id=" + str(image.id)]), formData, follow=True) self.assertEqual(res.redirect_chain, []) self.assertFormError( res, 'form', None, "The volume size cannot be less than the " "image size (20.0 GB)")
def test_delete_volume(self): volumes = self.cinder_volumes.list() volume = self.cinder_volumes.first() formData = {'action': 'volumes__delete__%s' % volume.id} cinder.volume_backup_supported(IsA(http.HttpRequest)). \ MultipleTimes().AndReturn(True) cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn(volumes) cinder.volume_delete(IsA(http.HttpRequest), volume.id) api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn([self.servers.list(), False]) cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn(volumes) api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn([self.servers.list(), False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).MultipleTimes().\ AndReturn(self.cinder_limits['absolute']) self.mox.ReplayAll() url = VOLUME_INDEX_URL res = self.client.post(url, formData, follow=True) self.assertIn("Scheduled deletion of Volume: Volume name", [m.message for m in res.context['messages']])
def test_delete_volume_error_existing_snapshot(self): volume = self.cinder_volumes.first() volumes = self.cinder_volumes.list() formData = {'action': 'volumes__delete__%s' % volume.id} exc = self.exceptions.cinder.__class__(400, "error: dependent snapshots") cinder.volume_backup_supported(IsA(http.HttpRequest)). \ MultipleTimes().AndReturn(True) cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn(volumes) cinder.volume_delete(IsA(http.HttpRequest), volume.id).\ AndRaise(exc) api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn([self.servers.list(), False]) cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn(volumes) api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\ AndReturn([self.servers.list(), False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).MultipleTimes().\ AndReturn(self.cinder_limits['absolute']) self.mox.ReplayAll() url = VOLUME_INDEX_URL res = self.client.post(url, formData, follow=True) self.assertEqual(list(res.context['messages'])[0].message, u'Unable to delete volume "%s". ' u'One or more snapshots depend on it.' % volume.name)
def test_create_volume_from_image_invalid_size(self): usage_limit = {'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': 6} image = self.images.first() formData = {'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 1, 'image_source': image.id} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) api.glance.image_get(IsA(http.HttpRequest), str(image.id)).AndReturn(image) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post("?".join([url, "image_id=" + str(image.id)]), formData, follow=True) self.assertEqual(res.redirect_chain, []) self.assertFormError(res, 'form', None, "The volume size cannot be less than the " "image size (20.0 GB)")
def test_create_button_disabled_when_quota_exceeded(self): limits = self.cinder_limits['absolute'] limits['totalVolumesUsed'] = limits['maxTotalVolumes'] volumes = self.cinder_volumes.list() api.cinder.volume_backup_supported(IsA(http.HttpRequest)). \ MultipleTimes().AndReturn(True) cinder.volume_list(IsA(http.HttpRequest), search_opts=None)\ .AndReturn(volumes) api.nova.server_list(IsA(http.HttpRequest), search_opts=None)\ .AndReturn([self.servers.list(), False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest))\ .MultipleTimes().AndReturn(limits) self.mox.ReplayAll() res = self.client.get(VOLUME_INDEX_URL) self.assertTemplateUsed(res, 'project/volumes/index.html') volumes = res.context['volumes_table'].data self.assertItemsEqual(volumes, self.cinder_volumes.list()) create_link = tables.CreateVolume() url = create_link.get_link_url() classes = list(create_link.get_default_classes())\ + list(create_link.classes) link_name = "%s (%s)" % (unicode(create_link.verbose_name), "Quota exceeded") expected_string = "<a href='%s' title='%s' class='%s disabled' "\ "id='volumes__action_create' data-update-url=" \ "'/project/volumes/?action=create&table=volumes'> "\ "<span class='glyphicon glyphicon-plus'></span>%s</a>" \ % (url, link_name, " ".join(classes), link_name) self.assertContains(res, expected_string, html=True, msg_prefix="The create button is not disabled")
def _test_encryption(self, encryption): volumes = self.volumes.list() for volume in volumes: volume.encrypted = encryption limits = self.cinder_limits['absolute'] cinder.volume_backup_supported(IsA(http.HttpRequest))\ .MultipleTimes('backup_supported').AndReturn(False) cinder.volume_list(IsA(http.HttpRequest), search_opts=None)\ .AndReturn(self.volumes.list()) api.nova.server_list(IsA(http.HttpRequest), search_opts=None)\ .AndReturn([self.servers.list(), False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest))\ .MultipleTimes('limits').AndReturn(limits) self.mox.ReplayAll() res = self.client.get(VOLUME_INDEX_URL) rows = res.context['volumes_table'].get_rows() if encryption: column_value = 'Yes' else: column_value = 'No' for row in rows: self.assertEqual(row.cells['encryption'].data, column_value)
def test_create_volume_encrypted(self): volume = self.volumes.first() volume_type = self.volume_types.first() usage_limit = { 'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6 } formData = { 'name': u'An Encrypted Volume', 'description': u'This volume has metadata for encryption.', 'method': u'CreateForm', 'type': volume_type.name, 'size': 50, 'snapshot_source': '', 'encryption': u'LUKS' } # check normal operation with can_encrypt_volumes = true PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = True cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], formData['type'], metadata={ 'encryption': formData['encryption'] }, snapshot_id=None, image_id=None).AndReturn(volume) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def test_create_volume_cannot_encrypt(self): volume = self.volumes.first() volume_type = self.volume_types.first() usage = {'gigabytes': {'available': 250}, 'volumes': {'available': 6}} formData = { 'name': u'An Encrypted Volume', 'description': u'This volume has metadata for encryption.', 'method': u'CreateForm', 'type': volume_type.name, 'size': 50, 'snapshot_source': '', 'encryption': u'LUKS' } # check that widget is hidden if can_encrypt_volumes = false PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = False volume = self.volumes.first() volume_type = self.volume_types.first() usage_limit = { 'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6 } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.get(url) # Assert the encryption field is hidden. form = res.context['form'] self.assertTrue( isinstance(form.fields['encryption'].widget, widgets.HiddenInput)) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def test_create_volume_encrypted(self): volume = self.volumes.first() volume_type = self.volume_types.first() usage_limit = {'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6} formData = {'name': u'An Encrypted Volume', 'description': u'This volume has metadata for encryption.', 'method': u'CreateForm', 'type': volume_type.name, 'size': 50, 'snapshot_source': '', 'encryption': u'LUKS'} # check normal operation with can_encrypt_volumes = true PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = True cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], formData['type'], metadata={'encryption': formData['encryption']}, snapshot_id=None, image_id=None).AndReturn(volume) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def test_create_volume_from_image_dropdown(self): volume = self.volumes.first() usage_limit = {'maxTotalVolumeGigabytes': 200, 'maxTotalVolumes': 6} image = self.images.first() formData = { 'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 30, 'type': '', 'volume_source_type': 'image_source', 'snapshot_source': self.volume_snapshots.first().id, 'image_source': image.id } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)) \ .AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)) \ .AndReturn(self.volumes.list()) api.glance.image_get(IsA(http.HttpRequest), str(image.id)).AndReturn(image) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], '', metadata={}, snapshot_id=None, image_id=image.id).\ AndReturn(volume) self.mox.ReplayAll() # get image from dropdown list url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url)
def test_create_volume_from_image_dropdown(self): volume = self.volumes.first() usage_limit = {'maxTotalVolumeGigabytes': 200, 'maxTotalVolumes': 6} image = self.images.first() formData = {'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 30, 'type': '', 'volume_source_type': 'image_source', 'snapshot_source': self.volume_snapshots.first().id, 'image_source': image.id} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)) \ .AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)) \ .AndReturn(self.volumes.list()) api.glance.image_get(IsA(http.HttpRequest), str(image.id)).AndReturn(image) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], '', metadata={}, snapshot_id=None, image_id=image.id).\ AndReturn(volume) self.mox.ReplayAll() # get image from dropdown list url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url)
def test_create_volume_cannot_encrypt(self): volume = self.volumes.first() volume_type = self.volume_types.first() usage = {'gigabytes': {'available': 250}, 'volumes': {'available': 6}} formData = {'name': u'An Encrypted Volume', 'description': u'This volume has metadata for encryption.', 'method': u'CreateForm', 'type': volume_type.name, 'size': 50, 'snapshot_source': '', 'encryption': u'LUKS'} # check that widget is hidden if can_encrypt_volumes = false PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = False volume = self.volumes.first() volume_type = self.volume_types.first() usage_limit = {'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.get(url) # Assert the encryption field is hidden. form = res.context['form'] self.assertTrue(isinstance(form.fields['encryption'].widget, widgets.HiddenInput)) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def tenant_limit_usages(request): # TODO(licostan): This method shall be removed from Quota module. # ProjectUsage/BaseUsage maybe used instead on volume/image dashboards. limits = {} try: if base.is_service_enabled(request, 'compute'): limits.update(nova.tenant_absolute_limits(request, reserved=True)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if cinder.is_volume_service_enabled(request): try: limits.update(cinder.tenant_absolute_limits(request)) except cinder.cinder_exception.ClientException: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) # TODO(amotoki): Support neutron quota details extensions # which returns limit/usage/reserved per resource. # Note that the data format is different from nova/cinder limit API. # https://developer.openstack.org/ # api-ref/network/v2/#quotas-details-extension-quota-details return limits
def tenant_limit_usages(request): # TODO(licostan): This method shall be removed from Quota module. # ProjectUsage/BaseUsage maybe used instead on volume/image dashboards. limits = {} try: limits.update(nova.tenant_absolute_limits(request)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if base.is_service_enabled(request, 'volume'): try: limits.update(cinder.tenant_absolute_limits(request)) volumes = cinder.volume_list(request) snapshots = cinder.volume_snapshot_list(request) total_size = sum([getattr(volume, 'size', 0) for volume in volumes]) limits['gigabytesUsed'] = total_size limits['volumesUsed'] = len(volumes) limits['snapshotsUsed'] = len(snapshots) except Exception: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def tenant_limit_usages(request): # TODO(licostan): This method shall be removed from Quota module. # ProjectUsage/BaseUsage maybe used instead on volume/image dashboards. limits = {} try: if base.is_service_enabled(request, 'compute'): limits.update(nova.tenant_absolute_limits(request, reserved=True)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if cinder.is_volume_service_enabled(request): try: limits.update(cinder.tenant_absolute_limits(request)) volumes = cinder.volume_list(request) snapshots = cinder.volume_snapshot_list(request) # gigabytesUsed should be a total of volumes and snapshots #mj - display the correct amount of volume usage in the volume creation panel #vol_size = sum([getattr(volume, 'size', 0) for volume # in volumes]) #snap_size = sum([getattr(snap, 'size', 0) for snap # in snapshots]) #limits['gigabytesUsed'] = vol_size + snap_size limits['gigabytesUsed'] = limits.get('totalGigabytesUsed', 0) limits['volumesUsed'] = limits.get('totalVolumesUsed', 0) limits['snapshotsUsed'] = limits.get('totalSnapshotsUsed', 0) #limits['volumesUsed'] = len(volumes) #limits['snapshotsUsed'] = len(snapshots) except cinder.cinder_exception.ClientException: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def test_create_volume_number_over_alloted_quota(self): usage_limit = { 'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': len(self.volumes.list()) } formData = { 'name': u'Too Many...', 'description': u'We have no volumes left!', 'method': u'CreateForm', 'size': 10 } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) expected_error = [ u'You are already using all of your available' ' volumes.' ] self.assertEqual(res.context['form'].errors['__all__'], expected_error)
def test_create_volume_from_snapshot(self): volume = self.volumes.first() usage_limit = {'maxTotalVolumeGigabytes': 250, 'maxTotalVolumes': 6} snapshot = self.volume_snapshots.first() formData = {'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 50, 'type': '', 'snapshot_source': snapshot.id} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_get(IsA(http.HttpRequest), str(snapshot.id)).AndReturn(snapshot) cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\ AndReturn(self.volumes.first()) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], '', metadata={}, snapshot_id=snapshot.id, image_id=None).\ AndReturn(volume) self.mox.ReplayAll() # get snapshot from url url = reverse('horizon:project:volumes:create') res = self.client.post("?".join([url, "snapshot_id=" + str(snapshot.id)]), formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url)
def test_create_volume_from_snapshot(self): volume = self.volumes.first() usage_limit = {'maxTotalVolumeGigabytes': 250, 'maxTotalVolumes': 6} snapshot = self.volume_snapshots.first() formData = { 'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'size': 50, 'type': '', 'snapshot_source': snapshot.id } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_get(IsA(http.HttpRequest), str(snapshot.id)).AndReturn(snapshot) cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\ AndReturn(self.volumes.first()) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], '', metadata={}, snapshot_id=snapshot.id, image_id=None).\ AndReturn(volume) self.mox.ReplayAll() # get snapshot from url url = reverse('horizon:project:volumes:create') res = self.client.post( "?".join([url, "snapshot_id=" + str(snapshot.id)]), formData) redirect_url = reverse('horizon:project:volumes:index') self.assertRedirectsNoFollow(res, redirect_url)
def test_create_volume_gb_used_over_alloted_quota(self): usage_limit = {'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': 6} formData = { 'name': u'This Volume Is Huge!', 'description': u'This is a volume that is just too big!', 'method': u'CreateForm', 'size': 5000 } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) expected_error = [ u'A volume of 5000GB cannot be created as you only' ' have 20GB of your quota available.' ] self.assertEqual(res.context['form'].errors['__all__'], expected_error)
def test_create_volume_cannot_encrypt(self): # check that widget is hidden if can_encrypt_volumes = false PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = False usage_limit = { 'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6 } cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.get(url) # Assert the encryption field is hidden. form = res.context['form'] self.assertTrue( isinstance(form.fields['encryption'].widget, widgets.HiddenInput)) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def get_context_data(self, **kwargs): context = super(CreateView, self).get_context_data(**kwargs) try: context['usages'] = cinder.tenant_absolute_limits(self.request) volumes = cinder.volume_list(self.request) total_size = sum( [getattr(volume, 'size', 0) for volume in volumes]) context['usages']['gigabytesUsed'] = total_size context['usages']['volumesUsed'] = len(volumes) except: exceptions.handle(self.request) return context
def get_context_data(self, **kwargs): context = super(CreateView, self).get_context_data(**kwargs) try: context['usages'] = cinder.tenant_absolute_limits(self.request) volumes = cinder.volume_list(self.request) total_size = sum([getattr(volume, 'size', 0) for volume in volumes]) context['usages']['gigabytesUsed'] = total_size context['usages']['volumesUsed'] = len(volumes) except: exceptions.handle(self.request) return context
def _get_tenant_volume_usages(request, usages, disabled_quotas, tenant_id): enabled_volume_quotas = CINDER_QUOTA_FIELDS - disabled_quotas if not enabled_volume_quotas: return try: limits = cinder.tenant_absolute_limits(request, tenant_id) except cinder.cinder_exception.ClientException: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) for quota_name, limit_keys in CINDER_QUOTA_LIMIT_MAP.items(): _add_limit_and_usage(usages, quota_name, limits[limit_keys['limit']], limits[limit_keys['usage']], disabled_quotas)
def test_create_volume_number_over_alloted_quota(self): usage_limit = {'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': len(self.volumes.list())} formData = {'name': u'Too Many...', 'description': u'We have no volumes left!', 'method': u'CreateForm', 'size': 10} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) expected_error = [u'You are already using all of your available' ' volumes.'] self.assertEqual(res.context['form'].errors['__all__'], expected_error)
def test_create_volume_gb_used_over_alloted_quota(self): usage_limit = {'maxTotalVolumeGigabytes': 100, 'maxTotalVolumes': 6} formData = {'name': u'This Volume Is Huge!', 'description': u'This is a volume that is just too big!', 'method': u'CreateForm', 'size': 5000} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post(url, formData) expected_error = [u'A volume of 5000GB cannot be created as you only' ' have 20GB of your quota available.'] self.assertEqual(res.context['form'].errors['__all__'], expected_error)
def test_create_volume_cannot_encrypt(self): # check that widget is hidden if can_encrypt_volumes = false PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = False usage_limit = {'maxTotalVolumeGigabytes': 250, 'gigabytesUsed': 20, 'maxTotalVolumes': 6} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) cinder.tenant_absolute_limits(IsA(http.HttpRequest)).\ AndReturn(usage_limit) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([self.images.list(), False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([[], False]) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.get(url) # Assert the encryption field is hidden. form = res.context['form'] self.assertTrue(isinstance(form.fields['encryption'].widget, widgets.HiddenInput)) settings.OPENSTACK_HYPERVISOR_FEATURES['can_encrypt_volumes'] = PREV
def tenant_limit_usages(request): # TODO(licostan): This method shall be removed from Quota module. # ProjectUsage/BaseUsage maybe used instead on volume/image dashboards. limits = {} try: if base.is_service_enabled(request, 'compute'): limits.update(nova.tenant_absolute_limits(request, reserved=True)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if cinder.is_volume_service_enabled(request): try: limits.update(cinder.tenant_absolute_limits(request)) except cinder.cinder_exception.ClientException: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def tenant_limit_usages(request): # TODO(licostan): This method shall be removed from Quota module. # ProjectUsage/BaseUsage maybe used instead on volume/image dashboards. limits = {} try: #limits.update(nova.tenant_absolute_limits(request)) if is_m1_user_admin(request): limits.update(tenant_absolute_limits_nova(request)) else: limits.update(nova.tenant_absolute_limits(request)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if base.is_service_enabled(request, 'volume'): try: #limits.update(cinder.tenant_absolute_limits(request)) #volumes = cinder.volume_list(request) #snapshots = cinder.volume_snapshot_list(request) if is_m1_user_admin(request): limits.update(tenant_absolute_limits_cinder(request)) volumes = get_volume_list(request) snapshots = get_volume_snapshot_list(request) else: limits.update(cinder.tenant_absolute_limits(request)) volumes = cinder.volume_list(request) snapshots = cinder.volume_snapshot_list(request) # gigabytesUsed should be a total of volumes and snapshots vol_size = sum([getattr(volume, 'size', 0) for volume in volumes]) snap_size = sum([getattr(snap, 'size', 0) for snap in snapshots]) limits['gigabytesUsed'] = vol_size + snap_size limits['volumesUsed'] = len(volumes) limits['snapshotsUsed'] = len(snapshots) except cinder.ClientException: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def tenant_limit_usages(request): limits = {} try: limits.update(nova.tenant_absolute_limits(request)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if base.is_service_enabled(request, 'volume'): try: limits.update(cinder.tenant_absolute_limits(request)) volumes = cinder.volume_list(request) total_size = sum([getattr(volume, 'size', 0) for volume in volumes]) limits['gigabytesUsed'] = total_size limits['volumesUsed'] = len(volumes) except Exception: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def tenant_limit_usages(request): limits = {} try: limits.update(nova.tenant_absolute_limits(request)) except Exception: msg = _("Unable to retrieve compute limit information.") exceptions.handle(request, msg) if base.is_service_enabled(request, 'volume'): try: limits.update(cinder.tenant_absolute_limits(request)) volumes = cinder.volume_list(request) total_size = sum( [getattr(volume, 'size', 0) for volume in volumes]) limits['gigabytesUsed'] = total_size limits['volumesUsed'] = len(volumes) except Exception: msg = _("Unable to retrieve volume limit information.") exceptions.handle(request, msg) return limits
def handle(self, request, data): try: usages = cinder.tenant_absolute_limits(self.request) volumes = cinder.volume_list(self.request) total_size = sum([getattr(volume, 'size', 0) for volume in volumes]) usages['gigabytesUsed'] = total_size usages['volumesUsed'] = len(volumes) availableGB = usages['maxTotalVolumeGigabytes'] -\ usages['gigabytesUsed'] availableVol = usages['maxTotalVolumes'] - usages['volumesUsed'] snapshot_id = None image_id = None source_type = data.get('volume_source_type', None) if (data.get("snapshot_source", None) and source_type in [None, 'snapshot_source']): # Create from Snapshot snapshot = self.get_snapshot(request, data["snapshot_source"]) snapshot_id = snapshot.id if (data['size'] < snapshot.size): error_message = _('The volume size cannot be less than ' 'the snapshot size (%sGB)' % snapshot.size) raise ValidationError(error_message) elif (data.get("image_source", None) and source_type in [None, 'image_source']): # Create from Snapshot image = self.get_image(request, data["image_source"]) image_id = image.id image_size = functions.bytes_to_gigabytes(image.size) if (data['size'] < image_size): error_message = _('The volume size cannot be less than ' 'the image size (%s)' % filesizeformat(image.size)) raise ValidationError(error_message) else: if type(data['size']) is str: data['size'] = int(data['size']) if availableGB < data['size']: error_message = _('A volume of %(req)iGB cannot be created as ' 'you only have %(avail)iGB of your quota ' 'available.') params = {'req': data['size'], 'avail': availableGB} raise ValidationError(error_message % params) elif availableVol <= 0: error_message = _('You are already using all of your available' ' volumes.') raise ValidationError(error_message) metadata = {} volume = cinder.volume_create(request, data['size'], data['name'], data['description'], data['type'], snapshot_id=snapshot_id, image_id=image_id, metadata=metadata) message = _('Creating volume "%s"') % data['name'] messages.info(request, message) return volume except ValidationError as e: self.api_error(e.messages[0]) return False except Exception: exceptions.handle(request, ignore=True) self.api_error(_("Unable to create volume.")) return False
def handle(self, request, data): try: usages = cinder.tenant_absolute_limits(self.request) volumes = cinder.volume_list(self.request) total_size = sum( [getattr(volume, 'size', 0) for volume in volumes]) usages['gigabytesUsed'] = total_size usages['volumesUsed'] = len(volumes) availableGB = usages['maxTotalVolumeGigabytes'] -\ usages['gigabytesUsed'] availableVol = usages['maxTotalVolumes'] - usages['volumesUsed'] snapshot_id = None image_id = None source_type = data.get('volume_source_type', None) if (data.get("snapshot_source", None) and source_type in [None, 'snapshot_source']): # Create from Snapshot snapshot = self.get_snapshot(request, data["snapshot_source"]) snapshot_id = snapshot.id if (data['size'] < snapshot.size): error_message = _('The volume size cannot be less than ' 'the snapshot size (%sGB)' % snapshot.size) raise ValidationError(error_message) elif (data.get("image_source", None) and source_type in [None, 'image_source']): # Create from Snapshot image = self.get_image(request, data["image_source"]) image_id = image.id image_size = bytes_to_gigabytes(image.size) if (data['size'] < image_size): error_message = _('The volume size cannot be less than ' 'the image size (%s)' % filesizeformat(image.size)) raise ValidationError(error_message) else: if type(data['size']) is str: data['size'] = int(data['size']) if availableGB < data['size']: error_message = _('A volume of %(req)iGB cannot be created as ' 'you only have %(avail)iGB of your quota ' 'available.') params = {'req': data['size'], 'avail': availableGB} raise ValidationError(error_message % params) elif availableVol <= 0: error_message = _('You are already using all of your available' ' volumes.') raise ValidationError(error_message) metadata = {} if data['encryption']: metadata['encryption'] = data['encryption'] volume = cinder.volume_create(request, data['size'], data['name'], data['description'], data['type'], snapshot_id=snapshot_id, image_id=image_id, metadata=metadata) message = _('Creating volume "%s"') % data['name'] messages.info(request, message) return volume except ValidationError as e: self.api_error(e.messages[0]) return False except Exception: exceptions.handle(request, ignore=True) self.api_error(_("Unable to create volume.")) return False