From db9fac5f4b5558c17dc08ea6a8619a5a54f12bf5 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Tue, 19 Jun 2018 10:03:54 +0200 Subject: [PATCH] Use `manage.py migrate` for django versions >= 1.9 `syncdb` subcommand was deprecated in django 1.7 and subsequently removed in 1.9. Use `subprocess.check_call()` so we catch errors. Add `shared-db` relation and enable debug logging in deployment used in functional test. Add functional test that authenticates through the dashboard. Update unit tests. Change-Id: I567461e57ec431fc470d7a2a31d3f16e9dc50e8b Closes-Bug: #1777358 --- hooks/horizon_utils.py | 9 +++-- tests/basic_deployment.py | 62 +++++++++++++++++++++++++++++++- unit_tests/test_horizon_utils.py | 16 +++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/hooks/horizon_utils.py b/hooks/horizon_utils.py index 1c7c4722..6be0db38 100644 --- a/hooks/horizon_utils.py +++ b/hooks/horizon_utils.py @@ -407,5 +407,10 @@ def _pause_resume_helper(f, configs): def db_migration(): - cmd = ['/usr/share/openstack-dashboard/manage.py', 'syncdb', '--noinput'] - subprocess.call(cmd) + if cmp_pkgrevno('python-django', '1.9') >= 0: + # syncdb was removed in django 1.9 + subcommand = 'migrate' + else: + subcommand = 'syncdb' + cmd = ['/usr/share/openstack-dashboard/manage.py', subcommand, '--noinput'] + subprocess.check_call(cmd) diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 0e62069a..78c8f0e5 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -15,6 +15,7 @@ # limitations under the License. import amulet +import requests import urllib2 import time @@ -79,6 +80,7 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): relations = { 'openstack-dashboard:identity-service': 'keystone:identity-service', + 'openstack-dashboard:shared-db': 'percona-cluster:shared-db', 'keystone:shared-db': 'percona-cluster:shared-db', } super(OpenstackDashboardBasicDeployment, self)._add_relations( @@ -86,7 +88,9 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): def _configure_services(self): """Configure all of the services.""" - horizon_config = {} + horizon_config = { + 'debug': 'yes', + } keystone_config = { 'admin-password': 'openstack', 'admin-token': 'ubuntutesting', @@ -235,6 +239,62 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment): msg = "Dashboard frontpage check failed" amulet.raise_status(amulet.FAIL, msg=msg) + def test_401_authenticate(self): + """Validate that authentication succeeds when client logs in through + the OpenStack Dashboard""" + + u.log.debug('Checking authentication through dashboard...') + unit = self.openstack_dashboard_sentry + dashboard_relation = unit.relation('identity-service', + 'keystone:identity-service') + dashboard_ip = dashboard_relation['private-address'] + url = 'http://{}/horizon/auth/login/'.format(dashboard_ip) + + api_version = None + if self._get_openstack_release() < self.xenial_queens: + api_version = 2 + + region = u.get_keystone_endpoint( + self.keystone_sentry.info['public-address'], api_version) + + # start session, get csrftoken + client = requests.session() + client.get(url) + response = client.get(url) + + if 'csrftoken' in client.cookies: + csrftoken = client.cookies['csrftoken'] + + # build and send post request + auth = { + 'domain': 'admin_domain', + 'username': 'admin', + 'password': 'openstack', + 'csrfmiddlewaretoken': csrftoken, + 'next': '/horizon/', + 'region': region, + } + if api_version == 2: + del auth['domain'] + + u.log.debug('POST data: "{}"'.format(auth)) + response = client.post(url, data=auth, headers={'Referer': url}) + + if self._get_openstack_release() == self.trusty_icehouse: + # icehouse horizon does not operate properly without the compute + # service present in the keystone catalog. However, checking for + # presence of the following text is sufficient to determine whether + # authentication succeeded or not + expect = 'ServiceCatalogException at /admin/' + else: + expect = 'Projects - OpenStack Dashboard' + + if expect not in response.text: + msg = 'FAILURE code={} text="{}"'.format(response, response.text) + amulet.raise_status(amulet.FAIL, msg=msg) + + u.log.debug('OK') + def test_404_connection(self): """Verify the apache status module gets disabled when hardening apache.""" diff --git a/unit_tests/test_horizon_utils.py b/unit_tests/test_horizon_utils.py index 14d2fdfb..dea1229c 100644 --- a/unit_tests/test_horizon_utils.py +++ b/unit_tests/test_horizon_utils.py @@ -229,3 +229,19 @@ class TestHorizonUtils(CharmTestCase): asf.assert_called_once_with('some-config') # ports=None whilst port checks are disabled. f.assert_called_once_with('assessor', services='s1', ports=None) + + @patch('subprocess.check_call') + def test_db_migration(self, mock_subprocess): + self.cmp_pkgrevno.return_value = -1 + horizon_utils.db_migration() + mock_subprocess.assert_called_with( + ['/usr/share/openstack-dashboard/manage.py', + 'syncdb', '--noinput']) + + @patch('subprocess.check_call') + def test_db_migration_bionic_and_beyond(self, mock_subprocess): + self.cmp_pkgrevno.return_value = 0 + horizon_utils.db_migration() + mock_subprocess.assert_called_with( + ['/usr/share/openstack-dashboard/manage.py', + 'migrate', '--noinput'])