"use strict";
const CloudControllerBase = require("./CloudControllerBase");
/**
* Manage Spaces on Cloud Foundry
* Supports both Cloud Foundry API v2 and v3
*/
class Spaces extends CloudControllerBase {
/**
* @param {String} endPoint [CC endpoint]
* @param {Object} options [Configuration options]
* @constructor
* @returns {void}
*/
constructor(endPoint, options) {
super(endPoint, options);
}
/**
* Get Spaces (supports both v2 and v3)
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_spaces.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-spaces}
*
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to spaces list]
*/
getSpaces(filter) {
if (this.isUsingV3()) {
return this._getSpacesV3(filter);
} else {
return this._getSpacesV2(filter);
}
}
_getSpacesV2(filter) {
const url = `${this.API_URL}/v2/spaces`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: this.getAuthorizationHeader()
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getSpacesV3(filter) {
const url = `${this.API_URL}/v3/spaces`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: this.getAuthorizationHeader(),
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get a specific Space by GUID
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/retrieve_a_particular_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#get-a-space}
*
* @param {String} guid [Space GUID]
* @return {Promise} [Promise resolving to space]
*/
getSpace(guid) {
if (this.isUsingV3()) {
return this._getSpaceV3(guid);
} else {
return this._getSpaceV2(guid);
}
}
/**
* Find a Space by name using server-side filtering.
* Returns the first matching resource or null if not found.
* Optionally filter by organization GUID to disambiguate.
*
* v2: Uses q=name:{name} filter (and q=organization_guid:{orgGuid} if provided)
* v3: Uses names={name} filter (and organization_guids={orgGuid} if provided)
*
* @param {String} name [Space name]
* @param {String} [orgGuid] [Optional organization GUID to narrow search]
* @return {Promise} [Promise resolving to space resource or null]
*/
getSpaceByName(name, orgGuid) {
if (!name || typeof name !== "string") {
return Promise.reject(new Error("Space name must be a non-empty string."));
}
let filter;
if (this.isUsingV3()) {
filter = { names: name };
if (orgGuid) { filter.organization_guids = orgGuid; }
} else {
filter = { q: [`name:${name}`] };
if (orgGuid) { filter.q.push(`organization_guid:${orgGuid}`); }
}
return this.getSpaces(filter).then(result => {
const resources = result.resources || [];
return resources.length > 0 ? resources[0] : null;
});
}
_getSpaceV2(guid) {
const url = `${this.API_URL}/v2/spaces/${guid}`;
const options = {
method: "GET",
url: url,
headers: {
Authorization: this.getAuthorizationHeader()
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getSpaceV3(guid) {
const url = `${this.API_URL}/v3/spaces/${guid}`;
const options = {
method: "GET",
url: url,
headers: {
Authorization: this.getAuthorizationHeader(),
"Content-Type": "application/json"
},
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get summary of a Space (v2 only)
* {@link http://apidocs.cloudfoundry.org/214/spaces/get_space_summary.html}
*
* @param {String} guid [Space GUID]
* @return {Promise} [Promise resolving to space summary]
*/
getSummary(guid) {
if (this.isUsingV3()) {
// In v3, use getSpace instead
return this._getSpaceV3(guid);
}
return this._getSummaryV2(guid);
}
_getSummaryV2(guid) {
const url = `${this.API_URL}/v2/spaces/${guid}/summary`;
const options = {
method: "GET",
url: url,
headers: {
Authorization: this.getAuthorizationHeader()
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Add a new Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/creating_a_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#create-a-space}
*
* @param {Object} spaceOptions [Space options]
* @return {Promise} [Promise resolving to created space]
*/
add(spaceOptions) {
if (this.isUsingV3()) {
return this._addV3(spaceOptions);
} else {
return this._addV2(spaceOptions);
}
}
_addV2(spaceOptions) {
const url = `${this.API_URL}/v2/spaces`;
const options = {
method: "POST",
url: url,
headers: {
Authorization: this.getAuthorizationHeader()
},
form: spaceOptions
};
return this.REST.request(options, this.HttpStatus.CREATED, true);
}
_addV3(spaceOptions) {
const url = `${this.API_URL}/v3/spaces`;
const options = {
method: "POST",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
json: spaceOptions
};
return this.REST.request(options, this.HttpStatus.CREATED, true);
}
/**
* Update a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/updating_a_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#update-a-space}
*
* @param {String} guid [Space GUID]
* @param {Object} spaceOptions [Space options]
* @return {Promise} [Promise resolving to updated space]
*/
update(guid, spaceOptions) {
if (this.isUsingV3()) {
return this._updateV3(guid, spaceOptions);
} else {
return this._updateV2(guid, spaceOptions);
}
}
_updateV2(guid, spaceOptions) {
const url = `${this.API_URL}/v2/spaces/${guid}`;
const options = {
method: "PUT",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
form: JSON.stringify(spaceOptions)
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_updateV3(guid, spaceOptions) {
const url = `${this.API_URL}/v3/spaces/${guid}`;
const options = {
method: "PATCH",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
json: spaceOptions
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Delete a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/delete_a_particular_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#delete-a-space}
*
* @param {String} guid [Space GUID]
* @param {Object} deleteOptions [Delete options]
* @return {Promise} [Promise resolving to delete result]
*/
remove(guid, deleteOptions) {
if (this.isUsingV3()) {
return this._removeV3(guid, deleteOptions);
} else {
return this._removeV2(guid, deleteOptions);
}
}
_removeV2(guid, deleteOptions) {
const url = `${this.API_URL}/v2/spaces/${guid}`;
let qs = deleteOptions || {};
const options = {
method: "DELETE",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.NO_CONTENT, false);
}
_removeV3(guid, deleteOptions) {
const url = `${this.API_URL}/v3/spaces/${guid}`;
let qs = deleteOptions || {};
const options = {
method: "DELETE",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.ACCEPTED, true);
}
/**
* Get apps in a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_apps_for_the_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-apps}
*
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to apps list]
*/
getApps(guid, filter) {
if (this.isUsingV3()) {
return this._getAppsV3(guid, filter);
} else {
return this._getAppsV2(guid, filter);
}
}
_getAppsV2(guid, filter) {
const url = `${this.API_URL}/v2/spaces/${guid}/apps`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getAppsV3(guid, filter) {
const qs = Object.assign({}, filter || {});
qs["space_guids"] = guid;
const url = `${this.API_URL}/v3/apps`;
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get users in a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_users_for_the_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-space-members}
*
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to users list]
*/
getUsers(guid, filter) {
if (this.isUsingV3()) {
return this._getUsersV3(guid, filter);
} else {
return this._getUsersV2(guid, filter);
}
}
_getUsersV2(guid, filter) {
const url = `${this.API_URL}/v2/spaces/${guid}/users`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getUsersV3(guid, filter) {
// v3: user roles are at /v3/roles with space_guids filter
const qs = Object.assign({}, filter || {});
qs.space_guids = guid;
const options = {
method: "GET",
url: `${this.API_URL}/v3/roles`,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get managers in a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_managers_for_the_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-space-managers}
*
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to managers list]
*/
getManagers(guid, filter) {
if (this.isUsingV3()) {
return this._getManagersV3(guid, filter);
} else {
return this._getManagersV2(guid, filter);
}
}
_getManagersV2(guid, filter) {
const url = `${this.API_URL}/v2/spaces/${guid}/managers`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getManagersV3(guid, filter) {
// v3: manager roles are at /v3/roles with space_guids filter
const qs = Object.assign({}, filter || {});
qs.space_guids = guid;
qs.types = "space_manager";
const options = {
method: "GET",
url: `${this.API_URL}/v3/roles`,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get developers in a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_developers_for_the_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-space-developers}
*
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to developers list]
*/
getDevelopers(guid, filter) {
if (this.isUsingV3()) {
return this._getDevelopersV3(guid, filter);
} else {
return this._getDevelopersV2(guid, filter);
}
}
_getDevelopersV2(guid, filter) {
const url = `${this.API_URL}/v2/spaces/${guid}/developers`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getDevelopersV3(guid, filter) {
// v3: developer roles are at /v3/roles with space_guids filter
const qs = Object.assign({}, filter || {});
qs.space_guids = guid;
qs.types = "space_developer";
const options = {
method: "GET",
url: `${this.API_URL}/v3/roles`,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get auditors in a Space
* v2: {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_auditors_for_the_space.html}
* v3: {@link https://v3-apidocs.cloudfoundry.org/#list-space-auditors}
*
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to auditors list]
*/
getAuditors(guid, filter) {
if (this.isUsingV3()) {
return this._getAuditorsV3(guid, filter);
} else {
return this._getAuditorsV2(guid, filter);
}
}
_getAuditorsV2(guid, filter) {
const url = `${this.API_URL}/v2/spaces/${guid}/auditors`;
let qs = filter || {};
const options = {
method: "GET",
url: url,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
},
qs: qs
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
_getAuditorsV3(guid, filter) {
// v3: auditor roles are at /v3/roles with space_guids filter
const qs = Object.assign({}, filter || {});
qs.space_guids = guid;
qs.types = "space_auditor";
const options = {
method: "GET",
url: `${this.API_URL}/v3/roles`,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`,
"Content-Type": "application/json"
},
qs: qs,
json: true
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
/**
* Get apps in a Space (alias for getApps — backward compatibility)
* @param {String} guid [Space GUID]
* @param {Object} filter [Filter options]
* @return {Promise} [Promise resolving to apps list]
*/
getSpaceApps(guid, filter) {
return this.getApps(guid, filter);
}
/**
* Get ALL spaces across all pages (auto-pagination).
* Returns a flat array of every space resource.
*
* Results are cached when caching is enabled.
*
* @param {Object} [filter] Base filter (merged with pagination params)
* @return {Promise<Array>} Flat array of all space resources
*/
getAllSpaces(filter) {
const self = this;
return this.getAllResources(function (f) { return self.getSpaces(f); }, filter);
}
}
module.exports = Spaces;