Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@f5devcentral/f5-cloud-libs

Package Overview
Dependencies
Maintainers
4
Versions
127
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@f5devcentral/f5-cloud-libs - npm Package Compare versions

Comparing version 4.0.0-beta.6 to 4.0.0

7

lib/autoscaleProvider.js

@@ -505,2 +505,5 @@ /**

*
* We only make a best effort here. If revoke fails, this still succeeds. This allows
* us not to care if the license even can be revoked (perhaps it is not issued by BIG-IQ).
*
* @param {Object[]} instances - Instances for which to revoke licenses. Instances

@@ -539,2 +542,6 @@ * should be as returned by getInstances

return q.all(promises);
})
.catch((err) => {
this.logger.debug('Could not revoke all licenses', err);
return q();
});

@@ -541,0 +548,0 @@ }

16

lib/bigIp.js

@@ -117,3 +117,3 @@ /**

.then((actualPassword) => {
this.password = actualPassword;
this.password = actualPassword.trim();
this.icontrol = new IControl({

@@ -314,4 +314,8 @@ host: this.host,

BigIp.prototype.active = function active(retryOptions) {
const retry = retryOptions || util.DEFAULT_RETRY;
const retry = {};
Object.assign(retry, retryOptions || util.DEFAULT_RETRY);
// While waiting for active, we may get errors but we want to keep trying
retry.continueOnError = true;
const func = function () {

@@ -613,3 +617,3 @@ const deferred = q.defer();

.then((password) => {
this.password = password;
this.password = password.trim();
this.icontrol = new IControl({

@@ -792,4 +796,8 @@ host: this.host,

BigIp.prototype.ready = function ready(retryOptions) {
const retry = retryOptions || util.DEFAULT_RETRY;
const retry = {};
Object.assign(retry, retryOptions || util.DEFAULT_RETRY);
// While waiting for ready, we may get errors but we want to keep trying
retry.continueOnError = true;
const func = function () {

@@ -796,0 +804,0 @@ const promises = [];

@@ -334,2 +334,4 @@ /**

.then((readPassword) => {
const trimmedPassword = readPassword ? readPassword.trim() : '';
const func = function () {

@@ -340,3 +342,3 @@ return bigIqControl.create(

username: user,
password: readPassword
password: trimmedPassword
}

@@ -349,3 +351,3 @@ );

user: user.trim(),
password: readPassword ? readPassword.trim() : '',
password: trimmedPassword,
strict: false

@@ -612,3 +614,3 @@ });

// Get the current provisionalbe modules with their levels
// Get the current provisionable modules with their levels
response.forEach((module) => {

@@ -632,15 +634,25 @@ currentProvisioning[module.name] = module.level;

provisioningCommands.push({
promise: this.core.active
});
provisioningCommands.push({
promise: this.core.modify,
arguments: [
PROVISION_PATH + module,
{ level: provisionSettings[module] },
null,
{
level: provisionSettings[module]
maxRetries: 90,
retryIntervalMs: 10000,
continueOnErrorMessage: /in progress/
}
]
});
provisioningCommands.push({
promise: this.core.active
});
}
});
// if provisioning, check for active after last module
if (provisioningCommands.length > 0) {
provisioningCommands.push({
promise: this.core.active
});
}

@@ -647,0 +659,0 @@ return util.callInSerial(this.core, provisioningCommands, DELAY_BETWEEN_PROVISION_COMMANDS);

@@ -185,2 +185,30 @@ /**

function verifyGtmServer() {
const usedAddresses = [];
function collectAddresses(server) {
server.addresses.forEach((address) => {
usedAddresses.push(address.name);
});
}
// when creating the server, we have to give it an IP address
// we use 192.0.2.X as that is defined in https://tools.ietf.org/html/rfc5737
// for use as a documentation server and is not likely to be in use
function getFirstAvailableAddress() {
let highestLastOctet = 0;
usedAddresses.forEach((address) => {
const octets = address.split('.');
const thisLastOctet = parseInt(octets[3], 10);
if (thisLastOctet > highestLastOctet) {
highestLastOctet = thisLastOctet;
}
});
highestLastOctet += 1;
if (highestLastOctet > 255) {
this.logger.error('No available addresses for GTM server');
return null;
}
return `192.0.2.${highestLastOctet}`;
}
return this.bigIp.list('/tm/gtm/server')

@@ -193,2 +221,4 @@ .then((servers) => {

}
collectAddresses(servers[i]);
}

@@ -201,5 +231,3 @@ }

// when creating the server, we have to give it an IP address
// we use 192.0.2.1 as that is defined in https://tools.ietf.org/html/rfc5737
// for use as a documentation server and is not likely to be in use
const dummyAddress = getFirstAvailableAddress();
return this.bigIp.create(

@@ -211,3 +239,3 @@ '/tm/gtm/server',

product: 'generic-host',
addresses: ['192.0.2.1']
addresses: [dummyAddress]
}

@@ -214,0 +242,0 @@ );

@@ -219,2 +219,3 @@ /**

let parsedResponse;
let contentType;

@@ -224,2 +225,3 @@ if (responseHeaders['content-type']

) {
contentType = 'application/json';
try {

@@ -240,3 +242,17 @@ parsedResponse = JSON.parse(totalResponse || '{}');

if (response.statusCode >= 300) {
deferred.reject(parsedResponse);
let error;
if (contentType === 'application/json') {
if (parsedResponse.code && parsedResponse.message) {
error = new Error(parsedResponse.message);
error.code = parsedResponse.code;
} else {
error = new Error(JSON.stringify(parsedResponse));
error.code = response.statusCode;
}
} else {
error = new Error(parsedResponse);
error.code = response.statusCode;
}
deferred.reject(error);
} else {

@@ -243,0 +259,0 @@ deferred.resolve(parsedResponse);

@@ -87,10 +87,19 @@ /**

*
* @param {Object} thisArg - The 'this' argument to pass to the called function
* @param {Object} retryOptions - Options for retrying the request.
* @param {Integer} retryOptions.maxRetries - Number of times to retry if first try fails.
* 0 to not retry. Default 60.
* @param {Integer} retryOptions.retryIntervalMs - Milliseconds between retries. Default 10000.
* @param {Function} funcToTry - Function to try. Function should return a
* Promise which is later resolved or rejected.
* @param {Object[]} args - Array of arguments to pass to funcToTry
* @param {Object} thisArg - The 'this' argument to pass to the
* called function
* @param {Object} retryOptions - Options for retrying the request.
* @param {Integer} retryOptions.maxRetries - Number of times to retry if first
* try fails. 0 to not retry.
* Default 60.
* @param {Integer} retryOptions.retryIntervalMs - Milliseconds between retries.
* Default 10000.
* @param {Boolean} [retryOptions.continueOnError] - Continue even if we get an
* HTTP BAD_REQUEST code. Default false.
* @param {String | RegExp} [retryOptions.continueOnErrorMessage] - Continue on error if the 400 error
* message matches this regex
* @param {Function} funcToTry - Function to try. Function should
* return a Promise which is later
* resolved or rejected.
* @param {Object[]} args - Array of arguments to pass to
* funcToTry
*

@@ -103,2 +112,19 @@ * @returns {Promise} A promise which is resolved with the return from funcToTry

const shouldReject = function (err) {
if (err && err.code === 400) {
if (retryOptions.continueOnError) {
return false;
}
if (err.message && retryOptions.continueOnErrorMessage) {
let regex = retryOptions.continueOnErrorMessage;
if (!(regex instanceof RegExp)) {
regex = new RegExp(retryOptions.continueOnErrorMessage);
}
return !regex.test(err.message);
}
return true;
}
return false;
};
const tryIt = function tryIt(maxRetries, interval, theFunc, deferredOrNull) {

@@ -109,3 +135,3 @@ let numRemaining = maxRetries;

const retryOrReject = function (err) {
if (err && err.code === 400) {
if (shouldReject(err)) {
logger.verbose('Unrecoverable error from HTTP request. Not retrying.');

@@ -118,3 +144,8 @@ deferred.reject(err);

logger.verbose('Max tries reached.');
deferred.reject(err);
const originalMessage = err && err.message ? err.message : 'unknown';
const updatedError = {};
Object.assign(updatedError, err);
updatedError.message = `tryUntil: max tries reached: ${originalMessage}`;
updatedError.name = err && err.name ? err.name : '';
deferred.reject(updatedError);
}

@@ -121,0 +152,0 @@ };

{
"name": "@f5devcentral/f5-cloud-libs",
"version": "4.0.0-beta.6",
"version": "4.0.0",
"description": "Common library code and scripts for deploying a BIG-IP in a cloud environment",

@@ -5,0 +5,0 @@ "keywords": [

# Release notes
## Version 4.0.0
**This version is not backwards compatible. The install location of `f5-cloud-libs`
and `f5-cloud-libs-<cloud>` has changed to support installation from npm**
* Scripts now exit with status code 1 on failure
* Support autoscaling with BYOL and utility billing instances in one cluster
* Support autoscaling with DNS updates
* Support for automatic backups in autoscaling solutions
* Update scripts and lib code to the [Airbnb JavaScript style guide](https://github.com/airbnb/javascript)
* Provide independent licensing script callable from tmsh
* Add options for CLPv2 when licensing via BIG-IQ
## Version 3.6.0

@@ -52,4 +64,4 @@ * Add --shell option to scripts/runScript.js

* Allows for autoscaling and clustering without providing a password in the template
* Adds hash verification for all downloaded files
* Fixes race condition when running multiple f5-cloud-libs scripts at once
* Add hash verification for all downloaded files
* Fix race condition when running multiple f5-cloud-libs scripts at once

@@ -59,4 +71,4 @@ ## Version 2.0.0

* All scripts that take --password now also support --password-url. Only 'file' URLs are supported for now.
* Added option to suppress console output (--no-console).
* Added support for verifying hash of downloaded f5-cloud-libs tarball.
* Added some parsing of sync messages to get sync to work more often.
* Add option to suppress console output (--no-console).
* Add support for verifying hash of downloaded f5-cloud-libs tarball.
* Add some parsing of sync messages to get sync to work more often.

@@ -55,2 +55,3 @@ /**

let rebooting;
let exiting;

@@ -386,2 +387,3 @@ Object.assign(optionsForTest, testOpts);

util.logAndExit(`Cluster failed: ${message}`, 'error', 1);
exiting = true;
return q();

@@ -395,2 +397,8 @@ })

ipc.send(options.signal || signals.CLUSTER_DONE);
if (!exiting) {
util.logAndExit('Cluster finished.');
}
} else if (!options.reboot) {
// If we are rebooting, but we were called with --no-reboot, send signal
ipc.send(options.signal || signals.CLUSTER_DONE);
}

@@ -401,4 +409,2 @@

}
util.logAndExit('Cluster finished.');
});

@@ -405,0 +411,0 @@

@@ -36,3 +36,3 @@ /**

return options
.version('4.0.0-beta.6')
.version('4.0.0')
.option(

@@ -39,0 +39,0 @@ '--host <ip_address>',

@@ -43,3 +43,3 @@ /**

options
.version('4.0.0-beta.6')
.version('4.0.0')
.option('--data-file <data_file>', 'Full path to file with data (use this or --data)')

@@ -46,0 +46,0 @@ .parse(argv);

@@ -58,3 +58,3 @@ /**

options
.version('4.0.0-beta.6')
.version('4.0.0')
.option(

@@ -61,0 +61,0 @@ '--background',

@@ -36,3 +36,3 @@ /**

options
.version('4.0.0-beta.6')
.version('4.0.0')
.option(

@@ -39,0 +39,0 @@ '--length <password_length>',

@@ -64,3 +64,3 @@ /**

options
.version('4.0.0-beta.6')
.version('4.0.0')
.option(

@@ -67,0 +67,0 @@ '--host <ip_address>',

@@ -69,2 +69,3 @@ /**

let rebooting;
let exiting;
let index;

@@ -584,2 +585,3 @@

util.logAndExit(`Onboard failed: ${message}`, 'error', 1);
exiting = true;
return q();

@@ -590,8 +592,2 @@ })

if (!rebooting) {
util.deleteArgs(ARGS_FILE_ID);
}
ipc.send(options.signal || signals.ONBOARD_DONE);
if (cb) {

@@ -601,3 +597,12 @@ cb();

util.logAndExit('Onboard finished.');
if (!rebooting) {
util.deleteArgs(ARGS_FILE_ID);
ipc.send(options.signal || signals.ONBOARD_DONE);
if (!exiting) {
util.logAndExit('Onboard finished.');
}
} else if (!options.reboot) {
// If we are rebooting, but we were called with --no-reboot, send signal
ipc.send(options.signal || signals.ONBOARD_DONE);
}
});

@@ -604,0 +609,0 @@

@@ -51,3 +51,3 @@ /**

options
.version('4.0.0-beta.6')
.version('4.0.0')
.option(

@@ -54,0 +54,0 @@ '--background',

@@ -417,4 +417,37 @@ /**

});
},
testRevokeFail: function(test) {
var instances = [
{
hostname: 'host1'
},
{
hostname: 'host2'
}
];
var licensePool = 'myLicensePool';
testAutoscaleProvider.clOptions = {
licensePool: true,
licensePoolName: licensePool
};
bigIqMock.revokeLicense = function(poolName, hostname) {
return q.reject(new Error('foo'));
}
test.expect(1);
testAutoscaleProvider.revokeLicenses(instances, {})
.then(function() {
test.ok(true);
})
.catch(function(err) {
test.ok(false, 'Revoke should not throw');
})
.finally(function() {
test.done();
});
}
}
};

@@ -238,2 +238,46 @@ /**

testServerCreatedAddressInUse: function(test) {
icontrolMock.when(
'list',
'/tm/gtm/server',
[
{
name: 'myOtherServer',
addresses: [
{name: '192.0.2.1'},
{name: '192.0.2.2'}
]
},
{
name: 'myThirdServer',
addresses: [
{name: '192.0.2.3'}
]
}
]);
test.expect(1);
gtmDnsProvider.init(providerOptions)
.then(function() {
return gtmDnsProvider.update(instances);
})
.then(function() {
test.deepEqual(
icontrolMock.getRequest('create', '/tm/gtm/server'),
{
name: 'myServer',
datacenter: 'myDatacenter',
product: 'generic-host',
addresses: [ '192.0.2.4' ]
}
);
})
.catch(function(err) {
test.ok(false, err);
})
.finally(function() {
test.done();
});
},
testServerNotCreated: function(test) {

@@ -240,0 +284,0 @@ icontrolMock.when(

@@ -74,3 +74,4 @@ /**

testBadStatusCode: function(test) {
httpMock.setResponse({foo: 'bar'}, {'Content-Type': 'application/json'}, 300);
const errorCode = 300;
httpMock.setResponse({foo: 'bar'}, {'Content-Type': 'application/json'}, errorCode);
iControl.list('somepath')

@@ -80,4 +81,4 @@ .then(function() {

})
.catch(function() {
test.ok(true);
.catch(function(err) {
test.strictEqual(err.code, errorCode);
})

@@ -84,0 +85,0 @@ .finally(function() {

@@ -1329,2 +1329,3 @@ /**

testBadRequest: function(test) {
const errorMessage = 'foo';
var func = function() {

@@ -1334,3 +1335,3 @@ return q.reject(

code: 400,
message: 'foo'
message: errorMessage
}

@@ -1345,4 +1346,4 @@ )

})
.catch(function() {
test.ok(true);
.catch(function(err) {
test.strictEqual(err.message, errorMessage);
})

@@ -1352,2 +1353,94 @@ .finally(function() {

});
},
testContinueOnError: function(test) {
var func = function() {
return q.reject(
{
code: 400,
message: 'foo'
}
)
};
test.expect(1);
util.tryUntil(this, {maxRetries: 2, retryIntervalMs: 10, continueOnError: true}, func)
.then(function() {
test.ok(false, 'func should never have resolved');
})
.catch(function(err) {
test.notStrictEqual(err.message.indexOf('max tries'), -1);
})
.finally(function() {
test.done();
});
},
testContinueOnErrorMessageIsMessage: function(test) {
var func = function() {
return q.reject(
{
code: 400,
message: 'is foo'
}
)
};
test.expect(1);
util.tryUntil(this, {maxRetries: 2, retryIntervalMs: 10, continueOnErrorMessage: 'foo'}, func)
.then(function() {
test.ok(false, 'func should never have resolved');
})
.catch(function(err) {
test.notStrictEqual(err.message.indexOf('max tries'), -1);
})
.finally(function() {
test.done();
});
},
testContinueOnErrorMessageIsMessageRegex: function(test) {
var func = function() {
return q.reject(
{
code: 400,
message: 'is foo'
}
)
};
test.expect(1);
util.tryUntil(this, {maxRetries: 2, retryIntervalMs: 10, continueOnErrorMessage: /foo/}, func)
.then(function() {
test.ok(false, 'func should never have resolved');
})
.catch(function(err) {
test.notStrictEqual(err.message.indexOf('max tries'), -1);
})
.finally(function() {
test.done();
});
},
testContinueOnErrorMessageIsNotMessage: function(test) {
var func = function() {
return q.reject(
{
code: 400,
message: 'is foo'
}
)
};
test.expect(1);
util.tryUntil(this, {maxRetries: 2, retryIntervalMs: 10, continueOnErrorMessage: 'bar'}, func)
.then(function() {
test.ok(false, 'func should never have resolved');
})
.catch(function(err) {
test.strictEqual(err.message.indexOf('max tries'), -1);
})
.finally(function() {
test.done();
});
}

@@ -1354,0 +1447,0 @@ },

@@ -816,2 +816,22 @@ /**

};
const instance1 = new AutoscaleInstance()
.setHostname('host1')
.setPrivateIp('1.2.3.4')
.setMgmtIp('1.2.3.4');
const instance2 = new AutoscaleInstance()
.setIsMaster()
.setHostname('host2')
.setPrivateIp('5.6.7.8')
.setMgmtIp('5.6.7.8');
instance2.masterStatus = {
instanceId: "two"
};
instances = {
"one": instance1,
"two": instance2
};
callback();

@@ -818,0 +838,0 @@ },

@@ -204,1 +204,11 @@ # Usage

-h, --help output usage information
## Standalone licensing
### Install
admin@(bigip1)(cfg-sync Standalone)(NO LICENSE)(/Common)(tmos)# run util bash -c "mkdir -p /config/licensing; cd /config/licensing; npm --loglevel=error install @f5devcentral/f5-cloud-libs"
### License from BIG-IQ
admin@(bigip1)(cfg-sync Standalone)(NO LICENSE)(/Common)(tmos)# license password <big_ip_admin_password> big-iq-host <big_iq_ip_address> big-iq-user <big_iq_admin_user> big-iq-password <big_iq_admin_password> license-pool-name <license_pool>
### Other licensing options
admin@(bigip1)(cfg-sync Standalone)(NO LICENSE)(/Common)(tmos)# license help

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc