diff --git a/app/app.js b/app/app.js
index 62c5013aae..cc2fc4b6de 100644
--- a/app/app.js
+++ b/app/app.js
@@ -511,6 +511,14 @@ YUI.add('juju-gui', function(Y) {
// Once the user logs in, we need to redraw.
this.env.after('login', this.onLogin, this);
+ // Once we know about MAAS server, update the header accordingly.
+ var maasServer = this.env.get('maasServer');
+ if (maasServer === undefined) {
+ this.env.once('maasServerChange', this._onMaasServer, this);
+ } else {
+ this._displayMaasLink(maasServer);
+ }
+
// Feed environment changes directly into the database.
this.env.on('delta', this.db.onDelta, this.db);
@@ -1215,6 +1223,34 @@ YUI.add('juju-gui', function(Y) {
}
},
+ /**
+ If we are in a MAAS environment, react to the MAAS server address
+ retrieval adding a link to the header pointing to the MAAS server.
+
+ @method _onMaasServer
+ @param {Object} evt An event object (with a "newVal" attribute).
+ */
+ _onMaasServer: function(evt) {
+ this._displayMaasLink(evt.newVal);
+ },
+
+ /**
+ If the given maasServer is not null, create a link to the MAAS server
+ in the GUI header.
+
+ @method _displayMaasLink
+ @param {String} maasServer The MAAS server URL (or null if not in MAAS).
+ */
+ _displayMaasLink: function(maasServer) {
+ if (maasServer === null) {
+ // The current environment is not MAAS.
+ return;
+ }
+ var maasContainer = Y.one('#maas-server');
+ maasContainer.one('a').set('href', maasServer);
+ maasContainer.show();
+ },
+
/**
Hides the fullscreen mask and stops the spinner.
diff --git a/app/index.html b/app/index.html
index ad9472dd3c..2372bf87f1 100644
--- a/app/index.html
+++ b/app/index.html
@@ -161,6 +161,9 @@
+
+ MAAS UI
+
Logout
diff --git a/app/store/env/fakebackend.js b/app/store/env/fakebackend.js
index bf9c668055..a9232e2d10 100644
--- a/app/store/env/fakebackend.js
+++ b/app/store/env/fakebackend.js
@@ -47,13 +47,14 @@ YUI.add('juju-env-fakebackend', function(Y) {
FakeBackend.NAME = 'fake-backend';
FakeBackend.ATTRS = {
- authorizedUsers: {value: {'admin': 'password'}},
- token: {value: 'demoToken'},
authenticated: {value: false},
- store: {required: true},
+ authorizedUsers: {value: {'admin': 'password'}},
defaultSeries: {value: 'precise'},
+ name: {value: 'Environment'},
+ maasServer: {value: null},
providerType: {value: 'demonstration'},
- name: {value: 'Environment'}
+ store: {required: true},
+ token: {value: 'demoToken'}
};
Y.extend(FakeBackend, Y.Base, {
diff --git a/app/store/env/go.js b/app/store/env/go.js
index 983782b495..c5b6cd2736 100644
--- a/app/store/env/go.js
+++ b/app/store/env/go.js
@@ -475,6 +475,10 @@ YUI.add('juju-env-go', function(Y) {
// For now we only need to call environmentGet if the provider is MAAS.
if (response.ProviderType === 'maas') {
this.environmentGet();
+ } else {
+ // Set the MAAS server to null, so that subscribers waiting for this
+ // attribute to be set can be released.
+ this.set('maasServer', null);
}
}
},
diff --git a/app/store/env/sandbox.js b/app/store/env/sandbox.js
index 80f6d240a7..c45059d8c8 100644
--- a/app/store/env/sandbox.js
+++ b/app/store/env/sandbox.js
@@ -846,7 +846,7 @@ YUI.add('juju-env-sandbox', function(Y) {
},
/**
- Handle EnvironmentView messages.
+ Handle EnvironmentInfo messages.
@method handleClientEnvironmentInfo
@param {Object} data The contents of the API arguments.
@@ -865,6 +865,24 @@ YUI.add('juju-env-sandbox', function(Y) {
});
},
+ /**
+ Handle EnvironmentGet messages.
+
+ @method handleClientEnvironmentGet
+ @param {Object} data The contents of the API arguments.
+ @param {Object} client The active ClientConnection.
+ @param {Object} state An instance of FakeBackend.
+ */
+ handleClientEnvironmentGet: function(data, client, state) {
+ client.receive({
+ RequestId: data.RequestId,
+ Response: {
+ // For now only the MAAS server is required by the GUI.
+ Config: {'maas-server': state.get('maasServer')}
+ }
+ });
+ },
+
/**
A white-list for model attributes. This translates them from the raw ATTRS
to the format expected by the environment's delta handling.
diff --git a/test/test_app.js b/test/test_app.js
index e778b1eb75..3395e6bf5c 100644
--- a/test/test_app.js
+++ b/test/test_app.js
@@ -347,6 +347,77 @@ function injectData(app, data) {
done();
});
});
+
+ describe('MAAS support', function() {
+ var env, maasNode;
+
+ beforeEach(function() {
+ // Set up the MAAS link node.
+ maasNode = Y.Node.create(
+ '');
+ container.appendChild(maasNode);
+ // Create the environment.
+ env = new juju.environments.GoEnvironment({
+ conn: new utils.SocketStub(),
+ ecs: new juju.EnvironmentChangeSet()
+ });
+ });
+
+ // Ensure the given MAAS node is shown and includes a link to the given
+ // address.
+ var assertMaasLinkExists = function(node, address) {
+ assert.strictEqual(node.getStyle('display'), 'block');
+ assert.strictEqual(node.one('a').get('href'), address);
+ };
+
+ it('shows a link to the MAAS server if provider is MAAS', function() {
+ constructAppInstance({env: env});
+ // The MAAS node is initially hidden.
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ env.set('maasServer', 'http://1.2.3.4/MAAS');
+ // Once the MAAS server becomes available, the node is activated and
+ // includes a link to the server.
+ assertMaasLinkExists(maasNode, 'http://1.2.3.4/MAAS');
+ // Further changes to the maasServer attribute don't change the link.
+ env.set('maasServer', 'http://example.com/MAAS');
+ assertMaasLinkExists(maasNode, 'http://1.2.3.4/MAAS');
+ });
+
+ it('shows a link to the MAAS server if already in the env', function() {
+ env.set('maasServer', 'http://1.2.3.4/MAAS');
+ constructAppInstance({env: env});
+ // The link to the MAAS server should be already activated.
+ assertMaasLinkExists(maasNode, 'http://1.2.3.4/MAAS');
+ // Further changes to the maasServer attribute don't change the link.
+ env.set('maasServer', 'http://example.com/MAAS');
+ assertMaasLinkExists(maasNode, 'http://1.2.3.4/MAAS');
+ });
+
+ it('does not show the MAAS link if provider is not MAAS', function() {
+ constructAppInstance({env: env});
+ // The MAAS node is initially hidden.
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ env.set('maasServer', null);
+ // The MAAS node is still hidden.
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ // Further changes to the maasServer attribute don't activate the link.
+ env.set('maasServer', 'http://1.2.3.4/MAAS');
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ });
+
+ it('does not show the MAAS link if already null in the env', function() {
+ env.set('maasServer', null);
+ constructAppInstance({env: env});
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ // Further changes to the maasServer attribute don't activate the link.
+ env.set('maasServer', 'http://1.2.3.4/MAAS');
+ assert.strictEqual(maasNode.getStyle('display'), 'none');
+ });
+
+ });
+
});
})();
diff --git a/test/test_app_hotkeys.js b/test/test_app_hotkeys.js
index 4c294a5e0f..6f1f4a3a42 100644
--- a/test/test_app_hotkeys.js
+++ b/test/test_app_hotkeys.js
@@ -28,6 +28,7 @@ describe('application hotkeys', function() {
after: function() {},
get: function() {},
on: function() {},
+ once: function() {},
set: function() {}
};
windowNode = Y.one(window);
diff --git a/test/test_env_go.js b/test/test_env_go.js
index 5f000e7d54..4011758667 100644
--- a/test/test_env_go.js
+++ b/test/test_env_go.js
@@ -507,6 +507,8 @@ with this program. If not, see .
});
it('does not call EnvironmentGet after Info when not on MAAS', function() {
+ // The MAAS server attribute is initially undefined.
+ assert.isUndefined(env.get('maasServer'));
// Simulate an EnvironmentInfo request/response.
env.environmentInfo();
conn.msg({
@@ -518,6 +520,8 @@ with this program. If not, see .
}
});
assert.lengthOf(conn.messages, 1);
+ // The MAAS server attribute has been set to null.
+ assert.isNull(env.get('maasServer'));
});
it('sends the correct AddServiceUnits message', function() {
diff --git a/test/test_sandbox_go.js b/test/test_sandbox_go.js
index 55d63a3541..48f3b241c6 100644
--- a/test/test_sandbox_go.js
+++ b/test/test_sandbox_go.js
@@ -245,6 +245,26 @@ with this program. If not, see .
client.send(Y.JSON.stringify(data));
});
+ it('returns EnvironmentGet responses', function(done) {
+ var data = {
+ RequestId: 42,
+ Type: 'Client',
+ Request: 'EnvironmentGet'
+ };
+ client.onmessage = function(received) {
+ var expected = {
+ RequestId: 42,
+ Response: {
+ Config: {'maas-server': state.get('maasServer')}
+ }
+ };
+ assert.deepEqual(Y.JSON.parse(received.data), expected);
+ done();
+ };
+ client.open();
+ client.send(Y.JSON.stringify(data));
+ });
+
it('can start the AllWatcher', function(done) {
var data = {
Type: 'Client',