github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/vdc_group.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 "fmt" 9 "net/url" 10 "strings" 11 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 ) 14 15 // VdcGroup is a structure defining a VdcGroup in Organization 16 type VdcGroup struct { 17 VdcGroup *types.VdcGroup 18 Href string 19 client *Client 20 parent organization 21 } 22 23 // CreateNsxtVdcGroup create NSX-T VDC group with provided VDC IDs. 24 // More generic creation method available also - CreateVdcGroup 25 func (adminOrg *AdminOrg) CreateNsxtVdcGroup(name, description, startingVdcId string, participatingVdcIds []string) (*VdcGroup, error) { 26 participatingVdcs, err := composeParticipatingOrgVdcs(adminOrg, startingVdcId, participatingVdcIds) 27 if err != nil { 28 return nil, err 29 } 30 31 vdcGroupConfig := &types.VdcGroup{} 32 vdcGroupConfig.OrgId = adminOrg.orgId() 33 vdcGroupConfig.Name = name 34 vdcGroupConfig.Description = description 35 vdcGroupConfig.ParticipatingOrgVdcs = participatingVdcs 36 vdcGroupConfig.LocalEgress = false 37 vdcGroupConfig.UniversalNetworkingEnabled = false 38 vdcGroupConfig.NetworkProviderType = "NSX_T" 39 vdcGroupConfig.Type = "LOCAL" 40 vdcGroupConfig.ParticipatingOrgVdcs = participatingVdcs 41 return adminOrg.CreateVdcGroup(vdcGroupConfig) 42 } 43 44 // composeParticipatingOrgVdcs converts fetched candidate VDCs to []types.ParticipatingOrgVdcs 45 // returns error also in case participatingVdcId not found as candidate VDC. 46 func composeParticipatingOrgVdcs(adminOrg *AdminOrg, startingVdcId string, participatingVdcIds []string) ([]types.ParticipatingOrgVdcs, error) { 47 candidateVdcs, err := adminOrg.GetAllNsxtVdcGroupCandidates(startingVdcId, nil) 48 if err != nil { 49 return nil, err 50 } 51 participatingVdcs := []types.ParticipatingOrgVdcs{} 52 var foundParticipatingVdcsIds []string 53 for _, candidateVdc := range candidateVdcs { 54 if contains(candidateVdc.Id, participatingVdcIds) { 55 participatingVdcs = append(participatingVdcs, types.ParticipatingOrgVdcs{ 56 OrgRef: candidateVdc.OrgRef, 57 SiteRef: candidateVdc.SiteRef, 58 VdcRef: types.OpenApiReference{ 59 ID: candidateVdc.Id, 60 }, 61 FaultDomainTag: candidateVdc.FaultDomainTag, 62 NetworkProviderScope: candidateVdc.NetworkProviderScope, 63 }) 64 foundParticipatingVdcsIds = append(foundParticipatingVdcsIds, candidateVdc.Id) 65 } 66 } 67 68 if len(participatingVdcs) != len(participatingVdcIds) { 69 var notFoundVdcs []string 70 for _, participatingVdcId := range participatingVdcIds { 71 if !contains(participatingVdcId, foundParticipatingVdcsIds) { 72 notFoundVdcs = append(notFoundVdcs, participatingVdcId) 73 } 74 } 75 return nil, fmt.Errorf("VDC IDs are not found as Candidate VDCs: %s", notFoundVdcs) 76 } 77 78 return participatingVdcs, nil 79 } 80 81 // contains tells whether slice of string contains item. 82 func contains(item string, slice []string) bool { 83 for _, n := range slice { 84 if item == n { 85 return true 86 } 87 } 88 return false 89 } 90 91 // CreateVdcGroup create VDC group with provided VDC ref. 92 // Only supports NSX-T VDCs. 93 func (adminOrg *AdminOrg) CreateVdcGroup(vdcGroup *types.VdcGroup) (*VdcGroup, error) { 94 tenantContext, err := adminOrg.getTenantContext() 95 if err != nil { 96 return nil, err 97 } 98 return createVdcGroup(adminOrg, vdcGroup, getTenantContextHeader(tenantContext)) 99 } 100 101 // createVdcGroup create VDC group with provided VDC ref. 102 // Only supports NSX-T VDCs. 103 func createVdcGroup(adminOrg *AdminOrg, vdcGroup *types.VdcGroup, 104 additionalHeader map[string]string) (*VdcGroup, error) { 105 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 106 apiVersion, err := adminOrg.client.checkOpenApiEndpointCompatibility(endpoint) 107 if err != nil { 108 return nil, err 109 } 110 111 urlRef, err := adminOrg.client.OpenApiBuildEndpoint(endpoint) 112 if err != nil { 113 return nil, err 114 } 115 116 typeResponse := &VdcGroup{ 117 VdcGroup: &types.VdcGroup{}, 118 client: adminOrg.client, 119 Href: urlRef.String(), 120 parent: adminOrg, 121 } 122 123 err = adminOrg.client.OpenApiPostItem(apiVersion, urlRef, nil, 124 vdcGroup, typeResponse.VdcGroup, additionalHeader) 125 if err != nil { 126 return nil, err 127 } 128 129 return typeResponse, nil 130 } 131 132 // GetAllNsxtVdcGroupCandidates returns NSXT candidate VDCs for VDC group 133 func (adminOrg *AdminOrg) GetAllNsxtVdcGroupCandidates(startingVdcId string, queryParameters url.Values) ([]*types.CandidateVdc, error) { 134 queryParams := copyOrNewUrlValues(queryParameters) 135 queryParams = queryParameterFilterAnd("_context==LOCAL", queryParams) 136 queryParams = queryParameterFilterAnd(fmt.Sprintf("_context==%s", startingVdcId), queryParams) 137 queryParams.Add("filterEncoded", "true") 138 queryParams.Add("links", "true") 139 return adminOrg.GetAllVdcGroupCandidates(queryParams) 140 } 141 142 // GetAllVdcGroupCandidates returns candidate VDCs for VDC group 143 func (adminOrg *AdminOrg) GetAllVdcGroupCandidates(queryParameters url.Values) ([]*types.CandidateVdc, error) { 144 tenantContext, err := adminOrg.getTenantContext() 145 if err != nil { 146 return nil, err 147 } 148 149 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsCandidateVdcs 150 minimumApiVersion, err := adminOrg.client.checkOpenApiEndpointCompatibility(endpoint) 151 if err != nil { 152 return nil, err 153 } 154 155 urlRef, err := adminOrg.client.OpenApiBuildEndpoint(endpoint) 156 if err != nil { 157 return nil, err 158 } 159 160 responses := []*types.CandidateVdc{} 161 err = adminOrg.client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParameters, &responses, getTenantContextHeader(tenantContext)) 162 if err != nil { 163 return nil, err 164 } 165 166 return responses, nil 167 } 168 169 // Delete deletes VDC group 170 func (vdcGroup *VdcGroup) Delete() error { 171 return vdcGroup.ForceDelete(false) 172 } 173 174 // ForceDelete deletes VDC group with force parameter if enabled 175 func (vdcGroup *VdcGroup) ForceDelete(force bool) error { 176 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 177 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 178 if err != nil { 179 return err 180 } 181 182 if vdcGroup.VdcGroup.Id == "" { 183 return fmt.Errorf("cannot delete VDC group without id") 184 } 185 186 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(endpoint, vdcGroup.VdcGroup.Id) 187 if err != nil { 188 return err 189 } 190 191 params := copyOrNewUrlValues(nil) 192 if force { 193 params.Add("force", "true") 194 } 195 196 err = vdcGroup.client.OpenApiDeleteItem(minimumApiVersion, urlRef, params, nil) 197 if err != nil { 198 return fmt.Errorf("error deleting VDC group (force %t): %s", force, err) 199 } 200 201 return nil 202 } 203 204 // GetAllVdcGroups retrieves all VDC groups. Query parameters can be supplied to perform additional filtering 205 func (adminOrg *AdminOrg) GetAllVdcGroups(queryParameters url.Values) ([]*VdcGroup, error) { 206 tenantContext, err := adminOrg.getTenantContext() 207 if err != nil { 208 return nil, err 209 } 210 211 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 212 minimumApiVersion, err := adminOrg.client.checkOpenApiEndpointCompatibility(endpoint) 213 if err != nil { 214 return nil, err 215 } 216 217 urlRef, err := adminOrg.client.OpenApiBuildEndpoint(endpoint) 218 if err != nil { 219 return nil, err 220 } 221 222 responses := []*types.VdcGroup{} 223 err = adminOrg.client.OpenApiGetAllItems(minimumApiVersion, urlRef, queryParameters, &responses, getTenantContextHeader(tenantContext)) 224 if err != nil { 225 return nil, err 226 } 227 228 var wrappedVdcGroups []*VdcGroup 229 for _, response := range responses { 230 urlRef, err := adminOrg.client.OpenApiBuildEndpoint(endpoint, response.Id) 231 if err != nil { 232 return nil, err 233 } 234 wrappedVdcGroup := &VdcGroup{ 235 VdcGroup: response, 236 client: adminOrg.client, 237 Href: urlRef.String(), 238 parent: adminOrg, 239 } 240 wrappedVdcGroups = append(wrappedVdcGroups, wrappedVdcGroup) 241 } 242 243 return wrappedVdcGroups, nil 244 } 245 246 // GetVdcGroupByName retrieves VDC group by given name 247 // When the name contains commas, semicolons or asterisks, the encoding is rejected by the API in VCD. 248 // For this reason, when one or more commas, semicolons or asterisks are present we run the search brute force, 249 // by fetching all VDC groups and comparing the names. 250 // Also, url.QueryEscape as well as url.Values.Encode() both encode the space as a + character. So we use 251 // search brute force too. Reference to issue: 252 // https://github.com/golang/go/issues/4013 253 // https://github.com/czos/goamz/pull/11/files 254 func (adminOrg *AdminOrg) GetVdcGroupByName(name string) (*VdcGroup, error) { 255 slowSearch, params := shouldDoSlowSearch("name", name) 256 257 var foundVdcGroups []*VdcGroup 258 vdcGroups, err := adminOrg.GetAllVdcGroups(params) 259 if err != nil { 260 return nil, err 261 } 262 if len(vdcGroups) == 0 { 263 return nil, ErrorEntityNotFound 264 } 265 foundVdcGroups = append(foundVdcGroups, vdcGroups[0]) 266 267 if slowSearch { 268 foundVdcGroups = nil 269 for _, vdcGroup := range vdcGroups { 270 if vdcGroup.VdcGroup.Name == name { 271 foundVdcGroups = append(foundVdcGroups, vdcGroup) 272 } 273 } 274 if len(foundVdcGroups) == 0 { 275 return nil, ErrorEntityNotFound 276 } 277 if len(foundVdcGroups) > 1 { 278 return nil, fmt.Errorf("more than one VDC group found with name '%s'", name) 279 } 280 } 281 282 if len(vdcGroups) > 1 && !slowSearch { 283 return nil, fmt.Errorf("more than one VDC group found with name '%s'", name) 284 } 285 286 return foundVdcGroups[0], nil 287 } 288 289 // GetVdcGroupById Returns VDC group using provided ID 290 func (adminOrg *AdminOrg) GetVdcGroupById(id string) (*VdcGroup, error) { 291 tenantContext, err := adminOrg.getTenantContext() 292 if err != nil { 293 return nil, err 294 } 295 296 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 297 minimumApiVersion, err := adminOrg.client.checkOpenApiEndpointCompatibility(endpoint) 298 if err != nil { 299 return nil, err 300 } 301 302 if id == "" { 303 return nil, fmt.Errorf("empty VDC group ID") 304 } 305 306 urlRef, err := adminOrg.client.OpenApiBuildEndpoint(endpoint, id) 307 if err != nil { 308 return nil, err 309 } 310 311 vdcGroup := &VdcGroup{ 312 VdcGroup: &types.VdcGroup{}, 313 client: adminOrg.client, 314 Href: urlRef.String(), 315 parent: adminOrg, 316 } 317 318 err = adminOrg.client.OpenApiGetItem(minimumApiVersion, urlRef, nil, vdcGroup.VdcGroup, getTenantContextHeader(tenantContext)) 319 if err != nil { 320 return nil, err 321 } 322 323 return vdcGroup, nil 324 } 325 326 // GetVdcGroupById Returns VDC group using provided ID 327 func (org *Org) GetVdcGroupById(id string) (*VdcGroup, error) { 328 if id == "" { 329 return nil, fmt.Errorf("empty VDC group ID") 330 } 331 332 tenantContext, err := org.getTenantContext() 333 if err != nil { 334 return nil, err 335 } 336 337 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 338 minimumApiVersion, err := org.client.checkOpenApiEndpointCompatibility(endpoint) 339 if err != nil { 340 return nil, err 341 } 342 343 urlRef, err := org.client.OpenApiBuildEndpoint(endpoint, id) 344 if err != nil { 345 return nil, err 346 } 347 348 vdcGroup := &VdcGroup{ 349 VdcGroup: &types.VdcGroup{}, 350 client: org.client, 351 Href: urlRef.String(), 352 parent: org, 353 } 354 355 err = org.client.OpenApiGetItem(minimumApiVersion, urlRef, nil, vdcGroup.VdcGroup, getTenantContextHeader(tenantContext)) 356 if err != nil { 357 return nil, err 358 } 359 360 return vdcGroup, nil 361 } 362 363 // Update updates existing Vdc group. Allows changing only name and description and participating VCDs 364 // Not restrictive update method also available - GenericUpdate 365 func (vdcGroup *VdcGroup) Update(name, description string, participatingOrgVddIs []string) (*VdcGroup, error) { 366 367 vdcGroup.VdcGroup.Name = name 368 vdcGroup.VdcGroup.Description = description 369 370 participatingOrgVdcs, err := composeParticipatingOrgVdcs(vdcGroup.parent.fullObject().(*AdminOrg), vdcGroup.VdcGroup.Id, participatingOrgVddIs) 371 if err != nil { 372 return nil, err 373 } 374 vdcGroup.VdcGroup.ParticipatingOrgVdcs = participatingOrgVdcs 375 376 return vdcGroup.GenericUpdate() 377 } 378 379 // GenericUpdate updates existing Vdc group. API allows changing only name and description and participating VCDs 380 func (vdcGroup *VdcGroup) GenericUpdate() (*VdcGroup, error) { 381 tenantContext, err := vdcGroup.getTenantContext() 382 if err != nil { 383 return nil, err 384 } 385 386 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroups 387 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 388 if err != nil { 389 return nil, err 390 } 391 392 if vdcGroup.VdcGroup.Id == "" { 393 return nil, fmt.Errorf("cannot update VDC group without id") 394 } 395 396 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(endpoint, vdcGroup.VdcGroup.Id) 397 if err != nil { 398 return nil, err 399 } 400 401 returnVdcGroup := &VdcGroup{ 402 VdcGroup: &types.VdcGroup{}, 403 client: vdcGroup.client, 404 Href: vdcGroup.Href, 405 parent: vdcGroup.parent, 406 } 407 408 err = vdcGroup.client.OpenApiPutItem(minimumApiVersion, urlRef, nil, vdcGroup.VdcGroup, 409 returnVdcGroup.VdcGroup, getTenantContextHeader(tenantContext)) 410 if err != nil { 411 return nil, fmt.Errorf("error updating VDC group: %s", err) 412 } 413 414 return returnVdcGroup, nil 415 } 416 417 // UpdateDfwPolicies updates distributed firewall policies 418 func (vdcGroup *VdcGroup) UpdateDfwPolicies(dfwPolicies types.DfwPolicies) (*VdcGroup, error) { 419 tenantContext, err := vdcGroup.getTenantContext() 420 if err != nil { 421 return nil, err 422 } 423 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwPolicies 424 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 425 if err != nil { 426 return nil, err 427 } 428 429 if vdcGroup.VdcGroup.Id == "" { 430 return nil, fmt.Errorf("cannot update VDC group Dfw policies without id") 431 } 432 433 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id)) 434 if err != nil { 435 return nil, err 436 } 437 438 err = vdcGroup.client.OpenApiPutItem(minimumApiVersion, urlRef, nil, dfwPolicies, 439 nil, getTenantContextHeader(tenantContext)) 440 if err != nil { 441 return nil, fmt.Errorf("error updating VDC group Dfw policies: %s", err) 442 } 443 444 adminOrg := vdcGroup.parent.fullObject().(*AdminOrg) 445 return adminOrg.GetVdcGroupById(vdcGroup.VdcGroup.Id) 446 } 447 448 // UpdateDefaultDfwPolicies updates distributed firewall default policies 449 func (vdcGroup *VdcGroup) UpdateDefaultDfwPolicies(defaultDfwPolicies types.DefaultPolicy) (*VdcGroup, error) { 450 tenantContext, err := vdcGroup.getTenantContext() 451 if err != nil { 452 return nil, err 453 } 454 455 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwDefaultPolicies 456 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 457 if err != nil { 458 return nil, err 459 } 460 461 if vdcGroup.VdcGroup.Id == "" { 462 return nil, fmt.Errorf("cannot update VDC group default DFW policies without id") 463 } 464 465 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id)) 466 if err != nil { 467 return nil, err 468 } 469 470 err = vdcGroup.client.OpenApiPutItem(minimumApiVersion, urlRef, nil, defaultDfwPolicies, 471 nil, getTenantContextHeader(tenantContext)) 472 if err != nil { 473 return nil, fmt.Errorf("error updating VDC group default DFW policies: %s", err) 474 } 475 476 adminOrg := vdcGroup.parent.fullObject().(*AdminOrg) 477 return adminOrg.GetVdcGroupById(vdcGroup.VdcGroup.Id) 478 } 479 480 // ActivateDfw activates distributed firewall 481 func (vdcGroup *VdcGroup) ActivateDfw() (*VdcGroup, error) { 482 return vdcGroup.UpdateDfwPolicies(types.DfwPolicies{ 483 Enabled: true, 484 }) 485 } 486 487 // DeactivateDfw deactivates distributed firewall 488 func (vdcGroup *VdcGroup) DeactivateDfw() (*VdcGroup, error) { 489 return vdcGroup.UpdateDfwPolicies(types.DfwPolicies{ 490 Enabled: false, 491 }) 492 } 493 494 // GetDfwPolicies retrieves all distributed firewall policies 495 func (vdcGroup *VdcGroup) GetDfwPolicies() (*types.DfwPolicies, error) { 496 tenantContext, err := vdcGroup.getTenantContext() 497 if err != nil { 498 return nil, err 499 } 500 501 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwPolicies 502 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 503 if err != nil { 504 return nil, err 505 } 506 507 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, vdcGroup.VdcGroup.Id)) 508 if err != nil { 509 return nil, err 510 } 511 512 response := types.DfwPolicies{} 513 err = vdcGroup.client.OpenApiGetItem(minimumApiVersion, urlRef, nil, &response, getTenantContextHeader(tenantContext)) 514 if err != nil { 515 return nil, err 516 } 517 518 return &response, nil 519 } 520 521 // EnableDefaultPolicy activates default dfw policy 522 func (vdcGroup *VdcGroup) EnableDefaultPolicy() (*VdcGroup, error) { 523 dfwPolicies, err := vdcGroup.GetDfwPolicies() 524 if err != nil { 525 return nil, err 526 } 527 528 if dfwPolicies.DefaultPolicy == nil { 529 return nil, fmt.Errorf("DFW has to be enabled before changing Default policy") 530 } 531 dfwPolicies.DefaultPolicy.Enabled = addrOf(true) 532 return vdcGroup.UpdateDefaultDfwPolicies(*dfwPolicies.DefaultPolicy) 533 } 534 535 // DisableDefaultPolicy deactivates default dfw policy 536 func (vdcGroup *VdcGroup) DisableDefaultPolicy() (*VdcGroup, error) { 537 dfwPolicies, err := vdcGroup.GetDfwPolicies() 538 if err != nil { 539 return nil, err 540 } 541 542 if dfwPolicies.DefaultPolicy == nil { 543 return nil, fmt.Errorf("DFW has to be enabled before changing Default policy") 544 } 545 dfwPolicies.DefaultPolicy.Enabled = addrOf(false) 546 return vdcGroup.UpdateDefaultDfwPolicies(*dfwPolicies.DefaultPolicy) 547 } 548 549 func getOwnerTypeFromUrn(urn string) (string, error) { 550 if !isUrn(urn) { 551 return "", fmt.Errorf("supplied ID is not URN: %s", urn) 552 } 553 554 ss := strings.Split(urn, ":") 555 return ss[2], nil 556 } 557 558 // OwnerIsVdcGroup evaluates given URN and returns true if it is a VDC Group 559 func OwnerIsVdcGroup(urn string) bool { 560 ownerType, err := getOwnerTypeFromUrn(urn) 561 if err != nil { 562 return false 563 } 564 565 if strings.EqualFold(ownerType, types.UrnTypeVdcGroup) { 566 return true 567 } 568 569 return false 570 } 571 572 // OwnerIsVdc evaluates a given URN and returns true if it is a VDC 573 func OwnerIsVdc(urn string) bool { 574 ownerType, err := getOwnerTypeFromUrn(urn) 575 if err != nil { 576 return false 577 } 578 579 if strings.EqualFold(ownerType, types.UrnTypeVdc) { 580 return true 581 } 582 583 return false 584 } 585 586 // GetCapabilities allows to retrieve a list of VDC capabilities. It has a list of values. Some particularly useful are: 587 // * networkProvider - overlay stack responsible for providing network functionality. (NSX_V or NSX_T) 588 // * crossVdc - supports cross vDC network creation 589 func (vdcGroup *VdcGroup) GetCapabilities() ([]types.VdcCapability, error) { 590 if vdcGroup.VdcGroup.Id == "" { 591 return nil, fmt.Errorf("VDC ID must be set to get capabilities") 592 } 593 594 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcCapabilities 595 minimumApiVersion, err := vdcGroup.client.checkOpenApiEndpointCompatibility(endpoint) 596 if err != nil { 597 return nil, err 598 } 599 600 urlRef, err := vdcGroup.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, url.QueryEscape(vdcGroup.VdcGroup.Id))) 601 if err != nil { 602 return nil, err 603 } 604 605 capabilities := make([]types.VdcCapability, 0) 606 err = vdcGroup.client.OpenApiGetAllItems(minimumApiVersion, urlRef, nil, &capabilities, nil) 607 if err != nil { 608 return nil, err 609 } 610 return capabilities, nil 611 } 612 613 // IsNsxt is a convenience function to check if VDC is backed by NSX-T pVdc 614 // If error occurs - it returns false 615 func (vdcGroup *VdcGroup) IsNsxt() bool { 616 vdcCapabilities, err := vdcGroup.GetCapabilities() 617 if err != nil { 618 return false 619 } 620 621 networkProviderCapability := getCapabilityValue(vdcCapabilities, "networkProvider") 622 return networkProviderCapability == types.VdcCapabilityNetworkProviderNsxt 623 }