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 }