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

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