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