@f5devcentral/f5-cloud-libs
Advanced tools
Comparing version 4.0.0-alpha.5 to 4.0.0-alpha.6
@@ -22,2 +22,3 @@ /** | ||
activeError: require('./lib/activeError'), | ||
autoscaleInstance: require('./lib/autoscaleInstance'), | ||
autoscaleProvider: require('./lib/autoscaleProvider'), | ||
@@ -24,0 +25,0 @@ bigIp: require('./lib/bigIp'), |
@@ -448,2 +448,17 @@ /** | ||
/** | ||
* Stores a UCS file in cloud storage | ||
* | ||
* @param {String} file - Full path to file to store. | ||
* @param {Number} maxCopies - Number of files to store. Oldest files over | ||
* this number should be deleted. | ||
* @param {String} prefix - The common prefix for autosaved UCS files | ||
* | ||
* @returns {Promise} A promise which is resolved when processing is complete. | ||
*/ | ||
AutoscaleProvider.prototype.storeUcs = function storeUcs(file, maxCopies, prefix) { | ||
this.logger.debug('No override for AutoscaleProvider.storeUcs', file, maxCopies, prefix); | ||
return q(); | ||
}; | ||
/** | ||
* Saves instance info | ||
@@ -450,0 +465,0 @@ * |
153
lib/bigIp.js
@@ -34,2 +34,4 @@ /** | ||
const UCS_TASK_PATH = '/tm/task/sys/ucs'; | ||
/** | ||
@@ -594,36 +596,7 @@ * BigIp constructor | ||
*/ | ||
BigIp.prototype.loadUcs = function loadUcs(file, loadOptions, options, retryOptions) { | ||
const TASK_PATH = '/tm/task/sys/ucs'; | ||
let taskId; | ||
BigIp.prototype.loadUcs = function loadUcs(file, loadOptions, options) { | ||
const initLocalKeys = options ? options.initLocalKeys : undefined; | ||
const restoreUser = options ? options.restoreUser : undefined; | ||
const ucsLoadOptions = loadOptions || {}; | ||
const retry = retryOptions || util.DEFAULT_RETRY; | ||
const checkTask = function checkTask(taskIdToCheck) { | ||
const func = function () { | ||
const deferred = q.defer(); | ||
this.list(`${TASK_PATH}/${taskIdToCheck}/result`, undefined, util.NO_RETRY) | ||
.then((response) => { | ||
if (response._taskState === 'COMPLETED') { // eslint-disable-line no-underscore-dangle | ||
deferred.resolve(true); | ||
} else if (response._taskState === 'FAILED') { // eslint-disable-line no-underscore-dangle | ||
deferred.resolve(false); | ||
} else { | ||
deferred.reject(); | ||
} | ||
}) | ||
.catch(() => { | ||
// if this throws, assume it is because restjavad has been restarted | ||
// and we are done for now - just need to wait for bigIp.ready | ||
deferred.resolve(true); | ||
}); | ||
return deferred.promise; | ||
}; | ||
return util.tryUntil(this, retry, func); | ||
}.bind(this); | ||
const restorePlainTextPasswordFromUrl = function restorePlainTextPasswordFromUrl() { | ||
@@ -693,23 +666,5 @@ const deferred = q.defer(); | ||
return this.create(TASK_PATH, commandBody, undefined, util.NO_RETRY); | ||
return this.runTask(UCS_TASK_PATH, commandBody); | ||
}) | ||
.then((response) => { | ||
taskId = response._taskId; // eslint-disable-line no-underscore-dangle | ||
this.logger.silly('loadUcs taskId:', taskId); | ||
return this.replace( | ||
`${TASK_PATH}/${taskId}`, | ||
{ | ||
_taskState: 'VALIDATING' | ||
}, | ||
undefined, | ||
util.NO_RETRY | ||
); | ||
}) | ||
.then(() => { | ||
return checkTask(taskId); | ||
}) | ||
.then((status) => { | ||
if (status !== true) { | ||
return q.reject(new Error('load UCS task failed')); | ||
} | ||
return this.ready(); | ||
@@ -756,2 +711,6 @@ }) | ||
return q(); | ||
}) | ||
.catch((err) => { | ||
this.logger.info('loadUcs failed', err); | ||
return q.reject(err); | ||
}); | ||
@@ -933,2 +892,35 @@ }; | ||
BigIp.prototype.runTask = function runTask(taskPath, taskConfig) { | ||
let taskId; | ||
return this.ready() | ||
.then(() => { | ||
return this.create(taskPath, taskConfig, undefined, util.NO_RETRY); | ||
}) | ||
.then((response) => { | ||
taskId = response._taskId; // eslint-disable-line no-underscore-dangle | ||
this.logger.silly('taskId:', taskId); | ||
return this.replace( | ||
`${taskPath}/${taskId}`, | ||
{ | ||
_taskState: 'VALIDATING' | ||
}, | ||
undefined, | ||
util.NO_RETRY | ||
); | ||
}) | ||
.then(() => { | ||
return checkTask.call(this, taskPath, taskId); | ||
}) | ||
.then((status) => { | ||
if (status !== true) { | ||
return q.reject(new Error(`task at ${taskPath} failed`)); | ||
} | ||
return q(); | ||
}) | ||
.catch((err) => { | ||
return q.reject(err); | ||
}); | ||
}; | ||
/** | ||
@@ -968,2 +960,26 @@ * Saves sys config | ||
/** | ||
* Save a ucs file in /var/local/ucs | ||
* | ||
* @param {String} file - Base name of ucs file | ||
* | ||
* @returns {Promise} - A promise which is resolve when the ucs is saved | ||
* or rejected if an error occurs | ||
*/ | ||
BigIp.prototype.saveUcs = function saveUcs(file) { | ||
return this.ready() | ||
.then(() => { | ||
const commandBody = { | ||
command: 'save', | ||
name: file | ||
}; | ||
return this.runTask(UCS_TASK_PATH, commandBody); | ||
}) | ||
.catch((err) => { | ||
this.logger.info('saveUcs failed', err); | ||
return q.reject(err); | ||
}); | ||
}; | ||
/** | ||
* Submits commands in a transaction | ||
@@ -1056,2 +1072,41 @@ * | ||
/** | ||
* Checks status of iControl REST task | ||
* | ||
* @param {String} taskPath - URL that created the task | ||
* @param {String} taskIdToCheck - ID of task as returned by create | ||
* | ||
* @returns {Promise} A promise which is resolved with true if the task completes | ||
* successfully, resolved with false if task goes to error state | ||
* or rejected if some other error occurs. | ||
*/ | ||
function checkTask(taskPath, taskIdToCheck) { | ||
const func = function () { | ||
const deferred = q.defer(); | ||
this.list(`${taskPath}/${taskIdToCheck}/result`, undefined, util.NO_RETRY) | ||
.then((response) => { | ||
const taskState = response._taskState; // eslint-disable-line no-underscore-dangle | ||
if (taskState === 'VALIDATING') { | ||
// this is a normal state, just not done yet - keep waiting | ||
deferred.reject(); | ||
} else if (taskState === 'COMPLETED') { | ||
deferred.resolve(true); | ||
} else if (taskState === 'FAILED') { | ||
deferred.resolve(false); | ||
} else { | ||
deferred.reject(new Error(`checkTask: unexpected command status: ${taskState}`)); | ||
} | ||
}) | ||
.catch(() => { | ||
// if this throws, assume it is because restjavad has been restarted | ||
// and we are done for now | ||
deferred.resolve(true); | ||
}); | ||
return deferred.promise; | ||
}; | ||
return util.tryUntil(this, util.DEFAULT_RETRY, func); | ||
} | ||
/** | ||
* Decrypts the password | ||
@@ -1058,0 +1113,0 @@ * |
{ | ||
"name": "@f5devcentral/f5-cloud-libs", | ||
"version": "4.0.0-alpha.5", | ||
"version": "4.0.0-alpha.6", | ||
"description": "Common library code and scripts for deploying a BIG-IP in a cloud environment", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -36,3 +36,3 @@ /** | ||
return options | ||
.version('4.0.0-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.option( | ||
@@ -39,0 +39,0 @@ '--host <ip_address>', |
@@ -43,3 +43,3 @@ /** | ||
options | ||
.version('4.0.0-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.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-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.option( | ||
@@ -61,0 +61,0 @@ '--background', |
@@ -36,3 +36,3 @@ /** | ||
options | ||
.version('4.0.0-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.option( | ||
@@ -39,0 +39,0 @@ '--length <password_length>', |
@@ -64,3 +64,3 @@ /** | ||
options | ||
.version('4.0.0-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.option( | ||
@@ -67,0 +67,0 @@ '--host <ip_address>', |
@@ -51,3 +51,3 @@ /** | ||
options | ||
.version('4.0.0-alpha.5') | ||
.version('4.0.0-alpha.6') | ||
.option( | ||
@@ -54,0 +54,0 @@ '--background', |
@@ -258,2 +258,9 @@ /** | ||
testUnimplementedStoreUcs: function(test) { | ||
test.doesNotThrow(function() { | ||
testAutoscaleProvider.storeUcs(); | ||
}); | ||
test.done(); | ||
}, | ||
testUnimplementedPutInstance: function(test) { | ||
@@ -260,0 +267,0 @@ test.doesNotThrow(function() { |
@@ -39,3 +39,4 @@ /** | ||
const TASK_PATH = '/tm/task/sys/ucs'; | ||
const UCS_TASK_PATH = '/tm/task/sys/ucs'; | ||
const DUMMY_TASK_PATH = '/foo/task/bar'; | ||
@@ -731,4 +732,4 @@ module.exports = { | ||
setUp: function(callback) { | ||
icontrolMock.when('create', TASK_PATH, {_taskId: '1234'}); | ||
icontrolMock.when('list', TASK_PATH + '/1234/result', {_taskState: 'COMPLETED'}); | ||
icontrolMock.when('create', UCS_TASK_PATH, {_taskId: '1234'}); | ||
icontrolMock.when('list', UCS_TASK_PATH + '/1234/result', {_taskState: 'COMPLETED'}); | ||
@@ -750,7 +751,6 @@ setTimeout = function(cb) { | ||
testBasic: function(test) { | ||
test.expect(1); | ||
bigIp.loadUcs('/tmp/foo') | ||
.then(function() { | ||
test.deepEqual(icontrolMock.getRequest('replace', TASK_PATH + '/1234'), {_taskState: 'VALIDATING'}); | ||
test.deepEqual(icontrolMock.getRequest('replace', UCS_TASK_PATH + '/1234'), {_taskState: 'VALIDATING'}); | ||
}) | ||
@@ -769,3 +769,3 @@ .catch(function(err) { | ||
.then(function() { | ||
var command = icontrolMock.getRequest('create', TASK_PATH); | ||
var command = icontrolMock.getRequest('create', UCS_TASK_PATH); | ||
test.deepEqual(command.options, [{foo: 'bar'}, {hello: 'world'}]); | ||
@@ -819,2 +819,17 @@ }) | ||
test.done(); | ||
});`` | ||
}, | ||
testFailed: function(test) { | ||
icontrolMock.when('list', UCS_TASK_PATH + '/1234/result', {_taskState: 'FAILED'}); | ||
test.expect(1); | ||
bigIp.loadUcs('foo') | ||
.then(function() { | ||
test.ok(false, 'Should not have completed'); | ||
}) | ||
.catch(function() { | ||
test.ok(true); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
@@ -824,3 +839,4 @@ }, | ||
testNeverComplete: function(test) { | ||
icontrolMock.when('list', TASK_PATH + '/1234/result', {_taskState: 'PENDING'}); | ||
icontrolMock.when('list', UCS_TASK_PATH + '/1234/result', {_taskState: 'PENDING'}); | ||
utilMock.DEFAULT_RETRY = {maxRetries: 0, retryIntervalMs: 0}; | ||
test.expect(1); | ||
@@ -858,19 +874,4 @@ bigIp.loadUcs('/tmp/foo', undefined, undefined, utilMock.NO_RETRY) | ||
testFailed: function(test) { | ||
icontrolMock.when('list', TASK_PATH + '/1234/result', {_taskState: 'FAILED'}); | ||
test.expect(1); | ||
bigIp.loadUcs('/tmp/foo') | ||
.then(function() { | ||
test.ok(false, 'Should not have completed'); | ||
}) | ||
.catch(function() { | ||
test.ok(true); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
}, | ||
testRestjavadRestart: function(test) { | ||
icontrolMock.fail('list', TASK_PATH + '/1234/result'); | ||
icontrolMock.fail('list', UCS_TASK_PATH + '/1234/result'); | ||
test.expect(1); | ||
@@ -1330,2 +1331,46 @@ bigIp.loadUcs('/tmp/foo', undefined, undefined, utilMock.NO_RETRY) | ||
testRunTask: { | ||
setUp: function(callback) { | ||
icontrolMock.when('create', DUMMY_TASK_PATH, {_taskId: '1234'}); | ||
icontrolMock.when('list', DUMMY_TASK_PATH + '/1234/result', {_taskState: 'COMPLETED'}); | ||
setTimeout = function(cb) { | ||
cb(); | ||
}; | ||
callback(); | ||
}, | ||
testBasic: function(test) { | ||
const commandBody = {foo: 'bar', hello: 'world'} | ||
test.expect(2); | ||
bigIp.runTask(DUMMY_TASK_PATH, commandBody) | ||
.then(function() { | ||
test.deepEqual(icontrolMock.getRequest('create', DUMMY_TASK_PATH), commandBody); | ||
test.deepEqual(icontrolMock.getRequest('replace', DUMMY_TASK_PATH + '/1234'), {_taskState: 'VALIDATING'}); | ||
}) | ||
.catch(function(err) { | ||
test.ok(false, err); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
}, | ||
testFailed: function(test) { | ||
icontrolMock.when('list', DUMMY_TASK_PATH + '/1234/result', {_taskState: 'FAILED'}); | ||
test.expect(1); | ||
bigIp.runTask(DUMMY_TASK_PATH) | ||
.then(function() { | ||
test.ok(false, 'Should not have completed'); | ||
}) | ||
.catch(function() { | ||
test.ok(true); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
} | ||
}, | ||
testSave: { | ||
@@ -1368,5 +1413,46 @@ testNoFile: function(test) { | ||
testTransaction: { | ||
testSaveUcs: { | ||
setUp: function(callback) { | ||
icontrolMock.when('create', UCS_TASK_PATH, {_taskId: '1234'}); | ||
icontrolMock.when('list', UCS_TASK_PATH + '/1234/result', {_taskState: 'COMPLETED'}); | ||
setTimeout = function(cb) { | ||
cb(); | ||
}; | ||
callback(); | ||
}, | ||
testBasic: function(test) { | ||
test.expect(1); | ||
bigIp.saveUcs('foo') | ||
.then(function() { | ||
test.deepEqual(icontrolMock.getRequest('replace', UCS_TASK_PATH + '/1234'), {_taskState: 'VALIDATING'}); | ||
}) | ||
.catch(function(err) { | ||
test.ok(false, err); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
}, | ||
testFailed: function(test) { | ||
icontrolMock.when('list', UCS_TASK_PATH + '/1234/result', {_taskState: 'FAILED'}); | ||
test.expect(1); | ||
bigIp.saveUcs('foo') | ||
.then(function() { | ||
test.ok(false, 'Should not have completed'); | ||
}) | ||
.catch(function() { | ||
test.ok(true); | ||
}) | ||
.finally(function() { | ||
test.done(); | ||
}); | ||
} | ||
}, | ||
testTransaction: { | ||
testBasic: function(test) { | ||
var commands = [ | ||
@@ -1373,0 +1459,0 @@ { |
@@ -22,2 +22,3 @@ /** | ||
var AutoscaleProvider = require('../../lib/autoscaleProvider'); | ||
var AutoscaleInstance = require('../../lib/autoscaleInstance'); | ||
var autoscale; | ||
@@ -51,2 +52,5 @@ var fsMock; | ||
var createWriteStream; | ||
var readdir; | ||
var stat; | ||
var rename; | ||
@@ -56,4 +60,7 @@ var execFile; | ||
var unlinkedFiles; | ||
var renamedFiles; | ||
var missingFilePrefix; | ||
var ucsBackupName; | ||
// Our tests cause too many event listeners. Turn off the check. | ||
@@ -134,2 +141,7 @@ var options = require('commander'); | ||
ProviderMock.prototype.storeUcs = function() { | ||
this.functionCalls.storeUcs = arguments; | ||
return q(); | ||
}; | ||
module.exports = { | ||
@@ -140,17 +152,15 @@ setUp: function(callback) { | ||
instanceId = "two"; | ||
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'); | ||
instances = { | ||
"one": { | ||
isMaster: false, | ||
hostname: 'host1', | ||
privateIp: '1.2.3.4', | ||
mgmtIp: '1.2.3.4', | ||
providerVisible: true | ||
}, | ||
"two": { | ||
isMaster: true, | ||
hostname: 'host2', | ||
privateIp: '5.6.7.8', | ||
mgmtIp: '5.6.7.8', | ||
providerVisible: true | ||
} | ||
"one": instance1, | ||
"two": instance2 | ||
}; | ||
@@ -185,9 +195,20 @@ | ||
createWriteStream = fsMock.createWriteStream; | ||
readdir = fsMock.readdir; | ||
stat = fsMock.stat; | ||
rename = fsMock.rename; | ||
execFile = childProcessMock.execFile; | ||
unlinkedFiles = []; | ||
renamedFiles = []; | ||
fsMock.unlinkSync = function(file) { | ||
unlinkedFiles.push(file); | ||
}; | ||
fsMock.rename = function(file, cb) { | ||
renamedFiles.push(file); | ||
cb(); | ||
} | ||
fsMock.writeFile = function(path, data, cb) { | ||
cb(); | ||
}; | ||
fsMock.unlinkSync = function() {}; | ||
@@ -308,2 +329,5 @@ providerMock = new ProviderMock(); | ||
fsMock.createWriteStream = createWriteStream; | ||
fsMock.readdir = readdir; | ||
fsMock.stat = stat; | ||
fsMock.rename = rename; | ||
@@ -794,2 +818,7 @@ childProcessMock.execFile = execFile; | ||
argv.push('--cluster-action', 'update'); | ||
bigIpMock.cluster.getCmSyncStatus = function() { | ||
return q({ | ||
disconnected: [] | ||
}); | ||
}; | ||
callback(); | ||
@@ -827,6 +856,2 @@ }, | ||
instanceId = "one"; | ||
unlinkedFiles = []; | ||
fsMock.unlinkSync = function(file) { | ||
unlinkedFiles.push(file); | ||
}; | ||
callback(); | ||
@@ -961,2 +986,58 @@ }, | ||
backupUcsTests: { | ||
setUp: function(callback) { | ||
argv.push('--cluster-action', 'backup-ucs'); | ||
ucsBackupName = undefined; | ||
bigIpMock.deviceInfo = function() { | ||
return q({ version: '13.1.0' }); | ||
}; | ||
bigIpMock.saveUcs = function(ucsName) { | ||
ucsBackupName = ucsName; | ||
return q(); | ||
}; | ||
fsMock.readdir = function(directory, cb) { | ||
cb(null, ['file1.ucs', 'ucsAutosave_1234.ucs']); | ||
}; | ||
callback(); | ||
}, | ||
testBasic: function(test) { | ||
autoscale.run(argv, testOptions, function() { | ||
test.ok(ucsBackupName.startsWith('ucsAutosave_')); | ||
test.done(); | ||
}); | ||
}, | ||
testOldFilesDeleted: function(test) { | ||
test.expect(2); | ||
autoscale.run(argv, testOptions, function() { | ||
test.strictEqual(unlinkedFiles.length, 1); | ||
test.strictEqual(unlinkedFiles[0], '/var/local/ucs/ucsAutosave_1234.ucs'); | ||
test.done(); | ||
}); | ||
}, | ||
testAjvCleanup: function(test) { | ||
bigIpMock.deviceInfo = function() { | ||
return q({ version: '13.0.0' }); | ||
}; | ||
fsMock.stat = function(file, cb) { | ||
if (file.endsWith('/ajv/lib/$data.js')) { | ||
cb(new Error()); | ||
} | ||
else { | ||
cb(null); | ||
} | ||
}; | ||
test.expect(2); | ||
autoscale.run(argv, testOptions, function() { | ||
test.strictEqual(renamedFiles.length, 1); | ||
test.ok(renamedFiles[0].endsWith('ajv/lib/refs/$data.json')); | ||
test.done(); | ||
}); | ||
} | ||
}, | ||
messagingTests: { | ||
@@ -963,0 +1044,0 @@ setUp: function(callback) { |
@@ -123,3 +123,3 @@ # Usage | ||
--provider-options <cloud_options> Options specific to cloud_provider. Ex: param1:value1,param2:value2 (default: [object Object]) | ||
-c, --cluster-action <type> join (join a cluster) | update (update cluster to match existing instances | unblock-sync (allow other devices to sync to us) | ||
-c, --cluster-action <type> join (join a cluster) | update (update cluster to match existing instances | unblock-sync (allow other devices to sync to us) | backup-ucs (save a ucs to cloud storage) | ||
--device-group <device_group> Device group name. | ||
@@ -146,2 +146,3 @@ --full-load-on-sync Enable full load on sync. Default false. | ||
--dns-provider-options <dns_provider_options> Options specific to dns_provider. Ex: param1:value1,param2:value2 (default: [object Object]) | ||
--max-ucs-files <max_ucs_files_to_save> When running cluster action backup-ucs, maximum number of backup files to keep. (default: 7) | ||
-h, --help output usage information | ||
@@ -148,0 +149,0 @@ ## network.js |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
957460
81
22179