function addTestVms(nbVms, concurrency, data) { assert.finite(nbVms, 'nbVms must be a number'); assert.ok(nbVms > 0, 'nbVms must be a positive number'); assert.finite(concurrency, 'concurrency must be a number'); assert.ok(concurrency > 0, 'concurrency must be a positive number'); assert.optionalObject(data, 'data must be an optional object'); var morayConfig = jsprim.deepCopy(config.moray); morayConfig.reconnect = true; data = data || {}; var morayClient; var moray; var morayBucketsInitializer; var moraySetup = morayInit.startMorayInit({ morayConfig: morayConfig, maxBucketsReindexAttempts: 1, maxBucketsSetupAttempts: 1, changefeedPublisher: changefeedUtils.createNoopCfPublisher() }); morayClient = moraySetup.morayClient; moray = moraySetup.moray; morayBucketsInitializer = moraySetup.morayBucketsInitializer; morayBucketsInitializer.on('done', function onMorayBucketsSetup() { log.debug('Number of test VMs to create:', nbVms); assert.number(nbVms); log.debug('concurrency:', concurrency); assert.number(concurrency); testVm.createTestVMs(nbVms, moray, { concurrency: concurrency, log: log }, data, function allVmsCreated(err) { if (err) { log.error({err: err}, 'Error when creating test VMs'); } else { log.info('All VMs created successfully'); } log.debug('Closing moray connection'); morayClient.close(); }); }); }
/* * Returns true if the response object "res" represents a response indicating a * successful HTTP request. */ function responseIndicatesSuccess(res) { assert.object(res, 'res'); assert.finite(res.statusCode, 'res.statusCode'); // Any 20X HTTP status code is considered to represent a successful request. return Math.floor(res.statusCode / 100) === 2; }
function createSocket (opts) { assert.object(opts, 'options'); assert.string(opts.host, 'options.host'); assert.finite(opts.port, 'options.port'); assert.object(opts.proxy, 'options.proxy'); assert.optionalBool(opts.tls, 'options.tls'); var transport = opts.tls ? tls : net; var socket = transport.connect({ host: opts.host, port: opts.port }); PROXY_EVENTS.forEach(function (event) { socket.on(event, opts.proxy.emit.bind(opts.proxy, event)); }); return (socket); }
/* * Import the given set of image objects (`args.imgs`) with the given * concurrency. * * @param {Object} args * - {Array} args.imgs - The array of image objects to import. * - {String} args.source - The source IMGAPI URL. * - {Number} args.concurrency - An integer number of images to import at * the same time. * - {Object} args.sdcadm - SdcAdm object. * - {Function} args.progress - Progress output function. * @param {Function} cb - called as `cb(err)` where `err` is null or * a single error, or a `verror.MultiError` if multiple concurrent imports * failed. * * Dev Note: If there are multiple errors, then `err` will be a * `verror.MultiError` -- which is different from a `errors.MultiError`. * This is an unfortunate middle ground, until sdcadm transitions from * its "errors.js" wrappers to raw VError instances using facilities * in verror v1.7.0 (see RFD 41). */ function importSetOfImages(args, cb) { assert.arrayOfObject(args.imgs, 'args.imgs'); assert.string(args.source, 'args.source'); assert.object(args.sdcadm, 'args.sdcadm'); assert.func(args.progress, 'args.progress'); assert.finite(args.concurrency, 'args.concurrency'); assert.func(cb, 'cb'); var errs = []; var progress = args.progress; var sdcadm = args.sdcadm; var q = vasync.queuev({ concurrency: args.concurrency, worker: function importAnImage(image, nextImg) { /* * Need to be verified here b/c there are callers other than * procedures/index.js calling DownloadImages. */ function checkIfImageIsUnactivated(_, nextStep) { if (image.state === 'unactivated') { nextStep(); return; } sdcadm.imgapi.getImage(image.uuid, function (err, local) { if (err && err.body.code === 'ResourceNotFound') { nextStep(); } else if (err) { nextStep(new errors.SDCClientError(err, 'imgapi')); } else { if (local.state === 'unactivated') { // Let DownloadImages know that it has to // remove the image first: image.state = 'unactivated'; } nextStep(); } }); } function deleteImage(_, nextStep) { if (image.state !== 'unactivated') { nextStep(); return; } progress('Removing unactivated image %s\n(%s@%s)', image.uuid, image.name, image.version); sdcadm.imgapi.deleteImage(image.uuid, function (err) { if (err) { progress('Error removing unactivated image %s\n(%s@%s)', image.uuid, image.name, image.version); var e = new errors.SDCClientError(err, 'imgapi'); e.image = image.uuid; sdcadm.log.error({err: e}, 'Error removing image'); nextStep(e); } else { nextStep(); } }); } function getImage(_, nextStep) { progress('Downloading image %s\n (%s@%s)', image.uuid, image.name, image.version); sdcadm.imgapi.adminImportRemoteImageAndWait( image.uuid, args.source, { // TODO: Once IMGAPI-408 is sufficient deployed, // then drop this `skipOwnerCheck`. skipOwnerCheck: true, // Retry image import 5 times by default: retries: 5 }, function (err, _img, res) { if (err) { progress('Error importing image %s\n (%s@%s)', image.uuid, image.name, image.version); var e = new errors.SDCClientError(err, 'imgapi'); e.image = image.uuid; nextStep(e); } else { progress('Imported image %s\n (%s@%s)', image.uuid, image.name, image.version); nextStep(); } }); } vasync.pipeline({funcs: [ checkIfImageIsUnactivated, deleteImage, getImage ]}, nextImg); } }); function onTaskComplete(err) { if (err) { errs.push(err); /* * Don't start more tasks. After a single image import failure * we want to fail reasonably fast, i.e. *not* wait for another * N image imports to be started from the queue. */ q.kill(); } } q.on('end', function done() { cb(VError.errorFromList(errs)); }); q.push(args.imgs, onTaskComplete); q.close(); }
/* * This function creates a large number of "test" VMs * (VMs with alias='test--'), and then sends GET requests to /vms to retrieve * them by passing a specific "limit" value. * It then makes sure that the correct number of VMs are included in the * results, that is the number of VMs created, unless it's greater than the * maximum value for "limit". */ function testValidLimit(limit, t, callback) { assert.finite(limit, 'options'); assert.object(t, 't'); assert.func(callback, 'callback'); var NB_TEST_VMS_TO_CREATE = limit + 1; var EXPECTED_NB_VMS_RETURNED = Math.min(limit, MAX_LIMIT); // limit === 0 means "unlimited" if (limit === 0) { EXPECTED_NB_VMS_RETURNED = NB_TEST_VMS_TO_CREATE; } async.series([ // Delete test VMs leftover from previous tests run function deleteTestVms(next) { vmTest.deleteTestVMs(moray, {}, function vmsDeleted(err) { t.ifError(err, 'deleting test VMs should not error'); return next(err); }); }, function createFakeVms(next) { vmTest.createTestVMs(NB_TEST_VMS_TO_CREATE, moray, {concurrency: 100}, {}, function fakeVmsCreated(err, vmUuids) { t.equal(vmUuids.length, NB_TEST_VMS_TO_CREATE, NB_TEST_VMS_TO_CREATE + ' vms should have been created'); t.ifError(err, NB_TEST_VMS_TO_CREATE + ' vms should be created successfully'); return next(err); }); }, function listVmsWithLimit(next) { var listVmsQuery = '/vms?limit=' + limit + '&alias=' + vmTest.TEST_VMS_ALIAS; client.get(listVmsQuery, function (err, req, res, body) { t.ifError(err); if (err) return next(err); t.equal(res.headers['x-joyent-resource-count'], NB_TEST_VMS_TO_CREATE, 'x-joyent-resource-count header should be equal to ' + NB_TEST_VMS_TO_CREATE); t.equal(body.length, EXPECTED_NB_VMS_RETURNED, EXPECTED_NB_VMS_RETURNED + ' vms should be returned from list vms'); return next(null); }); } ], function allDone(err, results) { t.ifError(err); return callback(); }); }
config = JSON.parse(contents); } else { config = { instances: [], logLevel: 'info', pollInterval: 120000 }; } if (ARGV['sapi-url']) { config.sapi = { url: ARGV['sapi-url'] }; } assert.object(config, 'config'); assert.string(config.logLevel, 'config.logLevel'); assert.finite(config.pollInterval, 'config.pollInterval'); assert.optionalObject(config.sapi, 'config.sapi'); var log = bunyan.createLogger({ name: 'config-agent', level: config.logLevel, stream: process.stdout, serializers: bunyan.stdSerializers }); var agent; var zonename; // For now we stash `autoMetadata` onto the config object. // TODO(refactor): pass autoMetadata as an opt to `new Agent`.