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  }