UNPKG

7.66 kBJavaScriptView Raw
1/**
2 * Copyright 2016-2018 F5 Networks, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17'use strict';
18
19const q = require('q');
20const util = require('./util');
21const Logger = require('./logger');
22
23const LICENSE_PATH = '/cm/shared/licensing/pools/';
24const LICENSE_TIMEOUT = { maxRetries: 40, retryIntervalMs: 5000 };
25
26let logger;
27
28/**
29 * BigIq 5.0 license provider constructor
30 *
31 * @class
32 * @classdesc
33 * Provides ability to get licenses from BIG-IQ 5.0 (and compatible versions).
34 *
35 * @param {Object} bigIp - Base {@link BigIp} object.
36 * @param {Object} [options] - Optional parameters.
37 * @param {Object} [options.logger] - Logger to use. Or, pass loggerOptions to get your own logger.
38 * @param {Object} [options.loggerOptions] - Options for the logger.
39 * See {@link module:logger.getLogger} for details.
40*/
41function BigIq50LicenseProvider(bigIp, options) {
42 const injectedLogger = options ? options.logger : undefined;
43 let loggerOptions = options ? options.loggerOptions : undefined;
44
45 if (injectedLogger) {
46 this.logger = injectedLogger;
47 util.setLogger(injectedLogger);
48 } else {
49 loggerOptions = loggerOptions || { logLevel: 'none' };
50 loggerOptions.module = module;
51 this.logger = Logger.getLogger(loggerOptions);
52 util.setLoggerOptions(loggerOptions);
53 }
54
55 logger = this.logger;
56 this.bigIp = bigIp;
57}
58
59/**
60 * Gets a license from BIG-IQ for an unmanaged BIG-IP
61 *
62 * @param {Object} bigIqControl - iControl object for BIG-IQ
63 * @param {String} poolName - Name of the BIG-IQ license pool to use
64 * @param {String} bigIpMgmtAddress - IP address of BIG-IP management port.
65 * @param {String} bigIpMgmtPort - IP port of BIG-IP management port.
66 *
67 * @returns {Promise} A promise which is resolved when the BIG-IP has been licensed
68 * or rejected if an error occurs.
69 */
70BigIq50LicenseProvider.prototype.getUnmanagedDeviceLicense = function getUnmanagedDeviceLicense(
71 bigIqControl,
72 poolName,
73 bigIpMgmtAddress,
74 bigIpMgmtPort
75) {
76 let poolUuid;
77
78 this.logger.debug('Getting BIG-IP license pool UUID.');
79 return getPoolUuid(bigIqControl, poolName)
80 .then((response) => {
81 poolUuid = response;
82 logger.silly('Got pool UUID:', poolUuid);
83
84 this.logger.debug('Requesting license from BIG-IQ license pool.');
85 return bigIqControl.create(
86 `${LICENSE_PATH}${poolUuid}/members`,
87 {
88 deviceAddress: `${bigIpMgmtAddress}:${bigIpMgmtPort}`,
89 username: this.bigIp.user,
90 password: this.bigIp.password
91 }
92 );
93 })
94 .then((response) => {
95 this.logger.debug(response);
96
97 let licenseUuid;
98
99 const isLicensed = function () {
100 const deferred = q.defer();
101
102 bigIqControl.list(`${LICENSE_PATH}${poolUuid}/members/${licenseUuid}`)
103 .then((licenseUuidRespnse) => {
104 const state = licenseUuidRespnse.state;
105 this.logger.verbose('Current licensing state:', state);
106 if (state === 'LICENSED') {
107 deferred.resolve();
108 } else {
109 deferred.reject();
110 }
111 });
112
113 return deferred.promise;
114 };
115
116 if (response) {
117 const state = response.state;
118 licenseUuid = response.uuid;
119 this.logger.verbose('Current licensing state:', state);
120 this.logger.debug('License UUID:', licenseUuid);
121
122 if (state === 'LICENSED') {
123 return q();
124 }
125 this.logger.verbose('Waiting to be LICENSED.');
126 return util.tryUntil(this, this.getLicenseTimeout(), isLicensed)
127 .then(() => {
128 return q();
129 })
130 .catch(() => {
131 return q.reject(new Error('Giving up on licensing via BIG-IQ.'));
132 });
133 }
134
135 return q();
136 });
137};
138/**
139 * Revokes a license from a BIG-IP
140 *
141 * @param {Object} bigIqControl - iControl object for BIG-IQ
142 * @param {String} poolName - Name of the BIG-IQ license pool to use
143 * @param {String} instance - {@link AutoscaleInstance} to revoke license for
144 *
145 * @returns {Promise} A promise which is resolved when the BIG-IP license has
146 * been revoked, or rejected if an error occurs.
147 */
148BigIq50LicenseProvider.prototype.revoke = function revoke(bigIqControl, poolName, instance) {
149 let poolUuid;
150
151 this.logger.debug('Getting BIG-IP license pool UUID.');
152 return getPoolUuid(bigIqControl, poolName)
153 .then((response) => {
154 poolUuid = response;
155 this.logger.debug('Getting licenses in pool');
156 return bigIqControl.list(`${LICENSE_PATH}${poolUuid}/members/`);
157 })
158 .then((response) => {
159 const licenses = response || [];
160 let license;
161
162 for (let i = 0; i < licenses.length; i++) {
163 if (licenses[i].deviceName && licenses[i].deviceName === instance.hostname) {
164 license = licenses[i];
165 break;
166 }
167 }
168
169 if (license) {
170 return bigIqControl.delete(
171 `${LICENSE_PATH}${poolUuid}/members/${license.uuid}`,
172 {
173 username: this.bigIp.user || 'dummyUser',
174 password: this.bigIp.password || 'dummyPassword',
175 uuid: license.uuid
176 }
177 );
178 }
179
180 return q.reject(new Error('no license found for host:', instance.hostname));
181 });
182};
183
184/**
185 * Gets the license timeout to use
186 *
187 * This is here so that it can be overridden by test code
188 *
189 * @returns the license timeout
190 */
191BigIq50LicenseProvider.prototype.getLicenseTimeout = function getLicenseTimeout() {
192 return LICENSE_TIMEOUT;
193};
194
195function getPoolUuid(bigIqControl, poolName) {
196 return bigIqControl.list(`${LICENSE_PATH}?$select=uuid,name`)
197 .then((response) => {
198 logger.debug(response);
199
200 let poolUuid;
201
202 if (Array.isArray(response)) {
203 for (let i = 0; i < response.length; i++) {
204 if (response[i].name === poolName) {
205 poolUuid = response[i].uuid;
206 break;
207 }
208 }
209
210 if (poolUuid) {
211 return poolUuid;
212 }
213 return q.reject(new Error(`No license pool found with name: ${poolName}`));
214 }
215
216 return q.reject(new Error(`Error getting license pools: ${response}`));
217 });
218}
219
220module.exports = BigIq50LicenseProvider;