github.com/vmware/govmomi@v0.37.2/vapi/library/library.go (about)

     1  /*
     2  Copyright (c) 2018-2024 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package library
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"net/url"
    24  	"time"
    25  
    26  	"github.com/vmware/govmomi/object"
    27  	"github.com/vmware/govmomi/vapi/internal"
    28  	"github.com/vmware/govmomi/vapi/rest"
    29  )
    30  
    31  // StorageBackings for Content Libraries
    32  type StorageBackings struct {
    33  	DatastoreID string `json:"datastore_id,omitempty"`
    34  	Type        string `json:"type,omitempty"`
    35  }
    36  
    37  // Library  provides methods to create, read, update, delete, and enumerate libraries.
    38  type Library struct {
    39  	CreationTime          *time.Time        `json:"creation_time,omitempty"`
    40  	Description           *string           `json:"description,omitempty"`
    41  	ID                    string            `json:"id,omitempty"`
    42  	LastModifiedTime      *time.Time        `json:"last_modified_time,omitempty"`
    43  	LastSyncTime          *time.Time        `json:"last_sync_time,omitempty"`
    44  	Name                  string            `json:"name,omitempty"`
    45  	Storage               []StorageBackings `json:"storage_backings,omitempty"`
    46  	Type                  string            `json:"type,omitempty"`
    47  	Version               string            `json:"version,omitempty"`
    48  	Subscription          *Subscription     `json:"subscription_info,omitempty"`
    49  	Publication           *Publication      `json:"publish_info,omitempty"`
    50  	SecurityPolicyID      string            `json:"security_policy_id,omitempty"`
    51  	UnsetSecurityPolicyID bool              `json:"unset_security_policy_id,omitempty"`
    52  }
    53  
    54  // Subscription info
    55  type Subscription struct {
    56  	AuthenticationMethod string `json:"authentication_method"`
    57  	AutomaticSyncEnabled *bool  `json:"automatic_sync_enabled,omitempty"`
    58  	OnDemand             *bool  `json:"on_demand,omitempty"`
    59  	Password             string `json:"password,omitempty"`
    60  	SslThumbprint        string `json:"ssl_thumbprint,omitempty"`
    61  	SubscriptionURL      string `json:"subscription_url,omitempty"`
    62  	UserName             string `json:"user_name,omitempty"`
    63  }
    64  
    65  // Publication info
    66  type Publication struct {
    67  	AuthenticationMethod string `json:"authentication_method"`
    68  	UserName             string `json:"user_name,omitempty"`
    69  	Password             string `json:"password,omitempty"`
    70  	CurrentPassword      string `json:"current_password,omitempty"`
    71  	PersistJSON          *bool  `json:"persist_json_enabled,omitempty"`
    72  	Published            *bool  `json:"published,omitempty"`
    73  	PublishURL           string `json:"publish_url,omitempty"`
    74  }
    75  
    76  // SubscriberSummary as returned by ListSubscribers
    77  type SubscriberSummary struct {
    78  	LibraryID              string `json:"subscribed_library"`
    79  	LibraryName            string `json:"subscribed_library_name"`
    80  	SubscriptionID         string `json:"subscription"`
    81  	LibraryVcenterHostname string `json:"subscribed_library_vcenter_hostname,omitempty"`
    82  }
    83  
    84  // Placement information used to place a virtual machine template
    85  type Placement struct {
    86  	ResourcePool string `json:"resource_pool,omitempty"`
    87  	Host         string `json:"host,omitempty"`
    88  	Folder       string `json:"folder,omitempty"`
    89  	Cluster      string `json:"cluster,omitempty"`
    90  	Network      string `json:"network,omitempty"`
    91  }
    92  
    93  // Vcenter contains information about the vCenter Server instance where a subscribed library associated with a subscription exists.
    94  type Vcenter struct {
    95  	Hostname   string `json:"hostname"`
    96  	Port       int    `json:"https_port,omitempty"`
    97  	ServerGUID string `json:"server_guid"`
    98  }
    99  
   100  // Subscriber contains the detailed info for a library subscriber.
   101  type Subscriber struct {
   102  	LibraryID       string     `json:"subscribed_library"`
   103  	LibraryName     string     `json:"subscribed_library_name"`
   104  	LibraryLocation string     `json:"subscribed_library_location"`
   105  	Placement       *Placement `json:"subscribed_library_placement,omitempty"`
   106  	Vcenter         *Vcenter   `json:"subscribed_library_vcenter,omitempty"`
   107  }
   108  
   109  // SubscriberLibrary is the specification for a subscribed library to be associated with a subscription.
   110  type SubscriberLibrary struct {
   111  	Target    string     `json:"target"`
   112  	LibraryID string     `json:"subscribed_library,omitempty"`
   113  	Location  string     `json:"location"`
   114  	Vcenter   *Vcenter   `json:"vcenter,omitempty"`
   115  	Placement *Placement `json:"placement,omitempty"`
   116  }
   117  
   118  // Patch merges updates from the given src.
   119  func (l *Library) Patch(src *Library) {
   120  	if src.Name != "" {
   121  		l.Name = src.Name
   122  	}
   123  	if src.Description != nil {
   124  		l.Description = src.Description
   125  	}
   126  	if src.Version != "" {
   127  		l.Version = src.Version
   128  	}
   129  }
   130  
   131  // Manager extends rest.Client, adding content library related methods.
   132  type Manager struct {
   133  	*rest.Client
   134  }
   135  
   136  // NewManager creates a new Manager instance with the given client.
   137  func NewManager(client *rest.Client) *Manager {
   138  	return &Manager{
   139  		Client: client,
   140  	}
   141  }
   142  
   143  // Find is the search criteria for finding libraries.
   144  type Find struct {
   145  	Name string `json:"name,omitempty"`
   146  	Type string `json:"type,omitempty"`
   147  }
   148  
   149  // FindLibrary returns one or more libraries that match the provided search
   150  // criteria.
   151  //
   152  // The provided name is case-insensitive.
   153  //
   154  // Either the name or type of library may be set to empty values in order
   155  // to search for all libraries, all libraries with a specific name, regardless
   156  // of type, or all libraries of a specified type.
   157  func (c *Manager) FindLibrary(ctx context.Context, search Find) ([]string, error) {
   158  	url := c.Resource(internal.LibraryPath).WithAction("find")
   159  	spec := struct {
   160  		Spec Find `json:"spec"`
   161  	}{search}
   162  	var res []string
   163  	return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
   164  }
   165  
   166  // CreateLibrary creates a new library with the given Type, Name,
   167  // Description, and CategoryID.
   168  func (c *Manager) CreateLibrary(ctx context.Context, library Library) (string, error) {
   169  	spec := struct {
   170  		Library Library `json:"create_spec"`
   171  	}{library}
   172  	path := internal.LocalLibraryPath
   173  	if library.Type == "SUBSCRIBED" {
   174  		path = internal.SubscribedLibraryPath
   175  		sub := library.Subscription
   176  		u, err := url.Parse(sub.SubscriptionURL)
   177  		if err != nil {
   178  			return "", err
   179  		}
   180  		if u.Scheme == "https" && sub.SslThumbprint == "" {
   181  			thumbprint := c.Thumbprint(u.Host)
   182  			if thumbprint == "" {
   183  				t := c.DefaultTransport()
   184  				if t.TLSClientConfig.InsecureSkipVerify {
   185  					var info object.HostCertificateInfo
   186  					_ = info.FromURL(u, t.TLSClientConfig)
   187  					thumbprint = info.ThumbprintSHA1
   188  				}
   189  				sub.SslThumbprint = thumbprint
   190  			}
   191  		}
   192  	}
   193  	url := c.Resource(path)
   194  	var res string
   195  	return res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
   196  }
   197  
   198  // SyncLibrary syncs a subscribed library.
   199  func (c *Manager) SyncLibrary(ctx context.Context, library *Library) error {
   200  	path := internal.SubscribedLibraryPath
   201  	url := c.Resource(path).WithID(library.ID).WithAction("sync")
   202  	return c.Do(ctx, url.Request(http.MethodPost), nil)
   203  }
   204  
   205  // PublishLibrary publishes the library to specified subscriptions.
   206  // If no subscriptions are specified, then publishes the library to all subscriptions.
   207  func (c *Manager) PublishLibrary(ctx context.Context, library *Library, subscriptions []string) error {
   208  	path := internal.LocalLibraryPath
   209  	var spec internal.SubscriptionDestinationSpec
   210  	for i := range subscriptions {
   211  		spec.Subscriptions = append(spec.Subscriptions, internal.SubscriptionDestination{ID: subscriptions[i]})
   212  	}
   213  	url := c.Resource(path).WithID(library.ID).WithAction("publish")
   214  	return c.Do(ctx, url.Request(http.MethodPost, spec), nil)
   215  }
   216  
   217  // UpdateLibrary can update one or both of the tag Description and Name fields.
   218  func (c *Manager) UpdateLibrary(ctx context.Context, l *Library) error {
   219  	spec := struct {
   220  		Library `json:"update_spec"`
   221  	}{
   222  		Library{
   223  			Name:        l.Name,
   224  			Description: l.Description,
   225  		},
   226  	}
   227  	url := c.Resource(internal.LibraryPath).WithID(l.ID)
   228  	return c.Do(ctx, url.Request(http.MethodPatch, spec), nil)
   229  }
   230  
   231  // DeleteLibrary deletes an existing library.
   232  func (c *Manager) DeleteLibrary(ctx context.Context, library *Library) error {
   233  	path := internal.LocalLibraryPath
   234  	if library.Type == "SUBSCRIBED" {
   235  		path = internal.SubscribedLibraryPath
   236  	}
   237  	url := c.Resource(path).WithID(library.ID)
   238  	return c.Do(ctx, url.Request(http.MethodDelete), nil)
   239  }
   240  
   241  // ListLibraries returns a list of all content library IDs in the system.
   242  func (c *Manager) ListLibraries(ctx context.Context) ([]string, error) {
   243  	url := c.Resource(internal.LibraryPath)
   244  	var res []string
   245  	return res, c.Do(ctx, url.Request(http.MethodGet), &res)
   246  }
   247  
   248  // GetLibraryByID returns information on a library for the given ID.
   249  func (c *Manager) GetLibraryByID(ctx context.Context, id string) (*Library, error) {
   250  	url := c.Resource(internal.LibraryPath).WithID(id)
   251  	var res Library
   252  	return &res, c.Do(ctx, url.Request(http.MethodGet), &res)
   253  }
   254  
   255  // GetLibraryByName returns information on a library for the given name.
   256  func (c *Manager) GetLibraryByName(ctx context.Context, name string) (*Library, error) {
   257  	// Lookup by name
   258  	libraries, err := c.GetLibraries(ctx)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	for i := range libraries {
   263  		if libraries[i].Name == name {
   264  			return &libraries[i], nil
   265  		}
   266  	}
   267  	return nil, fmt.Errorf("library name (%s) not found", name)
   268  }
   269  
   270  // GetLibraries returns a list of all content library details in the system.
   271  func (c *Manager) GetLibraries(ctx context.Context) ([]Library, error) {
   272  	ids, err := c.ListLibraries(ctx)
   273  	if err != nil {
   274  		return nil, fmt.Errorf("get libraries failed for: %s", err)
   275  	}
   276  
   277  	var libraries []Library
   278  	for _, id := range ids {
   279  		library, err := c.GetLibraryByID(ctx, id)
   280  		if err != nil {
   281  			return nil, fmt.Errorf("get library %s failed for %s", id, err)
   282  		}
   283  
   284  		libraries = append(libraries, *library)
   285  
   286  	}
   287  	return libraries, nil
   288  }
   289  
   290  // ListSubscribers lists the subscriptions of the published library.
   291  func (c *Manager) ListSubscribers(ctx context.Context, library *Library) ([]SubscriberSummary, error) {
   292  	url := c.Resource(internal.Subscriptions).WithParam("library", library.ID)
   293  	var res []SubscriberSummary
   294  	return res, c.Do(ctx, url.Request(http.MethodGet), &res)
   295  }
   296  
   297  // CreateSubscriber creates a subscription of the published library.
   298  func (c *Manager) CreateSubscriber(ctx context.Context, library *Library, s SubscriberLibrary) (string, error) {
   299  	var spec struct {
   300  		Sub struct {
   301  			SubscriberLibrary SubscriberLibrary `json:"subscribed_library"`
   302  		} `json:"spec"`
   303  	}
   304  	spec.Sub.SubscriberLibrary = s
   305  	url := c.Resource(internal.Subscriptions).WithID(library.ID)
   306  	var res string
   307  	return res, c.Do(ctx, url.Request(http.MethodPost, &spec), &res)
   308  }
   309  
   310  // GetSubscriber returns information about the specified subscriber of the published library.
   311  func (c *Manager) GetSubscriber(ctx context.Context, library *Library, subscriber string) (*Subscriber, error) {
   312  	id := internal.SubscriptionDestination{ID: subscriber}
   313  	url := c.Resource(internal.Subscriptions).WithID(library.ID).WithAction("get")
   314  	var res Subscriber
   315  	return &res, c.Do(ctx, url.Request(http.MethodPost, &id), &res)
   316  }
   317  
   318  // DeleteSubscriber deletes the specified subscription of the published library.
   319  // The subscribed library associated with the subscription will not be deleted.
   320  func (c *Manager) DeleteSubscriber(ctx context.Context, library *Library, subscriber string) error {
   321  	id := internal.SubscriptionDestination{ID: subscriber}
   322  	url := c.Resource(internal.Subscriptions).WithID(library.ID).WithAction("delete")
   323  	return c.Do(ctx, url.Request(http.MethodPost, &id), nil)
   324  }
   325  
   326  // EvictSubscribedLibrary evicts the cached content of an on-demand subscribed library.
   327  // This operation allows the cached content of a subscribed library to be removed to free up storage capacity.
   328  func (c *Manager) EvictSubscribedLibrary(ctx context.Context, library *Library) error {
   329  	path := internal.SubscribedLibraryPath
   330  	url := c.Resource(path).WithID(library.ID).WithAction("evict")
   331  	return c.Do(ctx, url.Request(http.MethodPost), nil)
   332  }