UNPKG

ilorest

Version:
583 lines (490 loc) 22.8 kB
'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;