github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/adminvdc.go (about)

     1  /*
     2   * Copyright 2021 VMware, Inc.  All rights reserved.  Licensed under the Apache v2 License.
     3   */
     4  
     5  package govcd
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"net/http"
    11  	"net/url"
    12  
    13  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    14  	"github.com/vmware/go-vcloud-director/v2/util"
    15  )
    16  
    17  type AdminVdc struct {
    18  	AdminVdc *types.AdminVdc
    19  	client   *Client
    20  	parent   organization
    21  }
    22  
    23  func NewAdminVdc(cli *Client) *AdminVdc {
    24  	return &AdminVdc{
    25  		AdminVdc: new(types.AdminVdc),
    26  		client:   cli,
    27  	}
    28  }
    29  
    30  // vdcVersionedFuncs is a generic representation of VDC CRUD operations across multiple versions
    31  type vdcVersionedFuncs struct {
    32  	SupportedVersion string
    33  	CreateVdc        func(adminOrg *AdminOrg, vdcConfiguration *types.VdcConfiguration) (*Vdc, error)
    34  	CreateVdcAsync   func(adminOrg *AdminOrg, vdcConfiguration *types.VdcConfiguration) (Task, error)
    35  	UpdateVdc        func(adminVdc *AdminVdc) (*AdminVdc, error)
    36  	UpdateVdcAsync   func(adminVdc *AdminVdc) (Task, error)
    37  }
    38  
    39  // VDC function mapping for API version 32.0 (from vCD 9.7)
    40  var vdcVersionedFuncsV97 = vdcVersionedFuncs{
    41  	SupportedVersion: "32.0",
    42  	CreateVdc:        createVdcV97,
    43  	CreateVdcAsync:   createVdcAsyncV97,
    44  	UpdateVdc:        updateVdcV97,
    45  	UpdateVdcAsync:   updateVdcAsyncV97,
    46  }
    47  
    48  // vdcVersionedFuncsByVcdVersion is a map of VDC functions by vCD version
    49  var vdcVersionedFuncsByVcdVersion = map[string]vdcVersionedFuncs{
    50  	"vdc9.7": vdcVersionedFuncsV97,
    51  
    52  	// If we add a new function to this list, we also need to update the "default" entry
    53  	// The "default" entry will hold the highest currently available function
    54  	"default": vdcVersionedFuncsV97,
    55  }
    56  
    57  // getVdcVersionedFuncsByVdcVersion is a wrapper function that retrieves the requested versioned VDC function
    58  // When the wanted version does  not exist in the map, it returns the highest available one.
    59  func getVdcVersionedFuncsByVdcVersion(version string) vdcVersionedFuncs {
    60  	f, ok := vdcVersionedFuncsByVcdVersion[version]
    61  	if ok {
    62  		return f
    63  	} else {
    64  		return vdcVersionedFuncsByVcdVersion["default"]
    65  	}
    66  }
    67  
    68  // GetAdminVdcByName function uses a valid VDC name and returns a admin VDC object.
    69  // If no VDC is found, then it returns an empty VDC and no error.
    70  // Otherwise it returns an empty VDC and an error.
    71  // Deprecated: Use adminOrg.GetAdminVDCByName
    72  func (adminOrg *AdminOrg) GetAdminVdcByName(vdcname string) (AdminVdc, error) {
    73  	for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs {
    74  		if vdcs.Name == vdcname {
    75  			adminVdc := NewAdminVdc(adminOrg.client)
    76  			_, err := adminOrg.client.ExecuteRequest(vdcs.HREF, http.MethodGet,
    77  				"", "error getting vdc: %s", nil, adminVdc.AdminVdc)
    78  			return *adminVdc, err
    79  		}
    80  	}
    81  	return AdminVdc{}, nil
    82  }
    83  
    84  // GetAdminVDCByHref retrieves a VDC using a direct call with the HREF
    85  func (adminOrg *AdminOrg) GetAdminVDCByHref(vdcHref string) (*AdminVdc, error) {
    86  	adminVdc := NewAdminVdc(adminOrg.client)
    87  	adminVdc.parent = adminOrg
    88  	_, err := adminOrg.client.ExecuteRequest(vdcHref, http.MethodGet,
    89  		"", "error getting vdc: %s", nil, adminVdc.AdminVdc)
    90  
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	return adminVdc, nil
    95  }
    96  
    97  // GetAdminVDCByName finds an Admin VDC by Name
    98  // On success, returns a pointer to the AdminVdc structure and a nil error
    99  // On failure, returns a nil pointer and an error
   100  func (adminOrg *AdminOrg) GetAdminVDCByName(vdcName string, refresh bool) (*AdminVdc, error) {
   101  	if refresh {
   102  		err := adminOrg.Refresh()
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  	}
   107  	for _, vdc := range adminOrg.AdminOrg.Vdcs.Vdcs {
   108  		if vdc.Name == vdcName {
   109  			return adminOrg.GetAdminVDCByHref(vdc.HREF)
   110  		}
   111  	}
   112  	return nil, ErrorEntityNotFound
   113  }
   114  
   115  // GetAdminVDCById finds an Admin VDC by ID
   116  // On success, returns a pointer to the AdminVdc structure and a nil error
   117  // On failure, returns a nil pointer and an error
   118  func (adminOrg *AdminOrg) GetAdminVDCById(vdcId string, refresh bool) (*AdminVdc, error) {
   119  	if refresh {
   120  		err := adminOrg.Refresh()
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  	}
   125  	for _, vdc := range adminOrg.AdminOrg.Vdcs.Vdcs {
   126  		if equalIds(vdcId, vdc.ID, vdc.HREF) {
   127  			return adminOrg.GetAdminVDCByHref(vdc.HREF)
   128  		}
   129  	}
   130  	return nil, ErrorEntityNotFound
   131  }
   132  
   133  // GetAdminVDCByNameOrId finds an Admin VDC by Name Or ID
   134  // On success, returns a pointer to the AdminVdc structure and a nil error
   135  // On failure, returns a nil pointer and an error
   136  func (adminOrg *AdminOrg) GetAdminVDCByNameOrId(identifier string, refresh bool) (*AdminVdc, error) {
   137  	getByName := func(name string, refresh bool) (interface{}, error) {
   138  		return adminOrg.GetAdminVDCByName(name, refresh)
   139  	}
   140  	getById := func(id string, refresh bool) (interface{}, error) { return adminOrg.GetAdminVDCById(id, refresh) }
   141  	entity, err := getEntityByNameOrId(getByName, getById, identifier, refresh)
   142  	if entity == nil {
   143  		return nil, err
   144  	}
   145  	return entity.(*AdminVdc), err
   146  }
   147  
   148  // CreateVdc creates a VDC with the given params under the given organization.
   149  // Returns an AdminVdc.
   150  // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/POST-VdcConfiguration.html
   151  // Deprecated in favor of adminOrg.CreateOrgVdcAsync
   152  func (adminOrg *AdminOrg) CreateVdc(vdcConfiguration *types.VdcConfiguration) (Task, error) {
   153  	err := validateVdcConfiguration(vdcConfiguration)
   154  	if err != nil {
   155  		return Task{}, err
   156  	}
   157  
   158  	vdcConfiguration.Xmlns = types.XMLNamespaceVCloud
   159  
   160  	vdcCreateHREF, err := url.ParseRequestURI(adminOrg.AdminOrg.HREF)
   161  	if err != nil {
   162  		return Task{}, fmt.Errorf("error parsing admin org url: %s", err)
   163  	}
   164  	vdcCreateHREF.Path += "/vdcsparams"
   165  
   166  	adminVdc := NewAdminVdc(adminOrg.client)
   167  
   168  	_, err = adminOrg.client.ExecuteRequest(vdcCreateHREF.String(), http.MethodPost,
   169  		"application/vnd.vmware.admin.createVdcParams+xml", "error creating VDC: %s", vdcConfiguration, adminVdc.AdminVdc)
   170  	if err != nil {
   171  		return Task{}, err
   172  	}
   173  
   174  	// Return the task
   175  	task := NewTask(adminOrg.client)
   176  	if adminVdc.AdminVdc.Tasks == nil || len(adminVdc.AdminVdc.Tasks.Task) == 0 {
   177  		return Task{}, fmt.Errorf("no task found after VDC %s creation", vdcConfiguration.Name)
   178  	}
   179  	task.Task = adminVdc.AdminVdc.Tasks.Task[0]
   180  	return *task, nil
   181  }
   182  
   183  // Creates the VDC and waits for the asynchronous task to complete.
   184  // Deprecated in favor of adminOrg.CreateOrgVdc
   185  func (adminOrg *AdminOrg) CreateVdcWait(vdcDefinition *types.VdcConfiguration) error {
   186  	task, err := adminOrg.CreateVdc(vdcDefinition)
   187  	if err != nil {
   188  		return err
   189  	}
   190  	err = task.WaitTaskCompletion()
   191  	if err != nil {
   192  		return fmt.Errorf("couldn't finish creating VDC %s", err)
   193  	}
   194  	return nil
   195  }
   196  
   197  // Given an adminVdc with a valid HREF, the function refresh the adminVdc
   198  // and updates the adminVdc data. Returns an error on failure
   199  // Users should use refresh whenever they suspect
   200  // a stale VDC due to the creation/update/deletion of a resource
   201  // within the the VDC itself.
   202  func (adminVdc *AdminVdc) Refresh() error {
   203  	if *adminVdc == (AdminVdc{}) || adminVdc.AdminVdc.HREF == "" {
   204  		return fmt.Errorf("cannot refresh, Object is empty or HREF is empty")
   205  	}
   206  
   207  	// Empty struct before a new unmarshal, otherwise we end up with duplicate
   208  	// elements in slices.
   209  	unmarshalledAdminVdc := &types.AdminVdc{}
   210  
   211  	_, err := adminVdc.client.ExecuteRequest(adminVdc.AdminVdc.HREF, http.MethodGet,
   212  		"", "error refreshing VDC: %s", nil, unmarshalledAdminVdc)
   213  	if err != nil {
   214  		return err
   215  	}
   216  	adminVdc.AdminVdc = unmarshalledAdminVdc
   217  
   218  	return nil
   219  }
   220  
   221  // UpdateAsync updates VDC from current VDC struct contents.
   222  // Any differences that may be legally applied will be updated.
   223  // Returns an error if the call to vCD fails.
   224  // API Documentation: https://vdc-repo.vmware.com/vmwb-repository/dcr-public/7a028e78-bd37-4a6a-8298-9c26c7eeb9aa/09142237-dd46-4dee-8326-e07212fb63a8/doc/doc/operations/PUT-Vdc.html
   225  func (adminVdc *AdminVdc) UpdateAsync() (Task, error) {
   226  	apiVersion, err := adminVdc.client.MaxSupportedVersion()
   227  	if err != nil {
   228  		return Task{}, err
   229  	}
   230  	vdcFunctions := getVdcVersionedFuncsByVdcVersion("vdc" + apiVersionToVcdVersion[apiVersion])
   231  	if vdcFunctions.UpdateVdcAsync == nil {
   232  		return Task{}, fmt.Errorf("function UpdateVdcAsync is not defined for %s", "vdc"+apiVersion)
   233  	}
   234  	util.Logger.Printf("[DEBUG] UpdateAsync call function for version %s", vdcFunctions.SupportedVersion)
   235  
   236  	return vdcFunctions.UpdateVdcAsync(adminVdc)
   237  
   238  }
   239  
   240  // Update function updates an Admin VDC from current VDC struct contents.
   241  // Any differences that may be legally applied will be updated.
   242  // Returns an empty AdminVdc struct and error if the call to vCD fails.
   243  // API Documentation: https://vdc-repo.vmware.com/vmwb-repository/dcr-public/7a028e78-bd37-4a6a-8298-9c26c7eeb9aa/09142237-dd46-4dee-8326-e07212fb63a8/doc/doc/operations/PUT-Vdc.html
   244  func (adminVdc *AdminVdc) Update() (AdminVdc, error) {
   245  	apiVersion, err := adminVdc.client.MaxSupportedVersion()
   246  	if err != nil {
   247  		return AdminVdc{}, err
   248  	}
   249  
   250  	vdcFunctions := getVdcVersionedFuncsByVdcVersion("vdc" + apiVersionToVcdVersion[apiVersion])
   251  	if vdcFunctions.UpdateVdc == nil {
   252  		return AdminVdc{}, fmt.Errorf("function UpdateVdc is not defined for %s", "vdc"+apiVersion)
   253  	}
   254  
   255  	util.Logger.Printf("[DEBUG] Update call function for version %s", vdcFunctions.SupportedVersion)
   256  
   257  	// Explicitly remove ResourcePoolRefs because it cannot be set and breaks Go marshaling bug
   258  	// https://github.com/golang/go/issues/9519
   259  	adminVdc.AdminVdc.ResourcePoolRefs = nil
   260  
   261  	updatedAdminVdc, err := vdcFunctions.UpdateVdc(adminVdc)
   262  	if err != nil {
   263  		return AdminVdc{}, err
   264  	}
   265  	return *updatedAdminVdc, err
   266  }
   267  
   268  // CreateOrgVdc creates a VDC with the given params under the given organization
   269  // and waits for the asynchronous task to complete.
   270  // Returns an AdminVdc pointer and an error.
   271  func (adminOrg *AdminOrg) CreateOrgVdc(vdcConfiguration *types.VdcConfiguration) (*Vdc, error) {
   272  	apiVersion, err := adminOrg.client.MaxSupportedVersion()
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	vdcFunctions := getVdcVersionedFuncsByVdcVersion("vdc" + apiVersionToVcdVersion[apiVersion])
   277  	if vdcFunctions.CreateVdc == nil {
   278  		return nil, fmt.Errorf("function CreateVdc is not defined for %s", "vdc"+apiVersion)
   279  	}
   280  
   281  	util.Logger.Printf("[DEBUG] CreateOrgVdc call function for version %s", vdcFunctions.SupportedVersion)
   282  	return vdcFunctions.CreateVdc(adminOrg, vdcConfiguration)
   283  }
   284  
   285  // CreateOrgVdcAsync creates a VDC with the given params under the given organization.
   286  // Returns a Task and an error.
   287  func (adminOrg *AdminOrg) CreateOrgVdcAsync(vdcConfiguration *types.VdcConfiguration) (Task, error) {
   288  	apiVersion, err := adminOrg.client.MaxSupportedVersion()
   289  	if err != nil {
   290  		return Task{}, err
   291  	}
   292  	vdcFunctions := getVdcVersionedFuncsByVdcVersion("vdc" + apiVersionToVcdVersion[apiVersion])
   293  	if vdcFunctions.CreateVdcAsync == nil {
   294  		return Task{}, fmt.Errorf("function CreateVdcAsync is not defined for %s", "vdc"+apiVersion)
   295  	}
   296  
   297  	util.Logger.Printf("[DEBUG] CreateOrgVdcAsync call function for version %s", vdcFunctions.SupportedVersion)
   298  
   299  	return vdcFunctions.CreateVdcAsync(adminOrg, vdcConfiguration)
   300  }
   301  
   302  // updateVdcAsyncV97 updates a VDC with the given params. Supports Flex type allocation.
   303  // Needs vCD 9.7+ to work. Returns a Task and an error.
   304  func updateVdcAsyncV97(adminVdc *AdminVdc) (Task, error) {
   305  	util.Logger.Printf("[TRACE] updateVdcAsyncV97 called %#v", *adminVdc)
   306  	adminVdc.AdminVdc.Xmlns = types.XMLNamespaceVCloud
   307  
   308  	// Return the task
   309  	return adminVdc.client.ExecuteTaskRequest(adminVdc.AdminVdc.HREF, http.MethodPut,
   310  		types.MimeAdminVDC, "error updating VDC: %s", adminVdc.AdminVdc)
   311  }
   312  
   313  // updateVdcV97 updates a VDC with the given params
   314  // and waits for the asynchronous task to complete. Supports Flex type allocation.
   315  // Needs vCD 9.7+ to work. Returns an AdminVdc pointer and an error.
   316  func updateVdcV97(adminVdc *AdminVdc) (*AdminVdc, error) {
   317  	util.Logger.Printf("[TRACE] updateVdcV97 called %#v", *adminVdc)
   318  	task, err := updateVdcAsyncV97(adminVdc)
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	err = task.WaitTaskCompletion()
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  	err = adminVdc.Refresh()
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  	return adminVdc, nil
   331  }
   332  
   333  // createVdcV97 creates a VDC with the given params under the given organization
   334  // and waits for the asynchronous task to complete. Supports Flex type allocation.
   335  // Needs vCD 9.7+ to work. Returns a Vdc pointer and error.
   336  func createVdcV97(adminOrg *AdminOrg, vdcConfiguration *types.VdcConfiguration) (*Vdc, error) {
   337  	util.Logger.Printf("[TRACE] createVdcV97 called %#v", *vdcConfiguration)
   338  	task, err := createVdcAsyncV97(adminOrg, vdcConfiguration)
   339  	if err != nil {
   340  		return nil, err
   341  	}
   342  	err = task.WaitTaskCompletion()
   343  	if err != nil {
   344  		return nil, fmt.Errorf("couldn't finish creating VDC %s", err)
   345  	}
   346  
   347  	vdc, err := adminOrg.GetVDCByName(vdcConfiguration.Name, true)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  	return vdc, nil
   352  }
   353  
   354  // createVdcAsyncV97 creates a VDC with the given params under the given organization. Supports Flex type allocation.
   355  // Needs vCD 9.7+ to work. Returns a Task and an error
   356  func createVdcAsyncV97(adminOrg *AdminOrg, vdcConfiguration *types.VdcConfiguration) (Task, error) {
   357  	util.Logger.Printf("[TRACE] createVdcAsyncV97 called %#v", *vdcConfiguration)
   358  	err := validateVdcConfigurationV97(*vdcConfiguration)
   359  	if err != nil {
   360  		return Task{}, err
   361  	}
   362  
   363  	vdcConfiguration.Xmlns = types.XMLNamespaceVCloud
   364  
   365  	vdcCreateHREF, err := url.ParseRequestURI(adminOrg.AdminOrg.HREF)
   366  	if err != nil {
   367  		return Task{}, fmt.Errorf("error parsing admin org url: %s", err)
   368  	}
   369  	vdcCreateHREF.Path += "/vdcsparams"
   370  
   371  	adminVdc := NewAdminVdc(adminOrg.client)
   372  
   373  	_, err = adminOrg.client.ExecuteRequest(vdcCreateHREF.String(), http.MethodPost,
   374  		"application/vnd.vmware.admin.createVdcParams+xml", "error creating VDC: %s",
   375  		vdcConfiguration, adminVdc.AdminVdc)
   376  	if err != nil {
   377  		return Task{}, err
   378  	}
   379  
   380  	// Return the task
   381  	task := NewTask(adminOrg.client)
   382  	if adminVdc.AdminVdc.Tasks == nil || len(adminVdc.AdminVdc.Tasks.Task) == 0 {
   383  		return Task{}, fmt.Errorf("no task found after VDC %s creation", vdcConfiguration.Name)
   384  	}
   385  	task.Task = adminVdc.AdminVdc.Tasks.Task[0]
   386  	return *task, nil
   387  }
   388  
   389  // validateVdcConfigurationV97 uses validateVdcConfiguration and additionally checks Flex dependent values
   390  func validateVdcConfigurationV97(vdcDefinition types.VdcConfiguration) error {
   391  	err := validateVdcConfiguration(&vdcDefinition)
   392  	if err != nil {
   393  		return err
   394  	}
   395  	if vdcDefinition.AllocationModel == "Flex" && vdcDefinition.IsElastic == nil {
   396  		return errors.New("VdcConfiguration missing required field: IsElastic")
   397  	}
   398  	if vdcDefinition.AllocationModel == "Flex" && vdcDefinition.IncludeMemoryOverhead == nil {
   399  		return errors.New("VdcConfiguration missing required field: IncludeMemoryOverhead")
   400  	}
   401  	return nil
   402  }
   403  
   404  // GetVappList returns the list of vApps for an Admin VDC
   405  func (vdc *AdminVdc) GetVappList() []*types.ResourceReference {
   406  	var list []*types.ResourceReference
   407  	for _, resourceEntities := range vdc.AdminVdc.ResourceEntities {
   408  		for _, resourceReference := range resourceEntities.ResourceEntity {
   409  			if resourceReference.Type == types.MimeVApp {
   410  				list = append(list, resourceReference)
   411  			}
   412  		}
   413  	}
   414  	return list
   415  }
   416  
   417  // UpdateStorageProfile updates VDC storage profile and returns refreshed VDC or error.
   418  func (vdc *AdminVdc) UpdateStorageProfile(storageProfileId string, storageProfile *types.AdminVdcStorageProfile) (*types.AdminVdcStorageProfile, error) {
   419  	if vdc.client.VCDHREF.String() == "" {
   420  		return nil, fmt.Errorf("cannot update VDC storage profile, VCD HREF is unset")
   421  	}
   422  
   423  	queryUrl := vdc.client.VCDHREF
   424  	queryUrl.Path += "/admin/vdcStorageProfile/" + storageProfileId
   425  
   426  	storageProfile.Xmlns = types.XMLNamespaceVCloud
   427  	updateAdminVdcStorageProfile := &types.AdminVdcStorageProfile{}
   428  
   429  	_, err := vdc.client.ExecuteRequest(queryUrl.String(), http.MethodPut,
   430  		types.MimeStorageProfile, "error updating VDC storage profile: %s", storageProfile, updateAdminVdcStorageProfile)
   431  	if err != nil {
   432  		return nil, fmt.Errorf("cannot update VDC storage profile, error: %s", err)
   433  	}
   434  
   435  	return updateAdminVdcStorageProfile, err
   436  }
   437  
   438  // AddStorageProfile adds a storage profile to a VDC
   439  func (vdc *AdminVdc) AddStorageProfile(storageProfile *types.VdcStorageProfileConfiguration, description string) (Task, error) {
   440  	if vdc.client.VCDHREF.String() == "" {
   441  		return Task{}, fmt.Errorf("cannot add VDC storage profile, VCD HREF is unset")
   442  	}
   443  
   444  	href := vdc.AdminVdc.HREF + "/vdcStorageProfiles"
   445  
   446  	var updateStorageProfile = types.UpdateVdcStorageProfiles{
   447  		Xmlns:                types.XMLNamespaceVCloud,
   448  		Name:                 storageProfile.ProviderVdcStorageProfile.Name,
   449  		Description:          description,
   450  		AddStorageProfile:    storageProfile,
   451  		RemoveStorageProfile: nil,
   452  	}
   453  
   454  	task, err := vdc.client.ExecuteTaskRequest(href, http.MethodPost,
   455  		types.MimeUpdateVdcStorageProfiles, "error adding VDC storage profile: %s", &updateStorageProfile)
   456  	if err != nil {
   457  		return Task{}, fmt.Errorf("cannot add VDC storage profile, error: %s", err)
   458  	}
   459  
   460  	return task, nil
   461  }
   462  
   463  // AddStorageProfileWait adds a storage profile to a VDC and return a refreshed VDC
   464  func (vdc *AdminVdc) AddStorageProfileWait(storageProfile *types.VdcStorageProfileConfiguration, description string) error {
   465  	task, err := vdc.AddStorageProfile(storageProfile, description)
   466  	if err != nil {
   467  		return err
   468  	}
   469  	err = task.WaitTaskCompletion()
   470  	if err != nil {
   471  		return err
   472  	}
   473  	return vdc.Refresh()
   474  }
   475  
   476  // RemoveStorageProfile remove a storage profile from a VDC
   477  func (vdc *AdminVdc) RemoveStorageProfile(storageProfileName string) (Task, error) {
   478  	if vdc.client.VCDHREF.String() == "" {
   479  		return Task{}, fmt.Errorf("cannot remove VDC storage profile: VCD HREF is unset")
   480  	}
   481  
   482  	var storageProfile *types.Reference
   483  	for _, sp := range vdc.AdminVdc.VdcStorageProfiles.VdcStorageProfile {
   484  		if sp.Name == storageProfileName {
   485  			storageProfile = sp
   486  		}
   487  	}
   488  	if storageProfile == nil {
   489  		return Task{}, fmt.Errorf("cannot remove VDC storage profile: storage profile '%s' not found in VDC", storageProfileName)
   490  	}
   491  
   492  	vdcStorageProfileDetails, err := vdc.client.GetStorageProfileByHref(storageProfile.HREF)
   493  	if err != nil {
   494  		return Task{}, fmt.Errorf("cannot retrieve VDC storage profile '%s' details: %s", storageProfileName, err)
   495  	}
   496  	if vdcStorageProfileDetails.Enabled != nil && *vdcStorageProfileDetails.Enabled {
   497  		_, err = vdc.UpdateStorageProfile(extractUuid(storageProfile.HREF), &types.AdminVdcStorageProfile{
   498  			Name:    vdcStorageProfileDetails.Name,
   499  			Units:   vdcStorageProfileDetails.Units,
   500  			Limit:   vdcStorageProfileDetails.Limit,
   501  			Default: false,
   502  			Enabled: addrOf(false),
   503  			ProviderVdcStorageProfile: &types.Reference{
   504  				HREF: vdcStorageProfileDetails.ProviderVdcStorageProfile.HREF,
   505  			},
   506  		},
   507  		)
   508  		if err != nil {
   509  			return Task{}, fmt.Errorf("cannot disable VDC storage profile '%s': %s", storageProfileName, err)
   510  		}
   511  	}
   512  
   513  	href := vdc.AdminVdc.HREF + "/vdcStorageProfiles"
   514  
   515  	var updateStorageProfile = types.UpdateVdcStorageProfiles{
   516  		Xmlns:                types.XMLNamespaceVCloud,
   517  		Name:                 vdcStorageProfileDetails.Name,
   518  		Description:          "",
   519  		RemoveStorageProfile: storageProfile,
   520  	}
   521  
   522  	task, err := vdc.client.ExecuteTaskRequest(href, http.MethodPost,
   523  		types.MimeUpdateVdcStorageProfiles, "error removing VDC storage profile: %s", &updateStorageProfile)
   524  	if err != nil {
   525  		return Task{}, fmt.Errorf("cannot remove VDC storage profile, error: %s", err)
   526  	}
   527  
   528  	return task, nil
   529  }
   530  
   531  // RemoveStorageProfileWait removes a storege profile from a VDC and returns a refreshed VDC or an error
   532  func (vdc *AdminVdc) RemoveStorageProfileWait(storageProfileName string) error {
   533  	task, err := vdc.RemoveStorageProfile(storageProfileName)
   534  	if err != nil {
   535  		return err
   536  	}
   537  	err = task.WaitTaskCompletion()
   538  	if err != nil {
   539  		return err
   540  	}
   541  	return vdc.Refresh()
   542  }
   543  
   544  // SetDefaultStorageProfile sets a given storage profile as default
   545  // This operation will automatically unset the previous default storage profile.
   546  func (vdc *AdminVdc) SetDefaultStorageProfile(storageProfileName string) error {
   547  	if vdc.client.VCDHREF.String() == "" {
   548  		return fmt.Errorf("cannot set VDC default storage profile: VCD HREF is unset")
   549  	}
   550  
   551  	var storageProfile *types.Reference
   552  	for _, sp := range vdc.AdminVdc.VdcStorageProfiles.VdcStorageProfile {
   553  		if sp.Name == storageProfileName {
   554  			storageProfile = sp
   555  		}
   556  	}
   557  	if storageProfile == nil {
   558  		return fmt.Errorf("cannot set VDC default storage profile: storage profile '%s' not found in VDC", storageProfileName)
   559  	}
   560  
   561  	vdcStorageProfileDetails, err := vdc.client.GetStorageProfileByHref(storageProfile.HREF)
   562  	if err != nil {
   563  		return fmt.Errorf("cannot retrieve VDC storage profile '%s' details: %s", storageProfileName, err)
   564  	}
   565  	_, err = vdc.UpdateStorageProfile(extractUuid(storageProfile.HREF), &types.AdminVdcStorageProfile{
   566  		Name:    vdcStorageProfileDetails.Name,
   567  		Units:   vdcStorageProfileDetails.Units,
   568  		Limit:   vdcStorageProfileDetails.Limit,
   569  		Default: true,
   570  		Enabled: addrOf(true),
   571  		ProviderVdcStorageProfile: &types.Reference{
   572  			HREF: vdcStorageProfileDetails.ProviderVdcStorageProfile.HREF,
   573  		},
   574  	},
   575  	)
   576  	if err != nil {
   577  		return fmt.Errorf("cannot set VDC default storage profile '%s': %s", storageProfileName, err)
   578  	}
   579  	return vdc.Refresh()
   580  }
   581  
   582  // GetDefaultStorageProfileReference finds the default storage profile for the VDC
   583  func (adminVdc *AdminVdc) GetDefaultStorageProfileReference() (*types.Reference, error) {
   584  	var defaultSp *types.Reference
   585  	if adminVdc.AdminVdc.VdcStorageProfiles == nil || adminVdc.AdminVdc.VdcStorageProfiles.VdcStorageProfile == nil {
   586  		return nil, fmt.Errorf("no storage profiles found in VDC %s", adminVdc.AdminVdc.Name)
   587  	}
   588  	for _, sp := range adminVdc.AdminVdc.VdcStorageProfiles.VdcStorageProfile {
   589  		fullSp, err := adminVdc.client.GetStorageProfileByHref(sp.HREF)
   590  		if err != nil {
   591  			return nil, fmt.Errorf("error retrieving storage profile %s for VDC %s: %s", sp.Name, adminVdc.AdminVdc.Name, err)
   592  		}
   593  		if fullSp.Default {
   594  			if defaultSp != nil {
   595  				return nil, fmt.Errorf("more than one default storage profile found for VDC %s: '%s' and '%s'", adminVdc.AdminVdc.Name, sp.Name, defaultSp.Name)
   596  			}
   597  			defaultSp = sp
   598  		}
   599  	}
   600  	if defaultSp != nil {
   601  		return defaultSp, nil
   602  	}
   603  	return nil, fmt.Errorf("no default storage profile found for VDC %s", adminVdc.AdminVdc.Name)
   604  }
   605  
   606  // IsNsxv is a convenience function to check if the Admin VDC is backed by NSX-V Provider VDC
   607  func (adminVdc *AdminVdc) IsNsxv() bool {
   608  	vdc := NewVdc(adminVdc.client)
   609  	vdc.Vdc = &adminVdc.AdminVdc.Vdc
   610  	vdc.parent = adminVdc.parent
   611  	return vdc.IsNsxv()
   612  }