def list_images(request, detail=False): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # overLimit (413) log.debug('list_images detail=%s', detail) since = utils.isoparse(request.GET.get('changes-since')) with image_backend(request.user_uniq) as backend: images = backend.list_images() if since: updated_since = lambda img: date_parse(img["updated_at"]) >= since images = ifilter(updated_since, images) if not images: return HttpResponse(status=304) images = sorted(images, key=lambda x: x['id']) reply = [image_to_dict(image, detail) for image in images] if request.serialization == 'xml': data = render_to_string('list_images.xml', dict(images=reply, detail=detail)) else: data = json.dumps(dict(images=reply)) return HttpResponse(data, status=200)
def create_metadata_item(request, image_id, key): # Normal Response Code: 201 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413) req = utils.get_request_dict(request) log.info("create_image_metadata_item %s %s %s", image_id, key, req) try: metadict = req["meta"] assert isinstance(metadict, dict) assert len(metadict) == 1 assert key in metadict except (KeyError, AssertionError): raise faults.BadRequest("Malformed request.") val = metadict[key] with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) properties = image["properties"] properties[key] = val backend.update_metadata(image_id, dict(properties=properties)) return util.render_meta(request, {key: val}, status=201)
def update_metadata(request, image_id): # Normal Response Code: 201 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413) req = utils.get_request_dict(request) log.info('update_image_metadata %s %s', image_id, req) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) try: metadata = req['metadata'] assert isinstance(metadata, dict) except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') properties = image['properties'] properties.update(metadata) backend.update_metadata(image_id, dict(properties=properties)) return util.render_metadata(request, properties, status=201)
def create_metadata_item(request, image_id, key): # Normal Response Code: 201 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413) req = utils.get_request_dict(request) log.info('create_image_metadata_item %s %s %s', image_id, key, req) try: metadict = req['meta'] assert isinstance(metadict, dict) assert len(metadict) == 1 assert key in metadict except (KeyError, AssertionError): raise faults.BadRequest('Malformed request.') val = metadict[key] with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) properties = image['properties'] properties[key] = val backend.update_metadata(image_id, dict(properties=properties)) return util.render_meta(request, {key: val}, status=201)
def list_images(request, detail=False): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # overLimit (413) log.debug("list_images detail=%s", detail) since = utils.isoparse(request.GET.get("changes-since")) with image_backend(request.user_uniq) as backend: images = backend.list_images() if since: updated_since = lambda img: date_parse(img["updated_at"]) >= since images = ifilter(updated_since, images) if not images: return HttpResponse(status=304) images = sorted(images, key=lambda x: x["id"]) reply = [image_to_dict(image, detail) for image in images] if request.serialization == "xml": data = render_to_string("list_images.xml", dict(images=reply, detail=detail)) else: data = json.dumps(dict(images=reply)) return HttpResponse(data, status=200)
def update_metadata(request, image_id): # Normal Response Code: 201 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413) req = utils.get_request_dict(request) log.info("update_image_metadata %s %s", image_id, req) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) try: metadata = req["metadata"] assert isinstance(metadata, dict) except (KeyError, AssertionError): raise faults.BadRequest("Malformed request.") properties = image["properties"] properties.update(metadata) backend.update_metadata(image_id, dict(properties=properties)) return util.render_metadata(request, properties, status=201)
def get_image_meta(request, image_id): """Return detailed metadata on a specific image Described in: 3.4. Requesting Detailed Metadata on a Specific Image """ with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) return _create_image_response(image)
def remove_image_member(request, image_id, member): """Remove a member from an image Described in: 3.10. Removing a Member from an Image """ log.debug('remove_image_member %s %s', image_id, member) with image_backend(request.user_uniq) as backend: backend.remove_user(image_id, member) return HttpResponse(status=204)
def list_images(request, detail=False): """Return a list of available images. This includes images owned by the user, images shared with the user and public images. """ def get_request_params(keys): params = {} for key in keys: val = request.GET.get(key, None) if val is not None: params[key] = val return params log.debug('list_public_images detail=%s', detail) filters = get_request_params(FILTERS) params = get_request_params(PARAMS) params.setdefault('sort_key', 'created_at') params.setdefault('sort_dir', 'desc') if not params['sort_key'] in SORT_KEY_OPTIONS: raise faults.BadRequest("Invalid 'sort_key'") if not params['sort_dir'] in SORT_DIR_OPTIONS: raise faults.BadRequest("Invalid 'sort_dir'") if 'size_max' in filters: try: filters['size_max'] = int(filters['size_max']) except ValueError: raise faults.BadRequest("Malformed request.") if 'size_min' in filters: try: filters['size_min'] = int(filters['size_min']) except ValueError: raise faults.BadRequest("Malformed request.") with image_backend(request.user_uniq) as backend: images = backend.list_images(filters, params) # Remove keys that should not be returned fields = DETAIL_FIELDS if detail else LIST_FIELDS for image in images: for key in image.keys(): if key not in fields: del image[key] data = json.dumps(images, indent=settings.DEBUG) return HttpResponse(data)
def add_image(request): """Add a new virtual machine image Described in: 3.6. Adding a New Virtual Machine Image Implementation notes: * The implementation is very inefficient as it loads the whole image in memory. Limitations: * x-image-meta-id is not supported. Will always return 409 Conflict. Extensions: * An x-image-meta-location header can be passed with a link to file, instead of uploading the data. """ params = _get_image_headers(request) log.debug('add_image %s', params) if not set(params.keys()).issubset(set(ADD_FIELDS)): raise faults.BadRequest("Invalid parameters") name = params.pop('name') if name is None: raise faults.BadRequest("Image 'name' parameter is required") elif len(uenc(name)) == 0: raise faults.BadRequest("Invalid image name") location = params.pop('location', None) if location is None: raise faults.BadRequest("'location' parameter is required") try: split_url(location) except InvalidLocation: raise faults.BadRequest("Invalid location '%s'" % location) validate_fields(params) if location: with image_backend(request.user_uniq) as backend: image = backend.register(name, location, params) else: #f = StringIO(request.body) #image = backend.put(name, f, params) return HttpResponse(status=501) # Not Implemented if not image: return HttpResponse('Registration failed', status=500) return _create_image_response(image)
def add_image(request): """Add a new virtual machine image Described in: 3.6. Adding a New Virtual Machine Image Implementation notes: * The implementation is very inefficient as it loads the whole image in memory. Limitations: * x-image-meta-id is not supported. Will always return 409 Conflict. Extensions: * An x-image-meta-location header can be passed with a link to file, instead of uploading the data. """ params = _get_image_headers(request) log.debug('add_image %s', params) if not set(params.keys()).issubset(set(ADD_FIELDS)): raise faults.BadRequest("Invalid parameters") name = params.pop('name', None) if name is None: raise faults.BadRequest("Image 'name' parameter is required") elif len(uenc(name)) == 0: raise faults.BadRequest("Invalid image name") location = params.pop('location', None) if location is None: raise faults.BadRequest("'location' parameter is required") try: split_url(location) except InvalidLocation: raise faults.BadRequest("Invalid location '%s'" % location) validate_fields(params) if location: with image_backend(request.user_uniq) as backend: image = backend.register(name, location, params) else: #f = StringIO(request.body) #image = backend.put(name, f, params) return HttpResponse(status=501) # Not Implemented if not image: return HttpResponse('Registration failed', status=500) return _create_image_response(image)
def list_image_members(request, image_id): """List image memberships Described in: 3.7. Requesting Image Memberships """ with image_backend(request.user_uniq) as backend: users = backend.list_users(image_id) members = [{'member_id': u, 'can_share': False} for u in users] data = json.dumps({'members': members}, indent=settings.DEBUG) return HttpResponse(data)
def delete_image(request, image_id): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # overLimit (413) log.info('delete_image %s', image_id) with image_backend(request.user_uniq) as backend: backend.unregister(image_id) log.info('User %s deleted image %s', request.user_uniq, image_id) return HttpResponse(status=204)
def delete_image(request, image_id): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # overLimit (413) log.info("delete_image %s", image_id) with image_backend(request.user_uniq) as backend: backend.unregister(image_id) log.info("User %s deleted image %s", request.user_uniq, image_id) return HttpResponse(status=204)
def list_metadata(request, image_id): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # overLimit (413) log.debug("list_image_metadata %s", image_id) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) metadata = image["properties"] return util.render_metadata(request, metadata, use_values=False, status=200)
def add_image_member(request, image_id, member): """Add a member to an image Described in: 3.9. Adding a Member to an Image Limitations: * Passing a body to enable `can_share` is not supported. """ log.debug('add_image_member %s %s', image_id, member) with image_backend(request.user_uniq) as backend: backend.add_user(image_id, member) return HttpResponse(status=204)
def handle(self, **options): user = options['userid'] with image_backend(user) as backend: images = backend._list_images(user) images.sort(key=lambda x: x['created_at'], reverse=True) headers = ("id", "name", "owner", "public") table = [] for img in images: fields = (img["id"], img["name"], img["owner"], str(img["is_public"])) table.append(fields) pprint_table(self.stdout, table, headers)
def handle(self, *args, **options): if len(args) != 1: raise CommandError("Please provide an image ID") image_id = args[0] with image_backend(None) as backend: images = backend._list_images(None) try: image = filter(lambda x: x["id"] == image_id, images)[0] except IndexError: raise CommandError("Image not found. Use snf-manage image-list" " to get the list of all images.") utils.pprint_table(out=self.stdout, table=[image.values()], headers=image.keys(), vertical=True)
def get_image(self, imageid, userid): if not imageid in self.images: try: with image_backend(userid) as ib: image = ib.get_image(imageid) properties = image.get("properties") os = properties.get("os", properties.get("osfamily", "unknown")) owner = image["owner"] owner = "system" if image["owner"] == self.system_user_uuid\ else "user" self.images[imageid] = owner + ":" + os except Exception: self.images[imageid] = "unknown:unknown" return self.images[imageid]
def get_image(self, imageid, userid): if imageid not in self.images: try: with image_backend(userid) as ib: image = ib.get_image(imageid) properties = image.get("properties") os = properties.get("os", properties.get("osfamily", "unknown")) owner = image["owner"] owner = "system" if image["owner"] == self.system_user_uuid\ else "user" self.images[imageid] = owner + ":" + os except Exception: self.images[imageid] = "unknown:unknown" return self.images[imageid]
def get_metadata_item(request, image_id, key): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # overLimit (413) log.debug('get_image_metadata_item %s %s', image_id, key) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) val = image['properties'].get(key) if val is None: raise faults.ItemNotFound('Metadata key not found.') return util.render_meta(request, {key: val}, status=200)
def list_metadata(request, image_id): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # overLimit (413) log.debug('list_image_metadata %s', image_id) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) metadata = image['properties'] return util.render_metadata(request, metadata, use_values=False, status=200)
def get_metadata_item(request, image_id, key): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # overLimit (413) log.debug("get_image_metadata_item %s %s", image_id, key) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) val = image["properties"].get(key) if val is None: raise faults.ItemNotFound("Metadata key not found.") return util.render_meta(request, {key: val}, status=200)
def delete_image(request, image_id): """Delete an Image. This API call is not described in the Openstack Glance API. Implementation notes: * The implementation does not delete the Image from the storage backend. Instead it unregisters the image by removing all the metadata from the plankton metadata domain. """ log.info("delete_image '%s'" % image_id) userid = request.user_uniq with image_backend(userid) as backend: backend.unregister(image_id) log.info("User '%s' deleted image '%s'" % (userid, image_id)) return HttpResponse(status=204)
def update_image(request, image_id): """Update an image Described in: 3.6.2. Updating an Image Implementation notes: * It is not clear which metadata are allowed to be updated. We support: name, disk_format, container_format, is_public, owner, properties and status. """ meta = _get_image_headers(request) log.debug('update_image %s', meta) assert set(meta.keys()).issubset(set(UPDATE_FIELDS)) with image_backend(request.user_uniq) as backend: image = backend.update_metadata(image_id, meta) return _create_image_response(image)
def get_image_details(request, image_id): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # itemNotFound (404), # overLimit (413) log.debug("get_image_details %s", image_id) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) reply = image_to_dict(image) if request.serialization == "xml": data = render_to_string("image.xml", dict(image=reply)) else: data = json.dumps(dict(image=reply)) return HttpResponse(data, status=200)
def delete_metadata_item(request, image_id, key): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413), log.info('delete_image_metadata_item %s %s', image_id, key) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) properties = image['properties'] properties.pop(key, None) backend.update_metadata(image_id, dict(properties=properties)) return HttpResponse(status=204)
def delete_metadata_item(request, image_id, key): # Normal Response Code: 204 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # itemNotFound (404), # badRequest (400), # buildInProgress (409), # badMediaType(415), # overLimit (413), log.info("delete_image_metadata_item %s %s", image_id, key) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) properties = image["properties"] properties.pop(key, None) backend.update_metadata(image_id, dict(properties=properties)) return HttpResponse(status=204)
def get_image_details(request, image_id): # Normal Response Codes: 200, 203 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # itemNotFound (404), # overLimit (413) log.debug('get_image_details %s', image_id) with image_backend(request.user_uniq) as backend: image = backend.get_image(image_id) reply = image_to_dict(image) if request.serialization == 'xml': data = render_to_string('image.xml', dict(image=reply)) else: data = json.dumps(dict(image=reply)) return HttpResponse(data, status=200)
def list_shared_images(request, member): """Request shared images Described in: 3.8. Requesting Shared Images Implementation notes: * It is not clear what this method should do. We return the IDs of the users's images that are accessible by `member`. """ log.debug('list_shared_images %s', member) images = [] with image_backend(request.user_uniq) as backend: for image in backend.list_shared_images(member=member): image_id = image['id'] images.append({'image_id': image_id, 'can_share': False}) data = json.dumps({'shared_images': images}, indent=settings.DEBUG) return HttpResponse(data)
def update_image_members(request, image_id): """Replace a membership list for an image Described in: 3.11. Replacing a Membership List for an Image Limitations: * can_share value is ignored """ log.debug('update_image_members %s', image_id) members = [] try: data = json.loads(request.raw_post_data) for member in data['memberships']: members.append(member['member_id']) except (ValueError, KeyError, TypeError): return HttpResponse(status=400) with image_backend(request.user_uniq) as backend: backend.replace_users(image_id, members) return HttpResponse(status=204)
def get_image(image_id, user_id): """Return an Image instance or raise ItemNotFound.""" with image_backend(user_id) as backend: return backend.get_image(image_id)