def test_list_image_error_private_image_list(self): public_images = [image for image in self.images.list() if image.status == "active" and image.is_public] private_images = [image for image in self.images.list() if (image.status == "active" and not image.is_public)] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"is_public": True, "status": "active"} ).AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": self.tenant.id, "status": "active"} ).AndRaise(self.exceptions.glance) exceptions.handle(IsA(http.HttpRequest), "Unable to retrieve images for the current project.") api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": self.tenant.id, "status": "active"} ).AndReturn([private_images, False, False]) self.mox.ReplayAll() images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in public_images if image.container_format not in ("ami", "aki")] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache["public_images"])) self.assertFalse(len(images_cache["images_by_project"])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in self.images.list() if image.container_format not in ("ami", "aki")] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache["public_images"])) self.assertEqual(1, len(images_cache["images_by_project"])) self.assertEqual(len(private_images), len(images_cache["images_by_project"][self.tenant.id]))
def test_list_image_communication_error_public_image_list(self): public_images = [image for image in self.images.list() if image.status == "active" and image.is_public] private_images = [image for image in self.images.list() if (image.status == "active" and not image.is_public)] api.glance.image_list_detailed(IsA(http.HttpRequest), filters={"is_public": True, "status": "active"}).AndRaise( glance_exec.CommunicationError ) # Make sure the exception is handled with the correct # error message. If the exception cannot be handled, # the error message will be different. messages.error(IsA(http.HttpRequest), "Unable to retrieve public images.") api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": self.tenant.id, "status": "active"} ).AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"is_public": True, "status": "active"} ).AndReturn([public_images, False, False]) self.mox.ReplayAll() images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in private_images if image.container_format not in ("ami", "aki")] self.assertEqual(len(expected_images), len(ret)) self.assertNotIn("public_images", images_cache) self.assertEqual(1, len(images_cache["images_by_project"])) self.assertEqual(len(private_images), len(images_cache["images_by_project"][self.tenant.id])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in self.images.list() if image.container_format not in ("ami", "aki")] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache["public_images"])) self.assertEqual(1, len(images_cache["images_by_project"])) self.assertEqual(len(private_images), len(images_cache["images_by_project"][self.tenant.id]))
def test_list_image_using_cache(self): public_images = [image for image in self.images.list() if image.status == 'active' and image.is_public] private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': 'other-tenant', 'status': 'active'}) \ .AndReturn([private_images, False, False]) self.mox.ReplayAll() expected_images = [image for image in self.images.list() if (image.status == 'active' and image.container_format not in ('ari', 'aki'))] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual( len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) # image list for other-tenant ret = utils.get_available_images(self.request, 'other-tenant', images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual( len(public_images), len(images_cache['public_images'])) self.assertEqual(2, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project']['other-tenant']))
def test_list_image_error_public_image_list(self): public_images = [image for image in self.images.list() if image.status == 'active' and image.is_public] private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndRaise(self.exceptions.glance) exceptions.handle(IsA(http.HttpRequest), "Unable to retrieve public images.") api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False, False]) self.mox.ReplayAll() images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in private_images if image.container_format not in ('ami', 'aki')] self.assertEqual(len(expected_images), len(ret)) self.assertNotIn('public_images', images_cache) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [image for image in self.images.list() if image.container_format not in ('ami', 'aki')] self.assertEqual(len(expected_images), len(ret)) self.assertEqual( len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id]))
def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = quotas.tenant_quota_usages( self.request, targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')) extra['usages_json'] = json.dumps(extra['usages']) extra['cinder_enabled'] = \ base.is_service_enabled(self.request, 'volume') flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size)} for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def test_list_image(self): public_images = [image for image in self.images.list() if image.status == 'active' and image.is_public] private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] shared_images = [image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared')] self.mock_image_list.side_effect = [ [public_images, False, False], [private_images, False, False], [shared_images, False, False] ] image_calls = [ mock.call(test.IsHttpRequest(), filters={'is_public': True, 'status': 'active'}), mock.call(test.IsHttpRequest(), filters={'property-owner_id': self.tenant.id, 'status': 'active'}), mock.call(test.IsHttpRequest(), filters={'visibility': 'shared', 'status': 'active'}) ] ret = utils.get_available_images(self.request, self.tenant.id) expected_images = [image for image in self.images.list() if (image.status == 'active' and image.container_format not in ('ami', 'aki'))] self.mock_image_list.assert_has_calls(image_calls) self.assertEqual(len(expected_images), len(ret))
def __init__(self, request, *args, **kwargs): super(RebuildInstanceForm, self).__init__(request, *args, **kwargs) instance_id = kwargs.get('initial', {}).get('instance_id') self.fields['instance_id'].initial = instance_id images = utils.get_available_images(request, request.user.tenant_id) choices = [(image.id, image) for image in images] if choices: choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) self.fields['image'].choices = choices if not api.nova.can_set_server_password(): del self.fields['password'] del self.fields['confirm_password'] try: if not api.nova.extension_supported("DiskConfig", request): del self.fields['disk_config'] else: # Set our disk_config choices config_choices = [("AUTO", _("Automatic")), ("MANUAL", _("Manual"))] self.fields['disk_config'].choices = config_choices except Exception: exceptions.handle(request, _('Unable to retrieve extensions ' 'information.'))
def get_data(self): token = self.request.user.token.id headers = {} headers['Accept'] = 'application/json' headers['X-Auth-Token'] = token graffiti_url = getattr(settings, 'GRAFFITI_URL', '') req = urllib2.Request(graffiti_url + "resource?query_string={%22resource_types%22%20:%20[%22OS::Glance::Image%22,%22OS::Glance::Snapshot%22]}", headers=headers) f = urllib2.urlopen(req) resources = json.loads(f.read()) f.close() boot_images = image_utils.get_available_images(self.request, self.request.user.project_id) boot_images_ids = [] for image in boot_images: boot_images_ids.append(image.id) boot_resources = [] for resource in resources: if resource['id'] in boot_images_ids: boot_resources.append(resource) req = urllib2.Request(graffiti_url + "resource?query_string={%22resource_types%22%20:%20[%22OS::Cinder::Volume%22,%22OS::Cinder::VolumeSnapshot%22]}", headers=headers) f = urllib2.urlopen(req) resources = json.loads(f.read()) f.close() for resource in resources: volume = api.cinder.volume_get(self.request, resource['id']) if volume._apiresource.bootable: boot_resources.append(resource) return boot_resources
def populate_image_id_choices(self, request, context): choices = [] image_dict = {} #images = image_utils.get_available_images(request, # context.get('zone_id'), # images_cache=self._images_cache) try: zones = api.proxy.availability_zone_list(request) except: zones = [] exceptions.handle(request, _('Unable to retrieve zones.'), ignore=True) for zone in zones: images = image_utils.get_available_images( request, zone.id, images_cache=self._images_cache) for image in images: image_dict[image.name] = image for image in image_dict.values(): image.bytes = image.size image.volume_size = max( image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.imageid, image)) if choices: choices.sort(key=lambda c: c[1].name) choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def __init__(self, request, *args, **kwargs): super(RescueInstanceForm, self).__init__(request, *args, **kwargs) images = image_utils.get_available_images(request, request.user.tenant_id) choices = [(image.id, image) for image in images] if not choices: choices.insert(0, ("", _("No images available"))) self.fields['image'].choices = choices
def populate_instance_snapshot_id_choices(self, request, context): images = image_utils.get_available_images(request, context.get("project_id"), self._images_cache) choices = [(image.id, image.name) for image in images if image.properties.get("image_type", "") == "snapshot"] if choices: choices.sort(key=operator.itemgetter(1)) choices.insert(0, ("", _("Select Instance Snapshot"))) else: choices.insert(0, ("", _("No snapshots available"))) return choices
def __init__(self, request, *args, **kwargs): super(RebuildForm, self).__init__(request, *args, **kwargs) images = utils.get_available_images(request, request.user.tenant_id) choices = [(image.id, image) for image in images] if choices: choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) self.fields['image'].choices = choices
def update(self, request, **kwargs): try: images = image_utils.get_available_images(request, request.user.tenant_id, None) except Exception: images = [] exceptions.handle(request, _("Unable to retrieve volume types.")) choices = [(image.id, image.name) for image in images] if not choices: choices.insert(0, ("", _("No images available"))) self.choices = choices
def _get_image(self, image_id): try: # We want to retrieve details for a given image, # however get_available_images uses a cache of image list, # so it is used instead of image_get to reduce the number # of API calls. images = image_utils.get_available_images(self.request, self.context.get("project_id"), self._images_cache) image = [x for x in images if x.id == image_id][0] except IndexError: image = None return image
def get_data(self): zones = [] image_dict = {} instances = [] try: instances = api.proxy.server_list(self.request) except: servers = [] exceptions.handle(self.request, _('Unable to retrieve instances.'), ignore=True) try: for zone in api.proxy.availability_zone_list(self.request, True): zones.append(zone) try: images = SortedDict([(image.imageid, image) for image in image_utils.get_available_images(self.request, zone.id)]) except: images = {} image_dict.update(images) except: zones = [] exceptions.handle(self.request, _('Unable to retrieve zones.'), ignore=True) # zone_dict = SortedDict([(zone.id, zone.name) for zone in zones]) # # gateway_dict = SortedDict([(g.hostname, g.ext_ip) # for g in api.proxy.gateway_list(self.request)]) for instance in instances: # if zone_dict.has_key(instance.availability_zone): # instance.availability_zone = zone_dict[instance.availability_zone] image = image_dict.get(instance.image_id) if image: instance.image_name = image.name if image.container_format == 'docker': instance.instance_type = 'Docker' instance.image_name += '(Container)' else: instance.instance_type = 'VM' instance.image_name += '(VM)' else: instance.image_name = instance.image_id # firewall = [(gateway_dict.get(f.hostname), f.gateway_port) for f in # api.proxy.firewall_get(self.request, instance.id)] # if firewall: # instance.gateway = '%s:%s' % firewall[0] # else: # instance.gateway= '' return instances
def __init__(self, request, *args, **kwargs): super(LaunchInstance, self).__init__(request, *args, **kwargs) images = imageutils.get_available_images( request, request.user.tenant_id) choices = [(image.id, image) for image in images] if choices: choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) zones = self._availability_zone_choices(request) self.fields['image'].choices = choices self.fields['availability_zone'].choices = zones self.fields['flavor'].choices = self._flavor_choices(request)
def get_images(request): _images = [] _type = {"docker": "container", "container": "container"} for zone in get_zones(request): images = image_utils.get_available_images(request, zone.id) for image in images: _images.append({'id': image.imageid, 'name': image.name, 'type': image.display_format, 'category': _type.get(image.container_format, 'vm'), 'class': image.display_format, 'dc_id': zone.id, 'dc_name': zone.name}) return _images
def _get_image(self, image_id): try: # We want to retrieve details for a given image, # however get_available_images uses a cache of image list, # so it is used instead of image_get to reduce the number # of API calls. images = image_utils.get_available_images( self.request, self.context.get('project_id'), self._images_cache) image = [x for x in images if x.id == image_id][0] except IndexError: image = None return image
def populate_instance_snapshot_id_choices(self, request, context): images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) choices = [(image.id, image.name) for image in images if image.properties.get("image_type", '') == "snapshot"] if choices: choices.sort(key=operator.itemgetter(1)) choices.insert(0, ("", _("Select Instance Snapshot"))) else: choices.insert(0, ("", _("No snapshots available"))) return choices
def prepare_source_fields_default(self, request): source_type_choices = [] self.fields['availability_zone'].choices = \ self.availability_zones(request) try: snapshot_list = cinder.volume_snapshot_list(request) snapshots = [s for s in snapshot_list if s.status == 'available'] if snapshots: source_type_choices.append(("snapshot_source", _("Snapshot"))) choices = [('', _("Choose a snapshot"))] + \ [(s.id, s) for s in snapshots] self.fields['snapshot_source'].choices = choices else: del self.fields['snapshot_source'] except Exception: exceptions.handle(request, _("Unable to retrieve volume snapshots.")) images = utils.get_available_images(request, request.user.tenant_id) if images: source_type_choices.append(("image_source", _("Image"))) choices = [('', _("Choose an image"))] for image in images: image.bytes = image.size image.size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) self.fields['image_source'].choices = choices else: del self.fields['image_source'] volumes = self.get_volumes(request) if volumes: source_type_choices.append(("volume_source", _("Volume"))) choices = [('', _("Choose a volume"))] for volume in volumes: choices.append((volume.id, volume)) self.fields['volume_source'].choices = choices else: del self.fields['volume_source'] if source_type_choices: choices = ([('no_source_type', _("No source, empty volume"))] + source_type_choices) self.fields['volume_source_type'].choices = choices else: del self.fields['volume_source_type']
def prepare_source_fields_default(self, request): source_type_choices = [] self.fields['availability_zone'].choices = \ availability_zones(request) try: available = api.cinder.VOLUME_STATE_AVAILABLE snapshots = cinder.volume_snapshot_list( request, search_opts=dict(status=available)) if snapshots: source_type_choices.append(("snapshot_source", _("Snapshot"))) choices = [('', _("Choose a snapshot"))] + \ [(s.id, s) for s in snapshots] self.fields['snapshot_source'].choices = choices else: del self.fields['snapshot_source'] except Exception: exceptions.handle(request, _("Unable to retrieve volume snapshots.")) images = utils.get_available_images(request, request.user.tenant_id) if images: source_type_choices.append(("image_source", _("Image"))) choices = [('', _("Choose an image"))] for image in images: image.bytes = image.size image.size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) self.fields['image_source'].choices = choices else: del self.fields['image_source'] volumes = self.get_volumes(request) if volumes: source_type_choices.append(("volume_source", _("Volume"))) choices = [('', _("Choose a volume"))] for volume in volumes: choices.append((volume.id, volume)) self.fields['volume_source'].choices = choices else: del self.fields['volume_source'] if source_type_choices: choices = ([('no_source_type', _("No source, empty volume"))] + source_type_choices) self.fields['volume_source_type'].choices = choices else: del self.fields['volume_source_type']
def test_list_image_error_public_image_list(self, mock_exception_handle): private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] community_images = [image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'community')] shared_images = [image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared')] self.mock_image_list.side_effect = [ self.exceptions.glance, [private_images, False, False], [community_images, False, False], [shared_images, False, False] ] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) image_calls = [ mock.call(test.IsHttpRequest(), filters={'is_public': True, 'status': 'active'}), mock.call(test.IsHttpRequest(), filters={'status': 'active', 'property-owner_id': '1'}), mock.call(test.IsHttpRequest(), filters={'visibility': 'community', 'status': 'active'}), mock.call(test.IsHttpRequest(), filters={'visibility': 'shared', 'status': 'active'}) ] self.mock_image_list.assert_has_calls(image_calls) mock_exception_handle.assert_called_once_with( test.IsHttpRequest(), "Unable to retrieve public images.") expected_images = [image for image in private_images if image.container_format not in ('ami', 'aki')] self.assertEqual(len(expected_images), len(ret)) self.assertNotIn('public_images', images_cache) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual( len(community_images), len(images_cache['community_images'])) self.assertEqual( len(shared_images), len(images_cache['shared_images']))
def test_list_image_using_cache(self): public_images = [image for image in self.images.list() if image.status == "active" and image.is_public] private_images = [image for image in self.images.list() if (image.status == "active" and not image.is_public)] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"is_public": True, "status": "active"} ).AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": self.tenant.id, "status": "active"} ).AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": "other-tenant", "status": "active"} ).AndReturn([private_images, False, False]) self.mox.ReplayAll() expected_images = [ image for image in self.images.list() if (image.status == "active" and image.container_format not in ("ari", "aki")) ] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache["public_images"])) self.assertEqual(1, len(images_cache["images_by_project"])) self.assertEqual(len(private_images), len(images_cache["images_by_project"][self.tenant.id])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) # image list for other-tenant ret = utils.get_available_images(self.request, "other-tenant", images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache["public_images"])) self.assertEqual(2, len(images_cache["images_by_project"])) self.assertEqual(len(private_images), len(images_cache["images_by_project"]["other-tenant"]))
def populate_image_id_choices(self, request, context): choices = [] images = utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: image.bytes = image.size image.volume_size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) if choices: choices.sort(key=lambda c: c[1].name) choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get("project_id"), self._images_cache) for image in images: image.bytes = getattr(image, "virtual_size", None) or image.size image.volume_size = max(image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.id, image)) if context.get("image_id") == image.id and "volume_size" not in context: context["volume_size"] = image.volume_size if choices: choices.sort(key=lambda c: c[1].name or "") choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def __init__(self, request, *args, **kwargs): super(RebuildInstanceForm, self).__init__(request, *args, **kwargs) instance_id = kwargs.get('initial', {}).get('instance_id') self.fields['instance_id'].initial = instance_id images = utils.get_available_images(request, request.user.tenant_id) choices = [(image.id, image) for image in images] if choices: choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) self.fields['image'].choices = choices if not api.nova.can_set_server_password(): del self.fields['password'] del self.fields['confirm_password']
def populate_image_id_choices(self, request, context): choices = [] images = utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: image.bytes = image.size image.volume_size = functions.bytes_to_gigabytes(image.bytes) img_attr = image.properties.get(IMG_ATTR, None) if img_attr is not None: choices.append((image.id, image)) if choices: choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def test_list_image(self): public_images = [ image for image in self.images.list() if image.status == 'active' and image.is_public ] private_images = [ image for image in self.images.list() if (image.status == 'active' and not image.is_public) ] shared_images = [ image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared') ] self.mock_image_list.side_effect = [[public_images, False, False], [private_images, False, False], [shared_images, False, False]] image_calls = [ mock.call(test.IsHttpRequest(), filters={ 'is_public': True, 'status': 'active' }), mock.call(test.IsHttpRequest(), filters={ 'property-owner_id': self.tenant.id, 'status': 'active' }), mock.call(test.IsHttpRequest(), filters={ 'visibility': 'shared', 'status': 'active' }) ] ret = utils.get_available_images(self.request, self.tenant.id) expected_images = [ image for image in self.images.list() if (image.status == 'active' and image.container_format not in ( 'ami', 'aki')) ] self.mock_image_list.assert_has_calls(image_calls) self.assertEqual(len(expected_images), len(ret))
def get_help_text(self, extra_context=None): extra = extra_context or {} try: extra["usages"] = api.nova.tenant_absolute_limits(self.request) extra["usages_json"] = json.dumps(extra["usages"]) flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) extra["flavors"] = flavors images = image_utils.get_available_images(self.request, self.initial["project_id"], self._images_cache) if images is not None: attrs = [ {"id": i.id, "min_disk": getattr(i, "min_disk", 0), "min_ram": getattr(i, "min_ram", 0)} for i in images ] extra["images"] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = api.nova.tenant_absolute_limits(self.request) for quota in cinder.tenant_quota_get(self.request, self.request.user.tenant_id): if quota.name == 'gigabytes_Tier1': extra['usages']['maxTotalTier1Size'] = quota.limit totalTier1Used = 0 volumes = [] # needed later for getting snapshot type for volume in cinder.volume_list(self.request): if volume.volume_type == 'Tier1': volumes.append(volume.id) totalTier1Used += volume.size for snapshot in cinder.volume_snapshot_list(self.request): if snapshot.volume_id in volumes: totalTier1Used += snapshot.size extra['usages']['totalTier1Used'] = totalTier1Used extra['usages_json'] = json.dumps(extra['usages']) flavors = json.dumps( [f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{ 'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size) } for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: image.bytes = getattr(image, 'virtual_size', None) or image.size image.volume_size = max(image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.id, image)) if context.get('image_id') == image.id and \ 'volume_size' not in context: context['volume_size'] = image.volume_size if choices: choices.sort(key=lambda c: c[1].name or '') choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def test_list_image_error_public_image_list(self, mock_exception_handle): private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] shared_images = [image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared')] self.mock_image_list.side_effect = [ self.exceptions.glance, [private_images, False, False], [shared_images, False, False], ] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) image_calls = [ mock.call(test.IsHttpRequest(), filters={'is_public': True, 'status': 'active'}), mock.call(test.IsHttpRequest(), filters={'status': 'active', 'property-owner_id': '1'}), mock.call(test.IsHttpRequest(), filters={'visibility': 'shared', 'status': 'active'}) ] self.mock_image_list.assert_has_calls(image_calls) handle_calls = [ mock.call(test.IsHttpRequest(), "Unable to retrieve public images."), ] mock_exception_handle.assert_has_calls(handle_calls) expected_images = [image for image in private_images if image.container_format not in ('ami', 'aki')] self.assertEqual(len(expected_images), len(ret)) self.assertNotIn('public_images', images_cache) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual( len(shared_images), len(images_cache['shared_images']))
def prepare_source_fields_default(self, request): source_type_choices = [] self.fields["availability_zone"].choices = self.availability_zones(request) try: available = api.cinder.VOLUME_STATE_AVAILABLE snapshots = cinder.volume_snapshot_list(request, search_opts=dict(status=available)) if snapshots: source_type_choices.append(("snapshot_source", _("Snapshot"))) choices = [("", _("Choose a snapshot"))] + [(s.id, s) for s in snapshots] self.fields["snapshot_source"].choices = choices else: del self.fields["snapshot_source"] except Exception: exceptions.handle(request, _("Unable to retrieve volume snapshots.")) images = utils.get_available_images(request, request.user.tenant_id) if images: source_type_choices.append(("image_source", _("Image"))) choices = [("", _("Choose an image"))] for image in images: image.bytes = image.size image.size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) self.fields["image_source"].choices = choices else: del self.fields["image_source"] volumes = self.get_volumes(request) if volumes: source_type_choices.append(("volume_source", _("Volume"))) choices = [("", _("Choose a volume"))] for volume in volumes: choices.append((volume.id, volume)) self.fields["volume_source"].choices = choices else: del self.fields["volume_source"] if source_type_choices: choices = [("no_source_type", _("No source, empty volume"))] + source_type_choices self.fields["volume_source_type"].choices = choices else: del self.fields["volume_source_type"]
def test_list_image(self): public_images = [image for image in self.images.list() if image.status == "active" and image.is_public] private_images = [image for image in self.images.list() if (image.status == "active" and not image.is_public)] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"is_public": True, "status": "active"} ).AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={"property-owner_id": self.tenant.id, "status": "active"} ).AndReturn([private_images, False, False]) self.mox.ReplayAll() ret = utils.get_available_images(self.request, self.tenant.id) expected_images = [ image for image in self.images.list() if (image.status == "active" and image.container_format not in ("ami", "aki")) ] self.assertEqual(len(expected_images), len(ret))
def get_help_text(self): extra = {} try: extra['usages'] = api.nova.tenant_absolute_limits(self.request) extra['usages_json'] = json.dumps(extra['usages']) flavors = json.dumps([f._info for f in _flavor_list(self.request)]) extra['flavors'] = flavors images = utils.get_available_images(self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0)} for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: if image.properties.get("image_type", '') != "snapshot": image.bytes = getattr( image, 'virtual_size', None) or image.size image.volume_size = max( image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.id, image)) if context.get('image_id') == image.id and \ 'volume_size' not in context: context['volume_size'] = image.volume_size if choices: choices.sort(key=lambda c: c[1].name or '') choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def get_help_text(self, extra_context=None): extra = extra_context or {} try: extra['usages'] = api.nova.tenant_absolute_limits(self.request) extra['usages_json'] = json.dumps(extra['usages']) flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0)} for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) for image in images: image.bytes = image.size image.volume_size = max( image.min_disk, functions.bytes_to_gigabytes(image.bytes)) # Commit @ https://github.com/JioCloud/horizon/commit/9e3766a608da0ba2ca78bd9091308817311cd320 # Do not show instance snapshots in image list. if image.properties.get('image_type', '') != 'snapshot': choices.append((image.id, image)) if context.get('image_id') == image.id and \ 'volume_size' not in context: context['volume_size'] = image.volume_size if choices: choices.sort(key=lambda c: c[1].name) choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def populate_image_id_choices(self, request, context): choices = [] images = image_utils.get_available_images(request, context.get('project_id'), self._images_cache) # prepare account plan marks plans = dict([(plan['id'], plan) for plan in get_plans(request)]) marks = [] for plan_map in get_project_plan_mappings(request, context.get('project_id')): plan = plans.get(plan_map['plan_id']) if plan: mark = plan.get('metadata_mark') if mark: marks.append(mark.upper()) for image in images: # filter out image by `astute_plan_mark` if marks: plan_mark = image.properties.get('astute_plan_mark') if plan_mark and not plan_mark.upper() in marks: continue image.bytes = getattr(image, 'virtual_size', None) or image.size image.volume_size = max(image.min_disk, functions.bytes_to_gigabytes(image.bytes)) choices.append((image.id, image)) if context.get('image_id') == image.id and \ 'volume_size' not in context: context['volume_size'] = image.volume_size if choices: #choices.sort(key=lambda c: c[1].name) #Converting to lowercase for sorting in alphabetical order choices.sort(key=lambda c: c[1].name.lower()) choices.insert(0, ("", _("Select Image"))) else: choices.insert(0, ("", _("No images available"))) return choices
def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = api.nova.tenant_absolute_limits(self.request) extra['usages_json'] = json.dumps(extra['usages']) flavors = json.dumps( [f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, images_cache=self._images_cache) if images is not None: attrs = [{ 'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size) } for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(CreateVPNDetailAction, self).get_help_text(extra)
def test_list_image(self): public_images = [image for image in self.images.list() if image.status == 'active' and image.is_public] private_images = [image for image in self.images.list() if (image.status == 'active' and not image.is_public)] api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False]) api.glance.image_list_detailed(IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False]) self.mox.ReplayAll() ret = utils.get_available_images(self.request, self.tenant.id) expected_images = [image for image in self.images.list() if (image.status == 'active' and image.container_format not in ('ami', 'aki'))] self.assertEqual(len(expected_images), len(ret))
def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = api.nova.tenant_absolute_limits(self.request) extra['usages_json'] = json.dumps(extra['usages']) # delete by zhihao.ding 2015/7/16 for kill_flavor start #flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) #extra['flavors'] = flavors # delete by zhihao.ding 2015/7/16 for kill_flavor start images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{ 'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size) } for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def get_help_text(self, extra_context=None): extra = {} if extra_context is None else dict(extra_context) try: extra['usages'] = quotas.tenant_limit_usages(self.request) extra['usages_json'] = json.dumps(extra['usages']) extra['cinder_enabled'] = \ base.is_service_enabled(self.request, 'volume') flavors = json.dumps([f._info for f in instance_utils.flavor_list(self.request)]) extra['flavors'] = flavors images = image_utils.get_available_images( self.request, self.initial['project_id'], self._images_cache) if images is not None: attrs = [{'id': i.id, 'min_disk': getattr(i, 'min_disk', 0), 'min_ram': getattr(i, 'min_ram', 0), 'size': functions.bytes_to_gigabytes(i.size)} for i in images] extra['images'] = json.dumps(attrs) except Exception: exceptions.handle(self.request, _("Unable to retrieve quota information.")) return super(SetInstanceDetailsAction, self).get_help_text(extra)
def test_list_image_error_private_image_list(self): public_images = [ image for image in self.images.list() if image.status == 'active' and image.is_public ] private_images = [ image for image in self.images.list() if (image.status == 'active' and not image.is_public) ] shared_images = [ image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared') ] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndRaise(self.exceptions.glance) exceptions.handle( IsA(http.HttpRequest), "Unable to retrieve images for the current project.") api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'visibility': 'shared', 'status': 'active'}) \ .AndReturn([shared_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False, False]) self.mox.ReplayAll() images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [ image for image in public_images if image.container_format not in ('ami', 'aki') ] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertFalse(len(images_cache['images_by_project'])) self.assertEqual(len(shared_images), len(images_cache['shared_images'])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [ image for image in self.images.list() if image.container_format not in ('ami', 'aki') ] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual(len(shared_images), len(images_cache['shared_images']))
def __init__(self, request, *args, **kwargs): super(CreateForm, self).__init__(request, *args, **kwargs) volume_types = cinder.volume_type_list(request) self.fields['type'].choices = [("", "")] + \ [(type.name, type.name) for type in volume_types] if "snapshot_id" in request.GET: try: snapshot = self.get_snapshot(request, request.GET["snapshot_id"]) self.fields['name'].initial = snapshot.display_name self.fields['size'].initial = snapshot.size self.fields['snapshot_source'].choices = ((snapshot.id, snapshot),) try: # Set the volume type from the original volume orig_volume = cinder.volume_get(request, snapshot.volume_id) self.fields['type'].initial = orig_volume.volume_type except Exception: pass self.fields['size'].help_text = _('Volume size must be equal ' 'to or greater than the snapshot size (%sGB)') \ % snapshot.size del self.fields['image_source'] del self.fields['volume_source_type'] del self.fields['availability_zone'] except Exception: exceptions.handle(request, _('Unable to load the specified snapshot.')) elif 'image_id' in request.GET: self.fields['availability_zone'].choices = \ self.availability_zones(request) try: image = self.get_image(request, request.GET["image_id"]) image.bytes = image.size self.fields['name'].initial = image.name min_vol_size = functions.bytes_to_gigabytes( image.size) size_help_text = _('Volume size must be equal to or greater ' 'than the image size (%s)') \ % filesizeformat(image.size) min_disk_size = getattr(image, 'min_disk', 0) if (min_disk_size > min_vol_size): min_vol_size = min_disk_size size_help_text = _('Volume size must be equal to or ' 'greater than the image minimum ' 'disk size (%sGB)') \ % min_disk_size self.fields['size'].initial = min_vol_size self.fields['size'].help_text = size_help_text self.fields['image_source'].choices = ((image.id, image),) del self.fields['snapshot_source'] del self.fields['volume_source_type'] except Exception: msg = _('Unable to load the specified image. %s') exceptions.handle(request, msg % request.GET['image_id']) elif 'volume_id' in request.GET: self.fields['availability_zone'].choices = \ self.availability_zones(request) volume = None try: volume = self.get_volume(request, request.GET["volume_id"]) except Exception: msg = _('Unable to load the specified volume. %s') exceptions.handle(request, msg % request.GET['volume_id']) if volume is not None: self.fields['name'].initial = volume.display_name self.fields['description'].initial = volume.display_description min_vol_size = volume.size size_help_text = _('Volume size must be equal to or greater ' 'than the origin volume size (%s)') \ % filesizeformat(volume.size) self.fields['size'].initial = min_vol_size self.fields['size'].help_text = size_help_text self.fields['volume_source'].choices = ((volume.id, volume),) self.fields['type'].initial = volume.type del self.fields['snapshot_source'] del self.fields['image_source'] del self.fields['volume_source_type'] else: source_type_choices = [] self.fields['availability_zone'].choices = \ self.availability_zones(request) try: snapshot_list = cinder.volume_snapshot_list(request) snapshots = [s for s in snapshot_list if s.status == 'available'] if snapshots: source_type_choices.append(("snapshot_source", _("Snapshot"))) choices = [('', _("Choose a snapshot"))] + \ [(s.id, s) for s in snapshots] self.fields['snapshot_source'].choices = choices else: del self.fields['snapshot_source'] except Exception: exceptions.handle(request, _("Unable to retrieve " "volume snapshots.")) images = utils.get_available_images(request, request.user.tenant_id) if images: source_type_choices.append(("image_source", _("Image"))) choices = [('', _("Choose an image"))] for image in images: image.bytes = image.size image.size = functions.bytes_to_gigabytes(image.bytes) choices.append((image.id, image)) self.fields['image_source'].choices = choices else: del self.fields['image_source'] volumes = self.get_volumes(request) if volumes: source_type_choices.append(("volume_source", _("Volume"))) choices = [('', _("Choose a volume"))] for volume in volumes: choices.append((volume.id, volume)) self.fields['volume_source'].choices = choices else: del self.fields['volume_source'] if source_type_choices: choices = ([('no_source_type', _("No source, empty volume"))] + source_type_choices) self.fields['volume_source_type'].choices = choices else: del self.fields['volume_source_type']
def clean(self): cleaned_data = super(SetInstanceDetailsAction, self).clean() 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) # Validate our instance source. source_type = self.data.get('source_type', None) if source_type == 'image_id': if not cleaned_data.get('image_id'): msg = _("You must select an image.") self._errors['image_id'] = self.error_class([msg]) else: # Prevents trying to launch an image needing more resources. try: image_id = cleaned_data.get('image_id') # We want to retrieve details for a given image, # however get_available_images uses a cache of image list, # so it is used instead of image_get to reduce the number # of API calls. images = utils.get_available_images( self.request, self.context.get('project_id'), self._images_cache) image = [x for x in images if x.id == image_id][0] except IndexError: image = None try: flavor_id = cleaned_data.get('flavor') # We want to retrieve details for a given flavor, # however flavor_list uses a memoized decorator # so it is used instead of flavor_get to reduce the number # of API calls. flavors = _flavor_list(self.request) flavor = [x for x in flavors if x.id == flavor_id][0] except IndexError: flavor = None if image and flavor: props_mapping = (("min_ram", "ram"), ("min_disk", "disk")) for iprop, fprop in props_mapping: if getattr(image, iprop) > 0 and \ getattr(image, iprop) > getattr(flavor, fprop): msg = _("The flavor '%(flavor)s' is too small for " "requested image.\n" "Minimum requirements: " "%(min_ram)s MB of RAM and " "%(min_disk)s GB of Root Disk." % {'flavor': flavor.name, 'min_ram': image.min_ram, 'min_disk': image.min_disk}) self._errors['image_id'] = self.error_class([msg]) break # Not necessary to continue the tests. elif source_type == 'instance_snapshot_id': if not cleaned_data['instance_snapshot_id']: msg = _("You must select a snapshot.") self._errors['instance_snapshot_id'] = self.error_class([msg]) elif source_type == 'volume_id': if not cleaned_data.get('volume_id'): msg = _("You must select a volume.") self._errors['volume_id'] = self.error_class([msg]) # Prevent launching multiple instances with the same volume. # TODO(gabriel): is it safe to launch multiple instances with # a snapshot since it should be cloned to new volumes? if count > 1: msg = _('Launching multiple instances is only supported for ' 'images and instance snapshots.') raise forms.ValidationError(msg) elif source_type == 'volume_image_id': if not cleaned_data['image_id']: msg = _("You must select an image.") self._errors['image_id'] = self.error_class([msg]) if not self.data.get('volume_size', None): msg = _("You must set volume size") self._errors['volume_size'] = self.error_class([msg]) if not cleaned_data.get('device_name'): msg = _("You must set device name") self._errors['device_name'] = self.error_class([msg]) elif source_type == 'volume_snapshot_id': if not cleaned_data.get('volume_snapshot_id'): msg = _("You must select a snapshot.") self._errors['volume_snapshot_id'] = self.error_class([msg]) if not cleaned_data.get('device_name'): msg = _("You must set device name") self._errors['device_name'] = self.error_class([msg]) return cleaned_data
def test_list_image_using_cache(self): public_images = [ image for image in self.images.list() if image.status == 'active' and image.is_public ] private_images = [ image for image in self.images.list() if (image.status == 'active' and not image.is_public) ] shared_images = [ image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared') ] self.mock_image_list.side_effect = [[public_images, False, False], [private_images, False, False], [shared_images, False, False], [private_images, False, False]] image_calls = [ mock.call(test.IsHttpRequest(), filters={ 'is_public': True, 'status': 'active' }), mock.call(test.IsHttpRequest(), filters={ 'property-owner_id': self.tenant.id, 'status': 'active' }), mock.call(test.IsHttpRequest(), filters={ 'visibility': 'shared', 'status': 'active' }), mock.call(test.IsHttpRequest(), filters={ 'property-owner_id': 'other-tenant', 'status': 'active' }) ] expected_images = [ image for image in self.images.list() if (image.status == 'active' and image.container_format not in ( 'ari', 'aki')) ] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual(len(shared_images), len(images_cache['shared_images'])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) # image list for other-tenant ret = utils.get_available_images(self.request, 'other-tenant', images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(2, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project']['other-tenant'])) self.mock_image_list.assert_has_calls(image_calls)
def test_list_image_communication_error_public_image_list(self): public_images = [ image for image in self.images.list() if image.status == 'active' and image.is_public ] private_images = [ image for image in self.images.list() if (image.status == 'active' and not image.is_public) ] shared_images = [ image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared') ] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndRaise(glance_exec.CommunicationError) # Make sure the exception is handled with the correct # error message. If the exception cannot be handled, # the error message will be different. messages.error(IsA(http.HttpRequest), "Unable to retrieve public images.") api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'visibility': 'shared', 'status': 'active'}) \ .AndReturn([shared_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False, False]) self.mox.ReplayAll() images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [ image for image in private_images if image.container_format not in ('ami', 'aki') ] self.assertEqual(len(expected_images), len(ret)) self.assertNotIn('public_images', images_cache) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual(len(shared_images), len(images_cache['shared_images'])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) expected_images = [ image for image in self.images.list() if image.container_format not in ('ami', 'aki') ] self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual(len(shared_images), len(images_cache['shared_images']))
def clean(self): cleaned_data = super(SetInstanceDetailsAction, self).clean() 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) try: flavor_id = cleaned_data.get('flavor') # We want to retrieve details for a given flavor, # however flavor_list uses a memoized decorator # so it is used instead of flavor_get to reduce the number # of API calls. flavors = instance_utils.flavor_list(self.request) flavor = [x for x in flavors if x.id == flavor_id][0] except IndexError: flavor = None count_error = [] # Validate cores and ram. available_cores = usages['cores']['available'] if flavor and available_cores < count * flavor.vcpus: count_error.append( _("Cores(Available: %(avail)s, " "Requested: %(req)s)") % { 'avail': available_cores, 'req': count * flavor.vcpus }) available_ram = usages['ram']['available'] if flavor and available_ram < count * flavor.ram: count_error.append( _("RAM(Available: %(avail)s, " "Requested: %(req)s)") % { 'avail': available_ram, 'req': count * flavor.ram }) 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) if count == 1: self._errors['flavor'] = self.error_class([msg]) else: self._errors['count'] = self.error_class([msg]) # Validate our instance source. source_type = self.data.get('source_type', None) if source_type in ('image_id', 'volume_image_id'): if source_type == 'volume_image_id': volume_size = self.data.get('volume_size', None) if not volume_size: msg = _("You must set volume size") self._errors['volume_size'] = self.error_class([msg]) if float(volume_size) <= 0: msg = _("Volume size must be greater than 0") self._errors['volume_size'] = self.error_class([msg]) if not cleaned_data.get('device_name'): msg = _("You must set device name") self._errors['device_name'] = self.error_class([msg]) if not cleaned_data.get('image_id'): msg = _("You must select an image.") self._errors['image_id'] = self.error_class([msg]) else: # Prevents trying to launch an image needing more resources. try: image_id = cleaned_data.get('image_id') # We want to retrieve details for a given image, # however get_available_images uses a cache of image list, # so it is used instead of image_get to reduce the number # of API calls. images = image_utils.get_available_images( self.request, self.context.get('project_id'), self._images_cache) image = [x for x in images if x.id == image_id][0] except IndexError: image = None if image and flavor: props_mapping = (("min_ram", "ram"), ("min_disk", "disk")) for iprop, fprop in props_mapping: if getattr(image, iprop) > 0 and \ getattr(image, iprop) > getattr(flavor, fprop): msg = (_("The flavor '%(flavor)s' is too small " "for requested image.\n" "Minimum requirements: " "%(min_ram)s MB of RAM and " "%(min_disk)s GB of Root Disk.") % { 'flavor': flavor.name, 'min_ram': image.min_ram, 'min_disk': image.min_disk }) self._errors['image_id'] = self.error_class([msg]) break # Not necessary to continue the tests. volume_size = cleaned_data.get('volume_size') if volume_size and source_type == 'volume_image_id': volume_size = int(volume_size) img_gigs = functions.bytes_to_gigabytes(image.size) smallest_size = max(img_gigs, image.min_disk) if volume_size < smallest_size: msg = (_("The Volume size is too small for the" " '%(image_name)s' image and has to be" " greater than or equal to " "'%(smallest_size)d' GB.") % { 'image_name': image.name, 'smallest_size': smallest_size }) self._errors['volume_size'] = self.error_class( [msg]) elif source_type == 'instance_snapshot_id': if not cleaned_data['instance_snapshot_id']: msg = _("You must select a snapshot.") self._errors['instance_snapshot_id'] = self.error_class([msg]) elif source_type == 'volume_id': if not cleaned_data.get('volume_id'): msg = _("You must select a volume.") self._errors['volume_id'] = self.error_class([msg]) # Prevent launching multiple instances with the same volume. # TODO(gabriel): is it safe to launch multiple instances with # a snapshot since it should be cloned to new volumes? if count > 1: msg = _('Launching multiple instances is only supported for ' 'images and instance snapshots.') raise forms.ValidationError(msg) elif source_type == 'volume_snapshot_id': if not cleaned_data.get('volume_snapshot_id'): msg = _("You must select a snapshot.") self._errors['volume_snapshot_id'] = self.error_class([msg]) if not cleaned_data.get('device_name'): msg = _("You must set device name") self._errors['device_name'] = self.error_class([msg]) return cleaned_data
def test_list_image_using_cache(self): public_images = [ image for image in self.images.list() if image.status == 'active' and image.is_public ] private_images = [ image for image in self.images.list() if (image.status == 'active' and not image.is_public) ] shared_images = [ image for image in self.imagesV2.list() if (image.status == 'active' and image.visibility == 'shared') ] api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'is_public': True, 'status': 'active'}) \ .AndReturn([public_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': self.tenant.id, 'status': 'active'}) \ .AndReturn([private_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'visibility': 'shared', 'status': 'active'}) \ .AndReturn([shared_images, False, False]) api.glance.image_list_detailed( IsA(http.HttpRequest), filters={'property-owner_id': 'other-tenant', 'status': 'active'}) \ .AndReturn([private_images, False, False]) self.mox.ReplayAll() expected_images = [ image for image in self.images.list() if (image.status == 'active' and image.container_format not in ( 'ari', 'aki')) ] images_cache = {} ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(1, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project'][self.tenant.id])) self.assertEqual(len(shared_images), len(images_cache['shared_images'])) ret = utils.get_available_images(self.request, self.tenant.id, images_cache) self.assertEqual(len(expected_images), len(ret)) # image list for other-tenant ret = utils.get_available_images(self.request, 'other-tenant', images_cache) self.assertEqual(len(expected_images), len(ret)) self.assertEqual(len(public_images), len(images_cache['public_images'])) self.assertEqual(2, len(images_cache['images_by_project'])) self.assertEqual( len(private_images), len(images_cache['images_by_project']['other-tenant']))