185 lines
6.2 KiB
JavaScript
185 lines
6.2 KiB
JavaScript
import AbstractService from './util/abstractService';
|
|
|
|
/**
|
|
* A list of all supported versions. Please keep this array sorted by most recent.
|
|
*
|
|
* @type {Array}
|
|
* @ignore
|
|
*/
|
|
const supportedKeystoneVersions = [
|
|
'v3.7'
|
|
];
|
|
|
|
export default class Keystone extends AbstractService {
|
|
|
|
/**
|
|
* This class provides direct, idempotent, low-level access to the Keystone API of a specific
|
|
* cloud. The constructor requires that you provide a configuration object for a specific
|
|
* cloud, formatted as per the os-client-config specification of clouds.yaml. An important
|
|
* difference is that it does not accept the entire clouds.yaml structure, only the subsection
|
|
* that refers to a specific cloud.
|
|
*
|
|
* @param {{}} cloudConfig The configuration object for a specific cloud.
|
|
* @see http://docs.openstack.org/developer/os-client-config/#site-specific-file-locations
|
|
*/
|
|
constructor(cloudConfig) {
|
|
// Sanity checks.
|
|
if (!cloudConfig) {
|
|
throw new Error('A configuration is required.');
|
|
}
|
|
// Clone the config, so that this instance is immutable
|
|
// at runtime (no modifying the config after the fact).
|
|
cloudConfig = Object.assign({}, cloudConfig);
|
|
|
|
super(cloudConfig.auth.auth_url, supportedKeystoneVersions);
|
|
this.cloudConfig = cloudConfig;
|
|
}
|
|
|
|
/**
|
|
* This method provides a safe method for reading values deep inside of an object structure,
|
|
* without encountering TypeErrors.
|
|
*
|
|
* @param {string} path A string representing the dot notation of a config path to read.
|
|
* @private
|
|
* @returns {String} The value found in the config, or null.
|
|
* @ignore
|
|
*/
|
|
_safeConfigGet(path) {
|
|
let segments = path.split('.');
|
|
let pointer = this.cloudConfig;
|
|
while (segments.length > 0) {
|
|
let prop = segments.shift();
|
|
if (pointer.hasOwnProperty(prop)) {
|
|
pointer = pointer[prop];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
return pointer;
|
|
}
|
|
|
|
/**
|
|
* Retrieve all the API versions available.
|
|
*
|
|
* @returns {Promise.<T>} A promise that will resolve with the list of API versions.
|
|
*/
|
|
versions() {
|
|
return super.versions()
|
|
.then((versions) => versions.values);
|
|
}
|
|
|
|
/**
|
|
* Issue a token from the provided credentials. Credentials will be read from the
|
|
* configuration, unless they have been explicitly provided.
|
|
*
|
|
* NOTE: This method is only applicable if the password auth plugin on keystone is enabled.
|
|
* Other auth methods will have to be provided by third-party developers.
|
|
*
|
|
* @param {Object} credentials Optional credentials.
|
|
* @param {String} credentials.user_id An optional user ID.
|
|
* @param {String} credentials.username An optional user name.
|
|
* @param {String} credentials.password An optional password.
|
|
* @param {String} credentials.user_domain_id An optional user domain ID.
|
|
* Not required if a user ID is given.
|
|
* @param {String} credentials.user_domain_name An optional user domain name.
|
|
* Not required if a user ID is given.
|
|
* @param {String} credentials.project_id An optional project ID.
|
|
* @param {String} credentials.project_name An optional project name.
|
|
* @param {String} credentials.project_domain_id An optional project domain ID.
|
|
* Not required if a project ID is given.
|
|
* @param {String} credentials.project_domain_name An optional project domain name.
|
|
* Not required if a project ID is given.
|
|
* @returns {Promise.<T>} A promise which will resolve with a valid token.
|
|
*/
|
|
tokenIssue({
|
|
user_id: userId = this._safeConfigGet('auth.user_id'),
|
|
username = this._safeConfigGet('auth.username'),
|
|
password = this._safeConfigGet('auth.password'),
|
|
user_domain_id: userDomainId = this._safeConfigGet('auth.user_domain_id'),
|
|
user_domain_name: userDomainName = this._safeConfigGet('auth.user_domain_name'),
|
|
project_id: projectId = this._safeConfigGet('auth.project_id'),
|
|
project_name: projectName = this._safeConfigGet('auth.project_name'),
|
|
project_domain_id: projectDomainId = this._safeConfigGet('auth.project_domain_id'),
|
|
project_domain_name: projectDomainName = this._safeConfigGet('auth.project_domain_name')
|
|
} = {}) {
|
|
let project;
|
|
let user = {password};
|
|
|
|
if (userId) {
|
|
user.id = userId;
|
|
} else if (username) {
|
|
user.name = username;
|
|
if (userDomainId) {
|
|
user.domain = {id: userDomainId};
|
|
} else if (userDomainName) {
|
|
user.domain = {name: userDomainName};
|
|
} else {
|
|
user.domain = {id: 'default'};
|
|
}
|
|
}
|
|
|
|
if (projectId) {
|
|
project = {id: projectId};
|
|
} else if (projectName) {
|
|
project = {name: projectName};
|
|
if (projectDomainId) {
|
|
project.domain = {id: projectDomainId};
|
|
} else if (projectDomainName) {
|
|
project.domain = {name: projectDomainName};
|
|
} else {
|
|
project.domain = {id: 'default'};
|
|
}
|
|
}
|
|
|
|
const body = {
|
|
auth: {
|
|
identity: {
|
|
methods: ['password'],
|
|
password: {user}
|
|
},
|
|
scope: project ? {project} : 'unscoped'
|
|
}
|
|
};
|
|
|
|
return this
|
|
.serviceEndpoint()
|
|
.then((url) => this.http.httpPost(`${url}auth/tokens`, body))
|
|
.then((response) => {
|
|
return response.headers.get('X-Subject-Token');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Revoke an authorization token.
|
|
*
|
|
* @param {String} token The token to revoke.
|
|
* @param {String} adminToken An optional admin token.
|
|
* @returns {Promise.<T>} A promise which will resolve if the token has been successfully revoked.
|
|
*/
|
|
tokenRevoke(token, adminToken = null) {
|
|
return Promise
|
|
.all([this.serviceEndpoint(), token, adminToken])
|
|
.then(([url, token, adminToken]) => {
|
|
return [url, {
|
|
'X-Subject-Token': token,
|
|
'X-Auth-Token': adminToken || token
|
|
}];
|
|
})
|
|
.then(([url, headers]) => this.http.httpRequest('DELETE', `${url}auth/tokens`, headers));
|
|
}
|
|
|
|
/**
|
|
* List the service catalog for the configured cloud.
|
|
*
|
|
* @param {String} token The authorization token.
|
|
* @returns {Promise.<T>} A promise which will resolve with the service catalog.
|
|
*/
|
|
catalogList(token = null) {
|
|
return this
|
|
._requestComponents(token)
|
|
.then(([url, headers]) => this.http.httpRequest('GET', `${url}auth/catalog`, headers))
|
|
.then((response) => response.json())
|
|
.then((body) => body.catalog);
|
|
}
|
|
}
|