github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/vapptemplate.go (about) 1 /* 2 * Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "fmt" 9 "net/http" 10 "net/url" 11 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 "github.com/vmware/go-vcloud-director/v2/util" 14 ) 15 16 type VAppTemplate struct { 17 VAppTemplate *types.VAppTemplate 18 client *Client 19 } 20 21 func NewVAppTemplate(cli *Client) *VAppTemplate { 22 return &VAppTemplate{ 23 VAppTemplate: new(types.VAppTemplate), 24 client: cli, 25 } 26 } 27 28 // Deprecated: wrong implementation and result 29 // Use vdc.CreateVappFromTemplate instead 30 func (vdc *Vdc) InstantiateVAppTemplate(template *types.InstantiateVAppTemplateParams) error { 31 vdcHref, err := url.ParseRequestURI(vdc.Vdc.HREF) 32 if err != nil { 33 return fmt.Errorf("error getting vdc href: %s", err) 34 } 35 vdcHref.Path += "/action/instantiateVAppTemplate" 36 37 vapptemplate := NewVAppTemplate(vdc.client) 38 39 _, err = vdc.client.ExecuteRequest(vdcHref.String(), http.MethodPut, 40 types.MimeInstantiateVappTemplateParams, "error instantiating a new vApp Template: %s", template, vapptemplate) 41 if err != nil { 42 return err 43 } 44 45 task := NewTask(vdc.client) 46 for _, taskItem := range vapptemplate.VAppTemplate.Tasks.Task { 47 task.Task = taskItem 48 err = task.WaitTaskCompletion() 49 if err != nil { 50 return fmt.Errorf("error performing task: %s", err) 51 } 52 } 53 return nil 54 } 55 56 // Refresh refreshes the vApp template item information by href 57 func (vAppTemplate *VAppTemplate) Refresh() error { 58 59 if vAppTemplate.VAppTemplate == nil { 60 return fmt.Errorf("cannot refresh, Object is empty") 61 } 62 63 url := vAppTemplate.VAppTemplate.HREF 64 if url == "nil" { 65 return fmt.Errorf("cannot refresh, HREF is empty") 66 } 67 68 vAppTemplate.VAppTemplate = &types.VAppTemplate{} 69 70 _, err := vAppTemplate.client.ExecuteRequest(url, http.MethodGet, 71 "", "error retrieving vApp Template: %s", nil, vAppTemplate.VAppTemplate) 72 73 return err 74 } 75 76 // GetCatalogName gets the catalog name to which the receiver vApp Template belongs 77 func (vAppTemplate *VAppTemplate) GetCatalogName() (string, error) { 78 queriedVappTemplates, err := queryVappTemplateListWithFilter(vAppTemplate.client, map[string]string{ 79 "id": vAppTemplate.VAppTemplate.ID, 80 }) 81 if err != nil { 82 return "", err 83 } 84 if len(queriedVappTemplates) != 1 { 85 return "", fmt.Errorf("found %d vApp Templates with ID %s", len(queriedVappTemplates), vAppTemplate.VAppTemplate.ID) 86 } 87 return queriedVappTemplates[0].CatalogName, nil 88 } 89 90 // GetVdcName gets the VDC name to which the receiver vApp Template belongs 91 func (vAppTemplate *VAppTemplate) GetVdcName() (string, error) { 92 queriedVappTemplates, err := queryVappTemplateListWithFilter(vAppTemplate.client, map[string]string{ 93 "id": vAppTemplate.VAppTemplate.ID, 94 }) 95 if err != nil { 96 return "", err 97 } 98 if len(queriedVappTemplates) != 1 { 99 return "", fmt.Errorf("found %d vApp Templates with ID %s", len(queriedVappTemplates), vAppTemplate.VAppTemplate.ID) 100 } 101 return queriedVappTemplates[0].VdcName, nil 102 } 103 104 // GetVappTemplateRecord gets the corresponding vApp template record 105 func (vAppTemplate *VAppTemplate) GetVappTemplateRecord() (*types.QueryResultVappTemplateType, error) { 106 queriedVappTemplates, err := queryVappTemplateListWithFilter(vAppTemplate.client, map[string]string{ 107 "id": vAppTemplate.VAppTemplate.ID, 108 }) 109 if err != nil { 110 return nil, err 111 } 112 if len(queriedVappTemplates) != 1 { 113 return nil, fmt.Errorf("found %d vApp Templates with ID %s", len(queriedVappTemplates), vAppTemplate.VAppTemplate.ID) 114 } 115 return queriedVappTemplates[0], nil 116 } 117 118 // Update updates the vApp template item information. 119 // VCD also updates the associated Catalog Item, in order to be in sync with the receiver vApp Template entity. 120 // For example, updating a vApp Template name "A" to "B" will make VCD to also update the Catalog Item to be renamed to "B". 121 // Returns vApp template and error. 122 func (vAppTemplate *VAppTemplate) Update() (*VAppTemplate, error) { 123 if vAppTemplate.VAppTemplate == nil { 124 return nil, fmt.Errorf("cannot update, Object is empty") 125 } 126 127 url := vAppTemplate.VAppTemplate.HREF 128 if url == "nil" { 129 return nil, fmt.Errorf("cannot update, HREF is empty") 130 } 131 132 task, err := vAppTemplate.UpdateAsync() 133 if err != nil { 134 return nil, err 135 } 136 err = task.WaitTaskCompletion() 137 if err != nil { 138 return nil, fmt.Errorf("error waiting for task completion after updating vApp Template %s: %s", vAppTemplate.VAppTemplate.Name, err) 139 } 140 err = vAppTemplate.Refresh() 141 if err != nil { 142 return nil, fmt.Errorf("error refreshing vApp Template %s: %s", vAppTemplate.VAppTemplate.Name, err) 143 } 144 return vAppTemplate, nil 145 } 146 147 // UpdateAsync updates the vApp template item information 148 // Returns Task and error. 149 func (vAppTemplate *VAppTemplate) UpdateAsync() (Task, error) { 150 151 if vAppTemplate.VAppTemplate == nil { 152 return Task{}, fmt.Errorf("cannot update, Object is empty") 153 } 154 155 url := vAppTemplate.VAppTemplate.HREF 156 if url == "nil" { 157 return Task{}, fmt.Errorf("cannot update, HREF is empty") 158 } 159 160 vappTemplatePayload := types.VAppTemplateForUpdate{ 161 Xmlns: types.XMLNamespaceVCloud, 162 HREF: vAppTemplate.VAppTemplate.HREF, 163 ID: vAppTemplate.VAppTemplate.ID, 164 Name: vAppTemplate.VAppTemplate.Name, 165 GoldMaster: vAppTemplate.VAppTemplate.GoldMaster, 166 Description: vAppTemplate.VAppTemplate.Description, 167 Link: vAppTemplate.VAppTemplate.Link, 168 } 169 170 return vAppTemplate.client.ExecuteTaskRequest(url, http.MethodPut, 171 types.MimeVAppTemplate, "error updating vApp Template: %s", vappTemplatePayload) 172 } 173 174 // DeleteAsync deletes the VAppTemplate, returning the Task that monitors the deletion process, or an error 175 // if something wrong happened. 176 func (vAppTemplate *VAppTemplate) DeleteAsync() (Task, error) { 177 util.Logger.Printf("[TRACE] Deleting vApp Template: %#v", vAppTemplate.VAppTemplate) 178 179 vappTemplateHref := vAppTemplate.client.VCDHREF 180 vappTemplateHref.Path += "/vAppTemplate/vappTemplate-" + extractUuid(vAppTemplate.VAppTemplate.ID) 181 182 util.Logger.Printf("[TRACE] Url for deleting vApp Template: %#v and name: %s", vappTemplateHref, vAppTemplate.VAppTemplate.Name) 183 184 return vAppTemplate.client.ExecuteTaskRequest(vappTemplateHref.String(), http.MethodDelete, 185 "", "error deleting vApp Template: %s", nil) 186 } 187 188 // Delete deletes the VAppTemplate and waits for the deletion to finish, returning an error if something wrong happened. 189 func (vAppTemplate *VAppTemplate) Delete() error { 190 task, err := vAppTemplate.DeleteAsync() 191 if err != nil { 192 return err 193 } 194 err = task.WaitTaskCompletion() 195 if err != nil { 196 return fmt.Errorf("error waiting for task completion after deleting vApp Template %s: %s", vAppTemplate.VAppTemplate.Name, err) 197 } 198 return nil 199 } 200 201 // GetVAppTemplateByHref finds a vApp template by HREF 202 // On success, returns a pointer to the vApp template structure and a nil error 203 // On failure, returns a nil pointer and an error 204 func (vcdClient *VCDClient) GetVAppTemplateByHref(href string) (*VAppTemplate, error) { 205 return getVAppTemplateByHref(&vcdClient.Client, href) 206 } 207 208 // GetVAppTemplateById finds a vApp Template by ID. 209 // On success, returns a pointer to the VAppTemplate structure and a nil error. 210 // On failure, returns a nil pointer and an error. 211 func (vcdClient *VCDClient) GetVAppTemplateById(vAppTemplateId string) (*VAppTemplate, error) { 212 return getVAppTemplateById(&vcdClient.Client, vAppTemplateId) 213 } 214 215 // QuerySynchronizedVAppTemplateById Finds a vApp Template by its URN that is synchronized in the catalog. 216 // Returns types.QueryResultVMRecordType if it is found, returns ErrorEntityNotFound if not found, or an error if many are 217 // found. 218 func (vcdClient *VCDClient) QuerySynchronizedVAppTemplateById(vAppTemplateId string) (*types.QueryResultVappTemplateType, error) { 219 queryType := types.QtVappTemplate 220 if vcdClient.Client.IsSysAdmin { 221 queryType = types.QtAdminVappTemplate 222 } 223 224 // this allows to query deployed and not deployed templates 225 results, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ 226 "type": queryType, 227 "filter": "id==" + url.QueryEscape(extractUuid(vAppTemplateId)) + 228 ";status!=FAILED_CREATION;status!=UNKNOWN;status!=UNRECOGNIZED;status!=UNRESOLVED;status!=LOCAL_COPY_UNAVAILABLE&links=true", 229 "filterEncoded": "true"}) 230 if err != nil { 231 return nil, fmt.Errorf("[QueryVAppTemplateById] error quering vApp templates with ID %s: %s", vAppTemplateId, err) 232 } 233 234 vAppTemplateRecords := results.Results.VappTemplateRecord 235 if vcdClient.Client.IsSysAdmin { 236 vAppTemplateRecords = results.Results.AdminVappTemplateRecord 237 } 238 if len(vAppTemplateRecords) == 0 { 239 return nil, ErrorEntityNotFound 240 } 241 242 if len(vAppTemplateRecords) > 1 { 243 return nil, fmt.Errorf("[QueryVmInVAppTemplateByHref] found %d results with with ID: %s", len(vAppTemplateRecords), vAppTemplateId) 244 } 245 246 return vAppTemplateRecords[0], nil 247 } 248 249 // QueryVmInVAppTemplateByHref Finds a VM inside a vApp Template using the latter HREF. 250 // Returns types.QueryResultVMRecordType if it is found, returns ErrorEntityNotFound if not found, or an error if many are 251 // found. 252 func (vcdClient *VCDClient) QueryVmInVAppTemplateByHref(vAppTemplateHref, vmNameInTemplate string) (*types.QueryResultVMRecordType, error) { 253 queryType := types.QtVm 254 if vcdClient.Client.IsSysAdmin { 255 queryType = types.QtAdminVm 256 } 257 258 // this allows to query deployed and not deployed templates 259 results, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ 260 "type": queryType, 261 "filter": "container==" + url.QueryEscape(vAppTemplateHref) + ";name==" + url.QueryEscape(vmNameInTemplate) + 262 ";isVAppTemplate==true;status!=FAILED_CREATION;status!=UNKNOWN;status!=UNRECOGNIZED;status!=UNRESOLVED&links=true;", 263 "filterEncoded": "true"}) 264 if err != nil { 265 return nil, fmt.Errorf("[QueryVmInVAppTemplateByHref] error quering vApp templates with HREF %s:, VM name: %s: Error: %s", vAppTemplateHref, vmNameInTemplate, err) 266 } 267 268 vmResults := results.Results.VMRecord 269 if vcdClient.Client.IsSysAdmin { 270 vmResults = results.Results.AdminVMRecord 271 } 272 273 if len(vmResults) == 0 { 274 return nil, ErrorEntityNotFound 275 } 276 277 if len(vmResults) > 1 { 278 return nil, fmt.Errorf("[QueryVmInVAppTemplateByHref] found %d results with with HREF: %s, VM name: %s", len(vmResults), vAppTemplateHref, vmNameInTemplate) 279 } 280 281 return vmResults[0], nil 282 } 283 284 // QuerySynchronizedVmInVAppTemplateByHref Finds a catalog-synchronized VM inside a vApp Template using the latter HREF. 285 // Returns types.QueryResultVMRecordType if it is found and it's synchronized in the catalog. 286 // Returns ErrorEntityNotFound if not found, or an error if many are found. 287 func (vcdClient *VCDClient) QuerySynchronizedVmInVAppTemplateByHref(vAppTemplateHref, vmNameInTemplate string) (*types.QueryResultVMRecordType, error) { 288 vmRecord, err := vcdClient.QueryVmInVAppTemplateByHref(vAppTemplateHref, vmNameInTemplate) 289 if err != nil { 290 return nil, err 291 } 292 if vmRecord.Status == "LOCAL_COPY_UNAVAILABLE" { 293 return nil, fmt.Errorf("vApp template %s is not synchronized", extractUuid(vAppTemplateHref)) 294 } 295 return vmRecord, nil 296 } 297 298 // RenewLease updates the lease terms for the vAppTemplate 299 func (vAppTemplate *VAppTemplate) RenewLease(storageLeaseInSeconds int) error { 300 301 href := "" 302 if vAppTemplate.VAppTemplate.LeaseSettingsSection != nil { 303 if vAppTemplate.VAppTemplate.LeaseSettingsSection.StorageLeaseInSeconds == storageLeaseInSeconds { 304 // Requested parameters are the same as existing parameters: exit without updating 305 return nil 306 } 307 href = vAppTemplate.VAppTemplate.LeaseSettingsSection.HREF 308 } 309 if href == "" { 310 href = getUrlFromLink(vAppTemplate.VAppTemplate.Link, "edit", types.MimeLeaseSettingSection) 311 } 312 313 if href == "" { 314 return fmt.Errorf("link to update lease settings not found for vAppTemplate %s", vAppTemplate.VAppTemplate.Name) 315 } 316 317 var leaseSettings = types.UpdateLeaseSettingsSection{ 318 HREF: href, 319 XmlnsOvf: types.XMLNamespaceOVF, 320 Xmlns: types.XMLNamespaceVCloud, 321 OVFInfo: "Lease section settings", 322 Type: types.MimeLeaseSettingSection, 323 StorageLeaseInSeconds: &storageLeaseInSeconds, 324 } 325 326 task, err := vAppTemplate.client.ExecuteTaskRequest(href, http.MethodPut, 327 types.MimeLeaseSettingSection, "error updating vAppTemplate lease : %s", &leaseSettings) 328 329 if err != nil { 330 return fmt.Errorf("unable to update vAppTemplate lease: %s", err) 331 } 332 333 err = task.WaitTaskCompletion() 334 if err != nil { 335 return fmt.Errorf("task for updating vAppTemplate lease failed: %s", err) 336 } 337 return vAppTemplate.Refresh() 338 } 339 340 // GetLease retrieves the lease terms for a vAppTemplate 341 func (vAppTemplate *VAppTemplate) GetLease() (*types.LeaseSettingsSection, error) { 342 343 href := "" 344 if vAppTemplate.VAppTemplate.LeaseSettingsSection != nil { 345 href = vAppTemplate.VAppTemplate.LeaseSettingsSection.HREF 346 } 347 if href == "" { 348 for _, link := range vAppTemplate.VAppTemplate.Link { 349 if link.Type == types.MimeLeaseSettingSection { 350 href = link.HREF 351 break 352 } 353 } 354 } 355 if href == "" { 356 return nil, fmt.Errorf("link to retrieve lease settings not found for vApp %s", vAppTemplate.VAppTemplate.Name) 357 } 358 var leaseSettings types.LeaseSettingsSection 359 360 _, err := vAppTemplate.client.ExecuteRequest(href, http.MethodGet, "", "error getting vAppTemplate lease info: %s", nil, &leaseSettings) 361 362 if err != nil { 363 return nil, err 364 } 365 return &leaseSettings, nil 366 } 367 368 // GetCatalogItemHref looks up Href for catalog item in vApp template 369 func (vAppTemplate *VAppTemplate) GetCatalogItemHref() (string, error) { 370 for _, link := range vAppTemplate.VAppTemplate.Link { 371 if link.Rel == "catalogItem" && link.Type == types.MimeCatalogItem { 372 return link.HREF, nil 373 } 374 } 375 return "", fmt.Errorf("error finding Catalog Item link in vApp template %s", vAppTemplate.VAppTemplate.ID) 376 } 377 378 // GetCatalogItemId returns ID for catalog item in vApp template 379 func (vAppTemplate *VAppTemplate) GetCatalogItemId() (string, error) { 380 href, err := vAppTemplate.GetCatalogItemHref() 381 if err != nil { 382 return "", err 383 } 384 385 return fmt.Sprintf("urn:vcloud:catalogitem:%s", extractUuid(href)), nil 386 }