const API = require('portainer_api') const { defer } = require('gefer') const originalCallApi = API.ApiClient.prototype.callApi API.ApiClient.prototype.callApi = function(path, httpMethod, pathParams, queryParams, collectionQueryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts, returnType, callback) { if (API.url) this.basePath = API.url + '/api' let deferred if (callback === undefined) { deferred = defer() callback = (err, res) => err ? deferred.reject(err) : deferred.resolve(res) } const superAgent = originalCallApi.call(this, path, httpMethod, pathParams, queryParams, collectionQueryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts, returnType, callback) return deferred && deferred.promise || superAgent } /** * @class * @param config Configuration for the API * @param config.username Username for Portainer * @param config.password Password for user * @param config.url Base url for portainer (http://myserver:9000) * @property {StacksApi} stacks * @property {EndpointsApi} endpoints */ function Api({username, password, url}) { let login = null //if (!(this instanceof Api)) return new Api() const ensureLogin = () => { if (login === null) { const authApi = new API.AuthApi() API.ApiClient.instance.basePath = url + '/api' login = authApi.authenticateUser({username, password}) } return login } Object.keys(providers).forEach(key => { const Class = providers[key] let instance = null const api = Object.assign({}, this[key]) this[key] = api Object.keys(api).forEach(name => { const fn = api[name] api[name] = async function() { if (!instance) { instance = new Class() } const { jwt } = await ensureLogin() // The following steps must occur synchronously. API.ApiClient.instance.basePath = url + '/api' API.ApiClient.instance.authentications.jwt.apiKey = jwt const ret = await fn.apply(instance, arguments) if (ret && ret.hasOwnProperty('length')) { return Array.from(ret) } return ret } }) }) } const providers = { stacks: API.StacksApi, endpoints: API.EndpointsApi } /** * @typedef StacksApi * @class * @hideconstructor **/ Api.prototype.stacks = { /** * @async * @memberof StacksApi# * @param {Number} type Stack deployment type. Possible values: 1 (Swarm stack) or 2 (Compose stack). * @param {String} method Stack deployment method. Possible values: file, string or repository. * @param {Number} endpointId Identifier of the endpoint that will be used to deploy the stack. * @param {module:model/StackCreateRequest} opts Stack details. Required when method equals string or repository. * @returns {module:model/Stack} */ async create(type, method, endpointId, opts) { return this.stackCreate(type, method, endpointId, opts) }, /** * @async * @returns {module:model/Stack[]} * @memberof StacksApi# * @param opts Filter options * @param {string} opts.filters Filters to process on the stack list. Encoded as JSON (a map[string]string). For example, {"SwarmID": "jpofkc0i9uo9wtx1zesuk649w"} will only return stacks that are part of the specified Swarm cluster. Available filters: EndpointID, SwarmID. */ async list(opts) { return this.stackList(opts) } } /** * @typedef EndpointsApi * @class * @hideconstructor */ Api.prototype.endpoints = { /** * @async * @returns {Promise} * @memberof EndpointsApi# * */ async list() { return this.endpointList() } } module.exports = Api