Fix horizon dashboard

Port the python2.7 local settings overrides to the python3.6 directory
structure.

Move all local_settings.py overrides into _05_snap_tweaks.py as part
of troubleshooting some remaining problems. Everything is more
organized and functional now :-)

Added selenium tests.

Change-Id: I54923e1dc9c7ffa47c2ef6fb90ea9d224b0d2eee
This commit is contained in:
Pete Vander Giessen 2019-09-03 15:40:58 +00:00
parent 30f09c0c9a
commit 0b4c7a22a3
23 changed files with 174 additions and 54 deletions

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
import os
import sys

View File

@ -1,22 +0,0 @@
# Tweaks to make this run nicely in a snap.
# We don't want django to try writing the secret key before we've told
# it not to attempt to write it out in the read only snap dir in our
# local_settings.py. So we override the behavior of the default
# settings.py here.
SECRET_KEY = "overridethis!"
# Django wants to write out compressed files even when we turn
# compression off (either a bug or something that I'm not
# understanding). Tell it to write them some place writeable.
STATIC_ROOT = '/var/snap/microstack/common/var/horizon/static'
# Disable extra themes for now. TODO: Re-enable when
# https://github.com/CanonicalLtd/microstack/issues/39 is
# addressed. (You'll need to uncomment the material theme below when testing
# the fix.)
AVAILABLE_THEMES = [
('default', 'Default', 'themes/default'),
# ('material', 'Material', 'themes/material'),
('ubuntu', 'Ubuntu', 'themes/ubuntu'),
]

View File

@ -0,0 +1,53 @@
# Tweaks to make this run nicely in a snap.
# TODO: turn this off once everything is working nicely.
DEBUG = True
# Set our webroot.
WEBROOT = '/'
# Caches and such should get written out here.
LOCAL_PATH = '/var/snap/microstack/common/etc/horizon/'
# We don't want django to try writing the secret key before we've told
# it not to attempt to write it out in the read only snap dir in our
# local_settings.py. So we override the behavior of the default
# settings.py here.
SECRET_KEY = secret_key.generate_or_read_from_file(
os.path.join(LOCAL_PATH, '.secret_key_store'))
# Django wants to write out compressed files even when we turn
# compression off (either a bug or something that I'm not
# understanding). Tell it to write them some place writeable.
STATIC_ROOT = '/var/snap/microstack/common/var/horizon/static'
# Disable extra themes for now. TODO: Re-enable when
# https://github.com/CanonicalLtd/microstack/issues/39 is
# addressed. (You'll need to uncomment the material theme below when testing
# the fix.)
AVAILABLE_THEMES = [
('default', 'Default', 'themes/default'),
# ('material', 'Material', 'themes/material'),
('ubuntu', 'Ubuntu', 'themes/ubuntu'),
]
# Point us at keystone.
OPENSTACK_HOST = "10.20.20.1"
OPENSTACK_KEYSTONE_URL = "http://%s:5000/v3" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
# Turn off external access for now. (This should be turned on once we
# have hooks for setting a non default password.)
ALLOWED_HOSTS = ['10.20.20.1', 'localhost', '127.0.0.1']
# Use memcached as our caching backend.
CACHES = {
'default': {
#
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '10.20.20.1:11211',
}
}
SESSION_ENGINE='django.contrib.sessions.backends.cache'

View File

