Glance-v2-community-image-sharing-use-cases-newton

This page explores how Images API calls will look/act based on the proposal in the glance spec: https://review.openstack.org/#/c/271019/

(1) Create a community image
what: An image producer wants to make an image available to anyone who wants to boot from it.

how: PATCH /v2/images/{image_id} with request body [{ "op": "replace", "path": "/visibility", "value": "community" }]

(2) Restrict access to a community image
what: An image producer wants to make an image available to everyone in the cloud except for a few specific tenants.

how: can't do it with community images

discussion: with current image sharing, the image contains a membership list of users allowed to use the image; there's no provision for a list of users *prohibited* from using the image. So you can't do this with current image sharing, either. The sharing model we've adopted is that you can share with (1) particular users or (2) all users. So not being able to satisfy this use case seems OK.

(3) Create a non-discoverable community image (The "public-image-downgrade" use case)
what: An image producer wants to make an image available to everyone in the cloud but doesn't want it to be discoverable (i.e., a consumer must know the UUID in order to see/use the image). (This is the public-image-downgrade case, that is, the cloud provider doesn't want to support the image any more and doesn't want new instances booted from it, but also doesn't want to delete the image as some customers may still require it.)

how: can't do it under this scheme

discussion: the whole point of community images is that they're discoverable by the community of users! To address this use case, glance currently has a "feature" whereby if the owner of an image is null, any user who independently knows the UUID can do an image-show operation on it (and can boot a server from it). Only a glance administrator can set an image owner to null; some providers have been using this as a workaround in the absence of community images. Its drawback is that (1) only an administrator can do it, and (2) such an image is not discoverable. But this meets the public-image-downgrade case perfectly! So maybe we should turn this "feature" into an actual feature?

(4) Withdraw a community image
what: An image producer wants to withdraw a community image.

how: PATCH /v2/images/{image_id} with request body [{ "op": "replace", "path": "/visibility", "value": "{viz_value}" }] where viz_value in {'private', 'shared'}.

discussion: The member-list on the community image (if any) remains. If the image is made 'shared', it will behave exactly as a shared image with respect to any image members. If the image is made 'private', it will disappear from the image-list of anyone who's bookmarked it. Since the member-list remains on the image, this gives an image producer a way to 'deactivate' a shared image (for example, a consumer reports a problem, the producer makes the image 'private', investigates the problem, and can make the image 'community' or 'shared' again if the investigation indicates the image isn't at fault.

(5) Community image discovery
what: An image consumer wants to discover what community images are available.

how: GET /v2/images?visibility=community

(6) Discovery of community images from a particular image producer
what: An image consumer wants to discover what community images are available from a particular image producer.

how: GET /v2/images?visibility=community&owner={producer_tenant_id}

(7) Bookmarking a community image
what: "Bookmarking": An image consumer really likes a community image and wants it to appear in his image-list.

how: PUT /v2/images/{IMAGE_UUID}/members/{consumer_tenant_id} with request body: { "status": "accepted" }

(8) Un-bookmarking (forgetting) a community image
what: An image consumer has a community image appearing in her image list but no longer wants it to show up there.

how: PUT /v2/images/{IMAGE_UUID}/members/{consumer_tenant_id} with request body: { "status": "rejected" }

todo: what should this call *really* do? remove the consumer_tenant_id from the image's member-list?
 * pro: (1) if we actually update the status on the image, then we should also (for consistency) allow a consumer doing a PUT with { "status": "pending" }, which doesn't really make sense. (2) this method allows the consumer to remove all trace that she was ever interested in the image (as far as the image producer is concerned, that is; the evidence is still in the glance database)
 * con: if the member is removed, then you won't be able to filter the community image list with "rejected" or "pending". Why would a consumer want to do that?  Well, if you did a   GET /v2/images?visibility=community&member_status=rejected, you'd get a list of community images that you had looked at but decided that you didn't want.  But that seems kind of dumb.

todo: what about PUT /v2/images/{IMAGE_UUID}/members/{consumer_tenant_id} with request body: { "status": "pending" } ? Should that be an error, or just delete the consumer_tenant_id from the member list (if that's the behavior adopted for the "rejected" call)?

Problematic API Calls
The above brings up some questions about what expected behavior should be for some API calls.

PUT rejected
call: PUT /v2/images/{IMAGE_UUID}/members/{consumer_tenant_id} with request body: { "status": "rejected" }

behavior: Need to decide whether this acts as a DELETE of the consumer_tenant_id, or whether we'll track this member_status.

PUT pending
call: PUT /v2/images/{IMAGE_UUID}/members/{consumer_tenant_id} with request body: { "status": "pending" }

behavior: Need to decide whether this acts as a DELETE of the consumer_tenant_id, or whether we'll track this member_status.

GET accepted
call: GET /v2/images?visibility=community&member_status=accepted behavior: Returns only those community images that the caller has accepted.

GET rejected
call: GET /v2/images?visibility=community&member_status=rejected

behavior: Returns all community images *except* community images that the caller has accepted? Or is the filter ignored and this is the same result as the GET /v2/images?visibility=community call?

GET pending
call: GET /v2/images?visibility=community&member_status=pending

behavior: Same questions as for GET "rejected", above.