Update vmware/govmomi vendor: add vapi package
Zones implementation for vSphere cloud provider needs dependencies which are not included in current vmware/govmomi vendor. So this update added "vapi" package to support zones.
This commit is contained in:
32
vendor/github.com/vmware/govmomi/vapi/tags/BUILD
generated
vendored
Normal file
32
vendor/github.com/vmware/govmomi/vapi/tags/BUILD
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"categories.go",
|
||||
"rest_client.go",
|
||||
"tag_association.go",
|
||||
"tags.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/vmware/govmomi/vapi/tags",
|
||||
importpath = "github.com/vmware/govmomi/vapi/tags",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/vmware/govmomi/vim25/soap:go_default_library",
|
||||
"//vendor/github.com/vmware/govmomi/vim25/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
226
vendor/github.com/vmware/govmomi/vapi/tags/categories.go
generated
vendored
Normal file
226
vendor/github.com/vmware/govmomi/vapi/tags/categories.go
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
// Copyright 2017 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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
CategoryURL = "/com/vmware/cis/tagging/category"
|
||||
ErrAlreadyExists = "already_exists"
|
||||
)
|
||||
|
||||
type CategoryCreateSpec struct {
|
||||
CreateSpec CategoryCreate `json:"create_spec"`
|
||||
}
|
||||
|
||||
type CategoryUpdateSpec struct {
|
||||
UpdateSpec CategoryUpdate `json:"update_spec,omitempty"`
|
||||
}
|
||||
|
||||
type CategoryCreate struct {
|
||||
AssociableTypes []string `json:"associable_types"`
|
||||
Cardinality string `json:"cardinality"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CategoryUpdate struct {
|
||||
AssociableTypes []string `json:"associable_types,omitempty"`
|
||||
Cardinality string `json:"cardinality,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type Category struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
Cardinality string `json:"cardinality"`
|
||||
AssociableTypes []string `json:"associable_types"`
|
||||
UsedBy []string `json:"used_by"`
|
||||
}
|
||||
|
||||
type CategoryInfo struct {
|
||||
Name string
|
||||
CategoryID string
|
||||
}
|
||||
|
||||
func (c *RestClient) CreateCategoryIfNotExist(ctx context.Context, name string, description string, categoryType string, multiValue bool) (*string, error) {
|
||||
categories, err := c.GetCategoriesByName(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if categories == nil {
|
||||
var multiValueStr string
|
||||
if multiValue {
|
||||
multiValueStr = "MULTIPLE"
|
||||
} else {
|
||||
multiValueStr = "SINGLE"
|
||||
}
|
||||
categoryCreate := CategoryCreate{[]string{categoryType}, multiValueStr, description, name}
|
||||
spec := CategoryCreateSpec{categoryCreate}
|
||||
id, err := c.CreateCategory(ctx, &spec)
|
||||
if err != nil {
|
||||
// in case there are two docker daemon try to create inventory category, query the category once again
|
||||
if strings.Contains(err.Error(), "ErrAlreadyExists") {
|
||||
if categories, err = c.GetCategoriesByName(ctx, name); err != nil {
|
||||
return nil, fmt.Errorf("failed to get inventory category for %s", err)
|
||||
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("failed to create inventory category for %s", err)
|
||||
|
||||
}
|
||||
} else {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
if categories != nil {
|
||||
return &categories[0].ID, nil
|
||||
}
|
||||
// should not happen
|
||||
return nil, fmt.Errorf("failed to create inventory for it's existed, but could not query back. Please check system")
|
||||
|
||||
}
|
||||
|
||||
func (c *RestClient) CreateCategory(ctx context.Context, spec *CategoryCreateSpec) (*string, error) {
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, CategoryURL, spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("create category failed with status code: %d, error message: %s", status, err)
|
||||
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
var pID RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pID); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
|
||||
}
|
||||
return &(pID.Value), nil
|
||||
}
|
||||
|
||||
func (c *RestClient) GetCategory(ctx context.Context, id string) (*Category, error) {
|
||||
|
||||
stream, _, status, err := c.call(ctx, http.MethodGet, fmt.Sprintf("%s/id:%s", CategoryURL, id), nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("get category failed with status code: %d, error message: %s", status, err)
|
||||
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value Category
|
||||
}
|
||||
|
||||
var pCategory RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pCategory); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
|
||||
}
|
||||
return &(pCategory.Value), nil
|
||||
}
|
||||
|
||||
func (c *RestClient) UpdateCategory(ctx context.Context, id string, spec *CategoryUpdateSpec) error {
|
||||
_, _, status, err := c.call(ctx, http.MethodPatch, fmt.Sprintf("%s/id:%s", CategoryURL, id), spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("update category failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) DeleteCategory(ctx context.Context, id string) error {
|
||||
|
||||
_, _, status, err := c.call(ctx, http.MethodDelete, fmt.Sprintf("%s/id:%s", CategoryURL, id), nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("delete category failed with status code: %d, error message: %s", status, err)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListCategories(ctx context.Context) ([]string, error) {
|
||||
|
||||
stream, _, status, err := c.call(ctx, http.MethodGet, CategoryURL, nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("get categories failed with status code: %d, error message: %s", status, err)
|
||||
|
||||
}
|
||||
|
||||
type Categories struct {
|
||||
Value []string
|
||||
}
|
||||
|
||||
var pCategories Categories
|
||||
if err := json.NewDecoder(stream).Decode(&pCategories); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
|
||||
}
|
||||
return pCategories.Value, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListCategoriesByName(ctx context.Context) ([]CategoryInfo, error) {
|
||||
categoryIds, err := c.ListCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category failed for: %s", err)
|
||||
}
|
||||
|
||||
var categoryInfoSlice []CategoryInfo
|
||||
for _, cID := range categoryIds {
|
||||
category, err := c.GetCategory(ctx, cID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
|
||||
}
|
||||
categoryCreate := &CategoryInfo{Name: category.Name, CategoryID: category.ID}
|
||||
|
||||
categoryInfoSlice = append(categoryInfoSlice, *categoryCreate)
|
||||
|
||||
}
|
||||
return categoryInfoSlice, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) GetCategoriesByName(ctx context.Context, name string) ([]Category, error) {
|
||||
categoryIds, err := c.ListCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category failed for: %s", err)
|
||||
|
||||
}
|
||||
|
||||
var categories []Category
|
||||
for _, cID := range categoryIds {
|
||||
category, err := c.GetCategory(ctx, cID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
|
||||
}
|
||||
if category.Name == name {
|
||||
categories = append(categories, *category)
|
||||
}
|
||||
}
|
||||
return categories, nil
|
||||
}
|
||||
272
vendor/github.com/vmware/govmomi/vapi/tags/rest_client.go
generated
vendored
Normal file
272
vendor/github.com/vmware/govmomi/vapi/tags/rest_client.go
generated
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
// Copyright 2017 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 (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
)
|
||||
|
||||
const (
|
||||
RestPrefix = "/rest"
|
||||
loginURL = "/com/vmware/cis/session"
|
||||
sessionIDCookieName = "vmware-api-session-id"
|
||||
)
|
||||
|
||||
type RestClient struct {
|
||||
mu sync.Mutex
|
||||
host string
|
||||
scheme string
|
||||
endpoint *url.URL
|
||||
user *url.Userinfo
|
||||
HTTP *http.Client
|
||||
cookies []*http.Cookie
|
||||
}
|
||||
|
||||
func NewClient(u *url.URL, insecure bool, thumbprint string) *RestClient {
|
||||
endpoint := &url.URL{}
|
||||
*endpoint = *u
|
||||
endpoint.Path = RestPrefix
|
||||
// Ignore "#" anchor
|
||||
endpoint.Fragment = ""
|
||||
|
||||
sc := soap.NewClient(endpoint, insecure)
|
||||
if thumbprint != "" {
|
||||
sc.SetThumbprint(endpoint.Host, thumbprint)
|
||||
}
|
||||
|
||||
user := endpoint.User
|
||||
endpoint.User = nil
|
||||
|
||||
return &RestClient{
|
||||
endpoint: endpoint,
|
||||
user: user,
|
||||
host: endpoint.Host,
|
||||
scheme: endpoint.Scheme,
|
||||
HTTP: &sc.Client,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientWithSessionID creates a new REST client with a supplied session ID
|
||||
// to re-connect to existing sessions.
|
||||
//
|
||||
// Note that the session is not checked for validity - to check for a valid
|
||||
// session after creating the client, use the Valid method. If the session is
|
||||
// no longer valid and the session needs to be re-saved, Login should be called
|
||||
// again before calling SessionID to extract the new session ID. Clients
|
||||
// created with this function function work in the exact same way as clients
|
||||
// created with NewClient, including supporting re-login on invalid sessions on
|
||||
// all SDK calls.
|
||||
func NewClientWithSessionID(u *url.URL, insecure bool, thumbprint string, sessionID string) *RestClient {
|
||||
c := NewClient(u, insecure, thumbprint)
|
||||
c.SetSessionID(sessionID)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *RestClient) encodeData(data interface{}) (*bytes.Buffer, error) {
|
||||
params := bytes.NewBuffer(nil)
|
||||
if data != nil {
|
||||
if err := json.NewEncoder(params).Encode(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) call(ctx context.Context, method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
|
||||
// Logger.Debugf("%s: %s, headers: %+v", method, path, headers)
|
||||
params, err := c.encodeData(data)
|
||||
if err != nil {
|
||||
return nil, nil, -1, err
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
if headers == nil {
|
||||
headers = make(map[string][]string)
|
||||
}
|
||||
headers["Content-Type"] = []string{"application/json"}
|
||||
}
|
||||
|
||||
body, hdr, statusCode, err := c.clientRequest(ctx, method, path, params, headers)
|
||||
if statusCode == http.StatusUnauthorized && strings.Contains(err.Error(), "This method requires authentication") {
|
||||
c.Login(ctx)
|
||||
return c.clientRequest(ctx, method, path, params, headers)
|
||||
}
|
||||
|
||||
return body, hdr, statusCode, err
|
||||
}
|
||||
|
||||
func (c *RestClient) clientRequest(ctx context.Context, method, path string, in io.Reader, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
|
||||
expectedPayload := (method == http.MethodPost || method == http.MethodPut)
|
||||
if expectedPayload && in == nil {
|
||||
in = bytes.NewReader([]byte{})
|
||||
}
|
||||
|
||||
req, err := c.newRequest(method, path, in)
|
||||
if err != nil {
|
||||
return nil, nil, -1, err
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
c.mu.Lock()
|
||||
if c.cookies != nil {
|
||||
req.AddCookie(c.cookies[0])
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
if headers != nil {
|
||||
for k, v := range headers {
|
||||
req.Header[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if expectedPayload && req.Header.Get("Content-Type") == "" {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
resp, err := c.HTTP.Do(req)
|
||||
return c.handleResponse(resp, err)
|
||||
}
|
||||
|
||||
func (c *RestClient) handleResponse(resp *http.Response, err error) (io.ReadCloser, http.Header, int, error) {
|
||||
statusCode := -1
|
||||
if resp != nil {
|
||||
statusCode = resp.StatusCode
|
||||
}
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "connection refused") {
|
||||
return nil, nil, statusCode, err
|
||||
}
|
||||
return nil, nil, statusCode, err
|
||||
}
|
||||
|
||||
if statusCode < http.StatusOK || statusCode >= http.StatusBadRequest {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, nil, statusCode, err
|
||||
}
|
||||
if len(body) == 0 {
|
||||
return nil, nil, statusCode, err
|
||||
}
|
||||
return nil, nil, statusCode, fmt.Errorf("error response: %s", bytes.TrimSpace(body))
|
||||
|
||||
}
|
||||
|
||||
return resp.Body, resp.Header, statusCode, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) Login(ctx context.Context) error {
|
||||
|
||||
request, err := c.newRequest(http.MethodPost, loginURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.user != nil {
|
||||
password, _ := c.user.Password()
|
||||
request.SetBasicAuth(c.user.Username(), password)
|
||||
}
|
||||
resp, err := c.HTTP.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
c.cookies = resp.Cookies()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) Logout(ctx context.Context) error {
|
||||
_, _, status, err := c.call(ctx, http.MethodDelete, loginURL, nil, nil)
|
||||
if status != http.StatusOK || err != nil {
|
||||
return err
|
||||
}
|
||||
c.SetSessionID("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) newRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
|
||||
return http.NewRequest(method, c.endpoint.String()+urlStr, body)
|
||||
}
|
||||
|
||||
// SessionID returns the current session ID of the REST client. An empty string
|
||||
// means there was no session cookie currently loaded.
|
||||
func (c *RestClient) SessionID() string {
|
||||
for _, cookie := range c.cookies {
|
||||
if cookie.Name == sessionIDCookieName {
|
||||
return cookie.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SetSessionID sets the session cookie with the supplied session ID.
|
||||
//
|
||||
// This does not necessarily mean the session is valid. The session should be
|
||||
// checked with Valid before proceeding, and logged back in if it has expired.
|
||||
//
|
||||
// This function will overwrite any existing session.
|
||||
func (c *RestClient) SetSessionID(sessionID string) {
|
||||
idx := -1
|
||||
for i, cookie := range c.cookies {
|
||||
if cookie.Name == sessionIDCookieName {
|
||||
idx = i
|
||||
}
|
||||
}
|
||||
sessionCookie := &http.Cookie{
|
||||
Name: sessionIDCookieName,
|
||||
Value: sessionID,
|
||||
Path: RestPrefix,
|
||||
}
|
||||
if idx > -1 {
|
||||
c.cookies[idx] = sessionCookie
|
||||
} else {
|
||||
c.cookies = append(c.cookies, sessionCookie)
|
||||
}
|
||||
}
|
||||
|
||||
// Valid checks to see if the session cookies in a REST client are still valid.
|
||||
// This should be used when restoring a session to determine if a new login is
|
||||
// necessary.
|
||||
func (c *RestClient) Valid(ctx context.Context) bool {
|
||||
_, _, statusCode, err := c.clientRequest(ctx, http.MethodPost, loginURL+"?~action=get", nil, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if statusCode == http.StatusOK {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
139
vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go
generated
vendored
Executable file
139
vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go
generated
vendored
Executable file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2017 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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
const (
|
||||
TagAssociationURL = "/com/vmware/cis/tagging/tag-association"
|
||||
)
|
||||
|
||||
type AssociatedObject struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type TagAssociationSpec struct {
|
||||
ObjectID *AssociatedObject `json:"object_id,omitempty"`
|
||||
TagID *string `json:"tag_id,omitempty"`
|
||||
}
|
||||
|
||||
type AttachedTagsInfo struct {
|
||||
Name string
|
||||
TagID string
|
||||
}
|
||||
|
||||
func (c *RestClient) getAssociatedObject(ref *types.ManagedObjectReference) *AssociatedObject {
|
||||
if ref == nil {
|
||||
return nil
|
||||
}
|
||||
object := AssociatedObject{
|
||||
ID: ref.Value,
|
||||
Type: ref.Type,
|
||||
}
|
||||
return &object
|
||||
}
|
||||
|
||||
func (c *RestClient) getAssociationSpec(tagID *string, ref *types.ManagedObjectReference) *TagAssociationSpec {
|
||||
object := c.getAssociatedObject(ref)
|
||||
spec := TagAssociationSpec{
|
||||
TagID: tagID,
|
||||
ObjectID: object,
|
||||
}
|
||||
return &spec
|
||||
}
|
||||
|
||||
func (c *RestClient) AttachTagToObject(ctx context.Context, tagID string, ref *types.ManagedObjectReference) error {
|
||||
spec := c.getAssociationSpec(&tagID, ref)
|
||||
_, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=attach", TagAssociationURL), *spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("attach tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) DetachTagFromObject(ctx context.Context, tagID string, ref *types.ManagedObjectReference) error {
|
||||
spec := c.getAssociationSpec(&tagID, ref)
|
||||
_, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=detach", TagAssociationURL), *spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("detach tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListAttachedTags(ctx context.Context, ref *types.ManagedObjectReference) ([]string, error) {
|
||||
spec := c.getAssociationSpec(nil, ref)
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=list-attached-tags", TagAssociationURL), *spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("detach tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value []string
|
||||
}
|
||||
|
||||
var pTag RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
}
|
||||
return pTag.Value, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListAttachedTagsByName(ctx context.Context, ref *types.ManagedObjectReference) ([]AttachedTagsInfo, error) {
|
||||
tagIds, err := c.ListAttachedTags(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get attached tag failed for: %s", err)
|
||||
}
|
||||
|
||||
var attachedTagsInfoSlice []AttachedTagsInfo
|
||||
for _, cID := range tagIds {
|
||||
tag, err := c.GetTag(ctx, cID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag %s failed for %s", cID, err)
|
||||
}
|
||||
attachedTagsCreate := &AttachedTagsInfo{Name: tag.Name, TagID: tag.ID}
|
||||
attachedTagsInfoSlice = append(attachedTagsInfoSlice, *attachedTagsCreate)
|
||||
}
|
||||
return attachedTagsInfoSlice, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListAttachedObjects(ctx context.Context, tagID string) ([]AssociatedObject, error) {
|
||||
spec := c.getAssociationSpec(&tagID, nil)
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s?~action=list-attached-objects", TagAssociationURL), *spec, nil)
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("list object failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value []AssociatedObject
|
||||
}
|
||||
|
||||
var pTag RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
}
|
||||
|
||||
return pTag.Value, nil
|
||||
}
|
||||
252
vendor/github.com/vmware/govmomi/vapi/tags/tags.go
generated
vendored
Normal file
252
vendor/github.com/vmware/govmomi/vapi/tags/tags.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright 2017 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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
TagURL = "/com/vmware/cis/tagging/tag"
|
||||
)
|
||||
|
||||
type TagCreateSpec struct {
|
||||
CreateSpec TagCreate `json:"create_spec"`
|
||||
}
|
||||
|
||||
type TagCreate struct {
|
||||
CategoryID string `json:"category_id"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type TagUpdateSpec struct {
|
||||
UpdateSpec TagUpdate `json:"update_spec,omitempty"`
|
||||
}
|
||||
|
||||
type TagUpdate struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Name string `json:"name"`
|
||||
CategoryID string `json:"category_id"`
|
||||
UsedBy []string `json:"used_by"`
|
||||
}
|
||||
|
||||
func (c *RestClient) CreateTagIfNotExist(ctx context.Context, name string, description string, categoryID string) (*string, error) {
|
||||
tagCreate := TagCreate{categoryID, description, name}
|
||||
spec := TagCreateSpec{tagCreate}
|
||||
id, err := c.CreateTag(ctx, &spec)
|
||||
if err == nil {
|
||||
return id, nil
|
||||
}
|
||||
// if already exists, query back
|
||||
if strings.Contains(err.Error(), ErrAlreadyExists) {
|
||||
tagObjs, err := c.GetTagByNameForCategory(ctx, name, categoryID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tagObjs != nil {
|
||||
return &tagObjs[0].ID, nil
|
||||
}
|
||||
|
||||
// should not happen
|
||||
return nil, fmt.Errorf("failed to create tag for it's existed, but could not query back. Please check system")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("created tag failed for %s", err)
|
||||
}
|
||||
|
||||
func (c *RestClient) DeleteTagIfNoObjectAttached(ctx context.Context, id string) error {
|
||||
objs, err := c.ListAttachedObjects(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(objs) > 0 {
|
||||
return fmt.Errorf("tag %s related objects is not empty, do not delete it", id)
|
||||
}
|
||||
return c.DeleteTag(ctx, id)
|
||||
}
|
||||
|
||||
func (c *RestClient) CreateTag(ctx context.Context, spec *TagCreateSpec) (*string, error) {
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, TagURL, spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("create tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
var pID RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pID); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
}
|
||||
return &pID.Value, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) GetTag(ctx context.Context, id string) (*Tag, error) {
|
||||
stream, _, status, err := c.call(ctx, http.MethodGet, fmt.Sprintf("%s/id:%s", TagURL, id), nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("get tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
type RespValue struct {
|
||||
Value Tag
|
||||
}
|
||||
|
||||
var pTag RespValue
|
||||
if err := json.NewDecoder(stream).Decode(&pTag); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
}
|
||||
return &(pTag.Value), nil
|
||||
}
|
||||
|
||||
func (c *RestClient) UpdateTag(ctx context.Context, id string, spec *TagUpdateSpec) error {
|
||||
_, _, status, err := c.call(ctx, http.MethodPatch, fmt.Sprintf("%s/id:%s", TagURL, id), spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("update tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) DeleteTag(ctx context.Context, id string) error {
|
||||
_, _, status, err := c.call(ctx, http.MethodDelete, fmt.Sprintf("%s/id:%s", TagURL, id), nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return fmt.Errorf("delete tag failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListTags(ctx context.Context) ([]string, error) {
|
||||
stream, _, status, err := c.call(ctx, http.MethodGet, TagURL, nil, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("get tags failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
return c.handleTagIDList(stream)
|
||||
}
|
||||
|
||||
type TagsInfo struct {
|
||||
Name string
|
||||
TagID string
|
||||
}
|
||||
|
||||
func (c *RestClient) ListTagsByName(ctx context.Context) ([]TagsInfo, error) {
|
||||
tagIds, err := c.ListTags(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tags failed for: %s", err)
|
||||
}
|
||||
|
||||
var tagsInfoSlice []TagsInfo
|
||||
for _, cID := range tagIds {
|
||||
tag, err := c.GetTag(ctx, cID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category %s failed for %s", cID, err)
|
||||
}
|
||||
tagsCreate := &TagsInfo{Name: tag.Name, TagID: tag.ID}
|
||||
|
||||
tagsInfoSlice = append(tagsInfoSlice, *tagsCreate)
|
||||
|
||||
}
|
||||
return tagsInfoSlice, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) ListTagsForCategory(ctx context.Context, id string) ([]string, error) {
|
||||
|
||||
type PostCategory struct {
|
||||
ID string `json:"category_id"`
|
||||
}
|
||||
spec := PostCategory{id}
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s/id:%s?~action=list-tags-for-category", TagURL, id), spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("list tags for category failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
|
||||
return c.handleTagIDList(stream)
|
||||
}
|
||||
|
||||
func (c *RestClient) ListTagsInfoForCategory(ctx context.Context, id string) ([]TagsInfo, error) {
|
||||
|
||||
type PostCategory struct {
|
||||
ID string `json:"category_id"`
|
||||
}
|
||||
spec := PostCategory{id}
|
||||
stream, _, status, err := c.call(ctx, http.MethodPost, fmt.Sprintf("%s/id:%s?~action=list-tags-for-category", TagURL, id), spec, nil)
|
||||
|
||||
if status != http.StatusOK || err != nil {
|
||||
return nil, fmt.Errorf("list tags for category failed with status code: %d, error message: %s", status, err)
|
||||
}
|
||||
var tagsInfoSlice []TagsInfo
|
||||
tmp, err := c.handleTagIDList(stream)
|
||||
for _, item := range tmp {
|
||||
tag, err := c.GetTag(ctx, item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get category %s failed for %s", item, err)
|
||||
}
|
||||
tagsCreate := &TagsInfo{Name: tag.Name, TagID: tag.ID}
|
||||
|
||||
tagsInfoSlice = append(tagsInfoSlice, *tagsCreate)
|
||||
}
|
||||
return tagsInfoSlice, nil
|
||||
}
|
||||
|
||||
func (c *RestClient) handleTagIDList(stream io.ReadCloser) ([]string, error) {
|
||||
type Tags struct {
|
||||
Value []string
|
||||
}
|
||||
|
||||
var pTags Tags
|
||||
if err := json.NewDecoder(stream).Decode(&pTags); err != nil {
|
||||
return nil, fmt.Errorf("decode response body failed for: %s", err)
|
||||
}
|
||||
return pTags.Value, nil
|
||||
}
|
||||
|
||||
// Get tag through tag name and category id
|
||||
func (c *RestClient) GetTagByNameForCategory(ctx context.Context, name string, id string) ([]Tag, error) {
|
||||
tagIds, err := c.ListTagsForCategory(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag failed for %s", err)
|
||||
}
|
||||
|
||||
var tags []Tag
|
||||
for _, tID := range tagIds {
|
||||
tag, err := c.GetTag(ctx, tID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get tag %s failed for %s", tID, err)
|
||||
}
|
||||
if tag.Name == name {
|
||||
tags = append(tags, *tag)
|
||||
}
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
Reference in New Issue
Block a user