diff --git a/.gitignore b/.gitignore index e6257802..974ccc2b 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ ChangeLog *~ .*.swp .*sw? + +.secret_key_store +*.lock diff --git a/MANIFEST.in b/MANIFEST.in index c978a52d..5e592be9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,5 +2,8 @@ include AUTHORS include ChangeLog exclude .gitignore exclude .gitreview +include setup.py + +recursive-include ironic_ui *.js *.html *.scss global-exclude *.pyc diff --git a/ironic_ui/tests/__init__.py b/ironic_ui/api/__init__.py similarity index 100% rename from ironic_ui/tests/__init__.py rename to ironic_ui/api/__init__.py diff --git a/ironic_ui/templates/ironic_ui/index.html b/ironic_ui/api/ironic.py similarity index 100% rename from ironic_ui/templates/ironic_ui/index.html rename to ironic_ui/api/ironic.py diff --git a/ironic_ui/api/rest/__init__.py b/ironic_ui/api/rest/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/api/rest/ironic.py b/ironic_ui/api/rest/ironic.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/enabled/_2200_ironic.py b/ironic_ui/enabled/_2200_ironic.py new file mode 100644 index 00000000..9a655dc2 --- /dev/null +++ b/ironic_ui/enabled/_2200_ironic.py @@ -0,0 +1,27 @@ +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP +# +# 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. + +# The name of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'ironic' +# The name of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'admin' +# The name of the panel group the PANEL is associated with. +PANEL_GROUP = 'admin' +# Python panel class of the PANEL to be added. +ADD_PANEL = 'ironic_ui.ironic.panel.Ironic' +# A list of applications to be prepended to INSTALLED_APPS +ADD_INSTALLED_APPS = ['ironic_ui', ] +# Automatically discover static resources in installed apps +AUTO_DISCOVER_STATIC_FILES = True diff --git a/ironic_ui/enabled/__init__.py b/ironic_ui/enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/ironic/__init__.py b/ironic_ui/ironic/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/ironic/panel.py b/ironic_ui/ironic/panel.py new file mode 100644 index 00000000..c3eda24e --- /dev/null +++ b/ironic_ui/ironic/panel.py @@ -0,0 +1,23 @@ +# Copyright 2016 Cisco Systems, Inc. +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP +# +# 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. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + + +class Ironic(horizon.Panel): + name = _("Ironic Bare Metal Provisioning") + slug = 'ironic' diff --git a/ironic_ui/ironic/templates/ironic/index.html b/ironic_ui/ironic/templates/ironic/index.html new file mode 100644 index 00000000..6238c19b --- /dev/null +++ b/ironic_ui/ironic/templates/ironic/index.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %} + {{ page_title }} +{% endblock %} + +{% block main %} + +{% endblock %} diff --git a/ironic_ui/ironic/urls.py b/ironic_ui/ironic/urls.py new file mode 100644 index 00000000..2b1780d3 --- /dev/null +++ b/ironic_ui/ironic/urls.py @@ -0,0 +1,21 @@ +# Copyright 2016 Cisco Systems, Inc. +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP +# +# 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. + +from django.conf.urls import url +from ironic_ui.ironic import views + +urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name="index"), +] diff --git a/ironic_ui/ironic/views.py b/ironic_ui/ironic/views.py new file mode 100644 index 00000000..7be81712 --- /dev/null +++ b/ironic_ui/ironic/views.py @@ -0,0 +1,22 @@ +# Copyright 2016 Cisco Systems, Inc. +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP +# +# 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. + +from django.utils.translation import ugettext_lazy as _ +from horizon import views + + +class IndexView(views.HorizonTemplateView): + template_name = 'admin/ironic/index.html' + page_title = _("Ironic Bare Metal Provisioning") diff --git a/ironic_ui/test/__init__.py b/ironic_ui/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/test/settings.py b/ironic_ui/test/settings.py new file mode 100644 index 00000000..0f2f0995 --- /dev/null +++ b/ironic_ui/test/settings.py @@ -0,0 +1,189 @@ +# Copyright 2016 Cisco Systems, Inc. +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP +# +# 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 importlib +import os +import six + +from horizon.test.settings import * # noqa +from horizon.utils import secret_key +from openstack_dashboard import exceptions + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_PATH = os.path.abspath(os.path.join(TEST_DIR, "..")) + +MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media')) +MEDIA_URL = '/media/' +STATIC_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'static')) +STATIC_URL = '/static/' + +SECRET_KEY = secret_key.generate_or_read_from_file( + os.path.join(TEST_DIR, '.secret_key_store')) +ROOT_URLCONF = 'ironic_ui.test.urls' +TEMPLATE_DIRS = ( + os.path.join(TEST_DIR, 'templates'), +) + +TEMPLATE_CONTEXT_PROCESSORS += ( + 'openstack_dashboard.context_processors.openstack', +) + +INSTALLED_APPS = ( + 'django.contrib.contenttypes', + 'django.contrib.auth', + 'django.contrib.sessions', + 'django.contrib.staticfiles', + 'django.contrib.messages', + 'django.contrib.humanize', + 'django_nose', + 'openstack_auth', + 'compressor', + 'horizon', + 'openstack_dashboard', + 'openstack_dashboard.dashboards', +) + +AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',) + +SITE_BRANDING = 'OpenStack' + +HORIZON_CONFIG = { + "password_validator": { + "regex": '^.{8,18}$', + "help_text": "Password must be between 8 and 18 characters." + }, + 'user_home': None, + 'help_url': "http://docs.openstack.org", + 'exceptions': {'recoverable': exceptions.RECOVERABLE, + 'not_found': exceptions.NOT_FOUND, + 'unauthorized': exceptions.UNAUTHORIZED}, + 'angular_modules': [], + 'js_files': [], +} + +# Load the pluggable dashboard settings +from openstack_dashboard.utils import settings +dashboard_module_names = [ + 'openstack_dashboard.enabled', + 'openstack_dashboard.local.enabled', + 'ironic_ui.enabled', +] +dashboard_modules = [] +# All dashboards must be enabled for the namespace to get registered, which is +# needed by the unit tests. +for module_name in dashboard_module_names: + module = importlib.import_module(module_name) + dashboard_modules.append(module) + for submodule in six.itervalues(settings.import_submodules(module)): + if getattr(submodule, 'DISABLED', None): + delattr(submodule, 'DISABLED') +INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable +settings.update_dashboards(dashboard_modules, HORIZON_CONFIG, INSTALLED_APPS) + + +# Set to True to allow users to upload images to glance via Horizon server. +# When enabled, a file form field will appear on the create image form. +# See documentation for deployment considerations. +HORIZON_IMAGES_ALLOW_UPLOAD = True + +AVAILABLE_REGIONS = [ + ('http://localhost:5000/v2.0', 'local'), + ('http://remote:5000/v2.0', 'remote'), +] + +OPENSTACK_API_VERSIONS = { + "identity": 3 +} + +OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0" +OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" + +OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True +OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'test_domain' + +OPENSTACK_KEYSTONE_BACKEND = { + 'name': 'native', + 'can_edit_user': True, + 'can_edit_group': True, + 'can_edit_project': True, + 'can_edit_domain': True, + 'can_edit_role': True +} + +OPENSTACK_CINDER_FEATURES = { + 'enable_backup': True, +} + +OPENSTACK_NEUTRON_NETWORK = { + 'enable_lb': False, + 'enable_firewall': False, + 'enable_vpn': False, +} + +OPENSTACK_HYPERVISOR_FEATURES = { + 'can_set_mount_point': True, + + # NOTE: as of Grizzly this is not yet supported in Nova so enabling this + # setting will not do anything useful + 'can_encrypt_volumes': False +} + +LOGGING['loggers']['openstack_dashboard'] = { + 'handlers': ['test'], + 'propagate': False, +} + +LOGGING['loggers']['selenium'] = { + 'handlers': ['test'], + 'propagate': False, +} + +LOGGING['loggers']['ironic_ui'] = { + 'handlers': ['test'], + 'propagate': False, +} + +SECURITY_GROUP_RULES = { + 'all_tcp': { + 'name': 'ALL TCP', + 'ip_protocol': 'tcp', + 'from_port': '1', + 'to_port': '65535', + }, + 'http': { + 'name': 'HTTP', + 'ip_protocol': 'tcp', + 'from_port': '80', + 'to_port': '80', + }, +} + +NOSE_ARGS = ['--nocapture', + '--nologcapture', + '--cover-package=openstack_dashboard', + '--cover-inclusive', + '--all-modules'] + +POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf") +POLICY_FILES = { + 'identity': 'keystone_policy.json', + 'compute': 'nova_policy.json' +} + +# The openstack_auth.user.Token object isn't JSON-serializable ATM +SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' diff --git a/ironic_ui/test/tests/__init__.py b/ironic_ui/test/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/ironic_ui/test/tests/registration.py b/ironic_ui/test/tests/registration.py new file mode 100644 index 00000000..51510a41 --- /dev/null +++ b/ironic_ui/test/tests/registration.py @@ -0,0 +1,25 @@ +# Copyright 2015 Cisco Systems, 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 horizon +from ironic_ui.ironic.panel import Ironic +from openstack_dashboard.test import helpers as test + + +class RegistrationTests(test.TestCase): + def test_registered(self): + dashboard = horizon.get_dashboard('admin') + panel = dashboard.get_panel('ironic') + + self.assertEqual(panel.__class__, Ironic) diff --git a/ironic_ui/test/urls.py b/ironic_ui/test/urls.py new file mode 100644 index 00000000..3c2ffc23 --- /dev/null +++ b/ironic_ui/test/urls.py @@ -0,0 +1,20 @@ +# +# 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. + +from django.conf.urls import include +from django.conf.urls import url +import openstack_dashboard.urls + +urlpatterns = [ + url(r'', include(openstack_dashboard.urls)) +] diff --git a/ironic_ui/tests/test_ironic_ui.py b/ironic_ui/tests/test_ironic_ui.py deleted file mode 100644 index 8fd8a30a..00000000 --- a/ironic_ui/tests/test_ironic_ui.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- - -# 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. - -""" -test_ironic-ui ----------------------------------- - -Tests for `ironic-ui` module. -""" - -from ironic_ui.tests import base - - -class TestIronic_ui(base.TestCase): - - def test_something(self): - pass diff --git a/ironic_ui/tests/base.py b/manage.py old mode 100644 new mode 100755 similarity index 63% rename from ironic_ui/tests/base.py rename to manage.py index 1c30cdb5..b9e0f36e --- a/ironic_ui/tests/base.py +++ b/manage.py @@ -1,7 +1,6 @@ -# -*- coding: utf-8 -*- +#!/usr/bin/env python -# Copyright 2010-2011 OpenStack Foundation -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# Copyright 2016 Cisco Systems, 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 @@ -15,9 +14,12 @@ # License for the specific language governing permissions and limitations # under the License. -from oslotest import base +import os +import sys +from django.core.management import execute_from_command_line # noqa -class TestCase(base.BaseTestCase): - - """Test case base class for all unit tests.""" +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", + "ironic_ui.test.settings") + execute_from_command_line(sys.argv) diff --git a/setup.cfg b/setup.cfg index beb4457e..45fa7021 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = ironic-ui -summary = cIronic plugin UI for Horizon to allow users to view and manage bare metal nodes, ports and drivers. +summary = Ironic plugin UI for Horizon to allow users to view and manage bare metal nodes, ports and drivers. description-file = README.rst author = OpenStack @@ -16,7 +16,6 @@ classifier = Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 [files] @@ -30,3 +29,17 @@ all_files = 1 [upload_sphinx] upload-dir = doc/build/html + +[compile_catalog] +directory = ironic_ui/locale +domain = ironic-ui + +[update_catalog] +domain = ironic-ui +output_dir = ironic_ui/locale +input_file = ironic_ui/locale/ironic-ui.pot + +[extract_messages] +keywords = _ gettext ngettext l_ lazy_gettext +mapping_file = babel.cfg +output_file = ironic_ui/locale/ironic_ui.pot diff --git a/setup.py b/setup.py index 782bb21f..c4f06b70 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# Copyright (c) 2016 Hewlett Packard Enterprise Development Company LP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test-requirements.txt b/test-requirements.txt index 68aade89..aea4a8b0 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,9 +2,13 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. +# Require Horizon +-e git://github.com/openstack/horizon.git#egg=horizon + hacking>=0.10.2,<0.11 # Apache-2.0 coverage>=3.6 # Apache-2.0 +django-nose>=1.2 # BSD python-subunit>=0.0.18 # Apache-2.0/BSD sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD oslosphinx>=2.5.0,!=3.4.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini index 53a7b34a..5691a672 100644 --- a/tox.ini +++ b/tox.ini @@ -1,17 +1,20 @@ [tox] minversion = 1.8 -envlist = py34-constraints,py27-constraints,pypy-constraints,pep8-constraints skipsdist = True +envlist = py34,py27,pep8 [testenv] usedevelop = True -install_command = - constraints: {[testenv:common-constraints]install_command} - pip install -U {opts} {packages} -setenv = - VIRTUAL_ENV={envdir} -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py test --slowest --testr-args='{posargs}' +install_command = pip install -U {opts} {packages} +setenv = VIRTUAL_ENV={envdir} + NOSE_WITH_OPENSTACK=1 + NOSE_OPENSTACK_COLOR=1 + NOSE_OPENSTACK_RED=0.05 + NOSE_OPENSTACK_YELLOW=0.025 + NOSE_OPENSTACK_SHOW_ELAPSED=1 +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt +commands = {toxinidir}/manage.py test ironic_ui --settings=ironic_ui.test.settings [testenv:common-constraints] install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} @@ -52,9 +55,7 @@ install_command = {[testenv:common-constraints]install_command} commands = oslo_debug_helper {posargs} [flake8] -# E123, E125 skipped as they are invalid PEP-8. show-source = True -ignore = E123,E125 builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build