Glance-api-v2-image-sharing

This is the Full Specification for the blueprint: glance-api-v2-image-sharing

NOTE: This feature was released in Grizzly. The documentation is available in the OpenStack Image Service API v2 Reference The use cases outlined below, however, may still be useful.

Quick Summary
We are proposing:
 * 1) porting image members to v2
 * 2) adding a state associated with an image member to v2
 * 3) adding some additional filters to the image-list call

Background
In this discussion, we'll assume 2 users:
 * "A" who wants to share images
 * "B" who is a user other than "A"

Currently, the image list for user B contains all of the following:
 * 1) all public images
 * 2) all images owned by B
 * 3) all images that have B as an image member (currently v1 only)

Currently, image owner A can add B as a member of A's image I1

Problem
The problem with using image members as a basis of full-blown image sharing is that B may not want to see I1 in the image list (i.e., the SPAM problem). So the implementation of image sharing that we want to do has two aspects: For an image G to show up in user B's list of images, it should be the case that both (a) A wants to share G, and (b) B actually wants to see G.

Proposal

 * Image members is ported to Images API v2 and Glance. As in v1, the image owner can add any user to the image-members list of that image.  As in v1, any user who is a member of an image can use that image to build a server.
 * the 'can_share' property of image members will not be ported to v2.
 * Add a status property for each element of the image-members list. The status values are one of {'accepted', 'rejected'} or null.  (See the 1-many use case discussion below for why it's useful to have this be nullable.)
 * Add an API call that would allow any user to POST a 'status' to URL `/v2/images/{image-uuid}/members/{tenant-id}`. The body of the call would be something like `{ "status" : "" }` (where the status-values would be as above).  The semantics of the call would be that it would only be accepted if the tenant-id of the user making the call matched the tenant-id occurring the URL (or is that un-RESTful?).  (The call would also be accepted if made by an admin.)  If tenant-id is not an image-member of that image, you'd get a 404 as you do now.
 * Ensure that the following filters are available on the image-list call:
 * public-images
 * my-owned-images
 * images-of-which-i-am-a-member
 * AND status={ACCEPTED,REJECTED,ALL} (default is ACCEPTED)
 * [ AND owned-by  ] (optional parameter)

Implications
Under this proposal:
 * image sharing is completely independent of public images. Public images are only set by the cloud provider (as is the case now)
 * image sharing is fine-grained ... it is on an image-by-image basis
 * image sharing occurs within a region only
 * no need for a concept of "trusted users"; A and B are both normal Glance users

Use Cases
Here's a list of things you might want to do with an image sharing capability. For each one, we assess how it could be accomplished using the scheme outlined above. If the use case cannot be addressed by this scheme, we provide a brief discussion in italics.

(1) Sharing an image
What: A wants image I1 to appear in B's image-list.

How:
 * 1) A adds B as a member of image I1
 * 2) Independently of Glance, A contacts B informing B of the UUID of image I1
 * 3) B makes a call to the Glance API requesting that B's status on image I1 be changed to 'accepted'

(2) Un-sharing a previously shared image
What: A no longer wants I1 to appear in B's image-list.

How:
 * 1) A removes B as a member of image I1

Note: There is no way for B to prevent this from occurring.

(3) Removing a shared image from my image-list
What: B no longer wants I1 to appear in B's image-list

How:
 * 1) B makes a call to the Glance API requesting that B's status on image I1 be changed to 'rejected'.

Note: There is no way for A to prevent this from occurring.

(4) Removing all images shared by user A from my image-list
What: B wants no images owned by A to appear in B's image-list.

How:
 * 1) B makes an image-list request with the filters: "images-of-which-i-am-a-member" AND "owned-by A"
 * 2) For each image UUID in the response, B makes a request to the Glance API requesting that B's status on that image be changed to 'rejected'

(5) Image Discovery of images available to me
What: B wants to know what images are available to B (i.e., the owner has shared them with B, but they are not in B's image-list).

How:
 * 1) B makes an image-list call with the filters: "images-of-which-i-am-a-member" AND "status=ALL"

(6) Image Discovery of shared images owned by a particular user
What: View all images available to me from user A that don't currently appear in my image-list.

How:
 * 1) B makes an image-list request with the filters: "images-of-which-i-am-a-member" AND "status=ALL" AND "owned-by A"

(7) Image Discovery of images owned by a particular user
What: View all images owned-by user A (even those of which I am not an image member) that don't currently appear in my image-list.

How: ''No way to do this through Glance under the current proposal. You would have to become aware of these via some other notification mechanism, e.g., A's webpage, and you would have to notify A independently of Glance that you would like access to the image.''

