1package cfclient 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "strconv" 11 12 "github.com/pkg/errors" 13) 14 15type SpaceRequest struct { 16 Name string `json:"name"` 17 OrganizationGuid string `json:"organization_guid"` 18 DeveloperGuid []string `json:"developer_guids,omitempty"` 19 ManagerGuid []string `json:"manager_guids,omitempty"` 20 AuditorGuid []string `json:"auditor_guids,omitempty"` 21 DomainGuid []string `json:"domain_guids,omitempty"` 22 SecurityGroupGuids []string `json:"security_group_guids,omitempty"` 23 SpaceQuotaDefGuid string `json:"space_quota_definition_guid,omitempty"` 24 IsolationSegmentGuid string `json:"isolation_segment_guid,omitempty"` 25 AllowSSH bool `json:"allow_ssh"` 26} 27 28type SpaceResponse struct { 29 Count int `json:"total_results"` 30 Pages int `json:"total_pages"` 31 NextUrl string `json:"next_url"` 32 Resources []SpaceResource `json:"resources"` 33} 34 35type SpaceResource struct { 36 Meta Meta `json:"metadata"` 37 Entity Space `json:"entity"` 38} 39 40type ServicePlanEntity struct { 41 Name string `json:"name"` 42 Free bool `json:"free"` 43 Public bool `json:"public"` 44 Active bool `json:"active"` 45 Description string `json:"description"` 46 ServiceOfferingGUID string `json:"service_guid"` 47 ServiceOffering ServiceOfferingResource `json:"service"` 48} 49 50type ServiceOfferingExtra struct { 51 DisplayName string `json:"displayName"` 52 DocumentationURL string `json:"documentationURL"` 53 LongDescription string `json:"longDescription"` 54} 55 56type ServiceOfferingEntity struct { 57 Label string 58 Description string 59 Provider string `json:"provider"` 60 BrokerGUID string `json:"service_broker_guid"` 61 Requires []string `json:"requires"` 62 ServicePlans []interface{} `json:"service_plans"` 63 Extra ServiceOfferingExtra 64} 65 66type ServiceOfferingResource struct { 67 Metadata Meta 68 Entity ServiceOfferingEntity 69} 70 71type ServiceOfferingResponse struct { 72 Count int `json:"total_results"` 73 Pages int `json:"total_pages"` 74 NextUrl string `json:"next_url"` 75 PrevUrl string `json:"prev_url"` 76 Resources []ServiceOfferingResource `json:"resources"` 77} 78 79type SpaceUserResponse struct { 80 Count int `json:"total_results"` 81 Pages int `json:"total_pages"` 82 NextURL string `json:"next_url"` 83 Resources []UserResource `json:"resources"` 84} 85 86type Space struct { 87 Guid string `json:"guid"` 88 CreatedAt string `json:"created_at"` 89 UpdatedAt string `json:"updated_at"` 90 Name string `json:"name"` 91 OrganizationGuid string `json:"organization_guid"` 92 OrgURL string `json:"organization_url"` 93 OrgData OrgResource `json:"organization"` 94 QuotaDefinitionGuid string `json:"space_quota_definition_guid"` 95 IsolationSegmentGuid string `json:"isolation_segment_guid"` 96 AllowSSH bool `json:"allow_ssh"` 97 c *Client 98} 99 100type SpaceSummary struct { 101 Guid string `json:"guid"` 102 Name string `json:"name"` 103 Apps []AppSummary `json:"apps"` 104 Services []ServiceSummary `json:"services"` 105} 106 107type SpaceRoleResponse struct { 108 Count int `json:"total_results"` 109 Pages int `json:"total_pages"` 110 NextUrl string `json:"next_url"` 111 Resources []SpaceRoleResource `json:"resources"` 112} 113 114type SpaceRoleResource struct { 115 Meta Meta `json:"metadata"` 116 Entity SpaceRole `json:"entity"` 117} 118 119type SpaceRole struct { 120 Guid string `json:"guid"` 121 Admin bool `json:"admin"` 122 Active bool `json:"active"` 123 DefaultSpaceGuid string `json:"default_space_guid"` 124 Username string `json:"username"` 125 SpaceRoles []string `json:"space_roles"` 126 SpacesUrl string `json:"spaces_url"` 127 OrganizationsUrl string `json:"organizations_url"` 128 ManagedOrganizationsUrl string `json:"managed_organizations_url"` 129 BillingManagedOrganizationsUrl string `json:"billing_managed_organizations_url"` 130 AuditedOrganizationsUrl string `json:"audited_organizations_url"` 131 ManagedSpacesUrl string `json:"managed_spaces_url"` 132 AuditedSpacesUrl string `json:"audited_spaces_url"` 133 c *Client 134} 135 136func (s *Space) Org() (Org, error) { 137 var orgResource OrgResource 138 r := s.c.NewRequest("GET", s.OrgURL) 139 resp, err := s.c.DoRequest(r) 140 if err != nil { 141 return Org{}, errors.Wrap(err, "Error requesting org") 142 } 143 resBody, err := ioutil.ReadAll(resp.Body) 144 if err != nil { 145 return Org{}, errors.Wrap(err, "Error reading org request") 146 } 147 148 err = json.Unmarshal(resBody, &orgResource) 149 if err != nil { 150 return Org{}, errors.Wrap(err, "Error unmarshaling org") 151 } 152 return s.c.mergeOrgResource(orgResource), nil 153} 154 155func (s *Space) Quota() (*SpaceQuota, error) { 156 var spaceQuota *SpaceQuota 157 var spaceQuotaResource SpaceQuotasResource 158 if s.QuotaDefinitionGuid == "" { 159 return nil, nil 160 } 161 requestUrl := fmt.Sprintf("/v2/space_quota_definitions/%s", s.QuotaDefinitionGuid) 162 r := s.c.NewRequest("GET", requestUrl) 163 resp, err := s.c.DoRequest(r) 164 if err != nil { 165 return &SpaceQuota{}, errors.Wrap(err, "Error requesting space quota") 166 } 167 resBody, err := ioutil.ReadAll(resp.Body) 168 defer resp.Body.Close() 169 if err != nil { 170 return &SpaceQuota{}, errors.Wrap(err, "Error reading space quota body") 171 } 172 err = json.Unmarshal(resBody, &spaceQuotaResource) 173 if err != nil { 174 return &SpaceQuota{}, errors.Wrap(err, "Error unmarshalling space quota") 175 } 176 spaceQuota = &spaceQuotaResource.Entity 177 spaceQuota.Guid = spaceQuotaResource.Meta.Guid 178 spaceQuota.c = s.c 179 return spaceQuota, nil 180} 181 182func (s *Space) Summary() (SpaceSummary, error) { 183 var spaceSummary SpaceSummary 184 requestUrl := fmt.Sprintf("/v2/spaces/%s/summary", s.Guid) 185 r := s.c.NewRequest("GET", requestUrl) 186 resp, err := s.c.DoRequest(r) 187 if err != nil { 188 return SpaceSummary{}, errors.Wrap(err, "Error requesting space summary") 189 } 190 resBody, err := ioutil.ReadAll(resp.Body) 191 defer resp.Body.Close() 192 if err != nil { 193 return SpaceSummary{}, errors.Wrap(err, "Error reading space summary body") 194 } 195 err = json.Unmarshal(resBody, &spaceSummary) 196 if err != nil { 197 return SpaceSummary{}, errors.Wrap(err, "Error unmarshalling space summary") 198 } 199 return spaceSummary, nil 200} 201 202func (s *Space) Roles() ([]SpaceRole, error) { 203 var roles []SpaceRole 204 requestUrl := fmt.Sprintf("/v2/spaces/%s/user_roles", s.Guid) 205 for { 206 rolesResp, err := s.c.getSpaceRolesResponse(requestUrl) 207 if err != nil { 208 return roles, err 209 } 210 for _, role := range rolesResp.Resources { 211 role.Entity.Guid = role.Meta.Guid 212 role.Entity.c = s.c 213 roles = append(roles, role.Entity) 214 } 215 requestUrl = rolesResp.NextUrl 216 if requestUrl == "" { 217 break 218 } 219 } 220 return roles, nil 221} 222 223func (c *Client) CreateSpace(req SpaceRequest) (Space, error) { 224 buf := bytes.NewBuffer(nil) 225 err := json.NewEncoder(buf).Encode(req) 226 if err != nil { 227 return Space{}, err 228 } 229 r := c.NewRequestWithBody("POST", "/v2/spaces", buf) 230 resp, err := c.DoRequest(r) 231 if err != nil { 232 return Space{}, err 233 } 234 if resp.StatusCode != http.StatusCreated { 235 return Space{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode) 236 } 237 return c.handleSpaceResp(resp) 238} 239 240func (c *Client) UpdateSpace(spaceGUID string, req SpaceRequest) (Space, error) { 241 space := Space{Guid: spaceGUID, c: c} 242 return space.Update(req) 243} 244 245func (c *Client) DeleteSpace(guid string, recursive, async bool) error { 246 resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/spaces/%s?recursive=%t&async=%t", guid, recursive, async))) 247 if err != nil { 248 return err 249 } 250 if resp.StatusCode != http.StatusNoContent { 251 return errors.Wrapf(err, "Error deleting space %s, response code: %d", guid, resp.StatusCode) 252 } 253 return nil 254} 255 256func (c *Client) ListSpaceManagersByQuery(spaceGUID string, query url.Values) ([]User, error) { 257 return c.listSpaceUsersByRoleAndQuery(spaceGUID, "managers", query) 258} 259 260func (c *Client) ListSpaceManagers(spaceGUID string) ([]User, error) { 261 return c.ListSpaceManagersByQuery(spaceGUID, nil) 262} 263 264func (c *Client) ListSpaceAuditorsByQuery(spaceGUID string, query url.Values) ([]User, error) { 265 return c.listSpaceUsersByRoleAndQuery(spaceGUID, "auditors", query) 266} 267 268func (c *Client) ListSpaceAuditors(spaceGUID string) ([]User, error) { 269 return c.ListSpaceAuditorsByQuery(spaceGUID, nil) 270} 271 272func (c *Client) ListSpaceDevelopersByQuery(spaceGUID string, query url.Values) ([]User, error) { 273 return c.listSpaceUsersByRoleAndQuery(spaceGUID, "developers", query) 274} 275 276func (c *Client) listSpaceUsersByRoleAndQuery(spaceGUID, role string, query url.Values) ([]User, error) { 277 var users []User 278 requestURL := fmt.Sprintf("/v2/spaces/%s/%s?%s", spaceGUID, role, query.Encode()) 279 for { 280 userResp, err := c.getUserResponse(requestURL) 281 if err != nil { 282 return []User{}, err 283 } 284 for _, u := range userResp.Resources { 285 users = append(users, c.mergeUserResource(u)) 286 } 287 requestURL = userResp.NextUrl 288 if requestURL == "" { 289 break 290 } 291 } 292 return users, nil 293} 294 295func (c *Client) ListSpaceDevelopers(spaceGUID string) ([]User, error) { 296 return c.ListSpaceDevelopersByQuery(spaceGUID, nil) 297} 298 299func (c *Client) AssociateSpaceDeveloper(spaceGUID, userGUID string) (Space, error) { 300 space := Space{Guid: spaceGUID, c: c} 301 return space.AssociateDeveloper(userGUID) 302} 303 304func (c *Client) AssociateSpaceDeveloperByUsername(spaceGUID, name string) (Space, error) { 305 space := Space{Guid: spaceGUID, c: c} 306 return space.AssociateDeveloperByUsername(name) 307} 308 309func (c *Client) AssociateSpaceDeveloperByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) { 310 space := Space{Guid: spaceGUID, c: c} 311 return space.AssociateDeveloperByUsernameAndOrigin(name, origin) 312} 313 314func (c *Client) RemoveSpaceDeveloper(spaceGUID, userGUID string) error { 315 space := Space{Guid: spaceGUID, c: c} 316 return space.RemoveDeveloper(userGUID) 317} 318 319func (c *Client) RemoveSpaceDeveloperByUsername(spaceGUID, name string) error { 320 space := Space{Guid: spaceGUID, c: c} 321 return space.RemoveDeveloperByUsername(name) 322} 323 324func (c *Client) RemoveSpaceDeveloperByUsernameAndOrigin(spaceGUID, name, origin string) error { 325 space := Space{Guid: spaceGUID, c: c} 326 return space.RemoveDeveloperByUsernameAndOrigin(name, origin) 327} 328 329func (c *Client) AssociateSpaceAuditor(spaceGUID, userGUID string) (Space, error) { 330 space := Space{Guid: spaceGUID, c: c} 331 return space.AssociateAuditor(userGUID) 332} 333 334func (c *Client) AssociateSpaceAuditorByUsername(spaceGUID, name string) (Space, error) { 335 space := Space{Guid: spaceGUID, c: c} 336 return space.AssociateAuditorByUsername(name) 337} 338 339func (c *Client) AssociateSpaceAuditorByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) { 340 space := Space{Guid: spaceGUID, c: c} 341 return space.AssociateAuditorByUsernameAndOrigin(name, origin) 342} 343 344func (c *Client) RemoveSpaceAuditor(spaceGUID, userGUID string) error { 345 space := Space{Guid: spaceGUID, c: c} 346 return space.RemoveAuditor(userGUID) 347} 348 349func (c *Client) RemoveSpaceAuditorByUsername(spaceGUID, name string) error { 350 space := Space{Guid: spaceGUID, c: c} 351 return space.RemoveAuditorByUsername(name) 352} 353 354func (c *Client) RemoveSpaceAuditorByUsernameAndOrigin(spaceGUID, name, origin string) error { 355 space := Space{Guid: spaceGUID, c: c} 356 return space.RemoveAuditorByUsernameAndOrigin(name, origin) 357} 358 359func (c *Client) AssociateSpaceManager(spaceGUID, userGUID string) (Space, error) { 360 space := Space{Guid: spaceGUID, c: c} 361 return space.AssociateManager(userGUID) 362} 363 364func (c *Client) AssociateSpaceManagerByUsername(spaceGUID, name string) (Space, error) { 365 space := Space{Guid: spaceGUID, c: c} 366 return space.AssociateManagerByUsername(name) 367} 368 369func (c *Client) AssociateSpaceManagerByUsernameAndOrigin(spaceGUID, name, origin string) (Space, error) { 370 space := Space{Guid: spaceGUID, c: c} 371 return space.AssociateManagerByUsernameAndOrigin(name, origin) 372} 373 374func (c *Client) RemoveSpaceManager(spaceGUID, userGUID string) error { 375 space := Space{Guid: spaceGUID, c: c} 376 return space.RemoveManager(userGUID) 377} 378 379func (c *Client) RemoveSpaceManagerByUsername(spaceGUID, name string) error { 380 space := Space{Guid: spaceGUID, c: c} 381 return space.RemoveManagerByUsername(name) 382} 383 384func (c *Client) RemoveSpaceManagerByUsernameAndOrigin(spaceGUID, name, origin string) error { 385 space := Space{Guid: spaceGUID, c: c} 386 return space.RemoveManagerByUsernameAndOrigin(name, origin) 387} 388 389func (s *Space) AssociateDeveloper(userGUID string) (Space, error) { 390 return s.associateRole(userGUID, "developers") 391} 392 393func (s *Space) AssociateDeveloperByUsername(name string) (Space, error) { 394 return s.associateUserByRole(name, "developers", "") 395} 396 397func (s *Space) AssociateDeveloperByUsernameAndOrigin(name, origin string) (Space, error) { 398 return s.associateUserByRole(name, "developers", origin) 399} 400 401func (s *Space) RemoveDeveloper(userGUID string) error { 402 return s.removeRole(userGUID, "developers") 403} 404 405func (s *Space) RemoveDeveloperByUsername(name string) error { 406 return s.removeUserByRole(name, "developers", "") 407} 408 409func (s *Space) RemoveDeveloperByUsernameAndOrigin(name, origin string) error { 410 return s.removeUserByRole(name, "developers", origin) 411} 412 413func (s *Space) AssociateAuditor(userGUID string) (Space, error) { 414 return s.associateRole(userGUID, "auditors") 415} 416 417func (s *Space) AssociateAuditorByUsername(name string) (Space, error) { 418 return s.associateUserByRole(name, "auditors", "") 419} 420 421func (s *Space) AssociateAuditorByUsernameAndOrigin(name, origin string) (Space, error) { 422 return s.associateUserByRole(name, "auditors", origin) 423} 424 425func (s *Space) RemoveAuditor(userGUID string) error { 426 return s.removeRole(userGUID, "auditors") 427} 428 429func (s *Space) RemoveAuditorByUsername(name string) error { 430 return s.removeUserByRole(name, "auditors", "") 431} 432 433func (s *Space) RemoveAuditorByUsernameAndOrigin(name, origin string) error { 434 return s.removeUserByRole(name, "auditors", origin) 435} 436 437func (s *Space) AssociateManager(userGUID string) (Space, error) { 438 return s.associateRole(userGUID, "managers") 439} 440 441func (s *Space) AssociateManagerByUsername(name string) (Space, error) { 442 return s.associateUserByRole(name, "managers", "") 443} 444 445func (s *Space) AssociateManagerByUsernameAndOrigin(name, origin string) (Space, error) { 446 return s.associateUserByRole(name, "managers", origin) 447} 448 449func (s *Space) RemoveManager(userGUID string) error { 450 return s.removeRole(userGUID, "managers") 451} 452 453func (s *Space) RemoveManagerByUsername(name string) error { 454 return s.removeUserByRole(name, "managers", "") 455} 456func (s *Space) RemoveManagerByUsernameAndOrigin(name, origin string) error { 457 return s.removeUserByRole(name, "managers", origin) 458} 459 460func (s *Space) associateRole(userGUID, role string) (Space, error) { 461 requestUrl := fmt.Sprintf("/v2/spaces/%s/%s/%s", s.Guid, role, userGUID) 462 r := s.c.NewRequest("PUT", requestUrl) 463 resp, err := s.c.DoRequest(r) 464 if err != nil { 465 return Space{}, err 466 } 467 if resp.StatusCode != http.StatusCreated { 468 return Space{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, userGUID, resp.StatusCode) 469 } 470 return s.c.handleSpaceResp(resp) 471} 472 473func (s *Space) associateUserByRole(name, role, origin string) (Space, error) { 474 requestUrl := fmt.Sprintf("/v2/spaces/%s/%s", s.Guid, role) 475 buf := bytes.NewBuffer(nil) 476 payload := make(map[string]string) 477 payload["username"] = name 478 if origin != "" { 479 payload["origin"] = origin 480 } 481 err := json.NewEncoder(buf).Encode(payload) 482 if err != nil { 483 return Space{}, err 484 } 485 r := s.c.NewRequestWithBody("PUT", requestUrl, buf) 486 resp, err := s.c.DoRequest(r) 487 if err != nil { 488 return Space{}, err 489 } 490 if resp.StatusCode != http.StatusCreated { 491 return Space{}, errors.Wrapf(err, "Error associating %s %s, response code: %d", role, name, resp.StatusCode) 492 } 493 return s.c.handleSpaceResp(resp) 494} 495 496func (s *Space) removeRole(userGUID, role string) error { 497 requestUrl := fmt.Sprintf("/v2/spaces/%s/%s/%s", s.Guid, role, userGUID) 498 r := s.c.NewRequest("DELETE", requestUrl) 499 resp, err := s.c.DoRequest(r) 500 if err != nil { 501 return err 502 } 503 if resp.StatusCode != http.StatusNoContent { 504 return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, userGUID, resp.StatusCode) 505 } 506 return nil 507} 508 509func (s *Space) removeUserByRole(name, role, origin string) error { 510 var requestURL string 511 var method string 512 513 buf := bytes.NewBuffer(nil) 514 payload := make(map[string]string) 515 payload["username"] = name 516 if origin != "" { 517 payload["origin"] = origin 518 requestURL = fmt.Sprintf("/v2/spaces/%s/%s/remove", s.Guid, role) 519 method = "POST" 520 } else { 521 requestURL = fmt.Sprintf("/v2/spaces/%s/%s", s.Guid, role) 522 method = "DELETE" 523 } 524 err := json.NewEncoder(buf).Encode(payload) 525 if err != nil { 526 return err 527 } 528 r := s.c.NewRequestWithBody(method, requestURL, buf) 529 resp, err := s.c.DoRequest(r) 530 if err != nil { 531 return err 532 } 533 if resp.StatusCode != http.StatusOK { 534 return errors.Wrapf(err, "Error removing %s %s, response code: %d", role, name, resp.StatusCode) 535 } 536 return nil 537} 538 539func (c *Client) ListSpaceSecGroups(spaceGUID string) (secGroups []SecGroup, err error) { 540 space := Space{Guid: spaceGUID, c: c} 541 return space.ListSecGroups() 542} 543 544func (s *Space) ListSecGroups() (secGroups []SecGroup, err error) { 545 requestURL := fmt.Sprintf("/v2/spaces/%s/security_groups?inline-relations-depth=1", s.Guid) 546 for requestURL != "" { 547 var secGroupResp SecGroupResponse 548 r := s.c.NewRequest("GET", requestURL) 549 resp, err := s.c.DoRequest(r) 550 551 if err != nil { 552 return nil, errors.Wrap(err, "Error requesting sec groups") 553 } 554 resBody, err := ioutil.ReadAll(resp.Body) 555 if err != nil { 556 return nil, errors.Wrap(err, "Error reading sec group response body") 557 } 558 559 err = json.Unmarshal(resBody, &secGroupResp) 560 if err != nil { 561 return nil, errors.Wrap(err, "Error unmarshaling sec group") 562 } 563 564 for _, secGroup := range secGroupResp.Resources { 565 secGroup.Entity.Guid = secGroup.Meta.Guid 566 secGroup.Entity.c = s.c 567 for i, space := range secGroup.Entity.SpacesData { 568 space.Entity.Guid = space.Meta.Guid 569 secGroup.Entity.SpacesData[i] = space 570 } 571 if len(secGroup.Entity.SpacesData) == 0 { 572 spaces, err := secGroup.Entity.ListSpaceResources() 573 if err != nil { 574 return nil, err 575 } 576 for _, space := range spaces { 577 secGroup.Entity.SpacesData = append(secGroup.Entity.SpacesData, space) 578 } 579 } 580 secGroups = append(secGroups, secGroup.Entity) 581 } 582 583 requestURL = secGroupResp.NextUrl 584 resp.Body.Close() 585 } 586 return secGroups, nil 587} 588 589func (s *Space) GetServiceOfferings() (ServiceOfferingResponse, error) { 590 var response ServiceOfferingResponse 591 requestURL := fmt.Sprintf("/v2/spaces/%s/services", s.Guid) 592 req := s.c.NewRequest("GET", requestURL) 593 594 resp, err := s.c.DoRequest(req) 595 if err != nil { 596 return ServiceOfferingResponse{}, errors.Wrap(err, "Error requesting service offerings") 597 } 598 599 body, err := ioutil.ReadAll(resp.Body) 600 if err != nil { 601 return ServiceOfferingResponse{}, errors.Wrap(err, "Error reading service offering response") 602 } 603 604 err = json.Unmarshal(body, &response) 605 if err != nil { 606 return ServiceOfferingResponse{}, errors.Wrap(err, "Error unmarshalling service offering response") 607 } 608 609 return response, nil 610} 611 612func (s *Space) Update(req SpaceRequest) (Space, error) { 613 buf := bytes.NewBuffer(nil) 614 err := json.NewEncoder(buf).Encode(req) 615 if err != nil { 616 return Space{}, err 617 } 618 r := s.c.NewRequestWithBody("PUT", fmt.Sprintf("/v2/spaces/%s", s.Guid), buf) 619 resp, err := s.c.DoRequest(r) 620 if err != nil { 621 return Space{}, err 622 } 623 if resp.StatusCode != http.StatusCreated { 624 return Space{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode) 625 } 626 return s.c.handleSpaceResp(resp) 627} 628 629func (c *Client) ListSpacesByQuery(query url.Values) ([]Space, error) { 630 return c.fetchSpaces("/v2/spaces?" + query.Encode()) 631} 632 633func (c *Client) ListSpaces() ([]Space, error) { 634 return c.ListSpacesByQuery(nil) 635} 636 637func (c *Client) fetchSpaces(requestUrl string) ([]Space, error) { 638 var spaces []Space 639 for { 640 spaceResp, err := c.getSpaceResponse(requestUrl) 641 if err != nil { 642 return []Space{}, err 643 } 644 for _, space := range spaceResp.Resources { 645 spaces = append(spaces, c.mergeSpaceResource(space)) 646 } 647 requestUrl = spaceResp.NextUrl 648 if requestUrl == "" { 649 break 650 } 651 } 652 return spaces, nil 653} 654 655func (c *Client) GetSpaceByName(spaceName string, orgGuid string) (space Space, err error) { 656 query := url.Values{} 657 query.Add("q", fmt.Sprintf("organization_guid:%s", orgGuid)) 658 query.Add("q", fmt.Sprintf("name:%s", spaceName)) 659 spaces, err := c.ListSpacesByQuery(query) 660 if err != nil { 661 return 662 } 663 664 if len(spaces) == 0 { 665 return space, fmt.Errorf("No space found with name: `%s` in org with GUID: `%s`", spaceName, orgGuid) 666 } 667 668 return spaces[0], nil 669 670} 671 672func (c *Client) GetSpaceByGuid(spaceGUID string) (Space, error) { 673 requestUrl := fmt.Sprintf("/v2/spaces/%s", spaceGUID) 674 r := c.NewRequest("GET", requestUrl) 675 resp, err := c.DoRequest(r) 676 if err != nil { 677 return Space{}, errors.Wrap(err, "Error requesting space info") 678 } 679 return c.handleSpaceResp(resp) 680} 681 682func (c *Client) getSpaceResponse(requestUrl string) (SpaceResponse, error) { 683 var spaceResp SpaceResponse 684 r := c.NewRequest("GET", requestUrl) 685 resp, err := c.DoRequest(r) 686 if err != nil { 687 return SpaceResponse{}, errors.Wrap(err, "Error requesting spaces") 688 } 689 resBody, err := ioutil.ReadAll(resp.Body) 690 defer resp.Body.Close() 691 if err != nil { 692 return SpaceResponse{}, errors.Wrap(err, "Error reading space request") 693 } 694 err = json.Unmarshal(resBody, &spaceResp) 695 if err != nil { 696 return SpaceResponse{}, errors.Wrap(err, "Error unmarshalling space") 697 } 698 return spaceResp, nil 699} 700 701func (c *Client) getSpaceRolesResponse(requestUrl string) (SpaceRoleResponse, error) { 702 var roleResp SpaceRoleResponse 703 r := c.NewRequest("GET", requestUrl) 704 resp, err := c.DoRequest(r) 705 if err != nil { 706 return roleResp, errors.Wrap(err, "Error requesting space roles") 707 } 708 resBody, err := ioutil.ReadAll(resp.Body) 709 defer resp.Body.Close() 710 if err != nil { 711 return roleResp, errors.Wrap(err, "Error reading space roles request") 712 } 713 err = json.Unmarshal(resBody, &roleResp) 714 if err != nil { 715 return roleResp, errors.Wrap(err, "Error unmarshalling space roles") 716 } 717 return roleResp, nil 718} 719 720func (c *Client) handleSpaceResp(resp *http.Response) (Space, error) { 721 body, err := ioutil.ReadAll(resp.Body) 722 defer resp.Body.Close() 723 if err != nil { 724 return Space{}, err 725 } 726 var spaceResource SpaceResource 727 err = json.Unmarshal(body, &spaceResource) 728 if err != nil { 729 return Space{}, err 730 } 731 return c.mergeSpaceResource(spaceResource), nil 732} 733 734func (c *Client) mergeSpaceResource(space SpaceResource) Space { 735 space.Entity.Guid = space.Meta.Guid 736 space.Entity.CreatedAt = space.Meta.CreatedAt 737 space.Entity.UpdatedAt = space.Meta.UpdatedAt 738 space.Entity.c = c 739 return space.Entity 740} 741 742type serviceOfferingExtra ServiceOfferingExtra 743 744func (resource *ServiceOfferingExtra) UnmarshalJSON(rawData []byte) error { 745 if string(rawData) == "null" { 746 return nil 747 } 748 749 extra := serviceOfferingExtra{} 750 751 unquoted, err := strconv.Unquote(string(rawData)) 752 if err != nil { 753 return err 754 } 755 756 err = json.Unmarshal([]byte(unquoted), &extra) 757 if err != nil { 758 return err 759 } 760 761 *resource = ServiceOfferingExtra(extra) 762 763 return nil 764} 765 766func (c *Client) IsolationSegmentForSpace(spaceGUID, isolationSegmentGUID string) error { 767 return c.updateSpaceIsolationSegment(spaceGUID, map[string]interface{}{"guid": isolationSegmentGUID}) 768} 769 770func (c *Client) ResetIsolationSegmentForSpace(spaceGUID string) error { 771 return c.updateSpaceIsolationSegment(spaceGUID, nil) 772} 773 774func (c *Client) updateSpaceIsolationSegment(spaceGUID string, data interface{}) error { 775 requestURL := fmt.Sprintf("/v3/spaces/%s/relationships/isolation_segment", spaceGUID) 776 buf := bytes.NewBuffer(nil) 777 err := json.NewEncoder(buf).Encode(map[string]interface{}{"data": data}) 778 if err != nil { 779 return err 780 } 781 r := c.NewRequestWithBody("PATCH", requestURL, buf) 782 resp, err := c.DoRequest(r) 783 if err != nil { 784 return err 785 } 786 if resp.StatusCode != http.StatusOK { 787 return errors.Wrapf(err, "Error setting isolation segment for space %s, response code: %d", spaceGUID, resp.StatusCode) 788 } 789 return nil 790} 791