github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/adminorg.go (about) 1 /* 2 * Copyright 2020 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 "regexp" 12 "strconv" 13 "strings" 14 15 "github.com/vmware/go-vcloud-director/v2/util" 16 17 "github.com/vmware/go-vcloud-director/v2/types/v56" 18 ) 19 20 // AdminOrg gives an admin representation of an org. 21 // Administrators can delete and update orgs with an admin org object. 22 // AdminOrg includes all members of the Org element, and adds several 23 // elements that can be viewed and modified only by system administrators. 24 // Definition: https://code.vmware.com/apis/220/vcloud#/doc/doc/types/AdminOrgType.html 25 type AdminOrg struct { 26 AdminOrg *types.AdminOrg 27 client *Client 28 TenantContext *TenantContext 29 } 30 31 func NewAdminOrg(cli *Client) *AdminOrg { 32 return &AdminOrg{ 33 AdminOrg: new(types.AdminOrg), 34 client: cli, 35 } 36 } 37 38 // CreateCatalog creates a catalog with given name and description under 39 // the given organization. Returns an AdminCatalog that contains a creation 40 // task. 41 // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/POST-CreateCatalog.html 42 func (adminOrg *AdminOrg) CreateCatalog(name, description string) (AdminCatalog, error) { 43 adminCatalog, err := adminOrg.CreateCatalogWithStorageProfile(name, description, nil) 44 if err != nil { 45 return AdminCatalog{}, err 46 } 47 adminCatalog.parent = adminOrg 48 49 err = adminCatalog.Refresh() 50 if err != nil { 51 return AdminCatalog{}, err 52 } 53 // Make sure that the creation task is finished 54 err = adminCatalog.WaitForTasks() 55 if err != nil { 56 return AdminCatalog{}, err 57 } 58 err = adminCatalog.WaitForTasks() 59 if err != nil { 60 return AdminCatalog{}, err 61 } 62 return *adminCatalog, nil 63 } 64 65 // CreateCatalogWithStorageProfile is like CreateCatalog, but allows to specify storage profile 66 func (adminOrg *AdminOrg) CreateCatalogWithStorageProfile(name, description string, storageProfiles *types.CatalogStorageProfiles) (*AdminCatalog, error) { 67 adminCatalog, err := CreateCatalogWithStorageProfile(adminOrg.client, adminOrg.AdminOrg.Link, name, description, storageProfiles) 68 if err != nil { 69 return nil, err 70 } 71 adminCatalogWithParent := NewAdminCatalogWithParent(adminOrg.client, adminOrg) 72 adminCatalogWithParent.AdminCatalog = adminCatalog.AdminCatalog 73 return adminCatalogWithParent, nil 74 } 75 76 // GetAllVDCs returns all depending VDCs for a particular Org 77 func (adminOrg *AdminOrg) GetAllVDCs(refresh bool) ([]*Vdc, error) { 78 if refresh { 79 err := adminOrg.Refresh() 80 if err != nil { 81 return nil, err 82 } 83 } 84 85 allVdcs := make([]*Vdc, len(adminOrg.AdminOrg.Vdcs.Vdcs)) 86 for vdcIndex, vdc := range adminOrg.AdminOrg.Vdcs.Vdcs { 87 vdc, err := adminOrg.GetVDCByHref(vdc.HREF) 88 if err != nil { 89 return nil, fmt.Errorf("error retrieving VDC '%s': %s", vdc.Vdc.Name, err) 90 } 91 allVdcs[vdcIndex] = vdc 92 93 } 94 95 return allVdcs, nil 96 } 97 98 // GetAllStorageProfileReferences traverses all depending VDCs and returns a slice of storage profile references 99 // available in those VDCs 100 func (adminOrg *AdminOrg) GetAllStorageProfileReferences(refresh bool) ([]*types.Reference, error) { 101 if refresh { 102 err := adminOrg.Refresh() 103 if err != nil { 104 return nil, err 105 } 106 } 107 108 allVdcs, err := adminOrg.GetAllVDCs(refresh) 109 if err != nil { 110 return nil, fmt.Errorf("could not retrieve storage profile references: %s", err) 111 } 112 113 allStorageProfileReferences := make([]*types.Reference, 0) 114 for _, vdc := range allVdcs { 115 if len(vdc.Vdc.VdcStorageProfiles.VdcStorageProfile) > 0 { 116 allStorageProfileReferences = append(allStorageProfileReferences, vdc.Vdc.VdcStorageProfiles.VdcStorageProfile...) 117 } 118 } 119 120 return allStorageProfileReferences, nil 121 } 122 123 // GetStorageProfileReferenceById finds storage profile reference by specified ID in Org or returns ErrorEntityNotFound 124 func (adminOrg *AdminOrg) GetStorageProfileReferenceById(id string, refresh bool) (*types.Reference, error) { 125 allStorageProfiles, err := adminOrg.GetAllStorageProfileReferences(refresh) 126 if err != nil { 127 return nil, fmt.Errorf("error getting all storage profiles: %s", err) 128 } 129 130 for _, storageProfileReference := range allStorageProfiles { 131 if storageProfileReference.ID == id { 132 return storageProfileReference, nil 133 } 134 } 135 136 return nil, fmt.Errorf("%s: storage profile with ID '%s' not found in Org '%s'", 137 ErrorEntityNotFound, id, adminOrg.AdminOrg.Name) 138 } 139 140 // Deletes the org, returning an error if the vCD call fails. 141 // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/DELETE-Organization.html 142 func (adminOrg *AdminOrg) Delete(force bool, recursive bool) error { 143 if force && recursive { 144 //undeploys vapps 145 err := adminOrg.undeployAllVApps() 146 if err != nil { 147 return fmt.Errorf("error could not undeploy: %s", err) 148 } 149 //removes vapps 150 err = adminOrg.removeAllVApps() 151 if err != nil { 152 return fmt.Errorf("error could not remove vapp: %s", err) 153 } 154 //removes catalogs 155 err = adminOrg.removeCatalogs() 156 if err != nil { 157 return fmt.Errorf("error could not remove all catalogs: %s", err) 158 } 159 //removes networks 160 err = adminOrg.removeAllOrgNetworks() 161 if err != nil { 162 return fmt.Errorf("error could not remove all networks: %s", err) 163 } 164 //removes org vdcs 165 err = adminOrg.removeAllOrgVDCs() 166 if err != nil { 167 return fmt.Errorf("error could not remove all vdcs: %s", err) 168 } 169 } 170 // Disable org 171 err := adminOrg.Disable() 172 if err != nil { 173 return fmt.Errorf("error disabling Org %s: %s", adminOrg.AdminOrg.Name, err) 174 } 175 // Get admin HREF 176 orgHREF, err := url.ParseRequestURI(adminOrg.AdminOrg.HREF) 177 if err != nil { 178 return fmt.Errorf("error getting AdminOrg HREF %s : %s", adminOrg.AdminOrg.HREF, err) 179 } 180 req := adminOrg.client.NewRequest(map[string]string{ 181 "force": strconv.FormatBool(force), 182 "recursive": strconv.FormatBool(recursive), 183 }, http.MethodDelete, *orgHREF, nil) 184 resp, err := checkResp(adminOrg.client.Http.Do(req)) 185 if err != nil { 186 return fmt.Errorf("error deleting Org %s: %s", adminOrg.AdminOrg.ID, err) 187 } 188 189 task := NewTask(adminOrg.client) 190 if err = decodeBody(types.BodyTypeXML, resp, task.Task); err != nil { 191 return fmt.Errorf("error decoding task response: %s", err) 192 } 193 return task.WaitTaskCompletion() 194 } 195 196 // Disables the org. Returns an error if the call to vCD fails. 197 // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/POST-DisableOrg.html 198 func (adminOrg *AdminOrg) Disable() error { 199 orgHREF, err := url.ParseRequestURI(adminOrg.AdminOrg.HREF) 200 if err != nil { 201 return fmt.Errorf("error getting AdminOrg HREF %s : %s", adminOrg.AdminOrg.HREF, err) 202 } 203 orgHREF.Path += "/action/disable" 204 205 return adminOrg.client.ExecuteRequestWithoutResponse(orgHREF.String(), http.MethodPost, "", "error disabling organization: %s", nil) 206 } 207 208 // Updates the Org definition from current org struct contents. 209 // Any differences that may be legally applied will be updated. 210 // Returns an error if the call to vCD fails. 211 // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/PUT-Organization.html 212 func (adminOrg *AdminOrg) Update() (Task, error) { 213 vcomp := &types.AdminOrg{ 214 Xmlns: types.XMLNamespaceVCloud, 215 Name: adminOrg.AdminOrg.Name, 216 IsEnabled: adminOrg.AdminOrg.IsEnabled, 217 FullName: adminOrg.AdminOrg.FullName, 218 Description: adminOrg.AdminOrg.Description, 219 OrgSettings: adminOrg.AdminOrg.OrgSettings, 220 } 221 222 // Same workaround used in Org creation, where OrgGeneralSettings properties 223 // are not set unless UseServerBootSequence is also set 224 if vcomp.OrgSettings.OrgGeneralSettings != nil { 225 vcomp.OrgSettings.OrgGeneralSettings.UseServerBootSequence = true 226 } 227 228 // Return the task 229 return adminOrg.client.ExecuteTaskRequest(adminOrg.AdminOrg.HREF, http.MethodPut, 230 "application/vnd.vmware.admin.organization+xml", "error updating Org: %s", vcomp) 231 } 232 233 // Undeploys every vapp within an organization 234 func (adminOrg *AdminOrg) undeployAllVApps() error { 235 for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs { 236 adminVdcHREF, err := url.Parse(vdcs.HREF) 237 if err != nil { 238 return err 239 } 240 vdc, err := adminOrg.getVdcByAdminHREF(adminVdcHREF) 241 if err != nil { 242 return fmt.Errorf("error retrieving vapp with url: %s and with error %s", adminVdcHREF.Path, err) 243 } 244 err = vdc.undeployAllVdcVApps() 245 if err != nil { 246 return fmt.Errorf("error deleting vapp: %s", err) 247 } 248 } 249 return nil 250 } 251 252 // Deletes every vapp within an organization 253 func (adminOrg *AdminOrg) removeAllVApps() error { 254 for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs { 255 adminVdcHREF, err := url.Parse(vdcs.HREF) 256 if err != nil { 257 return err 258 } 259 vdc, err := adminOrg.getVdcByAdminHREF(adminVdcHREF) 260 if err != nil { 261 return fmt.Errorf("error retrieving vapp with url: %s and with error %s", adminVdcHREF.Path, err) 262 } 263 err = vdc.removeAllVdcVApps() 264 if err != nil { 265 return fmt.Errorf("error deleting vapp: %s", err) 266 } 267 } 268 return nil 269 } 270 271 // Given an adminorg with a valid HREF, the function refetches the adminorg 272 // and updates the user's adminorg data. Otherwise if the function fails, 273 // it returns an error. Users should use refresh whenever they have 274 // a stale org due to the creation/update/deletion of a resource 275 // within the org or the org itself. 276 func (adminOrg *AdminOrg) Refresh() error { 277 if *adminOrg == (AdminOrg{}) { 278 return fmt.Errorf("cannot refresh, Object is empty") 279 } 280 281 // Empty struct before a new unmarshal, otherwise we end up with duplicate 282 // elements in slices. 283 unmarshalledAdminOrg := &types.AdminOrg{} 284 285 _, err := adminOrg.client.ExecuteRequest(adminOrg.AdminOrg.HREF, http.MethodGet, 286 "", "error refreshing organization: %s", nil, unmarshalledAdminOrg) 287 if err != nil { 288 return err 289 } 290 adminOrg.AdminOrg = unmarshalledAdminOrg 291 292 return nil 293 } 294 295 // Gets a vdc within org associated with an admin vdc url 296 func (adminOrg *AdminOrg) getVdcByAdminHREF(adminVdcUrl *url.URL) (*Vdc, error) { 297 // get non admin vdc path 298 vdcURL := adminOrg.client.VCDHREF 299 vdcURL.Path += strings.Split(adminVdcUrl.Path, "/api/admin")[1] //gets id 300 301 vdc := NewVdc(adminOrg.client) 302 303 vdc.parent = adminOrg 304 305 _, err := adminOrg.client.ExecuteRequest(vdcURL.String(), http.MethodGet, 306 "", "error retrieving vdc: %s", nil, vdc.Vdc) 307 308 return vdc, err 309 } 310 311 // Removes all vdcs in a org 312 func (adminOrg *AdminOrg) removeAllOrgVDCs() error { 313 for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs { 314 315 adminVdcUrl := adminOrg.client.VCDHREF 316 splitVdcId := strings.Split(vdcs.HREF, "/api/vdc/") 317 if len(splitVdcId) == 1 { 318 adminVdcUrl.Path += "/admin/vdc/" + strings.Split(vdcs.HREF, "/api/admin/vdc/")[1] + "/action/disable" 319 } else { 320 adminVdcUrl.Path += "/admin/vdc/" + splitVdcId[1] + "/action/disable" 321 } 322 323 req := adminOrg.client.NewRequest(map[string]string{}, http.MethodPost, adminVdcUrl, nil) 324 _, err := checkResp(adminOrg.client.Http.Do(req)) 325 if err != nil { 326 return fmt.Errorf("error disabling vdc: %s", err) 327 } 328 // Get admin vdc HREF for normal deletion 329 adminVdcUrl.Path = strings.Split(adminVdcUrl.Path, "/action/disable")[0] 330 req = adminOrg.client.NewRequest(map[string]string{ 331 "recursive": "true", 332 "force": "true", 333 }, http.MethodDelete, adminVdcUrl, nil) 334 resp, err := checkResp(adminOrg.client.Http.Do(req)) 335 if err != nil { 336 return fmt.Errorf("error deleting vdc: %s", err) 337 } 338 task := NewTask(adminOrg.client) 339 if err = decodeBody(types.BodyTypeXML, resp, task.Task); err != nil { 340 return fmt.Errorf("error decoding task response: %s", err) 341 } 342 if task.Task.Status == "error" { 343 return fmt.Errorf("vdc not properly destroyed") 344 } 345 err = task.WaitTaskCompletion() 346 if err != nil { 347 return fmt.Errorf("couldn't finish removing vdc %s", err) 348 } 349 350 } 351 352 return nil 353 } 354 355 // Removes All networks in the org 356 func (adminOrg *AdminOrg) removeAllOrgNetworks() error { 357 for _, networks := range adminOrg.AdminOrg.Networks.Networks { 358 // Get Network HREF 359 networkHREF := adminOrg.client.VCDHREF 360 networkHREF.Path += "/admin/network/" + strings.Split(networks.HREF, "/api/admin/network/")[1] //gets id 361 362 task, err := adminOrg.client.ExecuteTaskRequest(networkHREF.String(), http.MethodDelete, 363 "", "error deleting network: %s", nil) 364 if err != nil { 365 return err 366 } 367 368 if task.Task.Status == "error" { 369 return fmt.Errorf("network not properly destroyed") 370 } 371 err = task.WaitTaskCompletion() 372 if err != nil { 373 return fmt.Errorf("couldn't finish removing network %s", err) 374 } 375 } 376 return nil 377 } 378 379 // removeCatalogs force removal of all organization catalogs 380 func (adminOrg *AdminOrg) removeCatalogs() error { 381 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 382 isCatalogFromSameOrg, err := isCatalogFromSameOrg(adminOrg, catalog.Name) 383 if err != nil { 384 return fmt.Errorf("error deleting catalog: %s", err) 385 } 386 if isCatalogFromSameOrg { 387 // Get Catalog HREF 388 catalogHREF := adminOrg.client.VCDHREF 389 catalogHREF.Path += "/admin/catalog/" + strings.Split(catalog.HREF, "/api/admin/catalog/")[1] //gets id 390 req := adminOrg.client.NewRequest(map[string]string{ 391 "force": "true", 392 "recursive": "true", 393 }, http.MethodDelete, catalogHREF, nil) 394 _, err := checkResp(adminOrg.client.Http.Do(req)) 395 if err != nil { 396 return fmt.Errorf("error deleting catalog: %s, %s", err, catalogHREF.Path) 397 } 398 } 399 } 400 return nil 401 402 } 403 404 // isCatalogFromSameOrg checks if catalog is in same Org. Shared catalogs from other Org are showed as normal one 405 // in some API responses. 406 func isCatalogFromSameOrg(adminOrg *AdminOrg, catalogName string) (bool, error) { 407 foundCatalogs, err := adminOrg.FindAdminCatalogRecords(catalogName) 408 if err != nil { 409 return false, err 410 } 411 412 if len(foundCatalogs) == 1 { 413 return true, nil 414 } 415 return false, nil 416 } 417 418 // FindAdminCatalogRecords uses catalog name to return AdminCatalogRecord information. 419 func (adminOrg *AdminOrg) FindAdminCatalogRecords(name string) ([]*types.CatalogRecord, error) { 420 util.Logger.Printf("[DEBUG] FindAdminCatalogRecords with name: %s and org name: %s", name, adminOrg.AdminOrg.Name) 421 results, err := adminOrg.client.QueryWithNotEncodedParams(nil, map[string]string{ 422 "type": "adminCatalog", 423 "filter": fmt.Sprintf("name==%s;orgName==%s", url.QueryEscape(name), url.QueryEscape(adminOrg.AdminOrg.Name)), 424 "filterEncoded": "true", 425 }) 426 if err != nil { 427 return nil, err 428 } 429 430 util.Logger.Printf("[DEBUG] FindAdminCatalogRecords returned with : %#v and error: %s", results.Results.AdminCatalogRecord, err) 431 return results.Results.AdminCatalogRecord, nil 432 } 433 434 // Given a valid catalog name, FindAdminCatalog returns an AdminCatalog object. 435 // If no catalog is found, then returns an empty AdminCatalog and no error. 436 // Otherwise it returns an error. Function allows user to use an AdminOrg 437 // to also fetch a Catalog. If user does not have proper credentials to 438 // perform administrator tasks then function returns an error. 439 // API Documentation: https://code.vmware.com/apis/220/vcloud#/doc/doc/operations/GET-Catalog-AdminView.html 440 // Deprecated: Use adminOrg.GetAdminCatalog instead 441 func (adminOrg *AdminOrg) FindAdminCatalog(catalogName string) (AdminCatalog, error) { 442 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 443 // Get Catalog HREF 444 if catalog.Name == catalogName { 445 adminCatalog := NewAdminCatalog(adminOrg.client) 446 _, err := adminOrg.client.ExecuteRequest(catalog.HREF, http.MethodGet, 447 "", "error retrieving catalog: %s", nil, adminCatalog.AdminCatalog) 448 // The request was successful 449 return *adminCatalog, err 450 } 451 } 452 return AdminCatalog{}, nil 453 } 454 455 // Given a valid catalog name, FindCatalog returns a Catalog object. 456 // If no catalog is found, then returns an empty catalog and no error. 457 // Otherwise it returns an error. Function allows user to use an AdminOrg 458 // to also fetch a Catalog. 459 // Deprecated: Use adminOrg.GetCatalogByName instead 460 func (adminOrg *AdminOrg) FindCatalog(catalogName string) (Catalog, error) { 461 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 462 // Get Catalog HREF 463 if catalog.Name == catalogName { 464 catalogURL := adminOrg.client.VCDHREF 465 catalogURL.Path += "/catalog/" + strings.Split(catalog.HREF, "/api/admin/catalog/")[1] //gets id 466 467 cat := NewCatalog(adminOrg.client) 468 469 _, err := adminOrg.client.ExecuteRequest(catalogURL.String(), http.MethodGet, 470 "", "error retrieving catalog: %s", nil, cat.Catalog) 471 472 // The request was successful 473 return *cat, err 474 } 475 } 476 return Catalog{}, nil 477 } 478 479 // GetCatalogByHref finds a Catalog by HREF 480 // On success, returns a pointer to the Catalog structure and a nil error 481 // On failure, returns a nil pointer and an error 482 func (adminOrg *AdminOrg) GetCatalogByHref(catalogHref string) (*Catalog, error) { 483 splitByAdminHREF := strings.Split(catalogHref, "/api/admin") 484 485 // admin user and normal user will have different urls 486 var catalogHREF string 487 if len(splitByAdminHREF) == 1 { 488 catalogHREF = catalogHref 489 } else { 490 catalogHREF = splitByAdminHREF[0] + "/api" + splitByAdminHREF[1] 491 } 492 493 cat := NewCatalog(adminOrg.client) 494 495 _, err := adminOrg.client.ExecuteRequest(catalogHREF, http.MethodGet, 496 "", "error retrieving catalog: %s", nil, cat.Catalog) 497 498 if err != nil { 499 return nil, err 500 } 501 cat.parent = adminOrg 502 // The request was successful 503 return cat, nil 504 } 505 506 // GetCatalogByName finds a Catalog by Name 507 // On success, returns a pointer to the Catalog structure and a nil error 508 // On failure, returns a nil pointer and an error 509 func (adminOrg *AdminOrg) GetCatalogByName(catalogName string, refresh bool) (*Catalog, error) { 510 511 if refresh { 512 err := adminOrg.Refresh() 513 if err != nil { 514 return nil, err 515 } 516 } 517 518 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 519 if catalog.Name == catalogName { 520 return adminOrg.GetCatalogByHref(catalog.HREF) 521 } 522 } 523 return nil, ErrorEntityNotFound 524 } 525 526 // Extracts an UUID from a string, regardless of surrounding text, returns the last found occurrence 527 // Returns an empty string if no UUID was found 528 func extractUuid(input string) string { 529 reGetID := regexp.MustCompile(`([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})`) 530 matchListId := reGetID.FindAllStringSubmatch(input, -1) 531 if len(matchListId) > 0 && len(matchListId[0]) > 0 { 532 return matchListId[len(matchListId)-1][1] 533 } 534 return "" 535 } 536 537 // equalIds compares two IDs and return true if they are the same 538 // The comparison happens by extracting the bare UUID from both the 539 // wanted ID and the found one. 540 // When the found ID is empty, it used the HREF for such comparison, 541 // This function is useful when the reference structure in the parent lookup list 542 // may lack the ID (such as in Org.Links, AdminOrg.Catalogs) or has an ID 543 // that is only a UUID without prefixes (such as in CatalogItem list) 544 // 545 // wantedId is the input string to compare 546 // foundId is the ID field in the reference record (can be empty) 547 // foundHref is the HREF field in the reference record (should never be empty) 548 func equalIds(wantedId, foundId, foundHref string) bool { 549 550 wantedUuid := extractUuid(wantedId) 551 foundUuid := "" 552 553 if wantedUuid == "" { 554 return false 555 } 556 if foundId != "" { 557 // In some entities, the ID is a simple UUID without prefix 558 foundUuid = extractUuid(foundId) 559 } else { 560 foundUuid = extractUuid(foundHref) 561 } 562 return foundUuid == wantedUuid 563 } 564 565 // GetCatalogById finds a Catalog by ID 566 // On success, returns a pointer to the Catalog structure and a nil error 567 // On failure, returns a nil pointer and an error 568 func (adminOrg *AdminOrg) GetCatalogById(catalogId string, refresh bool) (*Catalog, error) { 569 if refresh { 570 err := adminOrg.Refresh() 571 if err != nil { 572 return nil, err 573 } 574 } 575 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 576 if equalIds(catalogId, catalog.ID, catalog.HREF) { 577 return adminOrg.GetCatalogByHref(catalog.HREF) 578 } 579 } 580 return nil, ErrorEntityNotFound 581 } 582 583 // GetCatalogByNameOrId finds a Catalog by name or ID 584 // On success, returns a pointer to the Catalog structure and a nil error 585 // On failure, returns a nil pointer and an error 586 func (adminOrg *AdminOrg) GetCatalogByNameOrId(identifier string, refresh bool) (*Catalog, error) { 587 getByName := func(name string, refresh bool) (interface{}, error) { return adminOrg.GetCatalogByName(name, refresh) } 588 getById := func(id string, refresh bool) (interface{}, error) { return adminOrg.GetCatalogById(id, refresh) } 589 entity, err := getEntityByNameOrId(getByName, getById, identifier, refresh) 590 if entity == nil { 591 return nil, err 592 } 593 return entity.(*Catalog), err 594 } 595 596 // GetAdminCatalogByHref finds an AdminCatalog by HREF 597 // On success, returns a pointer to the Catalog structure and a nil error 598 // On failure, returns a nil pointer and an error 599 func (adminOrg *AdminOrg) GetAdminCatalogByHref(catalogHref string) (*AdminCatalog, error) { 600 adminCatalog := NewAdminCatalog(adminOrg.client) 601 602 _, err := adminOrg.client.ExecuteRequest(catalogHref, http.MethodGet, 603 "", "error retrieving catalog: %s", nil, adminCatalog.AdminCatalog) 604 605 if err != nil { 606 return nil, err 607 } 608 609 adminCatalog.parent = adminOrg 610 // The request was successful 611 return adminCatalog, nil 612 } 613 614 // GetCatalogByName finds an AdminCatalog by Name 615 // On success, returns a pointer to the AdminCatalog structure and a nil error 616 // On failure, returns a nil pointer and an error 617 func (adminOrg *AdminOrg) GetAdminCatalogByName(catalogName string, refresh bool) (*AdminCatalog, error) { 618 if refresh { 619 err := adminOrg.Refresh() 620 if err != nil { 621 return nil, err 622 } 623 } 624 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 625 // Get Catalog HREF 626 if catalog.Name == catalogName { 627 return adminOrg.GetAdminCatalogByHref(catalog.HREF) 628 } 629 } 630 return nil, ErrorEntityNotFound 631 } 632 633 // GetCatalogById finds an AdminCatalog by ID 634 // On success, returns a pointer to the AdminCatalog structure and a nil error 635 // On failure, returns a nil pointer and an error 636 func (adminOrg *AdminOrg) GetAdminCatalogById(catalogId string, refresh bool) (*AdminCatalog, error) { 637 if refresh { 638 err := adminOrg.Refresh() 639 if err != nil { 640 return nil, err 641 } 642 } 643 for _, catalog := range adminOrg.AdminOrg.Catalogs.Catalog { 644 // Get Catalog HREF 645 if equalIds(catalogId, catalog.ID, catalog.HREF) { 646 return adminOrg.GetAdminCatalogByHref(catalog.HREF) 647 } 648 } 649 return nil, ErrorEntityNotFound 650 } 651 652 // GetAdminCatalogByNameOrId finds an AdminCatalog by name or ID 653 // On success, returns a pointer to the AdminCatalog structure and a nil error 654 // On failure, returns a nil pointer and an error 655 func (adminOrg *AdminOrg) GetAdminCatalogByNameOrId(identifier string, refresh bool) (*AdminCatalog, error) { 656 getByName := func(name string, refresh bool) (interface{}, error) { 657 return adminOrg.GetAdminCatalogByName(name, refresh) 658 } 659 getById := func(id string, refresh bool) (interface{}, error) { 660 return adminOrg.GetAdminCatalogById(id, refresh) 661 } 662 entity, err := getEntityByNameOrId(getByName, getById, identifier, refresh) 663 if entity == nil { 664 return nil, err 665 } 666 return entity.(*AdminCatalog), err 667 } 668 669 // GetVDCByHref retrieves a VDC using a direct call with the HREF 670 func (adminOrg *AdminOrg) GetVDCByHref(vdcHref string) (*Vdc, error) { 671 splitByAdminHREF := strings.Split(vdcHref, "/api/admin") 672 673 // admin user and normal user will have different urls 674 var vdcHREF string 675 if len(splitByAdminHREF) == 1 { 676 vdcHREF = vdcHref 677 } else { 678 vdcHREF = splitByAdminHREF[0] + "/api" + splitByAdminHREF[1] 679 } 680 681 vdc := NewVdc(adminOrg.client) 682 683 _, err := adminOrg.client.ExecuteRequest(vdcHREF, http.MethodGet, 684 "", "error getting vdc: %s", nil, vdc.Vdc) 685 686 if err != nil { 687 return nil, err 688 } 689 vdc.parent = adminOrg 690 691 return vdc, nil 692 } 693 694 // GetVDCByName finds a VDC by Name 695 // On success, returns a pointer to the Vdc structure and a nil error 696 // On failure, returns a nil pointer and an error 697 func (adminOrg *AdminOrg) GetVDCByName(vdcName string, refresh bool) (*Vdc, error) { 698 if refresh { 699 err := adminOrg.Refresh() 700 if err != nil { 701 return nil, err 702 } 703 } 704 for _, vdc := range adminOrg.AdminOrg.Vdcs.Vdcs { 705 if vdc.Name == vdcName { 706 return adminOrg.GetVDCByHref(vdc.HREF) 707 } 708 } 709 return nil, ErrorEntityNotFound 710 } 711 712 // GetVDCById finds a VDC by ID 713 // On success, returns a pointer to the Vdc structure and a nil error 714 // On failure, returns a nil pointer and an error 715 func (adminOrg *AdminOrg) GetVDCById(vdcId string, refresh bool) (*Vdc, error) { 716 if refresh { 717 err := adminOrg.Refresh() 718 if err != nil { 719 return nil, err 720 } 721 } 722 for _, vdc := range adminOrg.AdminOrg.Vdcs.Vdcs { 723 if equalIds(vdcId, vdc.ID, vdc.HREF) { 724 return adminOrg.GetVDCByHref(vdc.HREF) 725 } 726 } 727 return nil, ErrorEntityNotFound 728 } 729 730 // GetVDCByNameOrId finds a VDC by name or ID 731 // On success, returns a pointer to the VDC structure and a nil error 732 // On failure, returns a nil pointer and an error 733 func (adminOrg *AdminOrg) GetVDCByNameOrId(identifier string, refresh bool) (*Vdc, error) { 734 getByName := func(name string, refresh bool) (interface{}, error) { return adminOrg.GetVDCByName(name, refresh) } 735 getById := func(id string, refresh bool) (interface{}, error) { return adminOrg.GetVDCById(id, refresh) } 736 entity, err := getEntityByNameOrId(getByName, getById, identifier, refresh) 737 if entity == nil { 738 return nil, err 739 } 740 return entity.(*Vdc), err 741 } 742 743 // If user specifies valid vdc name then this returns a vdc object. 744 // If no vdc is found, then it returns an empty vdc and no error. 745 // Otherwise it returns an empty vdc and an error. This function 746 // allows users to use an AdminOrg to fetch a vdc as well. 747 // Deprecated: Use adminOrg.GetVDCByName instead 748 func (adminOrg *AdminOrg) GetVdcByName(vdcname string) (Vdc, error) { 749 for _, vdcs := range adminOrg.AdminOrg.Vdcs.Vdcs { 750 if vdcs.Name == vdcname { 751 splitByAdminHREF := strings.Split(vdcs.HREF, "/api/admin") 752 753 // admin user and normal user will have different urls 754 var vdcHREF string 755 if len(splitByAdminHREF) == 1 { 756 vdcHREF = vdcs.HREF 757 } else { 758 vdcHREF = splitByAdminHREF[0] + "/api" + splitByAdminHREF[1] 759 } 760 761 vdc := NewVdc(adminOrg.client) 762 763 _, err := adminOrg.client.ExecuteRequest(vdcHREF, http.MethodGet, 764 "", "error getting vdc: %s", nil, vdc.Vdc) 765 766 return *vdc, err 767 } 768 } 769 return Vdc{}, nil 770 } 771 772 // QueryCatalogList returns a list of catalogs for this organization 773 func (adminOrg *AdminOrg) QueryCatalogList() ([]*types.CatalogRecord, error) { 774 return adminOrg.FindCatalogRecords("") 775 } 776 777 // FindCatalogRecords given a catalog name, retrieves the catalogRecords for a given organization 778 func (adminOrg *AdminOrg) FindCatalogRecords(name string) ([]*types.CatalogRecord, error) { 779 util.Logger.Printf("[DEBUG] QueryCatalogList with org name %s", adminOrg.AdminOrg.Name) 780 781 var tenantHeaders map[string]string 782 783 if adminOrg.client.IsSysAdmin { 784 // Set tenant context headers just for the query 785 tenantHeaders = map[string]string{ 786 types.HeaderAuthContext: adminOrg.TenantContext.OrgName, 787 types.HeaderTenantContext: adminOrg.TenantContext.OrgId, 788 } 789 } 790 791 var filter string 792 filter = fmt.Sprintf("orgName==%s", url.QueryEscape(adminOrg.AdminOrg.Name)) 793 if name != "" { 794 filter = fmt.Sprintf("%s;name==%s", filter, url.QueryEscape(name)) 795 } 796 797 results, err := adminOrg.client.cumulativeQueryWithHeaders(types.QtCatalog, nil, map[string]string{ 798 "type": types.QtCatalog, 799 "filter": filter, 800 "filterEncoded": "true", 801 }, tenantHeaders) 802 if err != nil { 803 return nil, err 804 } 805 806 catalogs := results.Results.CatalogRecord 807 if catalogs == nil { 808 return nil, ErrorEntityNotFound 809 } 810 811 util.Logger.Printf("[DEBUG] QueryCatalogList returned with : %#v and error: %s", catalogs, err) 812 return catalogs, nil 813 }