github.com/vmware/govmomi@v0.37.1/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 }