ilorest
Version:
iLO REST JavaScript Library
583 lines (490 loc) • 22.8 kB
JavaScript
'use strict';
/*
* (c) Copyright 2018 Hewlett Packard Enterprise Development LP
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*/
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _requestPromise = require('request-promise');
var _requestPromise2 = _interopRequireDefault(_requestPromise);
var _bluebird = require('bluebird');
var _bluebird2 = _interopRequireDefault(_bluebird);
var _throttleThrottle = require('../throttle/throttle');
var _cacheCacheFactory = require('../cache/cacheFactory');
var _jsSha256 = require('js-sha256');
var _jsSha2562 = _interopRequireDefault(_jsSha256);
// import gzip from 'gzip-js';
var _zlib = require('zlib');
var _zlib2 = _interopRequireDefault(_zlib);
// if (typeof(WeakMap) === 'undefined') {
// var WeakMap = require('weakmap');
// }
var _p = new WeakMap();
exports._p = _p;
function isPromiseLike(obj) {
return obj && typeof obj.then === 'function';
}
var authMethod = function authMethod() {
_classCallCheck(this, authMethod);
};
exports.authMethod = authMethod;
authMethod.BASIC = 'basic';
authMethod.SESSION = 'session';
/** Base RESTful/Redfish class */
var baseClient = (function () {
/**
* This class is initiated by other helper function. User won't need to initiate it directly.
*/
function baseClient(baseUrl) {
var userName = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var password = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
var biosPassword = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
var sessionKey = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
var defaultPrefix = arguments.length <= 5 || arguments[5] === undefined ? '/rest/v1' : arguments[5];
var timeout = arguments.length <= 6 || arguments[6] === undefined ? 60 : arguments[6];
var concurrent = arguments.length <= 7 || arguments[7] === undefined ? 5 : arguments[7];
var cacheOptions = arguments.length <= 8 || arguments[8] === undefined ? null : arguments[8];
var proxy = arguments.length <= 9 || arguments[9] === undefined ? null : arguments[9];
_classCallCheck(this, baseClient);
var whiteList = _requestPromise2['default'].Request ? _requestPromise2['default'].Request.defaultProxyHeaderWhiteList : [];
if (whiteList.indexOf('content-length') >= 0) {
whiteList.splice(whiteList.indexOf('content-length'), 1);
}
if (whiteList.indexOf('transfer-encoding') >= 0) {
whiteList.splice(whiteList.indexOf('transfer-encoding'), 1);
}
_p.set(this, {
baseUrl: baseUrl,
userName: userName,
password: password,
biosPassword: biosPassword,
proxyHeaderWhiteList: whiteList,
sessionKey: sessionKey,
authorizationKey: null,
sessionLocation: null,
throttle: new _throttleThrottle.throttle(concurrent),
cache: _cacheCacheFactory.cacheFactory.create((+new Date()).toString(), cacheOptions),
rootPromise: null
});
this.loginUrl = null;
this.defaultPrefix = defaultPrefix;
this.timeout = timeout * 1000;
this.proxy = proxy;
this.concurrent = concurrent;
this.connCount = 0;
this.strictSSL = false;
this.root = null;
}
_createClass(baseClient, [{
key: 'getBaseUrl',
value: function getBaseUrl() {
return _p.get(this).baseUrl;
}
}, {
key: 'getUserName',
value: function getUserName() {
return _p.get(this).userName;
}
}, {
key: 'getPassword',
value: function getPassword() {
return _p.get(this).password;
}
}, {
key: 'getBiosPassword',
value: function getBiosPassword() {
return _p.get(this).biosPassword;
}
}, {
key: 'setBiosPassword',
value: function setBiosPassword(password) {
return _p.set(this, { biosPassword: password });
}
}, {
key: 'getSessionKey',
value: function getSessionKey() {
return _p.get(this).sessionKey;
}
}, {
key: 'getAuthorizationKey',
value: function getAuthorizationKey() {
return _p.get(this).authorizationKey;
}
}, {
key: 'getSessionLocation',
value: function getSessionLocation() {
return _p.get(this).sessionLocation;
}
/**
* Retrieve the root object
* @param {object} headers - Additional headers can be passed-in
* @return {promise} A Promise object which returns the HTTP response after login
*/
}, {
key: 'getRootObject',
value: function getRootObject(headers) {
try {
return this.get(this.defaultPrefix, null, null, headers).then(function (res) {
var statusCode = res.statusCode;
if (statusCode >= 400) {
throw Error('Server not reachable, iLO return code: ' + statusCode);
}
return res;
});
} catch (e) {
throw e;
}
}
}, {
key: 'getCache',
value: function getCache() {
return _p.get(this).cache;
}
/**
* Send GET request
* @param {string} path - relative URI of RESTful/Redfish
* @param {bool} useCache - Use data from local cache or not
* @param {object} headers - Additional headers can be passed-in, default to null
* @return {promise} Promise object of this GET request
*/
}, {
key: 'get',
value: function get(path, args, useCache) {
var _this = this;
var headers = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
var timeout = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
return _p.get(this).throttle.run(function () {
var options = _this.__formOptions(path, 'GET', args, null, headers, timeout, null, null);
return _this.__doRequest(options, useCache);
});
}
/**
* Send POST request
* @param {string} path - relative URI of RESTful/Redfish
* @param {object} body - body
* @param {string} providerHeader - Perhaps we should hide this one?
* @param {object} headers - Additional headers can be passed-in, default to null
* @return {promise} Promise object of this POST request
*/
}, {
key: 'post',
value: function post(path, body, providerHeader) {
var _this2 = this;
var headers = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
var timeout = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
return _p.get(this).throttle.run(function () {
var options;
options = _this2.__formOptions(path, 'POST', null, body, headers, timeout, null, providerHeader);
return _this2.__doRequest(options);
});
}
/**
* Send PUT request
* @param {string} path - relative URI of RESTful/Redfish
* @param {object} body - body
* @param {string} optionalPassword - Optional password
* @param {string} providerHeader - Perhaps we should hide this one?
* @param {object} headers - Additional headers can be passed-in, default to null
* @return {promise} Promise object of this PUT request
*/
}, {
key: 'put',
value: function put(path, body, optionalPassword, providerHeader) {
var _this3 = this;
var headers = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
var timeout = arguments.length <= 5 || arguments[5] === undefined ? null : arguments[5];
return _p.get(this).throttle.run(function () {
var options;
options = _this3.__formOptions(path, 'PUT', null, body, headers, timeout, optionalPassword, providerHeader);
return _this3.get(path).then(function (res) {
if (res.statusCode >= 200 && res.statusCode <= 299 && res.headers['content-encoding'] === 'gzip') {
// Going to gzip the body
// Set type to json, but it's gzip format
// Let json to false, avoid requests to be confused
options.headers['Content-Type'] = 'application/json';
options.json = false;
options.body = _zlib2['default'].gzipSync(JSON.stringify(options.body));
// options.body = Buffer.from(gzip.zip(JSON.stringify(options.body)));
}
return _this3.__doRequest(options);
});
});
}
/**
* Send PATCH request
* @param {string} path - relative URI of RESTful/Redfish
* @param {object} body - body
* @param {string} optionalPassword - Optional password
* @param {string} providerHeader - Perhaps we should hide this one?
* @param {object} headers - Additional headers can be passed-in, default to null
* @return {promise} Promise object of this PATCH request
*/
}, {
key: 'patch',
value: function patch(path, body, optionalPassword, providerHeader) {
var _this4 = this;
var headers = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
var timeout = arguments.length <= 5 || arguments[5] === undefined ? null : arguments[5];
return _p.get(this).throttle.run(function () {
var options;
options = _this4.__formOptions(path, 'PATCH', null, body, headers, timeout, optionalPassword, providerHeader);
return _this4.__doRequest(options);
});
}
}, {
key: 'delete',
value: function _delete(path, optionalPassword, providerHeader) {
var _this5 = this;
var headers = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
var timeout = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
return _p.get(this).throttle.run(function () {
var options = _this5.__formOptions(path, 'DELETE', null, null, headers, timeout, optionalPassword, providerHeader);
return _this5.__doRequest(options);
});
}
}, {
key: '__getReqHeaders',
value: function __getReqHeaders() {
var headers = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var providerHeader = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
var optionalPassword = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
headers = headers && typeof headers === 'object' ? headers : {};
if (providerHeader) {
headers['X-CHRP-RIS-Provider-ID'] = providerHeader;
}
if (this.getBiosPassword()) {
headers['X-HPRESTFULAPI-AuthToken'] = (0, _jsSha2562['default'])(this.getBiosPassword()).toUpperCase();
} else if (optionalPassword) {
headers['X-HPRESTFULAPI-AuthToken'] = (0, _jsSha2562['default'])(optionalPassword).toUpperCase();
}
if (this.getSessionKey()) {
headers['X-Auth-Token'] = this.getSessionKey();
} else if (this.getAuthorizationKey()) {
headers['Authorization'] = this.getAuthorizationKey();
}
headers['Accept'] = '*/*';
headers['Connection'] = 'Keep-Alive';
return headers;
}
}, {
key: '__formOptions',
value: function __formOptions(path) {
var method = arguments.length <= 1 || arguments[1] === undefined ? 'GET' : arguments[1];
var args = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
var body = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
var headers = arguments.length <= 4 || arguments[4] === undefined ? null : arguments[4];
var timeout = arguments.length <= 5 || arguments[5] === undefined ? null : arguments[5];
var optionalPassword = arguments.length <= 6 || arguments[6] === undefined ? null : arguments[6];
var providerHeader = arguments.length <= 7 || arguments[7] === undefined ? null : arguments[7];
var options,
jsonBody,
urlEncodeBody,
json = true,
reqPath,
baseUrl = this.getBaseUrl();
if (!path) {
throw Error('URI incorrect: ' + path);
}
reqPath = path.replace('//', '/');
headers = this.__getReqHeaders(headers, providerHeader, optionalPassword);
options = {
baseUrl: baseUrl,
method: method,
timeout: timeout !== null ? timeout * 1000 : this.timeout,
strictSSL: this.strictSSL,
followAllRedirects: true,
time: true,
tunnel: true,
proxy: this.proxy ? this.proxy : false,
proxyHeaderWhiteList: _p.get(this).proxyHeaderWhiteList,
gzip: process.browser ? false : true,
resolveWithFullResponse: true
};
if (method === 'GET' && args) {
options.qs = args;
}
if (body) {
try {
jsonBody = JSON.stringify(body);
} catch (e) {
urlEncodeBody = body.toString();
headers['Content-Type'] = 'application/x-www-form-urlencoded';
json = false;
}
options.body = body;
}
options.json = json;
options.uri = reqPath;
options.headers = headers;
return options;
}
}, {
key: '__doRequest',
value: function __doRequest() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var useCache = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var cache = _p.get(this).cache,
cachedResp,
_resolve,
_reject;
var promise = new _bluebird2['default'](function (resolve, reject) {
_resolve = resolve;
_reject = reject;
});
function resolvePromise(res) {
var statusCode = res.statusCode;
(statusCode >= 200 && statusCode < 400 ? _resolve : _reject)(res);
}
if (useCache && options.method === 'GET') {
cachedResp = cache.get(options.uri);
if (cachedResp !== undefined) {
if (isPromiseLike(cachedResp)) {
// Got a Promise
cachedResp.then(resolvePromise, resolvePromise);
} else {
// Got a real response
resolvePromise(cachedResp);
}
} else {
// No data cached
cache.put(options.uri, promise);
}
}
if (cachedResp === undefined) {
this.__sendRequest(options, resolvePromise);
}
return promise;
}
}, {
key: '__sendRequest',
value: function __sendRequest(options, resolvePromise) {
var cache = _p.get(this).cache;
var req = (0, _requestPromise2['default'])(options);
this.__handleManualTimeout(req);
req.then(function (res) {
if (options.method === 'GET') {
var statusCode = res.statusCode;
var uri = options.uri;
if (statusCode >= 200 && statusCode < 300) {
cache.put(uri, res.toJSON());
} else if (statusCode >= 400) {
cache.remove(uri);
}
}
resolvePromise(res.toJSON());
})['catch'](function (res) {
cache.remove(res.options.uri);
resolvePromise(res);
});
}
}, {
key: '__handleManualTimeout',
value: function __handleManualTimeout(req) {
// timeout function of request (ver 2.82) module will be gone after doing browserify
// so we handle timeout by ourselves
if (process.browser) {
// request module does clearTimeout when response/error occurs if it's timeoutTimer has value.
if (!req.timeoutTimer) {
req.timeoutTimer = setTimeout(function () {
req.abort();
var e = new Error('ETIMEDOUT');
e.code = 'ETIMEDOUT';
e.connect = true;
req.emit('error', e);
}, req.timeout);
}
}
}
/**
* Login to the RESTful/Redfish API
* @param {string} userName - Your iLO user account
* @param {string} password - Password for your account
* @return {promise} A Promise object which returns the HTTP response after login
*/
}, {
key: 'login',
value: function login() {
var userName = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
var _this6 = this;
var password = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var auth = arguments.length <= 2 || arguments[2] === undefined ? authMethod.SESSION : arguments[2];
return _p.get(this).rootPromise.then(function () {
return _this6.__doLogin(userName, password, auth);
});
}
}, {
key: '__doLogin',
value: function __doLogin() {
var userName = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
var _this7 = this;
var password = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var auth = arguments.length <= 2 || arguments[2] === undefined ? authMethod.SESSION : arguments[2];
var __userName = this.getUserName();
var __password = this.getPassword();
if (typeof userName === 'string') {
__userName = userName;
_p.get(this).userName = userName;
}
if (typeof password === 'string') {
__password = password;
_p.get(this).password = password;
}
_p.get(this).sessionKey = null;
_p.get(this).authorizationKey = null;
if (auth === authMethod.BASIC) {
var encBase64 = Buffer.from(__userName + ':' + __password).toString('base64');
var authKey = 'Basic ' + encBase64;
_p.get(this).authorizationKey = authKey;
return this.get(this.loginUrl);
} else if (auth === authMethod.SESSION) {
var body = {};
body.UserName = __userName;
body.Password = __password;
return this.post(this.loginUrl, body).then(function (res) {
var _json = res;
_p.get(_this7).sessionKey = _json.headers['x-auth-token'];
_p.get(_this7).sessionLocation = _json.headers['location'];
return res;
});
} else {
throw Error('No matching authorize method');
}
return;
}
/**
* Logout
* @return {promise} A Promise object which returns the HTTP response after logout
*/
}, {
key: 'logout',
value: function logout() {
var _this8 = this;
var __sessionLocation = this.getSessionLocation();
var path = this.defaultPrefix + __sessionLocation.split(this.defaultPrefix)[1];
return this['delete'](path).then(function (res) {
if (res.statusCode === 200) {
_p.get(_this8).sessionKey = null;
_p.get(_this8).sessionLocation = null;
_p.get(_this8).authorizationKey = null;
return res;
} else {
throw Error('Logout failed');
}
});
}
}]);
return baseClient;
})();
exports.baseClient = baseClient;