| /* |
| Copyright (c) 2018 VMware, Inc. All Rights Reserved. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package tags |
| |
| import ( |
| "context" |
| "fmt" |
| "net/http" |
| "strings" |
| |
| "github.com/vmware/govmomi/vapi/internal" |
| "github.com/vmware/govmomi/vapi/rest" |
| ) |
| |
| // Manager extends rest.Client, adding tag related methods. |
| type Manager struct { |
| *rest.Client |
| } |
| |
| // NewManager creates a new Manager instance with the given client. |
| func NewManager(client *rest.Client) *Manager { |
| return &Manager{ |
| Client: client, |
| } |
| } |
| |
| // isName returns true if the id is not a urn. |
| func isName(id string) bool { |
| return !strings.HasPrefix(id, "urn:") |
| } |
| |
| // Tag provides methods to create, read, update, delete, and enumerate tags. |
| type Tag struct { |
| ID string `json:"id,omitempty"` |
| Description string `json:"description,omitempty"` |
| Name string `json:"name,omitempty"` |
| CategoryID string `json:"category_id,omitempty"` |
| UsedBy []string `json:"used_by,omitempty"` |
| } |
| |
| // Patch merges updates from the given src. |
| func (t *Tag) Patch(src *Tag) { |
| if src.Name != "" { |
| t.Name = src.Name |
| } |
| if src.Description != "" { |
| t.Description = src.Description |
| } |
| if src.CategoryID != "" { |
| t.CategoryID = src.CategoryID |
| } |
| } |
| |
| // CreateTag creates a new tag with the given Name, Description and CategoryID. |
| func (c *Manager) CreateTag(ctx context.Context, tag *Tag) (string, error) { |
| // create avoids the annoyance of CreateTag requiring a "description" key to be included in the request, |
| // even though the field value can be empty. |
| type create struct { |
| Name string `json:"name"` |
| Description string `json:"description"` |
| CategoryID string `json:"category_id"` |
| } |
| spec := struct { |
| Tag create `json:"create_spec"` |
| }{ |
| Tag: create{ |
| Name: tag.Name, |
| Description: tag.Description, |
| CategoryID: tag.CategoryID, |
| }, |
| } |
| if isName(tag.CategoryID) { |
| cat, err := c.GetCategory(ctx, tag.CategoryID) |
| if err != nil { |
| return "", err |
| } |
| spec.Tag.CategoryID = cat.ID |
| } |
| url := internal.URL(c, internal.TagPath) |
| var res string |
| return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res) |
| } |
| |
| // UpdateTag can update one or both of the tag Description and Name fields. |
| func (c *Manager) UpdateTag(ctx context.Context, tag *Tag) error { |
| spec := struct { |
| Tag Tag `json:"update_spec"` |
| }{ |
| Tag: Tag{ |
| Name: tag.Name, |
| Description: tag.Description, |
| }, |
| } |
| url := internal.URL(c, internal.TagPath).WithID(tag.ID) |
| return c.Do(ctx, url.Request(http.MethodPatch, spec), nil) |
| } |
| |
| // DeleteTag deletes an existing tag. |
| func (c *Manager) DeleteTag(ctx context.Context, tag *Tag) error { |
| url := internal.URL(c, internal.TagPath).WithID(tag.ID) |
| return c.Do(ctx, url.Request(http.MethodDelete), nil) |
| } |
| |
| // GetTag fetches the tag information for the given identifier. |
| // The id parameter can be a Tag ID or Tag Name. |
| func (c *Manager) GetTag(ctx context.Context, id string) (*Tag, error) { |
| if isName(id) { |
| tags, err := c.GetTags(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| for i := range tags { |
| if tags[i].Name == id { |
| return &tags[i], nil |
| } |
| } |
| } |
| |
| url := internal.URL(c, internal.TagPath).WithID(id) |
| var res Tag |
| return &res, c.Do(ctx, url.Request(http.MethodGet), &res) |
| |
| } |
| |
| // GetTagForCategory fetches the tag information for the given identifier in the given category. |
| func (c *Manager) GetTagForCategory(ctx context.Context, id, category string) (*Tag, error) { |
| if category == "" { |
| return c.GetTag(ctx, id) |
| } |
| |
| ids, err := c.ListTagsForCategory(ctx, category) |
| if err != nil { |
| return nil, err |
| } |
| |
| for _, id := range ids { |
| tag, err := c.GetTag(ctx, id) |
| if err != nil { |
| return nil, fmt.Errorf("get tag for category %s %s: %s", category, id, err) |
| } |
| if tag.ID == id || tag.Name == id { |
| return tag, nil |
| } |
| } |
| |
| return nil, fmt.Errorf("tag %q not found in category %q", id, category) |
| } |
| |
| // ListTags returns all tag IDs in the system. |
| func (c *Manager) ListTags(ctx context.Context) ([]string, error) { |
| url := internal.URL(c, internal.TagPath) |
| var res []string |
| return res, c.Do(ctx, url.Request(http.MethodGet), &res) |
| } |
| |
| // GetTags fetches an array of tag information in the system. |
| func (c *Manager) GetTags(ctx context.Context) ([]Tag, error) { |
| ids, err := c.ListTags(ctx) |
| if err != nil { |
| return nil, fmt.Errorf("get tags failed for: %s", err) |
| } |
| |
| var tags []Tag |
| for _, id := range ids { |
| tag, err := c.GetTag(ctx, id) |
| if err != nil { |
| return nil, fmt.Errorf("get category %s failed for %s", id, err) |
| } |
| |
| tags = append(tags, *tag) |
| |
| } |
| return tags, nil |
| } |
| |
| // The id parameter can be a Category ID or Category Name. |
| func (c *Manager) ListTagsForCategory(ctx context.Context, id string) ([]string, error) { |
| if isName(id) { |
| cat, err := c.GetCategory(ctx, id) |
| if err != nil { |
| return nil, err |
| } |
| id = cat.ID |
| } |
| |
| body := struct { |
| ID string `json:"category_id"` |
| }{id} |
| url := internal.URL(c, internal.TagPath).WithID(id).WithAction("list-tags-for-category") |
| var res []string |
| return res, c.Do(ctx, url.Request(http.MethodPost, body), &res) |
| } |
| |
| // The id parameter can be a Category ID or Category Name. |
| func (c *Manager) GetTagsForCategory(ctx context.Context, id string) ([]Tag, error) { |
| ids, err := c.ListTagsForCategory(ctx, id) |
| if err != nil { |
| return nil, err |
| } |
| |
| var tags []Tag |
| for _, id := range ids { |
| tag, err := c.GetTag(ctx, id) |
| if err != nil { |
| return nil, fmt.Errorf("get tag %s: %s", id, err) |
| } |
| |
| tags = append(tags, *tag) |
| } |
| return tags, nil |
| } |