def _test_subnets_tab_subnet_exception(self, mac_learning=False): network_id = self.networks.first().id quota_data = self.neutron_quota_usages.first() quota_data['networks']['available'] = 5 quota_data['subnets']['available'] = 5 api.neutron.network_get(IsA(http.HttpRequest), network_id).\ MultipleTimes().AndReturn(self.networks.first()) api.neutron.subnet_list(IsA(http.HttpRequest), network_id=network_id).\ AndRaise(self.exceptions.neutron) # Called from SubnetTable api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['subnets']) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:subnets_tab', args=[network_id])) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') subnets = res.context['subnets_table'].data self.assertEqual(len(subnets), 0)
def test_allocate_button_disabled_when_quota_exceeded(self): floating_ips = self.floating_ips.list() floating_pools = self.pools.list() quota_data = self.neutron_quota_usages.first() quota_data['floatingip']['available'] = 0 api.neutron.tenant_floating_ip_list( IsA(http.HttpRequest)) \ .AndReturn(floating_ips) api.neutron.floating_ip_pools_list( IsA(http.HttpRequest)) \ .AndReturn(floating_pools) api.nova.server_list( IsA(http.HttpRequest), detailed=False) \ .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('floatingip', )).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') self.assertIn('disabled', allocate_action.classes, 'The create button should be disabled') self.assertEqual('Allocate IP To Project (Quota exceeded)', six.text_type(allocate_action.verbose_name))
def _test_create_button_shown_when_quota_disabled( self, find_button_fn): # if quota_data doesnt contain a networks|subnets|routers key or # these keys are empty dicts, its disabled quota_data = self.neutron_quota_usages.first() quota_data['networks'].pop('available') quota_data['subnets'].pop('available') self._stub_net_list() quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['networks']) \ .MultipleTimes().AndReturn(quota_data) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['subnets']) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, INDEX_TEMPLATE) networks = res.context['networks_table'].data self.assertItemsEqual(networks, self.networks.list()) button = find_button_fn(res) self.assertFalse('disabled' in button.classes, "The create button should not be disabled") return button
def test_create_button_disabled_when_quota_exceeded(self): quota_usages = self.quota_usages.first() quota_usages['volumes']['available'] = 0 volumes = self.cinder_volumes.list() 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.volume_snapshot_list(IsA(http.HttpRequest))\ .AndReturn(self.cinder_volume_snapshots.list()) cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest))\ .MultipleTimes().AndReturn(quota_usages) 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'>%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_router_delete(self): router = self.routers.first() quota_data = self.quota_usages.first() quota_data['routers']['available'] = 5 api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) self._mock_external_network_list() api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) self._mock_external_network_list() api.neutron.port_list(IsA(http.HttpRequest), device_id=router.id, device_owner=IgnoreArg())\ .AndReturn([]) api.neutron.router_delete(IsA(http.HttpRequest), router.id) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) formData = {'action': 'Routers__delete__' + router.id} res = self.client.post(self.INDEX_URL, formData, follow=True) self.assertNoFormErrors(res) self.assertMessageCount(response=res, success=1) self.assertIn('Deleted Router: ' + router.name, res.content)
def _test_index(self, backup_supported=True): vol_backups = self.cinder_volume_backups.list() vol_snaps = self.cinder_volume_snapshots.list() volumes = self.cinder_volumes.list() api.cinder.volume_backup_supported(IsA(http.HttpRequest)).\ MultipleTimes().AndReturn(backup_supported) api.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]) api.cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(vol_snaps) api.cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) if backup_supported: api.cinder.volume_backup_list(IsA(http.HttpRequest)).\ AndReturn(vol_backups) api.cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes(). \ AndReturn(self.quota_usages.first()) self.mox.ReplayAll() res = self.client.get(INDEX_URL) self.assertEqual(res.status_code, 200) self.assertTemplateUsed(res, 'project/volumes/index.html')
def test_index(self): sec_groups = self.security_groups.list() quota_data = self.neutron_quota_usages.first() quota_data['security_group']['available'] = 10 api.neutron.security_group_list(IsA(http.HttpRequest)) \ .AndReturn(sec_groups) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('security_group', )).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'horizon/common/_data_table_view.html') # Security groups sec_groups_from_ctx = res.context['security_groups_table'].data # Context data needs to contains all items from the test data. self.assertItemsEqual(sec_groups_from_ctx, sec_groups) # Sec groups in context need to be sorted by their ``name`` attribute. # This assertion is somewhat weak since it's only meaningful as long as # the sec groups in the test data are *not* sorted by name (which is # the case as of the time of this addition). self.assertTrue( all([sec_groups_from_ctx[i].name <= sec_groups_from_ctx[i + 1].name for i in range(len(sec_groups_from_ctx) - 1)]))
def test_allocate_button_attributes(self): floating_ips = self.floating_ips.list() floating_pools = self.pools.list() quota_data = self.neutron_quota_usages.first() api.neutron.tenant_floating_ip_list( IsA(http.HttpRequest)) \ .AndReturn(floating_ips) api.neutron.floating_ip_pools_list( IsA(http.HttpRequest)) \ .AndReturn(floating_pools) api.nova.server_list( IsA(http.HttpRequest), detailed=False) \ .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('floatingip', )).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') self.assertEqual(set(['ajax-modal']), set(allocate_action.classes)) self.assertEqual('Allocate IP To Project', six.text_type(allocate_action.verbose_name)) self.assertIsNone(allocate_action.policy_rules) url = 'horizon:project:floating_ips:allocate' self.assertEqual(url, allocate_action.url)
def _test_network_detail(self, mac_learning=False): quota_data = self.neutron_quota_usages.first() network_id = self.networks.first().id api.neutron.network_get(IsA(http.HttpRequest), network_id)\ .AndReturn(self.networks.first()) api.neutron.subnet_list(IsA(http.HttpRequest), network_id=network_id)\ .AndReturn([self.subnets.first()]) api.neutron.port_list(IsA(http.HttpRequest), network_id=network_id)\ .AndReturn([self.ports.first()]) api.neutron.network_get(IsA(http.HttpRequest), network_id)\ .AndReturn(self.networks.first()) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(reverse('horizon:project:networks:detail', args=[network_id])) self.assertTemplateUsed(res, 'project/networks/detail.html') subnets = res.context['subnets_table'].data ports = res.context['ports_table'].data self.assertItemsEqual(subnets, [self.subnets.first()]) self.assertItemsEqual(ports, [self.ports.first()])
def test_subnet_create_button_disabled_when_quota_exceeded_detail(self): network_id = self.networks.first().id quota_data = self.neutron_quota_usages.first() quota_data['subnets']['available'] = 0 api.neutron.network_get( IsA(http.HttpRequest), network_id)\ .MultipleTimes().AndReturn(self.networks.first()) api.neutron.subnet_list( IsA(http.HttpRequest), network_id=network_id)\ .AndReturn(self.subnets.list()) api.neutron.port_list( IsA(http.HttpRequest), network_id=network_id)\ .AndReturn([self.ports.first()]) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(False) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(reverse('horizon:project:networks:detail', args=[network_id])) self.assertTemplateUsed(res, 'project/networks/detail.html') subnets = res.context['subnets_table'].data self.assertItemsEqual(subnets, self.subnets.list()) create_action = self.getAndAssertTableAction(res, 'subnets', 'create') self.assertTrue('disabled' in create_action.classes, 'The create button should be disabled')
def test_usage(self): now = timezone.now() usage_obj = api.nova.NovaUsage(self.usages.first()) quota_data = self.quota_usages.first() api.keystone.tenant_list(IsA(http.HttpRequest), admin=True) \ .AndReturn(self.tenants.list()) api.usage_list(IsA(http.HttpRequest), datetime.datetime(now.year, now.month, 1, 0, 0, 0), Func(usage.almost_now)) \ .AndReturn([usage_obj]) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(reverse('horizon:admin:overview:index')) self.assertTemplateUsed(res, 'admin/overview/usage.html') self.assertTrue(isinstance(res.context['usage'], usage.GlobalUsage)) self.assertContains(res, '<td class="sortable normal_column">test_tenant' '</td>' '<td class="sortable normal_column">%s</td>' '<td class="sortable normal_column">%s</td>' '<td class="sortable normal_column">%s</td>' '<td class="sortable normal_column">%.2f</td>' '<td class="sortable normal_column">%.2f</td>' % (usage_obj.vcpus, usage_obj.disk_gb_hours, mbformat(usage_obj.memory_mb), usage_obj.vcpu_hours, usage_obj.total_local_gb_usage))
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_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.volume_snapshot_list(IsA(http.HttpRequest))\ .AndReturn(self.cinder_volume_snapshots.list()) cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().\ AndReturn(self.quota_usages.first()) 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_subnet_create_button(self, quota_data): network_id = self.networks.first().id api.neutron.network_get( IsA(http.HttpRequest), network_id)\ .MultipleTimes().AndReturn(self.networks.first()) api.neutron.subnet_list( IsA(http.HttpRequest), network_id=network_id)\ .AndReturn(self.subnets.list()) api.neutron.is_extension_supported( IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(False) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['subnets']) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() url = urlunquote(reverse('horizon:project:networks:subnets_tab', args=[network_id])) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') subnets = res.context['subnets_table'].data self.assertItemsEqual(subnets, self.subnets.list()) return self.getAndAssertTableAction(res, 'subnets', 'create')
def test_create_button_shown_when_quota_disabled(self): quota_data = self.neutron_quota_usages.first() quota_data['routers'].pop('available') api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed(res, 'project/routers/index.html') routers = res.context['routers_table'].data self.assertItemsEqual(routers, self.routers.list()) create_action = self.getAndAssertTableAction(res, 'routers', 'create') self.assertFalse('disabled' in create_action.classes, 'Create button should not be disabled') self.assertEqual('Create Router', create_action.verbose_name)
def test_delete_volume_snapshot(self): vol_snapshots = self.volume_snapshots.list() volumes = self.volumes.list() snapshot = self.volume_snapshots.first() api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \ AndReturn(vol_snapshots) api.cinder.volume_list(IsA(http.HttpRequest)). \ AndReturn(volumes) api.cinder.volume_snapshot_delete(IsA(http.HttpRequest), snapshot.id) api.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]) api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \ AndReturn([]) api.cinder.volume_list(IsA(http.HttpRequest)). \ AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes(). \ AndReturn(self.quota_usages.first()) self.mox.ReplayAll() formData = {'action': 'volume_snapshots__delete__%s' % snapshot.id} res = self.client.post(INDEX_URL, formData, follow=True) self.assertIn("Scheduled deletion of Volume Snapshot: test snapshot", [m.message for m in res.context['messages']])
def test_allocate_button_disabled_when_quota_exceeded(self): keypairs = self.keypairs.list() floating_ips = self.floating_ips.list() floating_pools = self.pools.list() quota_data = self.quota_usages.first() quota_data["floating_ips"]["available"] = 0 sec_groups = self.security_groups.list() api.network.floating_ip_supported(IsA(http.HttpRequest)).AndReturn(True) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)).AndReturn(floating_ips) api.network.security_group_list(IsA(http.HttpRequest)).MultipleTimes().AndReturn(sec_groups) api.network.floating_ip_pools_list(IsA(http.HttpRequest)).AndReturn(floating_pools) api.nova.keypair_list(IsA(http.HttpRequest)).AndReturn(keypairs) api.nova.server_list(IsA(http.HttpRequest)).AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().AndReturn(quota_data) api.base.is_service_enabled(IsA(http.HttpRequest), "network").MultipleTimes().AndReturn(True) api.base.is_service_enabled(IsA(http.HttpRequest), "ec2").MultipleTimes().AndReturn(False) self.mox.ReplayAll() res = self.client.get(INDEX_URL + "?tab=access_security_tabs__floating_ips_tab") allocate_action = self.getAndAssertTableAction(res, "floating_ips", "allocate") self.assertTrue("disabled" in allocate_action.classes, "The create button should be disabled") self.assertEqual("Allocate IP To Project (Quota exceeded)", six.text_type(allocate_action.verbose_name))
def test_launch_flavorlist_error(self): cinder.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).AndReturn(self.volumes.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]) api.quantum.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).AndReturn( self.networks.list()[:1] ) api.quantum.network_list(IsA(http.HttpRequest), shared=True).AndReturn(self.networks.list()[1:]) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(self.quota_usages.first()) api.nova.flavor_list(IsA(http.HttpRequest)).AndRaise(self.exceptions.nova) api.nova.flavor_list(IsA(http.HttpRequest)).AndRaise(self.exceptions.nova) api.nova.keypair_list(IsA(http.HttpRequest)).AndReturn(self.keypairs.list()) api.nova.security_group_list(IsA(http.HttpRequest)).AndReturn(self.security_groups.list()) self.mox.ReplayAll() url = reverse("horizon:project:instances:launch") res = self.client.get(url) self.assertTemplateUsed(res, "project/instances/launch.html")
def test_create_volume(self): volume = self.volumes.first() volume_type = self.volume_types.first() usage = {'gigabytes': {'available': 250}, 'volumes': {'available': 6}} formData = {'name': u'A Volume I Am Making', 'description': u'This is a volume I am making for a test.', 'method': u'CreateForm', 'type': volume_type.name, 'size': 50, 'snapshot_source': ''} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) cinder.volume_create(IsA(http.HttpRequest), formData['size'], formData['name'], formData['description'], formData['type'], metadata={}, snapshot_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)
def test_create_volume_from_snapshot_invalid_size(self): usage = {'gigabytes': {'available': 250}, 'volumes': {'available': 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': 20, 'snapshot_source': snapshot.id} cinder.volume_type_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_types.list()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) 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()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) self.mox.ReplayAll() url = reverse('horizon:project:volumes:create') res = self.client.post("?".join([url, "snapshot_id=" + str(snapshot.id)]), formData, follow=True) self.assertEqual(res.redirect_chain, []) self.assertFormError(res, 'form', None, "The volume size cannot be less than the " "snapshot size (40GB)")
def _test_encryption(self, encryption): volumes = self.volumes.list() for volume in volumes: volume.encrypted = encryption quota_usages = self.quota_usages.first() cinder.volume_list(IsA(http.HttpRequest), search_opts=None)\ .MultipleTimes().AndReturn(self.volumes.list()) cinder.volume_list(IsA(http.HttpRequest)).AndReturn([]) cinder.volume_snapshot_list(IsA(http.HttpRequest)).AndReturn([]) api.nova.server_list(IsA(http.HttpRequest), search_opts=None)\ .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages(IsA(http.HttpRequest))\ .MultipleTimes().AndReturn(quota_usages) 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_button_attributes(self): sec_groups = self.security_groups.list() quota_data = self.neutron_quota_usages.first() quota_data['security_group']['available'] = 10 api.neutron.security_group_list( IsA(http.HttpRequest)) \ .AndReturn(sec_groups) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('security_group', )).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) security_groups = res.context['security_groups_table'].data self.assertItemsEqual(security_groups, self.security_groups.list()) create_action = self.getAndAssertTableAction(res, 'security_groups', 'create') self.assertEqual('Create Security Group', six.text_type(create_action.verbose_name)) self.assertIsNone(create_action.policy_rules) self.assertEqual(set(['ajax-modal']), set(create_action.classes)) url = 'horizon:project:security_groups:create' self.assertEqual(url, create_action.url)
def test_select_default_keypair_if_only_one(self): keypair = self.keypairs.first() quota_usages = self.quota_usages.first() image = self.images.first() cinder.volume_list(IsA(http.HttpRequest)).AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).AndReturn(self.volumes.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]) api.quantum.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False).AndReturn( self.networks.list()[:1] ) api.quantum.network_list(IsA(http.HttpRequest), shared=True).AndReturn(self.networks.list()[1:]) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(quota_usages) api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list()) api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(self.flavors.list()) api.nova.keypair_list(IsA(http.HttpRequest)).AndReturn([keypair]) api.nova.security_group_list(IsA(http.HttpRequest)).AndReturn(self.security_groups.list()) self.mox.ReplayAll() url = reverse("horizon:project:instances:launch") res = self.client.get(url) self.assertContains( res, "<option selected='selected' value='%(key)s'>" "%(key)s</option>" % {"key": keypair.name}, html=True, msg_prefix="The default keypair was not selected.", )
def test_router_with_interface_delete(self): router = self.routers.first() ports = self.ports.list() quota_data = self.neutron_quota_usages.first() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn( self.routers.list() ) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn( self.routers.list() ) self._mock_external_network_list() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn( self.routers.list() ) self._mock_external_network_list() api.neutron.port_list(IsA(http.HttpRequest), device_id=router.id, device_owner=IgnoreArg()).AndReturn(ports) for port in ports: api.neutron.router_remove_interface(IsA(http.HttpRequest), router.id, port_id=port.id) api.neutron.router_delete(IsA(http.HttpRequest), router.id) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) formData = {"action": "routers__delete__" + router.id} res = self.client.post(self.INDEX_URL, formData, follow=True) self.assertNoFormErrors(res) self.assertMessageCount(response=res, success=1) self.assertIn("Deleted Router: " + router.name, res.content.decode("utf-8"))
def test_index(self): keypairs = self.keypairs.list() sec_groups = self.security_groups.list() floating_ips = self.floating_ips.list() quota_data = self.quota_usages.first() self.mox.StubOutWithMock(api.network, "tenant_floating_ip_list") self.mox.StubOutWithMock(api.network, "security_group_list") self.mox.StubOutWithMock(api.nova, "keypair_list") self.mox.StubOutWithMock(api.nova, "server_list") self.mox.StubOutWithMock(quotas, "tenant_quota_usages") api.nova.server_list(IsA(http.HttpRequest)).AndReturn([self.servers.list(), False]) api.nova.keypair_list(IsA(http.HttpRequest)).AndReturn(keypairs) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)).AndReturn(floating_ips) api.network.security_group_list(IsA(http.HttpRequest)).AndReturn(sec_groups) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() url = reverse("horizon:project:access_and_security:index") res = self.client.get(url) self.assertTemplateUsed(res, "project/access_and_security/index.html") self.assertItemsEqual(res.context["keypairs_table"].data, keypairs) self.assertItemsEqual(res.context["security_groups_table"].data, sec_groups) self.assertItemsEqual(res.context["floating_ips_table"].data, floating_ips)
def test_delete_volume(self): volumes = self.cinder_volumes.list() volume = self.cinder_volumes.first() formData = {'action': 'volumes__delete__%s' % volume.id} 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_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.cinder_volume_snapshots.list()) 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.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().\ AndReturn(self.quota_usages.first()) 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_launch_form_instance_count_error(self): flavor = self.flavors.first() image = self.images.first() keypair = self.keypairs.first() server = self.servers.first() volume = self.volumes.first() sec_group = self.security_groups.first() customization_script = 'user data' device_name = u'vda' volume_choice = "%s:vol" % volume.id api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) api.nova.keypair_list(IsA(http.HttpRequest)) \ .AndReturn(self.keypairs.list()) api.nova.security_group_list(IsA(http.HttpRequest)) \ .AndReturn(self.security_groups.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]) api.quantum.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False) \ .AndReturn(self.networks.list()[:1]) api.quantum.network_list(IsA(http.HttpRequest), shared=True) \ .AndReturn(self.networks.list()[1:]) cinder.volume_list(IsA(http.HttpRequest)) \ .AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)).AndReturn([]) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) quotas.tenant_quota_usages(IsA(http.HttpRequest)) \ .AndReturn(self.quota_usages.first()) self.mox.ReplayAll() form_data = {'flavor': flavor.id, 'source_type': 'image_id', 'image_id': image.id, 'keypair': keypair.name, 'name': server.name, 'customization_script': customization_script, 'project_id': self.tenants.first().id, 'user_id': self.user.id, 'groups': sec_group.name, 'volume_type': 'volume_id', 'volume_id': volume_choice, 'device_name': device_name, 'count': 0} url = reverse('horizon:project:instances:launch') res = self.client.post(url, form_data) self.assertContains(res, "greater than or equal to 1")
def test_create_button_disabled_when_quota_exceeded(self): quota_data = self.quota_usages.first() quota_data['routers']['available'] = 0 api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed(res, 'project/routers/index.html') routers = res.context['Routers_table'].data self.assertItemsEqual(routers, self.routers.list()) create_link = tables.CreateRouter() 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='Routers__action_create'>" \ "<span class='fa fa-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_create_button_disabled_when_quota_exceeded(self, network_enabled): sec_groups = self.security_groups.list() quota_data = self.neutron_quota_usages.first() quota_data['security_group']['available'] = 0 api.neutron.security_group_list( IsA(http.HttpRequest)) \ .AndReturn(sec_groups) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('security_group', )).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) security_groups = res.context['security_groups_table'].data self.assertItemsEqual(security_groups, self.security_groups.list()) create_action = self.getAndAssertTableAction(res, 'security_groups', 'create') self.assertIn('disabled', create_action.classes, 'The create button should be disabled')
def test_create_button_attributes(self): quota_data = self.neutron_quota_usages.first() quota_data['routers']['available'] = 10 api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id, search_opts=None).AndReturn(self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed(res, 'project/routers/index.html') routers = res.context['routers_table'].data self.assertItemsEqual(routers, self.routers.list()) create_action = self.getAndAssertTableAction(res, 'routers', 'create') self.assertEqual(set(['ajax-modal']), set(create_action.classes)) self.assertEqual('Create Router', six.text_type(create_action.verbose_name)) self.assertEqual('horizon:project:routers:create', create_action.url) self.assertEqual((('network', 'create_router'),), create_action.policy_rules)
def _test_create_button_disabled_when_quota_exceeded( self, find_button_fn, network_quota=5, subnet_quota=5, ): quota_data = self.neutron_quota_usages.first() quota_data['networks']['available'] = network_quota quota_data['subnets']['available'] = subnet_quota self._stub_net_list() quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['networks']) \ .MultipleTimes().AndReturn(quota_data) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['subnets']) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, INDEX_TEMPLATE) networks = res.context['networks_table'].data self.assertItemsEqual(networks, self.networks.list()) button = find_button_fn(res) self.assertIn('disabled', button.classes, "The create button should be disabled") return button
def test_create_volume_number_over_alloted_quota(self): usage = {'gigabytes': {'available': 100, 'used': 20}, 'volumes': {'available': 0}} 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()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) cinder.volume_snapshot_list(IsA(http.HttpRequest)).\ AndReturn(self.volume_snapshots.list()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) 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 allowed(self, request, datum=None): usages = quotas.tenant_quota_usages(request, targets=('subnet', )) # when Settings.OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False # usages["subnets'] is empty if usages.get('subnet', {}).get('available', 1) <= 0: if 'disabled' not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = _('Create Subnet (Quota exceeded)') else: self.verbose_name = _('Create Subnet') self.classes = [c for c in self.classes if c != 'disabled'] return True
def allowed(self, request, datum=None): network = self.table._get_network() tenant_id = network.tenant_id usages = quotas.tenant_quota_usages( request, tenant_id=tenant_id, targets=('port', )) if usages.get('port', {}).get('available', 1) <= 0: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ["disabled"] self.verbose_name = _("Create Port (Quota exceeded)") else: self.verbose_name = _("Create Port") self.classes = [c for c in self.classes if c != "disabled"] return True
def allowed(self, request, datum=None): usages = quotas.tenant_quota_usages(request, targets=('key_pairs', )) usages.tally('key_pairs', len(self.table.data)) if usages['key_pairs']['available'] <= 0: if "disabled" not in self.classes: self.classes = list(self.classes) + ['disabled'] self.verbose_name = format_lazy( '{verbose_name} {quota_exceeded}', verbose_name=self.verbose_name, quota_exceeded=_("(Quota exceeded)")) return False classes = [c for c in self.classes if c != "disabled"] self.classes = classes return True
def test_set_external_network_empty(self): router = self.routers.first() quota_data = self.neutron_quota_usages.first() api.neutron.router_list( IsA(http.HttpRequest), tenant_id=self.tenant.id).MultipleTimes().AndReturn([router]) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=('router', )) \ .MultipleTimes().AndReturn(quota_data) api.neutron.is_extension_supported(IsA(http.HttpRequest), "router_availability_zone")\ .AndReturn(True) self._mock_external_network_list(alter_ids=True) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) table_data = res.context['table'].data self.assertEqual(len(table_data), 1) self.assertIn('(Not Found)', table_data[0]['external_gateway_info']['network']) self.assertTemplateUsed(res, INDEX_TEMPLATE) self.assertMessageCount(res, error=1)
def test_create_button_shown_when_quota_disabled(self): quota_data = self.neutron_quota_usages.first() quota_data['routers'].pop('available') api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id).AndReturn( self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['routers']) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed(res, INDEX_TEMPLATE) routers = res.context['routers_table'].data self.assertItemsEqual(routers, self.routers.list()) create_action = self.getAndAssertTableAction(res, 'routers', 'create') self.assertFalse('disabled' in create_action.classes, 'Create button should not be disabled') self.assertEqual('Create Router', create_action.verbose_name)
def test_tenant_quota_usages_no_instances_running(self): api.cinder.is_volume_service_enabled(IsA( http.HttpRequest)).AndReturn(False) api.base.is_service_enabled(IsA(http.HttpRequest), 'network').AndReturn(False) api.base.is_service_enabled(IsA(http.HttpRequest), 'compute').MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.quotas.first()) api.network.floating_ip_supported(IsA(http.HttpRequest)) \ .AndReturn(True) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ .AndReturn([]) search_opts = {'tenant_id': self.request.user.tenant_id} api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts, all_tenants=True) \ .AndReturn([[], False]) self.mox.ReplayAll() quota_usages = quotas.tenant_quota_usages(self.request) expected_output = self.get_usages(with_volume=False) expected_output.update({ 'ram': { 'available': 10000, 'used': 0, 'quota': 10000 }, 'floating_ips': { 'available': 1, 'used': 0, 'quota': 1 }, 'instances': { 'available': 10, 'used': 0, 'quota': 10 }, 'cores': { 'available': 10, 'used': 0, 'quota': 10 } }) # Compare internal structure of usages to expected. self.assertItemsEqual(expected_output, quota_usages.usages)
def _test_tenant_quota_usages_with_target(self, targets, use_compute_call=True, use_flavor_list=False, use_cinder_call=False): cinder.is_volume_service_enabled(IsA(http.HttpRequest)).AndReturn(True) api.base.is_service_enabled(IsA(http.HttpRequest), 'network') \ .AndReturn(False) api.base.is_service_enabled(IsA(http.HttpRequest), 'compute') \ .MultipleTimes().AndReturn(True) if use_compute_call: servers = [ s for s in self.servers.list() if s.tenant_id == self.request.user.tenant_id ] if use_flavor_list: api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'tenant_id': self.request.user.tenant_id} api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ .AndReturn([servers, False]) api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.quotas.first()) if use_cinder_call: opts = { 'all_tenants': 1, 'project_id': self.request.user.tenant_id } cinder.volume_list(IsA(http.HttpRequest), opts) \ .AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest), opts) \ .AndReturn(self.cinder_volume_snapshots.list()) cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.cinder_quotas.first()) self.mox.ReplayAll() quota_usages = quotas.tenant_quota_usages(self.request, targets=targets) expected = self.get_usages() expected = dict((k, v) for k, v in expected.items() if k in targets) # Compare internal structure of usages to expected. self.assertItemsEqual(expected, quota_usages.usages) # Compare available resources self.assertAvailableQuotasEqual(expected, quota_usages.usages)
def allowed(self, request, fip=None): usages = quotas.tenant_quota_usages(request, targets=('floatingip', )) if usages['floatingip']['available'] <= 0: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ', _("(Quota exceeded)")) else: self.verbose_name = _("Allocate IP To Project") classes = [c for c in self.classes if c != "disabled"] self.classes = classes policy_rules = (("network", "create_floatingip"), ) return policy.check(policy_rules, request)
def test_network_detail(self, mac_learning=False): network_id = self.networks.first().id quota_data = self.neutron_quota_usages.first() api.neutron.network_get(IsA(http.HttpRequest), network_id) \ .MultipleTimes().AndReturn(self.networks.first()) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning') \ .AndReturn(mac_learning) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() url = urlunquote( reverse('horizon:project:networks:detail', args=[network_id])) res = self.client.get(url) network = res.context['network'] self.assertEqual(self.networks.first().name_or_id, network.name_or_id) self.assertEqual(self.networks.first().status_label, network.status_label) self.assertTemplateUsed(res, 'horizon/common/_detail.html')
def _test_new_button_disabled_when_quota_exceeded(self, expected_string, networks_quota=10, routers_quota=10, instances_quota=10): quota_data = self.quota_usages.first() quota_data['networks']['available'] = networks_quota quota_data['routers']['available'] = routers_quota quota_data['instances']['available'] = instances_quota quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'project/network_topology/index.html') self.assertContains(res, expected_string, html=True, msg_prefix="The create button is not disabled")
def test_usage_csv(self): now = timezone.now() usage_obj = api.nova.NovaUsage(self.usages.first()) quota_data = self.quota_usages.first() api.keystone.tenant_list(IsA(http.HttpRequest), admin=True) \ .AndReturn(self.tenants.list()) api.usage_list(IsA(http.HttpRequest), datetime.datetime(now.year, now.month, 1, 0, 0, 0), Func(usage.almost_now)) \ .AndReturn([usage_obj, usage_obj]) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(quota_data) self.mox.ReplayAll() csv_url = reverse('horizon:admin:overview:index') + "?format=csv" res = self.client.get(csv_url) self.assertTemplateUsed(res, 'admin/overview/usage.csv') self.assertTrue(isinstance(res.context['usage'], usage.GlobalUsage)) hdr = 'Tenant,VCPUs,RamMB,DiskGB,Usage(Hours)' row = '%s,%s,%s,%s,%.2f' % (usage_obj.tenant_id, usage_obj.vcpus, usage_obj.memory_mb, usage_obj.disk_gb_hours, usage_obj.vcpu_hours) self.assertContains(res, '%s\n%s\n%s\n' % (hdr, row, row))
def allowed(self, request, keypair=None): usages = quotas.tenant_quota_usages(request) count = len(self.table.data) if (usages.get('key_pairs') and usages['key_pairs']['quota'] <= count): if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ', _("(Quota exceeded)")) else: self.verbose_name = _("Create Key Pair") classes = [c for c in self.classes if c != "disabled"] self.classes = classes return True
def test_usage_csv(self): now = timezone.now() usage_obj = [api.nova.NovaUsage(u) for u in self.usages.list()] quota_data = self.quota_usages.first() api.keystone.tenant_list(IsA(http.HttpRequest)) \ .AndReturn(self.tenants.list()) api.nova.usage_list(IsA(http.HttpRequest), datetime.datetime(now.year, now.month, 1, 0, 0, 0), Func(usage.almost_now)) \ .AndReturn(usage_obj) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(quota_data) self.mox.ReplayAll() csv_url = reverse('horizon:admin:overview:index') + "?format=csv" res = self.client.get(csv_url) self.assertTemplateUsed(res, 'admin/overview/usage.csv') self.assertTrue(isinstance(res.context['usage'], usage.GlobalUsage)) hdr = 'Project Name,VCPUs,Ram (MB),Disk (GB),Usage (Hours)' self.assertContains(res, '%s\r\n' % (hdr)) for obj in usage_obj: row = u'{0},{1},{2},{3},{4:.2f}\r\n'.format( obj.project_name, obj.vcpus, obj.memory_mb, obj.disk_gb_hours, obj.vcpu_hours) self.assertContains(res, row)
def _check_quotas(self, cleaned_data): count = cleaned_data.get('count', 1) # Prevent launching more instances than the quota allows usages = quotas.tenant_quota_usages(self.request) available_count = usages['instances']['available'] if available_count < count: error_message = ungettext_lazy( 'The requested instance cannot be launched as you only ' 'have %(avail)i of your quota available. ', 'The requested %(req)i instances cannot be launched as you ' 'only have %(avail)i of your quota available.', count) params = {'req': count, 'avail': available_count} raise forms.ValidationError(error_message % params) # change by zhihao.ding 2015/7/16 for kill_flavor start #flavor_id = cleaned_data.get('flavor') #flavor = self._get_flavor(flavor_id) vcpus = int(cleaned_data.get('vcpus')) ram = int(cleaned_data.get('memory_mb')) count_error = [] # Validate cores and ram. available_cores = usages['cores']['available'] #if flavor and available_cores < count * flavor.vcpus: if vcpus and available_cores < count * vcpus: count_error.append( _("Cores(Available: %(avail)s, " "Requested: %(req)s)") % { 'avail': available_cores, 'req': count * vcpus }) available_ram = usages['ram']['available'] #if flavor and available_ram < count * flavor.ram: if ram and available_ram < count * ram: count_error.append( _("RAM(Available: %(avail)s, " "Requested: %(req)s)") % { 'avail': available_ram, 'req': count * ram }) # change by zhihao.ding 2015/7/16 for kill_flavor end if count_error: value_str = ", ".join(count_error) msg = (_('The requested instance cannot be launched. ' 'The following requested resource(s) exceed ' 'quota(s): %s.') % value_str) self._errors['count'] = self.error_class([msg])
def _test_network_detail_ip_availability_exception(self, mac_learning=False): network = self.networks.first() quota_data = self.neutron_quota_usages.first() api.neutron.is_extension_supported(IsA( http.HttpRequest), 'network-ip-availability').AndReturn(True) api.neutron.show_network_ip_availability(IsA(http.HttpRequest), network.id).\ MultipleTimes().AndRaise(self.exceptions.neutron) api.neutron.network_get(IsA(http.HttpRequest), network.id).\ MultipleTimes().AndReturn(self.networks.first()) api.neutron.subnet_list(IsA(http.HttpRequest), network_id=network.id).\ AndReturn([self.subnets.first()]) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning') \ .AndReturn(mac_learning) api.neutron.is_extension_supported(IsA( http.HttpRequest), 'network-ip-availability').AndReturn(True) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'network_availability_zone')\ .MultipleTimes().AndReturn(True) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'dhcp_agent_scheduler')\ .MultipleTimes().AndReturn(True) quotas.tenant_quota_usages( IsA(http.HttpRequest), tenant_id=network.tenant_id, targets=('subnets', )).MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() from django.utils.http import urlunquote url = urlunquote( reverse('horizon:admin:networks:subnets_tab', args=[network.id])) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') subnets = res.context['subnets_table'].data self.assertItemsEqual(subnets, [self.subnets.first()])
def test_create_volume_from_snapshot(self): volume = self.volumes.first() usage = {'gigabytes': {'available': 250}, 'volumes': {'available': 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()) quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage) 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_launch_flavorlist_error(self): cinder.volume_list(IsA(http.HttpRequest)) \ .AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest)) \ .AndReturn(self.volumes.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]) api.quantum.network_list(IsA(http.HttpRequest), tenant_id=self.tenant.id, shared=False) \ .AndReturn(self.networks.list()[:1]) api.quantum.network_list(IsA(http.HttpRequest), shared=True) \ .AndReturn(self.networks.list()[1:]) quotas.tenant_quota_usages(IsA(http.HttpRequest)) \ .AndReturn(self.quota_usages.first()) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndRaise(self.exceptions.nova) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndRaise(self.exceptions.nova) api.nova.keypair_list(IsA(http.HttpRequest)) \ .AndReturn(self.keypairs.list()) api.nova.security_group_list(IsA(http.HttpRequest)) \ .AndReturn(self.security_groups.list()) self.mox.ReplayAll() url = reverse('horizon:project:instances:launch') res = self.client.get(url) self.assertTemplateUsed(res, 'project/instances/launch.html')
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.volume_snapshot_list(IsA(http.HttpRequest))\ .AndReturn(self.cinder_volume_snapshots.list()) cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) cinder.volume_backup_list(IsA(http.HttpRequest)).\ AndReturn(self.cinder_volume_backups.list()) cinder.volume_list(IsA(http.HttpRequest)).\ AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().\ AndReturn(self.quota_usages.first()) 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_router_with_interface_delete(self): router = self.routers.first() ports = self.ports.list() quota_data = self.neutron_quota_usages.first() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id).AndReturn( self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest), targets=['routers']) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id).AndReturn( self.routers.list()) self._mock_external_network_list() api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id).AndReturn( self.routers.list()) self._mock_external_network_list() api.neutron.port_list(IsA(http.HttpRequest), device_id=router.id, device_owner=IgnoreArg())\ .AndReturn(ports) for port in ports: api.neutron.router_remove_interface(IsA(http.HttpRequest), router.id, port_id=port.id) api.neutron.router_delete(IsA(http.HttpRequest), router.id) self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) formData = {'action': 'routers__delete__' + router.id} res = self.client.post(self.INDEX_URL, formData, follow=True) self.assertNoFormErrors(res) self.assertMessageCount(response=res, success=1) self.assertIn('Deleted Router: ' + router.name, res.content.decode('utf-8'))
def test_delete_volume_backup(self): vol_backups = self.cinder_volume_backups.list() volumes = self.cinder_volumes.list() backup = self.cinder_volume_backups.first() api.cinder.volume_backup_supported(IsA(http.HttpRequest)). \ MultipleTimes().AndReturn(True) api.cinder.volume_backup_list(IsA(http.HttpRequest)). \ AndReturn(vol_backups) api.cinder.volume_list(IsA(http.HttpRequest)). \ AndReturn(volumes) api.cinder.volume_backup_delete(IsA(http.HttpRequest), backup.id) api.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]) api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \ AndReturn([]) api.cinder.volume_list(IsA(http.HttpRequest)). \ AndReturn(volumes) api.cinder.volume_backup_list(IsA(http.HttpRequest)). \ AndReturn(vol_backups) api.cinder.volume_list(IsA(http.HttpRequest)). \ AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes(). \ AndReturn(self.quota_usages.first()) self.mox.ReplayAll() formData = {'action': 'volume_backups__delete__%s' % backup.id} res = self.client.post(INDEX_URL + "?tab=volumes_and_snapshots__backups_tab", formData, follow=True) self.assertIn("Scheduled deletion of Volume Backup: backup1", [m.message for m in res.context['messages']])
def test_tenant_quota_usages_without_volume(self): quotas.is_service_enabled(IsA(http.HttpRequest), 'volume').AndReturn(False) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.quotas.first()) api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \ .AndReturn(self.floating_ips.list()) api.nova.server_list(IsA(http.HttpRequest)) \ .AndReturn(self.servers.list()) self.mox.ReplayAll() quota_usages = quotas.tenant_quota_usages(self.request) expected_output = { 'injected_file_content_bytes': { 'quota': 1 }, 'metadata_items': { 'quota': 1 }, 'injected_files': { 'quota': 1 }, 'ram': { 'available': 8976, 'used': 1024, 'quota': 10000 }, 'floating_ips': { 'available': 0, 'used': 2, 'quota': 1 }, 'instances': { 'available': 8, 'used': 2, 'quota': 10 }, 'cores': { 'available': 8, 'used': 2, 'quota': 10 } } # Compare internal structure of usages to expected. self.assertEquals(quota_usages.usages, expected_output)
def _test_tenant_quota_usages(self, nova_quotas_enabled=True, with_compute=True, with_volume=True): cinder.is_volume_service_enabled(IsA(http.HttpRequest)).AndReturn( with_volume) api.base.is_service_enabled(IsA(http.HttpRequest), 'network').AndReturn(False) api.base.is_service_enabled( IsA(http.HttpRequest), 'compute' ).MultipleTimes().AndReturn(with_compute) if with_compute: servers = [s for s in self.servers.list() if s.tenant_id == self.request.user.tenant_id] api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) api.network.floating_ip_supported(IsA(http.HttpRequest)) \ .AndReturn(True) api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ .AndReturn(self.floating_ips.list()) search_opts = {'tenant_id': self.request.user.tenant_id} api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ .AndReturn([servers, False]) if nova_quotas_enabled: api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.quotas.first()) if with_volume: opts = {'all_tenants': 1, 'project_id': self.request.user.tenant_id} cinder.volume_list(IsA(http.HttpRequest), opts) \ .AndReturn(self.volumes.list()) cinder.volume_snapshot_list(IsA(http.HttpRequest), opts) \ .AndReturn(self.cinder_volume_snapshots.list()) cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \ .AndReturn(self.cinder_quotas.first()) self.mox.ReplayAll() quota_usages = quotas.tenant_quota_usages(self.request) expected_output = self.get_usages( nova_quotas_enabled=nova_quotas_enabled, with_volume=with_volume, with_compute=with_compute) # Compare internal structure of usages to expected. self.assertItemsEqual(expected_output, quota_usages.usages) # Compare available resources self.assertAvailableQuotasEqual(expected_output, quota_usages.usages)
def _test_create_button_disabled_when_quota_exceeded( self, network_enabled): sec_groups = self.security_groups.list() quota_data = self.quota_usages.first() quota_data['security_groups']['available'] = 0 api.neutron.security_group_list( IsA(http.HttpRequest)) \ .AndReturn(sec_groups) quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) self.mox.ReplayAll() res = self.client.get(INDEX_URL) security_groups = res.context['security_groups_table'].data self.assertItemsEqual(security_groups, self.security_groups.list()) create_action = self.getAndAssertTableAction(res, 'security_groups', 'create') self.assertIn('disabled', create_action.classes, 'The create button should be disabled')
def test_create_button_disabled_when_quota_exceeded(self): quota_usages = self.quota_usages.first() quota_usages['volumes']['available'] = 0 volumes = self.volumes.list() 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.volume_snapshot_list(IsA(http.HttpRequest))\ .AndReturn(self.volume_snapshots.list()) cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes) quotas.tenant_quota_usages(IsA(http.HttpRequest))\ .MultipleTimes().AndReturn(quota_usages) self.mox.ReplayAll() res = self.client.get(reverse('horizon:project:volumes:index')) self.assertTemplateUsed(res, 'project/volumes/index.html') volumes = res.context['volumes_table'].data self.assertItemsEqual(volumes, self.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'>%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_subnets_tab_port_exception(self, mac_learning=False): network_id = self.networks.first().id quota_data = self.neutron_quota_usages.first() quota_data['subnets']['available'] = 5 api.neutron.network_get(IsA(http.HttpRequest), network_id).\ AndReturn(self.networks.first()) api.neutron.subnet_list(IsA(http.HttpRequest), network_id=network_id).\ AndReturn([self.subnets.first()]) api.neutron.network_get(IsA(http.HttpRequest), network_id).\ AndReturn(self.networks.first()) api.neutron.is_extension_supported(IsA(http.HttpRequest), 'mac-learning')\ .AndReturn(mac_learning) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self.mox.ReplayAll() url = urlunquote( reverse('horizon:project:networks:subnets_tab', args=[network_id])) res = self.client.get(url) self.assertTemplateUsed(res, 'horizon/common/_detail.html') subnets = res.context['subnets_table'].data self.assertItemsEqual(subnets, [self.subnets.first()])
def allowed(self, request, volume=None): usages = quotas.tenant_quota_usages(request, targets=('volumes', 'gigabytes')) gb_available = usages['gigabytes']['available'] volumes_available = usages['volumes']['available'] if gb_available <= 0 or volumes_available <= 0: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ', _("(Quota exceeded)")) else: self.verbose_name = _("Accept Transfer") classes = [c for c in self.classes if c != "disabled"] self.classes = classes return True
def test_allocate_button_attributes(self): floating_ips = self.floating_ips.list() floating_pools = self.pools.list() quota_data = self.quota_usages.first() quota_data['floating_ips']['available'] = 10 api.network.tenant_floating_ip_list( IsA(http.HttpRequest)) \ .AndReturn(floating_ips) api.network.floating_ip_pools_list( IsA(http.HttpRequest)) \ .AndReturn(floating_pools) api.nova.server_list( IsA(http.HttpRequest), detailed=False) \ .AndReturn([self.servers.list(), False]) quotas.tenant_quota_usages( IsA(http.HttpRequest)).MultipleTimes() \ .AndReturn(quota_data) api.base.is_service_enabled( IsA(http.HttpRequest), 'network').MultipleTimes() \ .AndReturn(True) self.mox.ReplayAll() res = self.client.get(INDEX_URL) allocate_action = self.getAndAssertTableAction(res, 'floating_ips', 'allocate') self.assertEqual(set(['ajax-modal']), set(allocate_action.classes)) self.assertEqual('Allocate IP To Project', six.text_type(allocate_action.verbose_name)) self.assertIsNone(allocate_action.policy_rules) url = 'horizon:project:floating_ips:allocate' self.assertEqual(url, allocate_action.url)
def allowed(self, request, security_group=None): usages = quotas.tenant_quota_usages(request) if usages['security_groups'].get('available', 1) <= 0: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ["disabled"] self.verbose_name = _("Create Security Group (Quota exceeded)") else: self.verbose_name = _("Create Security Group") self.classes = [c for c in self.classes if c != "disabled"] if not api.base.is_service_enabled(request, "network"): policy_rules = (("compute", "compute_extension:security_groups"),) return policy.check(policy_rules, request, target={}) return True
def test_create_button_disabled_when_quota_exceeded(self): quota_data = self.neutron_quota_usages.first() quota_data['routers']['available'] = 0 api.neutron.router_list(IsA(http.HttpRequest), tenant_id=self.tenant.id).AndReturn( self.routers.list()) quotas.tenant_quota_usages( IsA(http.HttpRequest)) \ .MultipleTimes().AndReturn(quota_data) self._mock_external_network_list() self.mox.ReplayAll() res = self.client.get(self.INDEX_URL) self.assertTemplateUsed(res, 'project/routers/index.html') routers = res.context['routers_table'].data self.assertItemsEqual(routers, self.routers.list()) create_action = self.getAndAssertTableAction(res, 'routers', 'create') self.assertIn('disabled', create_action.classes, 'Create button is not disabled') self.assertEqual('Create Router (Quota exceeded)', create_action.verbose_name)