Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Add a ghost unit right after deploying a service. #301

Merged
merged 1 commit into from May 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/models/models.js
Expand Up @@ -636,7 +636,11 @@ YUI.add('juju-models', function(Y) {
obj.number = parseInt(raw[1], 10);
obj.urlName = obj.id.replace('/', '-');
obj.name = 'serviceUnit'; // This lets us more easily mimic models.
obj.displayName = this.createDisplayName(obj.id);
if (!obj.displayName) {
// The display name can be provided by callers, e.g. in the case a
// ghost unit is being added to a ghost service.
obj.displayName = this.createDisplayName(obj.id);
}
},

/**
Expand Down
6 changes: 5 additions & 1 deletion app/store/env/fakebackend.js
Expand Up @@ -496,7 +496,11 @@ YUI.add('juju-env-fakebackend', function(Y) {
// This is the current behavior in both implementations.
unitCount = 1;
}
var response = this.addUnit(options.name, unitCount, options.toMachine);
var response = {};
// Add units if requested.
if (unitCount !== 0) {
response = this.addUnit(options.name, unitCount, options.toMachine);
}
response.service = service;
callback(response);
},
Expand Down
38 changes: 29 additions & 9 deletions app/views/ghost-deployer-extension.js
Expand Up @@ -55,27 +55,47 @@ YUI.add('ghost-deployer-extension', function(Y) {
this._setupXYAnnotations(ghostAttributes, ghostService);

if (window.flags && window.flags.il) {
var serviceName = charm.get('name') + '-' +
Math.floor((Math.random() * 1000) + 1);
var constraints = { 'arch': '', 'cpu-cores': '', 'cpu-power': '',
'mem': '', 'root-disk': '', 'tags': '' };
var ghostServiceId = ghostService.get('id');
// XXX frankban 2014-05-11:
// after the ODS demo, find a smarter way to set a unique service name.
var serviceName = charm.get('name');
var charmId = charm.get('id');
var config = {};
var constraints = {};
this.env.deploy(
charm.get('id'),
charmId,
serviceName,
config,
undefined, // config file content
1, // number of units
undefined, // Config file content.
0, // Number of units.
constraints,
null, // toMachine
null, // toMachine.
Y.bind(this._deployCallbackHandler,
this,
serviceName,
config,
constraints,
ghostService),
// Options used by ECS, ignored by environment
{ modelId: ghostService.get('id') });
{modelId: ghostServiceId});

// Add an unplaced unit to this service.
// The service is not yet deployed (we just added it to ECS), so we can
// safely assume the first unit to be unit 0. Each subsequent unit
// added to the ghost service would have number
// `ghostService.get('units').size()`.
db.addUnits({
id: ghostServiceId + '/0',
displayName: serviceName + '/0',
charmUrl: charmId,
is_subordinate: charm.get('is_subordinate')
});
// XXX frankban 2014-05-11:
// Add an ECS add_unit record by calling this.env.add_unit.
// The call is not yet implemented.
// When adding the call, attach a callback that, when called, removes
// all the ghost units for this service. Real units should be then
// created reacting to the mega-watcher changes.
} else {
var environment = this.views.environment.instance;
environment.createServiceInspector(ghostService);
Expand Down
22 changes: 18 additions & 4 deletions test/test_fakebackend.js
Expand Up @@ -143,9 +143,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
fakebackend.db.charms.getById('cs:precise/wordpress-15'),
'Fakebackend returned null when a charm was expected.');
var service = fakebackend.db.services.getById('wordpress');
assert.isObject(
service,
'Null returend when a service was expected.');
assert.isObject(service, 'Null returned when a service was expected.');
assert.strictEqual(service, result.service);
var attrs = service.getAttrs();
// clientId varies.
Expand Down Expand Up @@ -305,7 +303,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
});
});


it('deploys multiple units.', function() {
fakebackend.deploy('cs:precise/wordpress-15', callback, {unitCount: 3});
var units = result.service.get('units').toArray();
Expand All @@ -314,6 +311,23 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
assert.deepEqual(units, result.units);
});

it('returns an error when adding multiple units to a machine', function() {
fakebackend.deploy(
'cs:precise/wordpress-15', callback, {unitCount: 3, toMachine: '2'});
assert.strictEqual(
result.error,
'When deploying to a specific machine, ' +
'the number of units requested must be 1.');
});

it('allows deploying a service without units', function() {
fakebackend.deploy('cs:precise/wordpress-15', callback, {unitCount: 0});
// There is no error.
assert.isUndefined(result.error);
// No units have been added.
assert.strictEqual(result.service.get('units').size(), 0);
});

it('reports when the API is inaccessible.', function() {
fakebackend.get('store').charm = function(path, callbacks, bindscope) {
callbacks.failure({boo: 'hiss'});
Expand Down
71 changes: 66 additions & 5 deletions test/test_ghost_deployer_extension.js
Expand Up @@ -49,8 +49,13 @@ describe('Ghost Deployer Extension', function() {
var getMethod = utils.makeStubFunction();
ghostDeployer.db = {
charms: { add: utils.makeStubFunction({ get: getMethod }) },
services: { ghostService: utils.makeStubFunction({ get: getMethod }) },
notifications: { add: utils.makeStubFunction() }
services: {
ghostService: utils.makeStubFunction({
get: utils.makeStubFunction('ghost-service-id')
})
},
notifications: { add: utils.makeStubFunction() },
addUnits: utils.makeStubFunction()
};
});

Expand All @@ -59,11 +64,67 @@ describe('Ghost Deployer Extension', function() {
window.flags = {};
});

// Create and return a charm model instance.
var makeCharm = function() {
return new Y.Model({
id: 'cs:trusty/django-42',
name: 'django',
is_subordinate: false
});
};

it('calls the env deploy method with the default charm data', function() {
window.flags.il = true;
var charmGetStub = utils.makeStubFunction();
ghostDeployer.deployService({ get: charmGetStub });
assert.equal(ghostDeployer.env.deploy.calledOnce(), true);
var charm = makeCharm();
ghostDeployer.deployService(charm);
assert.strictEqual(ghostDeployer.env.deploy.calledOnce(), true);
var args = ghostDeployer.env.deploy.lastArguments();
assert.strictEqual(args[0], 'cs:trusty/django-42'); // Charm URL.
assert.strictEqual(args[1], 'django'); // Service name.
assert.deepEqual(args[2], {}); // Config.
assert.strictEqual(args[4], 0); // Number of units.
assert.deepEqual(args[5], {}); // Constraints.
assert.isNull(args[6]); // Machine placement.
});

it('adds the ECS modelId option when deploying the charm', function() {
window.flags.il = true;
var charm = makeCharm();
ghostDeployer.deployService(charm);
assert.strictEqual(ghostDeployer.env.deploy.calledOnce(), true);
var args = ghostDeployer.env.deploy.lastArguments();
var options = args[args.length - 1];
assert.property(options, 'modelId');
// The model id is the ghost service identifier.
assert.strictEqual(options.modelId, 'ghost-service-id');
});

it('creates a ghost service', function() {
window.flags.il = true;
var charm = makeCharm();
ghostDeployer.deployService(charm);
var services = ghostDeployer.db.services;
assert.strictEqual(services.ghostService.calledOnce(), true);
var args = services.ghostService.lastArguments();
assert.lengthOf(args, 1);
assert.deepEqual(args[0], charm);
});

it('creates a ghost unit', function() {
window.flags.il = true;
var charm = makeCharm();
ghostDeployer.deployService(charm);
var db = ghostDeployer.db;
assert.strictEqual(db.addUnits.calledOnce(), true);
var args = db.addUnits.lastArguments();
assert.lengthOf(args, 1);
var expectedUnit = {
id: 'ghost-service-id/0',
displayName: charm.get('name') + '/0',
charmUrl: charm.get('id'),
is_subordinate: charm.get('is_subordinate')
};
assert.deepEqual(args[0], expectedUnit);
});

it('sets the proper annotations in the deploy handler', function() {
Expand Down