Note: We do not see this as a disadvantage.

(8) General Image Discovery
What: I want to know what images exist "out there" that I don't currently know about (i.e., I want to see a list of images that aren't public AND of which I am NOT an image-member).

How: ''No way to do this through Glance under the current proposal. You would have to become aware of these via some other notification mechanism, e.g., someone's webpage or something, and you would have to notify the image owner independently of Glance that you would like access to the image.''

Note: We do not see this as a disadvantage.

(9) Force a user to see my images
What: I have created some fantastic images that are so good that I want user B to see them in B's image-list, whether or not B is really interested in them, because the images are so good that I know once B sees them, B will want to continue to see them.

How: Cannot be done.

Note: We see this as an advantage ... after all, it's the whole point of this proposal!

(10) Never see any images from a specific user ("banned list")
What: B is sick of getting notifications about images that A would like to share, B does not want to receive any notifications about image sharing from A.

How: ''Can't be done in Glance since the A-to-B notifications occur independently of Glance. Would have to be done by the normal spam control measures of whatever notification service is used.''

(11) Automatically see new images from a specific user
What: B likes A's images and would like to "accept" all sharing requests from A without having to make an API call to accept a new image from A.

How: Can't be done in Glance since Glance does not directly track user-to-user relations

Note: This could be done in the UI or via some kind of system job (see the discussion of 1-many sharing, below).

(12) Image sharing inheritance
What: User A has shared image I1 with user B (and B has accepted). For some reason (e.g., security update), user A wants to withdraw image I1 and replace it with image I8, and image I8 should show up in user B's image-list in the place of image I1.

How: Can't be done in Glance under the current proposal.

Note: There's no way for Glance to know that I8 is a "replacement" for I1. Not sure that we want to implement it, either, because allowing A to unilaterally swap shared images would allow the old bait-and-switch. This is really a matter for the cloud provider to decide, could be handled in the UI or via some kind of system job (see the discussion of 1-many sharing, below).

(13) 1-1 image sharing
What: A wants to share image I1 with B.

How:
 * 1) This is simply user story (1), above.  (Just wanted to be excruciatingly explicit about this use case!)

(14) 1-many image sharing
What: A wants to share image I1 with users {B, C, D, ..., Z} (e.g., suppose that A is an IT dude for company SMB, and {B, C, D, ..., Z} are all employees of SMB, and A prefers all employees to use I1 instead of some similar public image)

How:
 * For user U-sub-i in {B, C, D, ..., Z}:
 * A adds U-sub-i as a member of image I1
 * Independently of Glance, A contacts U-sub-i informing U-sub-i of the UUID of image I1
 * U-sub-i makes a call to the Glance API requesting that U-sub-i's status on image I1 be changed to 'accepted'

Note: This requires the individual users to take an action, which is not what A wants; A wants I1 available for immediate use by fellow employees. In other words, this is user story (9), above. Our position is that it is not Glance's business to distinguish between "trusted" users like this IT dude and "normal" users who simply want to share some images. Rather, this distinction must be made at the cloud provider level. So here's another approach:

How:
 * 1) Independently of Glance, A is recognized by the cloud provider as a "trusted" user.
 * 2) For user U-sub-i in {B, C, D, ..., Z}: A adds U-sub-i as a member of image I1 (and I2, etc.)
 * 3) Independently of Glance, the cloud provider runs a system job (with admin credentials), say every 30 minutes, that goes through A's image-list and for each image-member whose status is null, marks the image as 'accepted' 

Note: This would still allow individual employees to reject the image, which seems OK to us, since they would have to make a conscious decision to reject the image, and if so, then they really don't want to see it. But the cloud provider could modify the system job to handle this case and mark the image as 'accepted'; this all depends on the relation between A and the cloud provider and is not a Glance concern. The key point is that a kind of fascist 1-many image sharing is possible under this proposal.

Pain Points

 * 1) This proposal requires porting the (unliked) image members implementation from glance v1.
 * 2) Sharing is regional only; if image cloning to other regions is implemented so that a UUID is preserved across regions, this could easily be handled in the UI/API script.
 * 3) The API operations are very fine-grained, i.e., at the individual image level.  They can be coarsened in the UI.
 * 4) Orchestration of sharing (i.e., the notification to B from A that there is stuff to be shared is completely independent of Glance.  We see this as an advantage.
 * 5) When image members are ported to v2, have to make sure it's the case that if B doesn't own image G, B can only build a server from G if B is a member of G.

Open Questions

 * 1) Need to decide how the PUT request to `v2/images/{image-uuid}/members` will work with respect to the member status ... guess any existing members with non-null status should have their status preserved, any new members will have null status?