diff --git a/nailgun/nailgun/api/v1/urls.py b/nailgun/nailgun/api/v1/urls.py
index 61701af8fe..7d9d82294b 100644
--- a/nailgun/nailgun/api/v1/urls.py
+++ b/nailgun/nailgun/api/v1/urls.py
@@ -366,5 +366,4 @@ def public_urls():
return {
r'/nodes/?$': ['POST'],
r'/nodes/agent/?$': ['PUT'],
- r'/version/?$': ['GET']
}
diff --git a/nailgun/nailgun/test/integration/test_public_api.py b/nailgun/nailgun/test/integration/test_public_api.py
index aec8f61aec..8fab173f2c 100644
--- a/nailgun/nailgun/test/integration/test_public_api.py
+++ b/nailgun/nailgun/test/integration/test_public_api.py
@@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from mock import patch
from oslo_serialization import jsonutils
from nailgun.test.base import BaseAuthenticationIntegrationTest
@@ -47,37 +46,3 @@ class TestPublicHandlers(BaseAuthenticationIntegrationTest):
headers=self.default_headers)
self.assertEqual(201, resp.status_code)
-
- def test_version_api(self):
- resp = self.app.get(
- reverse('VersionHandler'),
- headers=self.default_headers
- )
- self.assertEqual(200, resp.status_code)
-
- @patch('nailgun.api.v1.handlers.version.utils.get_fuel_release_versions')
- def test_500_no_html_dev(self, handler_get):
- exc_text = "Here goes an exception"
- handler_get.side_effect = Exception(exc_text)
- resp = self.app.get(
- reverse('VersionHandler'),
- headers=self.default_headers,
- expect_errors=True
- )
- self.assertEqual(500, resp.status_code)
- self.assertIn(exc_text, resp.body)
- self.assertIn("Traceback", resp.body)
- self.assertNotIn("html", resp.body)
-
- @patch('nailgun.api.v1.handlers.version.utils.get_fuel_release_versions')
- def test_500_no_html_production(self, handler_get):
- exc_text = "Here goes an exception"
- handler_get.side_effect = Exception(exc_text)
- with patch('nailgun.settings.settings.DEVELOPMENT', 0):
- resp = self.app.get(
- reverse('VersionHandler'),
- headers=self.default_headers,
- expect_errors=True
- )
- self.assertEqual(500, resp.status_code)
- self.assertEqual(exc_text, resp.body)
diff --git a/nailgun/nailgun/test/integration/test_version_api.py b/nailgun/nailgun/test/integration/test_version_api.py
new file mode 100644
index 0000000000..26190a9dd5
--- /dev/null
+++ b/nailgun/nailgun/test/integration/test_version_api.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2016 Mirantis, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from mock import patch
+
+from nailgun.test.base import BaseAuthenticationIntegrationTest
+from nailgun.test.base import reverse
+
+
+class TestVersionApi(BaseAuthenticationIntegrationTest):
+ """Test the version api
+
+ Test the version api to make sure it requires authentication
+ and works when passed a valid auth token.
+ """
+
+ def setUp(self):
+ super(TestVersionApi, self).setUp()
+ self.token = self.get_auth_token()
+ self.headers = copy.deepcopy(self.default_headers)
+
+ def test_version_api_noauth(self):
+ """Check that version api requires auth."""
+ resp = self.app.get(
+ reverse('VersionHandler'),
+ headers=self.default_headers,
+ expect_errors=True
+ )
+ self.assertEqual(401, resp.status_code)
+
+ def test_version_api_auth(self):
+ """Check that version api works with auth."""
+ self.headers['X-Auth-Token'] = self.token
+ resp = self.app.get(
+ reverse('VersionHandler'),
+ headers=self.headers
+ )
+ self.assertEqual(200, resp.status_code)
+
+ @patch('nailgun.api.v1.handlers.version.utils.get_fuel_release_versions')
+ def test_500_no_html_dev(self, handler_get):
+ exc_text = "Here goes an exception"
+ handler_get.side_effect = Exception(exc_text)
+ self.headers['X-Auth-Token'] = self.token
+ resp = self.app.get(
+ reverse('VersionHandler'),
+ headers=self.headers,
+ expect_errors=True
+ )
+ self.assertEqual(500, resp.status_code)
+ self.assertIn(exc_text, resp.body)
+ self.assertIn("Traceback", resp.body)
+ self.assertNotIn("html", resp.body)
+
+ @patch('nailgun.api.v1.handlers.version.utils.get_fuel_release_versions')
+ def test_500_no_html_production(self, handler_get):
+ exc_text = "Here goes an exception"
+ handler_get.side_effect = Exception(exc_text)
+ self.headers['X-Auth-Token'] = self.token
+ with patch('nailgun.settings.settings.DEVELOPMENT', 0):
+ resp = self.app.get(
+ reverse('VersionHandler'),
+ headers=self.headers,
+ expect_errors=True
+ )
+ self.assertEqual(500, resp.status_code)
+ self.assertEqual(exc_text, resp.body)
diff --git a/nailgun/static/app.js b/nailgun/static/app.js
index 9fc9d88579..9279da0718 100644
--- a/nailgun/static/app.js
+++ b/nailgun/static/app.js
@@ -153,29 +153,35 @@ function($, _, i18n, Backbone, React, utils, layoutComponents, Coccyx, models, K
this.mountNode = $('#main-container');
this.router = new Router();
- this.keystoneClient = new KeystoneClient('/keystone', {
- cacheTokenFor: 10 * 60 * 1000,
- tenant: 'admin'
- });
this.version = new models.FuelVersion();
this.settings = new models.FuelSettings();
this.user = new models.User();
this.statistics = new models.NodesStatistics();
this.notifications = new models.Notifications();
-
+ this.keystoneClient = new KeystoneClient('/keystone', {
+ cacheTokenFor: 10 * 60 * 1000,
+ tenant: 'admin',
+ token: this.user.get('token')
+ });
this.fetchData();
}
_.extend(App.prototype, {
fetchData: function() {
- this.version.fetch().then(_.bind(function() {
+ this.version.fetch().then(null, _.bind(function(response) {
+ if (response.status == 401) {
+ this.version.set({auth_required: true});
+ return $.Deferred().resolve();
+ }
+ }, this)).then(_.bind(function() {
this.user.set({authenticated: !this.version.get('auth_required')});
this.patchBackboneSync();
if (this.version.get('auth_required')) {
_.extend(this.keystoneClient, this.user.pick('token'));
return this.keystoneClient.authenticate()
- .done(_.bind(function() {
+ .then(_.bind(function() {
this.user.set({authenticated: true});
+ return this.version.fetch({cache: true});
}, this));
}
return $.Deferred().resolve();
@@ -233,7 +239,7 @@ function($, _, i18n, Backbone, React, utils, layoutComponents, Coccyx, models, K
if (method == 'patch') {
method = 'update';
}
- if (app.version.get('auth_required') && !this.authExempt) {
+ if (app.version && app.version.get('auth_required')) {
// FIXME(vkramskikh): manually moving success/error callbacks
// to deferred-style callbacks. Everywhere in the code we use
// deferreds, but backbone uses success/error callbacks. It
@@ -249,6 +255,7 @@ function($, _, i18n, Backbone, React, utils, layoutComponents, Coccyx, models, K
app.logout();
})
.then(_.bind(function() {
+ app.user.set('token', app.keystoneClient.token);
options = options || {};
options.headers = options.headers || {};
options.headers['X-Auth-Token'] = app.keystoneClient.token;
diff --git a/nailgun/static/keystone_client.js b/nailgun/static/keystone_client.js
index 3b068c471d..6f605d8fde 100644
--- a/nailgun/static/keystone_client.js
+++ b/nailgun/static/keystone_client.js
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations
* under the License.
**/
-define(['jquery', 'underscore', 'js-cookie'], function($, _, Cookies) {
+define(['jquery', 'underscore'], function($, _) {
'use strict';
function KeystoneClient(url, options) {
@@ -57,9 +57,6 @@ define(['jquery', 'underscore', 'js-cookie'], function($, _, Cookies) {
this.userId = result.access.user.id;
this.token = result.access.token.id;
this.tokenUpdateTime = new Date();
-
- Cookies.set('token', result.access.token.id);
-
return deferred;
} catch(e) {
return $.Deferred().reject();
@@ -88,9 +85,6 @@ define(['jquery', 'underscore', 'js-cookie'], function($, _, Cookies) {
try {
this.token = result.access.token.id;
this.tokenUpdateTime = new Date();
-
- Cookies.set('token', result.access.token.id);
-
return deferred;
} catch(e) {
return $.Deferred().reject();
@@ -111,8 +105,6 @@ define(['jquery', 'underscore', 'js-cookie'], function($, _, Cookies) {
delete this.token;
delete this.tokenUpdateTime;
- Cookies.remove('token');
-
this.tokenRemoveRequest = $.ajax(this.url + '/v2.0/tokens/' + token, {
type: 'DELETE',
dataType: 'json',
diff --git a/nailgun/static/models.js b/nailgun/static/models.js
index 8bf8cea6dd..23d359faa9 100644
--- a/nailgun/static/models.js
+++ b/nailgun/static/models.js
@@ -22,8 +22,9 @@ define([
'expression',
'expression/objects',
'jsx!views/custom_controls',
+ 'js-cookie',
'deepModel'
-], function($, _, i18n, Backbone, utils, Expression, expressionObjects, customControls) {
+], function($, _, i18n, Backbone, utils, Expression, expressionObjects, customControls, Cookies) {
'use strict';
var models = {};
@@ -83,6 +84,7 @@ define([
if (this.cacheFor && options && options.cache && this.lastSyncTime && (this.cacheFor > (new Date() - this.lastSyncTime))) {
return $.Deferred().resolve();
}
+ if (options) delete options.cache;
return this._super('fetch', arguments);
},
sync: function() {
@@ -998,10 +1000,10 @@ define([
urlRoot: '/api/ostf'
});
- models.FuelVersion = BaseModel.extend({
+ models.FuelVersion = BaseModel.extend(cacheMixin).extend({
+ cacheFor: 60 * 1000,
constructorName: 'FuelVersion',
- urlRoot: '/api/version',
- authExempt: true
+ urlRoot: '/api/version'
});
models.User = BaseModel.extend({
@@ -1021,6 +1023,14 @@ define([
}
});
}, this);
+ this.on('change:token', function() {
+ var token = this.get('token');
+ if (_.isUndefined(token)) {
+ Cookies.remove('token');
+ } else {
+ Cookies.set('token', token);
+ }
+ }, this);
}
});
diff --git a/nailgun/static/views/login_page.jsx b/nailgun/static/views/login_page.jsx
index c57ccdfed3..1a4f342e9f 100644
--- a/nailgun/static/views/login_page.jsx
+++ b/nailgun/static/views/login_page.jsx
@@ -40,12 +40,6 @@ function($, _, i18n, React, dispatcher, utils) {
{i18n('common.copyright')}
- } -{i18n('common.version')}: {app.version.get('release')}
-