@ -8,7 +8,7 @@ from horizon.utils import secret_key
from openstack_dashboard.settings import HORIZON_CONFIG
DEBUG = True
DEBUG = False
# This setting controls whether or not compression is enabled. Disabling
# compression makes Horizon considerably slower, but makes it much easier
@ -26,6 +26,8 @@ DEBUG = True
WEBROOT = '/'
#LOGIN_URL = WEBROOT + 'auth/login/'
#LOGOUT_URL = WEBROOT + 'auth/logout/'
#LOGIN_ERROR = WEBROOT + 'auth/error/'
#
# LOGIN_REDIRECT_URL can be used as an alternative for
# HORIZON_CONFIG.user_home, if user_home is not set.
@ -36,7 +38,7 @@ WEBROOT = '/'
# with the list of host/domain names that the application can serve.
# For more information see:
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = ['10.20.20.1', 'localhost']
#ALLOWED_HOSTS = '*'
# Set SSL proxy settings:
# Pass this header from the proxy after terminating the SSL,
@ -63,10 +65,9 @@ ALLOWED_HOSTS = ['10.20.20.1', 'localhost']
# use of the decimal point, so valid options would be 2.0 or 3.
# Minimum compute version to get the instance locked status is 2.9.
#OPENSTACK_API_VERSIONS = {
# "data-processing": 1.1,
# "identity": 3,
# "image": 2,
# "volume": 2,
# "volume": 3,
# "compute": 2,
#}
@ -111,7 +112,15 @@ ALLOWED_HOSTS = ['10.20.20.1', 'localhost']
# Toggle showing the openrc file for Keystone V2.
# If set to false the link will be removed from the user dropdown menu
# and the API Access page
#SHOW_KEYSTONE_V2_RC = True
#SHOW_KEYSTONE_V2_RC = False
# Controls whether the keystone openrc file is accesible from the user
# menu and the api access panel.
SHOW_OPENRC_FILE = True
# Controls whether clouds.yaml is accesible from the user
# menu and the api access panel.
SHOW_OPENSTACK_CLOUDS_YAML = True
# If provided, a "Report Bug" link will be displayed in the site header
# which links to the value of this setting (ideally a URL containing
@ -137,7 +146,6 @@ ALLOWED_HOSTS = ['10.20.20.1', 'localhost']
#HORIZON_CONFIG["disable_password_reveal"] = False
#LOCAL_PATH = os.path.dirname(os.path.abspath(__file__))
LOCAL_PATH = '/var/snap/microstack/common/etc/horizon/'
# Set custom secret key:
# You can either set it to a specific value or you can let horizon generate a
@ -148,24 +156,24 @@ LOCAL_PATH = '/var/snap/microstack/common/etc/horizon/'
# (usually behind a load-balancer). Either you have to make sure that a session
# gets all requests routed to the same dashboard instance or you set the same
# SECRET_KEY for all of them.
SECRET_KEY = secret_key.generate_or_read_from_file(
os.path.join(LOCAL_PATH, '.secret_key_store'))
#SECRET_KEY = secret_key.generate_or_read_from_file(
# os.path.join(LOCAL_PATH, '.secret_key_store'))
# We recommend you use memcached for development; otherwise after every reload
# of the django development server, you will have to login again. To use
# memcached set CACHES to something like
# memcached set CACHES to something like below.
# For more information, see
# https://docs.djangoproject.com/en/1.11/topics/http/sessions/.
#CACHES = {
# 'default': {
# 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
# 'LOCATION': '127.0.0.1:11211',
# 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
# },
#}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
}
# If you use ``tox -e runserver`` for developments,then configure
# SESSION_ENGINE to django.contrib.sessions.backends.signed_cookies
# as shown below:
#SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
# Send email to the console by default
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@ -232,6 +240,21 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
# "acme_saml2": ("acme", "saml2"),
#}
# Enables redirection on login to the identity provider defined on
# WEBSSO_DEFAULT_REDIRECT_PROTOCOL and WEBSSO_DEFAULT_REDIRECT_REGION
#WEBSSO_DEFAULT_REDIRECT = False
# Specifies the protocol to use for default redirection on login
#WEBSSO_DEFAULT_REDIRECT_PROTOCOL = None
# Specifies the region to which the connection will be established on login
#WEBSSO_DEFAULT_REDIRECT_REGION = OPENSTACK_KEYSTONE_URL
# Enables redirection on logout to the method specified on the identity provider.
# Once logout the client will be redirected to the address specified in this
# variable.
#WEBSSO_DEFAULT_REDIRECT_LOGOUT = None
# If set this URL will be used for web single-sign-on authentication
# instead of OPENSTACK_KEYSTONE_URL. This is needed in the deployment
# scenarios where network segmentation is used per security requirement.
@ -523,6 +546,7 @@ TIME_ZONE = "UTC"
#AVAILABLE_THEMES = [
# ('default', 'Default', 'themes/default'),
# ('material', 'Material', 'themes/material'),
# ('example', 'Example', 'themes/example'),
#]
LOGGING = {
@ -780,12 +804,6 @@ SECURITY_GROUP_RULES = {
# See Metadata Definitions on:
# https://docs.openstack.org/glance/latest/user/glancemetadefcatalogapi.html
# The hash algorithm to use for authentication tokens. This must
# match the hash algorithm that the identity server and the
# auth_token middleware are using. Allowed values are the
# algorithms supported by Python's hashlib library.
#OPENSTACK_TOKEN_HASH_ALGORITHM = 'md5'
# AngularJS requires some settings to be made available to
# the client side. Some settings are required by in-tree / built-in horizon
# features. These settings must be added to REST_API_REQUIRED_SETTINGS in the

View File

@ -1 +1,3 @@
petname
selenium
xvfbwrapper

View File

@ -161,12 +161,14 @@ done;
# Cleanup
unset IP
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "++ Completed tests. Cleaning up ++"
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
if [[ $PREFIX == *"multipass"* ]]; then
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "++ Completed tests. Cleaning up ++"
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
sudo multipass delete $MACHINE
sudo multipass purge
else
$PREFIX sudo snap remove microstack
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "++ Completed tests. Leaving snap installed. ++"
echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
fi

47
tests/test_horizonlogin.py Executable file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
"""
test_horizonlogin.py
This is a basic test of Horizon functionality. We verify that:
1) Horizon is running, and we can hit the landing page.
2) We can login successfully.
This is based on code generated by the Selinum Web IDE.
"""
import os
import socket
import unittest
import xvfbwrapper
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestHorizonlogin(unittest.TestCase):
def setUp(self):
self.display = xvfbwrapper.Xvfb(width=1280, height=720)
self.display.start()
self.driver = webdriver.PhantomJS()
def tearDown(self):
self.driver.quit()
self.display.stop()
def test_horizonlogin(self):
self.driver.get("http://10.20.20.1/")
# Login to horizon!
self.driver.find_element(By.ID, "id_username").click()
self.driver.find_element(By.ID, "id_username").send_keys("admin")
self.driver.find_element(By.ID, "id_password").send_keys("keystone")
self.driver.find_element(By.CSS_SELECTOR, "#loginBtn > span").click()
# Verify that we can click something on the dashboard -- e.g.,
# we're still not sitting at the login screen.
self.driver.find_element(By.LINK_TEXT, "Images").click()
if __name__ == '__main__':
# Run our tests, ignorning deprecation warnings and warnings about
# unclosed sockets. (TODO: setup a selenium server so that we can
# move from PhantomJS, which is deprecated, to to Selenium headless.)
unittest.main(warnings='ignore')

View File

@ -5,10 +5,19 @@ set -ex
export PATH=/snap/bin:$PATH
sudo apt update
sudo apt install -y snapd
# Install the X virtual framebuffer, which is required for selenium
# tests of the horizon dashboard.
sudo apt install -y xvfb npm libfontconfig1
sudo npm install -g phantomjs-prebuilt
# Verify that PhantomJS, our selenium web driver, works.
phantomjs -v
# Setup snapd and snapcraft
sudo apt install -y snapd
sudo snap install --classic snapcraft
sudo snap install --classic lxd
sudo lxd init --auto
# Build our snap!
sudo snapcraft --use-lxd

19
tox.ini
View File

@ -3,9 +3,10 @@ envlist = init_lint, init_unit, multipass
skipsdist = True
[testenv]
basepython=python3
install_command = pip install {opts} {packages}
setenv =
PATH = {env:PATH}:/snap/bin
PATH = /snap/bin:{env:PATH}
passenv = HOME TERM
whitelist_externals =
sudo
@ -15,10 +16,12 @@ whitelist_externals =
# Testing environment for the gerrit gate. Named 'snap' to conform to
# the requirements of the snap friendly job that we inherit from in
# .zuul.yaml.
basepython=python3
deps = -r{toxinidir}/test-requirements.txt
commands =
{toxinidir}/tools/lxd_build.sh
{toxinidir}/tests/basic-test.sh
{toxinidir}/tests/test_horizonlogin.py
[testenv:multipass]
# Default testing environment for a human operated machine. Builds the
@ -28,6 +31,7 @@ commands =
# use the "snap" environment above. Beware that you will wind up with
# a lot of things installed, including potentially the locally built
# version of MicroStack!
deps = -r{toxinidir}/test-requirements.txt
commands =
{toxinidir}/tools/multipass_build.sh
{toxinidir}/tests/basic-test.sh -m
@ -37,15 +41,22 @@ commands =
commands =
{toxinidir}/tests/basic-test.sh -m
[testenv:init_lint]
basepython=python3
deps = -r{toxinidir}/tools/init/test-requirements.txt
-r{toxinidir}/tools/init/requirements.txt
commands = flake8 {toxinidir}/tools/init/init/
[testenv:init_unit]
basepython=python3
deps = -r{toxinidir}/tools/init/test-requirements.txt
-r{toxinidir}/tools/init/requirements.txt
commands = stestr run {posargs}
[testenv:browser]
# Run browser tests. Assumes that you have the snap installed and
# initialized locally, and a valid DISPLAY (install xvfb for a virtual
# one).
# TODO: figure out how to integrate this w/ multipass. (e.g. setup
# port forwarding and call into the mulitpass machine.)
deps = -r{toxinidir}/test-requirements.txt
commands =
{toxinidir}/tests/test_horizonlogin.py