From 00e4585ce5c7cbd51c34067a6c4e3d88b08229df Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Tue, 13 Dec 2016 16:32:30 -0800 Subject: [PATCH] first pass at adding new members --- builder/openstack/builder.go | 1 + builder/openstack/step_add_image_members.go | 44 +++++++++ .../imageservice/v2/members/requests.go | 77 ++++++++++++++++ .../imageservice/v2/members/results.go | 91 +++++++++++++++++++ .../openstack/imageservice/v2/members/urls.go | 31 +++++++ vendor/vendor.json | 6 ++ 6 files changed, 250 insertions(+) create mode 100644 builder/openstack/step_add_image_members.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/requests.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/results.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/urls.go diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index b5f44bb6e..7eeb18b4b 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -115,6 +115,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &StepStopServer{}, &stepCreateImage{}, &stepUpdateImageVisibility{}, + &stepAddImageMembers{}, } // Run! diff --git a/builder/openstack/step_add_image_members.go b/builder/openstack/step_add_image_members.go new file mode 100644 index 000000000..cd26b822f --- /dev/null +++ b/builder/openstack/step_add_image_members.go @@ -0,0 +1,44 @@ +package openstack + +import ( + "fmt" + + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/members" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +type stepAddImageMembers struct{} + +func (s *stepAddImageMembers) Run(state multistep.StateBag) multistep.StepAction { + imageId := state.Get("image").(string) + ui := state.Get("ui").(packer.Ui) + config := state.Get("config").(Config) + + if len(config.ImageMembers) == 0 { + return multistep.ActionContinue + } + + imageClient, err := config.imageV2Client() + if err != nil { + err = fmt.Errorf("Error initializing image service client: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } + + for _, member := range config.ImageMembers { + ui.Say(fmt.Sprintf("Adding member '%s' to image %s", member, imageId)) + r := members.Create(imageClient, imageId, member) + if _, err = r.Extract(); err != nil { + err = fmt.Errorf("Error adding member to image: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } + } + + return multistep.ActionContinue +} + +func (s *stepAddImageMembers) Cleanup(multistep.StateBag) { + // No cleanup... +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/requests.go new file mode 100644 index 000000000..8c667cbdd --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/requests.go @@ -0,0 +1,77 @@ +package members + +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// Create member for specific image +// +// Preconditions +// The specified images must exist. +// You can only add a new member to an image which 'visibility' attribute is private. +// You must be the owner of the specified image. +// Synchronous Postconditions +// With correct permissions, you can see the member status of the image as pending through API calls. +// +// More details here: http://developer.openstack.org/api-ref-image-v2.html#createImageMember-v2 +func Create(client *gophercloud.ServiceClient, id string, member string) (r CreateResult) { + b := map[string]interface{}{"member": member} + _, r.Err = client.Post(createMemberURL(client, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200, 409, 403}, + }) + return +} + +// List members returns list of members for specifed image id +// More details: http://developer.openstack.org/api-ref-image-v2.html#listImageMembers-v2 +func List(client *gophercloud.ServiceClient, id string) pagination.Pager { + return pagination.NewPager(client, listMembersURL(client, id), func(r pagination.PageResult) pagination.Page { + return MemberPage{pagination.SinglePageBase(r)} + }) +} + +// Get image member details. +// More details: http://developer.openstack.org/api-ref-image-v2.html#getImageMember-v2 +func Get(client *gophercloud.ServiceClient, imageID string, memberID string) (r DetailsResult) { + _, r.Err = client.Get(getMemberURL(client, imageID, memberID), &r.Body, &gophercloud.RequestOpts{OkCodes: []int{200}}) + return +} + +// Delete membership for given image. +// Callee should be image owner +// More details: http://developer.openstack.org/api-ref-image-v2.html#deleteImageMember-v2 +func Delete(client *gophercloud.ServiceClient, imageID string, memberID string) (r DeleteResult) { + _, r.Err = client.Delete(deleteMemberURL(client, imageID, memberID), &gophercloud.RequestOpts{OkCodes: []int{204, 403}}) + return +} + +// UpdateOptsBuilder allows extensions to add additional attributes to the Update request. +type UpdateOptsBuilder interface { + ToImageMemberUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts implements UpdateOptsBuilder +type UpdateOpts struct { + Status string +} + +// ToMemberUpdateMap formats an UpdateOpts structure into a request body. +func (opts UpdateOpts) ToImageMemberUpdateMap() (map[string]interface{}, error) { + return map[string]interface{}{ + "status": opts.Status, + }, nil +} + +// Update function updates member +// More details: http://developer.openstack.org/api-ref-image-v2.html#updateImageMember-v2 +func Update(client *gophercloud.ServiceClient, imageID string, memberID string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToImageMemberUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Put(updateMemberURL(client, imageID, memberID), b, &r.Body, + &gophercloud.RequestOpts{OkCodes: []int{200}}) + return +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/results.go new file mode 100644 index 000000000..1d2a9c05c --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/results.go @@ -0,0 +1,91 @@ +package members + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/pagination" +) + +// Member model +type Member struct { + CreatedAt time.Time `json:"-"` + ImageID string `json:"image_id"` + MemberID string `json:"member_id"` + Schema string `json:"schema"` + Status string `json:"status"` + UpdatedAt time.Time `json:"-"` +} + +func (s *Member) UnmarshalJSON(b []byte) error { + type tmp Member + var p *struct { + tmp + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } + err := json.Unmarshal(b, &p) + if err != nil { + return err + } + + *s = Member(p.tmp) + s.CreatedAt, err = time.Parse(time.RFC3339, p.CreatedAt) + if err != nil { + return err + } + s.UpdatedAt, err = time.Parse(time.RFC3339, p.UpdatedAt) + return err +} + +// Extract Member model from request if possible +func (r commonResult) Extract() (*Member, error) { + var s *Member + err := r.ExtractInto(&s) + return s, err +} + +// MemberPage is a single page of Members results. +type MemberPage struct { + pagination.SinglePageBase +} + +// ExtractMembers returns a slice of Members contained in a single page of results. +func ExtractMembers(r pagination.Page) ([]Member, error) { + var s struct { + Members []Member `json:"members"` + } + err := r.(MemberPage).ExtractInto(&s) + return s.Members, err +} + +// IsEmpty determines whether or not a page of Members contains any results. +func (r MemberPage) IsEmpty() (bool, error) { + members, err := ExtractMembers(r) + return len(members) == 0, err +} + +type commonResult struct { + gophercloud.Result +} + +// CreateResult result model +type CreateResult struct { + commonResult +} + +// DetailsResult model +type DetailsResult struct { + commonResult +} + +// UpdateResult model +type UpdateResult struct { + commonResult +} + +// DeleteResult model +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/urls.go new file mode 100644 index 000000000..0898364e7 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/imageservice/v2/members/urls.go @@ -0,0 +1,31 @@ +package members + +import "github.com/gophercloud/gophercloud" + +func imageMembersURL(c *gophercloud.ServiceClient, imageID string) string { + return c.ServiceURL("images", imageID, "members") +} + +func listMembersURL(c *gophercloud.ServiceClient, imageID string) string { + return imageMembersURL(c, imageID) +} + +func createMemberURL(c *gophercloud.ServiceClient, imageID string) string { + return imageMembersURL(c, imageID) +} + +func imageMemberURL(c *gophercloud.ServiceClient, imageID string, memberID string) string { + return c.ServiceURL("images", imageID, "members", memberID) +} + +func getMemberURL(c *gophercloud.ServiceClient, imageID string, memberID string) string { + return imageMemberURL(c, imageID, memberID) +} + +func updateMemberURL(c *gophercloud.ServiceClient, imageID string, memberID string) string { + return imageMemberURL(c, imageID, memberID) +} + +func deleteMemberURL(c *gophercloud.ServiceClient, imageID string, memberID string) string { + return imageMemberURL(c, imageID, memberID) +} diff --git a/vendor/vendor.json b/vendor/vendor.json index ed62f5173..8afc6c2e1 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -434,6 +434,12 @@ "revision": "d5eda9707e146108e4d424062b602fd97a71c2e6", "revisionTime": "2016-11-14T18:28:31Z" }, + { + "checksumSHA1": "HKHLR7xxAb5aJ5zN8XYhDkn/PoM=", + "path": "github.com/gophercloud/gophercloud/openstack/imageservice/v2/members", + "revision": "d5eda9707e146108e4d424062b602fd97a71c2e6", + "revisionTime": "2016-11-14T18:28:31Z" + }, { "checksumSHA1": "TDOZnaS0TO0NirpxV1QwPerAQTY=", "path": "github.com/gophercloud/gophercloud/openstack/utils",