1 | /**
|
2 | * Copyright 2017-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 | ;
|
18 |
|
19 | const q = require('q');
|
20 | const util = require('./util');
|
21 | const authn = require('./authn');
|
22 | const sharedConstants = require('./sharedConstants');
|
23 | const bigIqLicenseProviderFactory = require('./bigIqLicenseProviderFactory');
|
24 | const Logger = require('./logger');
|
25 | const PRODUCTS = require('./sharedConstants').PRODUCTS;
|
26 |
|
27 | /**
|
28 | * BigIq constructor
|
29 | *
|
30 | * @class
|
31 | * @classdesc
|
32 | * Provides core functionality (CRUD operations, ready, etc) and maintains
|
33 | * references to other modules in f5-cloud-libs.
|
34 | *
|
35 | * After creating a BigIq with this constructor, you must call the
|
36 | * async init() method.
|
37 | *
|
38 | * @param {Object} [options] - Optional parameters.
|
39 | * @param {Object} [options.logger] - Logger to use. Or, pass loggerOptions to get your own logger.
|
40 | * @param {Object} [options.loggerOptions] - Options for the logger.
|
41 | * See {@link module:logger.getLogger} for details.
|
42 | */
|
43 | function BigIq(options) {
|
44 | const logger = options ? options.logger : undefined;
|
45 | let loggerOptions = options ? options.loggerOptions : undefined;
|
46 |
|
47 | this.constructorOptions = {};
|
48 | if (options) {
|
49 | Object.keys(options).forEach((option) => {
|
50 | this.constructorOptions[option] = options[option];
|
51 | });
|
52 | }
|
53 |
|
54 | if (logger) {
|
55 | this.logger = logger;
|
56 | util.setLogger(logger);
|
57 | } else {
|
58 | loggerOptions = loggerOptions || { logLevel: 'none' };
|
59 | loggerOptions.module = module;
|
60 | this.logger = Logger.getLogger(loggerOptions);
|
61 | util.setLoggerOptions(loggerOptions);
|
62 | }
|
63 | }
|
64 |
|
65 | /**
|
66 | * Initialize this instance w/ host user password
|
67 | *
|
68 | * @param {String} host - Host to connect to.
|
69 | * @param {String} user - User (with admin rights).
|
70 | * @param {String} passwordOrUri - Password for user or URL (file, http, https, arn) to
|
71 | * location containing password.
|
72 | * @param {Object} [options] - Optional parameters.
|
73 | * @param {Boolean} [options.passwordIsUri] - Indicates that password is a URI for the password
|
74 | * @param {Boolean} [options.passwordEncrypted] - Indicates that the password is encrypted
|
75 | * @param {Number} [options.port] - Port of management port. Default 443.
|
76 | * @param {Object} [options.bigIp] - {@link BigIp} object. BigIp to control.
|
77 | *
|
78 | * @returns {Promise} A promise which is resolved when initialization is complete
|
79 | * or rejected if an error occurs.
|
80 | */
|
81 | BigIq.prototype.init = function init(host, user, passwordOrUri, options) {
|
82 | this.initOptions = {};
|
83 | Object.assign(this.initOptions, options);
|
84 |
|
85 | this.host = host ? host.trim() : 'localhost';
|
86 | this.user = user ? user.trim() : null;
|
87 |
|
88 | this.bigIp = options ? options.bigIp || {} : {};
|
89 |
|
90 | const authnOptions = {
|
91 | product: PRODUCTS.BIGIQ,
|
92 | passwordIsUri: this.initOptions.passwordIsUri,
|
93 | passwordEncrypted: this.initOptions.passwordEncrypted,
|
94 | port: this.initOptions.port
|
95 | };
|
96 |
|
97 | return authn.authenticate(this.host, this.user, passwordOrUri, authnOptions)
|
98 | .then((icontrol) => {
|
99 | this.icontrol = icontrol;
|
100 | this.logger.debug('Getting BIG-IQ version.');
|
101 |
|
102 | const getVersion = function () {
|
103 | return this.icontrol.list(
|
104 | '/shared/resolver/device-groups/cm-shared-all-big-iqs/devices?$select=version'
|
105 | );
|
106 | };
|
107 |
|
108 | return util.tryUntil(this, util.MEDIUM_RETRY, getVersion);
|
109 | })
|
110 | .then((response) => {
|
111 | this.logger.debug(response);
|
112 | this.version = response[0].version;
|
113 | })
|
114 | .catch((err) => {
|
115 | this.logger.info('Unable to initialize BIG-IQ', err && err.message ? err.message : err);
|
116 | return q.reject(err);
|
117 | });
|
118 | };
|
119 |
|
120 | /**
|
121 | * Licenses a BIG-IP from a license pool
|
122 | *
|
123 | * @param {String} poolName - Name of the BIG-IQ pool to license from.
|
124 | * @param {String} bigIpMgmtAddress - Management address of BIG-IP
|
125 | * @param {String} bigIpMgmtPort - Management port of BIG-IP
|
126 | * @param {Object} [options] - Optional parameters
|
127 | * @param {String} [options.cloud] - Name of cloud. Only BIG-IQ 5.4+ needs this.
|
128 | * Supported values are:
|
129 | * aws, azure, gce, vmware, hyperv, kvm, xen
|
130 | * @param {String} [options.skuKeyword1] - skuKeyword1 parameter for CLPv2 licensing. Default none.
|
131 | * @param {String} [options.skuKeyword2] - skuKeyword2 parameter for CLPv2 licensing. Default none.
|
132 | * @param {String} [options.unitOfMeasure] - unitOfMeasure parameter for CLPv2 licensing. Default none.
|
133 | * @param {Boolean} [options.noUnreachable] - Do not use the unreachable API even on BIG-IQs that support it.
|
134 | * @param {Boolean} [options.autoApiType] - Automatically determine API type rather than basing on BIG-IQ
|
135 | * version.
|
136 | *
|
137 | * @returns {Promise} A promise which is resolved when the licensing
|
138 | * is complete or rejected if an error occurs.
|
139 | */
|
140 | BigIq.prototype.licenseBigIp = function licenseBigIp(poolName, bigIpMgmtAddress, bigIpMgmtPort, options) {
|
141 | const methodOptions = {};
|
142 | Object.assign(methodOptions, options);
|
143 |
|
144 | this.logger.debug('Getting license provider');
|
145 | return getLicenseProvider.call(this, poolName, methodOptions)
|
146 | .then((licenseProvider) => {
|
147 | this.logger.debug('Getting license from provider.');
|
148 | return licenseProvider.getUnmanagedDeviceLicense(
|
149 | this.icontrol,
|
150 | poolName,
|
151 | bigIpMgmtAddress,
|
152 | bigIpMgmtPort,
|
153 | {
|
154 | cloud: methodOptions.cloud,
|
155 | skuKeyword1: methodOptions.skuKeyword1,
|
156 | skuKeyword2: methodOptions.skuKeyword2,
|
157 | unitOfMeasure: methodOptions.unitOfMeasure,
|
158 | tenant: methodOptions.tenant,
|
159 | noUnreachable: methodOptions.noUnreachable
|
160 | }
|
161 | );
|
162 | });
|
163 | };
|
164 |
|
165 | /**
|
166 | * Revokes a license for a BIG-IP
|
167 | *
|
168 | * @param {String} poolName - The name of the license pool to revoke from
|
169 | * @param {String} instance - {@link AutoscaleInstance} to revoke license for
|
170 | * @param {Object} [options] - Optional parameters
|
171 | * @param {Boolean} [options.noUnreachable] - Do not use the unreachable API even on BIG-IQs that support it.
|
172 | */
|
173 | BigIq.prototype.revokeLicense = function revokeLicense(poolName, instance, options) {
|
174 | let licenseProvider;
|
175 | this.logger.silly('Revoking license for', instance);
|
176 | try {
|
177 | licenseProvider = bigIqLicenseProviderFactory.getLicenseProviderByVersion(
|
178 | this.version,
|
179 | this.bigIp,
|
180 | this.constructorOptions
|
181 | );
|
182 | this.logger.silly('Calling license provider revoke');
|
183 | return licenseProvider.revoke(this.icontrol, poolName, instance, options);
|
184 | } catch (err) {
|
185 | this.logger.debug('Error revoking license', err && err.message ? err.message : err);
|
186 | return q.reject(err);
|
187 | }
|
188 | };
|
189 |
|
190 | /**
|
191 | * Gets a license provider based on api type or version
|
192 | * @param {String} poolName - The name of the license pool
|
193 | * @param {Object} options - Options
|
194 | * @param {Boolean} options.autoApiType - Automatically determine API type rather
|
195 | * than basing on BIG-IQ version.
|
196 | * @param {Boolean} [options.noUnreachable] - Do not use the unreachable API even on BIG-IQs that support it.
|
197 | */
|
198 | function getLicenseProvider(poolName, options) {
|
199 | const methodOptions = {};
|
200 | Object.assign(methodOptions, options);
|
201 | const factoryOptions = {};
|
202 | Object.assign(factoryOptions, this.constructorOptions);
|
203 |
|
204 | let licenseProvider;
|
205 |
|
206 | if (methodOptions.autoApiType) {
|
207 | return getApiType.call(this, methodOptions)
|
208 | .then((apiType) => {
|
209 | // Even though the main API by type is the same across BIG-IQ versions,
|
210 | // there are some subtle differences the implementations need to know
|
211 | // about
|
212 | factoryOptions.version = this.version;
|
213 | try {
|
214 | licenseProvider = bigIqLicenseProviderFactory.getLicenseProviderByType(
|
215 | apiType,
|
216 | this.bigIp,
|
217 | factoryOptions
|
218 | );
|
219 | return q(licenseProvider);
|
220 | } catch (err) {
|
221 | this.logger.info(
|
222 | 'Error getting license provider by type', err && err.message ? err.message : err
|
223 | );
|
224 | return q.reject(err);
|
225 | }
|
226 | })
|
227 | .catch((err) => {
|
228 | this.logger.info('Error getting api type', err && err.message ? err.message : err);
|
229 | return q.reject(err);
|
230 | });
|
231 | }
|
232 |
|
233 | try {
|
234 | licenseProvider = bigIqLicenseProviderFactory.getLicenseProviderByVersion(
|
235 | this.version,
|
236 | this.bigIp,
|
237 | factoryOptions
|
238 | );
|
239 |
|
240 | return q(licenseProvider);
|
241 | } catch (err) {
|
242 | this.logger.info(
|
243 | 'Error getting license provider by type', err && err.message ? err.message : err
|
244 | );
|
245 | return q.reject(err);
|
246 | }
|
247 | }
|
248 |
|
249 | function getApiType(options) {
|
250 | const apiType = options.noUnreachable ?
|
251 | sharedConstants.LICENSE_API_TYPES.UTILITY :
|
252 | sharedConstants.LICENSE_API_TYPES.UTILITY_UNREACHABLE;
|
253 |
|
254 | this.logger.silly(`using api type ${apiType}`);
|
255 | return q.resolve(apiType);
|
256 | }
|
257 |
|
258 | module.exports = BigIq;
|