diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91f4e43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,112 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +ut_*_nose_results.html + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# own settings +.idea/* + +# angular old versions +*angular-1.3.7* +*angular-1.5.6* + +# backup files +*.bak diff --git a/heat_dashboard/api/__init__.py b/heat_dashboard/api/__init__.py index 6262470..4d3bf13 100644 --- a/heat_dashboard/api/__init__.py +++ b/heat_dashboard/api/__init__.py @@ -31,25 +31,9 @@ In other words, Horizon developers not working on openstack_dashboard.api shouldn't need to understand the finer details of APIs for Keystone/Nova/Glance/Swift et. al. """ -from openstack_dashboard.api import base -from openstack_dashboard.api import cinder -from openstack_dashboard.api import glance from openstack_dashboard.api import heat -from openstack_dashboard.api import keystone -from openstack_dashboard.api import network -from openstack_dashboard.api import neutron -from openstack_dashboard.api import nova -from openstack_dashboard.api import swift __all__ = [ - "base", - "cinder", - "glance", "heat", - "keystone", - "network", - "neutron", - "nova", - "swift", ] diff --git a/heat_dashboard/api/heat.py b/heat_dashboard/api/heat.py index c31c61d..0811fff 100644 --- a/heat_dashboard/api/heat.py +++ b/heat_dashboard/api/heat.py @@ -12,15 +12,17 @@ import contextlib +import six + +from six.moves.urllib import request + from django.conf import settings +from oslo_serialization import jsonutils + from heatclient import client as heat_client from heatclient.common import template_format from heatclient.common import template_utils from heatclient.common import utils as heat_utils -from oslo_serialization import jsonutils -import six -from six.moves.urllib import request - from horizon import exceptions from horizon.utils import functions as utils from horizon.utils.memoized import memoized diff --git a/heat_dashboard/api/rest/heat.py b/heat_dashboard/api/rest/heat.py index df8752f..106363c 100644 --- a/heat_dashboard/api/rest/heat.py +++ b/heat_dashboard/api/rest/heat.py @@ -13,7 +13,8 @@ from django.views import generic -from openstack_dashboard import api +# from openstack_dashboard import api +from heat_dashboard import api from openstack_dashboard.api.rest import urls from openstack_dashboard.api.rest import utils as rest_utils diff --git a/heat_dashboard/content/resource_types/panel.py b/heat_dashboard/content/resource_types/panel.py index b1f3744..779d115 100644 --- a/heat_dashboard/content/resource_types/panel.py +++ b/heat_dashboard/content/resource_types/panel.py @@ -18,6 +18,6 @@ import horizon class ResourceTypes(horizon.Panel): name = _("Resource Types") - slug = "stacks.resource_types" + slug = "resource_types" permissions = ('openstack.services.orchestration',) policy_rules = (("orchestration", "stacks:list_resource_types"),) diff --git a/heat_dashboard/content/resource_types/tables.py b/heat_dashboard/content/resource_types/tables.py index 66e7702..893e465 100644 --- a/heat_dashboard/content/resource_types/tables.py +++ b/heat_dashboard/content/resource_types/tables.py @@ -24,7 +24,7 @@ class ResourceTypesFilterAction(tables.FilterAction): class ResourceTypesTable(tables.DataTable): name = tables.Column("resource_type", verbose_name=_("Type"), - link="horizon:project:stacks.resource_types:details",) + link="horizon:project:resource_types:details",) def get_object_id(self, resource): return resource.resource_type diff --git a/heat_dashboard/content/resource_types/tabs.py b/heat_dashboard/content/resource_types/tabs.py index b0d5467..03b4690 100644 --- a/heat_dashboard/content/resource_types/tabs.py +++ b/heat_dashboard/content/resource_types/tabs.py @@ -19,7 +19,8 @@ from horizon import tabs class ResourceTypeOverviewTab(tabs.Tab): name = _("Overview") slug = "resource_type_overview" - template_name = "project/stacks.resource_types/_details.html" + # template_name = "project/stacks.resource_types/_details.html" + template_name = "project/resource_types/_details.html" def get_context_data(self, request): return {"r_type": self.tab_group.kwargs['rt'], diff --git a/heat_dashboard/content/resource_types/urls.py b/heat_dashboard/content/resource_types/urls.py index 8ab8cb0..e3729a4 100644 --- a/heat_dashboard/content/resource_types/urls.py +++ b/heat_dashboard/content/resource_types/urls.py @@ -13,7 +13,7 @@ from django.conf.urls import url -from openstack_dashboard.dashboards.project.stacks.resource_types import views +from heat_dashboard.content.resource_types import views urlpatterns = [ url(r'^$', views.ResourceTypesView.as_view(), name='index'), diff --git a/heat_dashboard/content/resource_types/views.py b/heat_dashboard/content/resource_types/views.py index 8afcdf8..b699b24 100644 --- a/heat_dashboard/content/resource_types/views.py +++ b/heat_dashboard/content/resource_types/views.py @@ -20,11 +20,14 @@ from horizon import exceptions from horizon import tables from horizon import tabs -from openstack_dashboard import api -import openstack_dashboard.dashboards.project.stacks.resource_types.tables \ - as project_tables -import openstack_dashboard.dashboards.project.stacks.resource_types.tabs \ - as project_tabs +# from openstack_dashboard import api +# import openstack_dashboard.dashboards.project.stacks.resource_types.tables \ +# as project_tables +# import openstack_dashboard.dashboards.project.stacks.resource_types.tabs \ +# as project_tabs +from heat_dashboard import api +import heat_dashboard.content.resource_types.tables as project_tables +import heat_dashboard.content.resource_types.tabs as project_tabs class ResourceTypesView(tables.DataTableView): @@ -75,4 +78,4 @@ class DetailView(tabs.TabView): @staticmethod def get_redirect_url(): - return reverse('horizon:project:stacks.resources:index') + return reverse('horizon:project:resource_types:index') diff --git a/heat_dashboard/content/stacks/forms.py b/heat_dashboard/content/stacks/forms.py index e8b9702..7ec66b3 100644 --- a/heat_dashboard/content/stacks/forms.py +++ b/heat_dashboard/content/stacks/forms.py @@ -26,7 +26,8 @@ from horizon import exceptions from horizon import forms from horizon import messages -from openstack_dashboard import api +# from openstack_dashboard import api +from heat_dashboard import api from openstack_dashboard.dashboards.project.images \ import utils as image_utils from openstack_dashboard.dashboards.project.instances \ diff --git a/heat_dashboard/content/stacks/mappings.py b/heat_dashboard/content/stacks/mappings.py index eeab18c..7ca203c 100644 --- a/heat_dashboard/content/stacks/mappings.py +++ b/heat_dashboard/content/stacks/mappings.py @@ -142,7 +142,9 @@ def stack_output(output): output = json.dumps(output, indent=2) return safestring.mark_safe(u'
%s
' % html.escape(output)) + static_url = getattr(settings, "STATIC_URL", "/static/") + resource_images = { 'LB_FAILED': static_url + 'dashboard/img/lb-red.svg', 'LB_DELETE': static_url + 'dashboard/img/lb-red.svg', diff --git a/heat_dashboard/content/stacks/tables.py b/heat_dashboard/content/stacks/tables.py index 8159b2b..45809a0 100644 --- a/heat_dashboard/content/stacks/tables.py +++ b/heat_dashboard/content/stacks/tables.py @@ -16,15 +16,17 @@ from django.template.defaultfilters import title from django.utils.translation import pgettext_lazy from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy -from heatclient import exc -from horizon import exceptions from horizon import messages from horizon import tables from horizon.utils import filters -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.stacks import mappings +from heatclient import exc + +# from openstack_dashboard import api +# from openstack_dashboard.dashboards.project.stacks import mappings +from heat_dashboard import api +from heat_dashboard.content.stacks import mappings class LaunchStack(tables.LinkAction): @@ -96,11 +98,8 @@ class SuspendStack(tables.BatchAction): ) def action(self, request, stack_id): - try: - api.heat.action_suspend(request, stack_id) - except Exception: - msg = _('Failed to suspend stack.') - exceptions.handle(request, msg) + # api.heat.action_suspend(request, stack_id) + api.heat.action_suspend(request, stack_id) class ResumeStack(tables.BatchAction): @@ -126,11 +125,8 @@ class ResumeStack(tables.BatchAction): ) def action(self, request, stack_id): - try: - api.heat.action_resume(request, stack_id) - except Exception: - msg = _('Failed to resume stack.') - exceptions.handle(request, msg) + # api.heat.action_resume(request, stack_id) + api.heat.action_resume(request, stack_id) class ChangeStackTemplate(tables.LinkAction): @@ -164,11 +160,8 @@ class DeleteStack(tables.DeleteAction): policy_rules = (("orchestration", "stacks:delete"),) def delete(self, request, stack_id): - try: - api.heat.stack_delete(request, stack_id) - except Exception: - msg = _('Failed to delete stack.') - exceptions.handle(request, msg) + # api.heat.stack_delete(request, stack_id) + api.heat.stack_delete(request, stack_id) def allowed(self, request, stack): if stack is not None: @@ -184,6 +177,7 @@ class StacksUpdateRow(tables.Row): def get_data(self, request, stack_id): try: + # stack = api.heat.stack_get(request, stack_id) stack = api.heat.stack_get(request, stack_id) if stack.stack_status == 'DELETE_COMPLETE': # returning 404 to the ajax call removes the @@ -351,8 +345,11 @@ class ResourcesUpdateRow(tables.Row): try: stack = self.table.stack stack_identifier = '%s/%s' % (stack.stack_name, stack.id) - return api.heat.resource_get( - request, stack_identifier, resource_name) + # return api.heat.resource_get( + # request, stack_identifier, resource_name) + return api.heat.resource_get(request, + stack_identifier, + resource_name) except exc.HTTPNotFound: # returning 404 to the ajax call removes the # row from the table on the ui diff --git a/heat_dashboard/content/stacks/tabs.py b/heat_dashboard/content/stacks/tabs.py index 1e6c92b..a6508ff 100644 --- a/heat_dashboard/content/stacks/tabs.py +++ b/heat_dashboard/content/stacks/tabs.py @@ -16,14 +16,13 @@ from django.utils.translation import ugettext_lazy as _ from horizon import messages from horizon import tabs -from openstack_dashboard import api -from openstack_dashboard import policy -from openstack_dashboard.dashboards.project.stacks \ - import api as project_api -from openstack_dashboard.dashboards.project.stacks import mappings -from openstack_dashboard.dashboards.project.stacks \ - import tables as project_tables +from heat_dashboard import api +from heat_dashboard.content.stacks import api as project_api +from heat_dashboard.content.stacks import mappings +from heat_dashboard.content.stacks import tables as project_tables + +from openstack_dashboard import policy LOG = logging.getLogger(__name__) @@ -33,6 +32,7 @@ class StackTopologyTab(tabs.Tab): name = _("Topology") slug = "topology" template_name = "project/stacks/_detail_topology.html" + # template_name = "stacks/_detail_topology.html" preload = False def allowed(self, request): @@ -55,6 +55,7 @@ class StackOverviewTab(tabs.Tab): name = _("Overview") slug = "overview" template_name = "project/stacks/_detail_overview.html" + # template_name = "stacks/_detail_overview.html" def allowed(self, request): return policy.check( @@ -71,6 +72,7 @@ class ResourceOverviewTab(tabs.Tab): name = _("Overview") slug = "resource_overview" template_name = "project/stacks/_resource_overview.html" + # template_name = "stacks/_resource_overview.html" def get_context_data(self, request): resource = self.tab_group.kwargs['resource'] @@ -85,6 +87,7 @@ class StackEventsTab(tabs.Tab): name = _("Events") slug = "events" template_name = "project/stacks/_detail_events.html" + # template_name = "stacks/_detail_events.html" preload = False def allowed(self, request): @@ -116,6 +119,7 @@ class StackResourcesTab(tabs.Tab): name = _("Resources") slug = "resources" template_name = "project/stacks/_detail_resources.html" + # template_name = "stacks/_detail_resources.html" preload = False def allowed(self, request): @@ -148,6 +152,7 @@ class StackTemplateTab(tabs.Tab): name = _("Template") slug = "stack_template" template_name = "project/stacks/_stack_template.html" + # template_name = "stacks/_stack_template.html" def allowed(self, request): return policy.check( diff --git a/heat_dashboard/content/stacks/urls.py b/heat_dashboard/content/stacks/urls.py index c63a18f..77aa1f5 100644 --- a/heat_dashboard/content/stacks/urls.py +++ b/heat_dashboard/content/stacks/urls.py @@ -12,7 +12,7 @@ from django.conf.urls import url -from openstack_dashboard.dashboards.project.stacks import views +from heat_dashboard.content.stacks import views urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), diff --git a/heat_dashboard/content/stacks/views.py b/heat_dashboard/content/stacks/views.py index f5d47ec..bbb90bb 100644 --- a/heat_dashboard/content/stacks/views.py +++ b/heat_dashboard/content/stacks/views.py @@ -19,23 +19,21 @@ from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse_lazy from django.http import HttpResponse from django.utils.translation import ugettext_lazy as _ + import django.views.generic +from heat_dashboard import api +from heat_dashboard.content.stacks import api as project_api +from heat_dashboard.content.stacks import forms as project_forms +from heat_dashboard.content.stacks import tables as project_tables +from heat_dashboard.content.stacks import tabs as project_tabs + from horizon import exceptions from horizon import forms from horizon import tables from horizon import tabs from horizon.utils import memoized from horizon import views -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.stacks \ - import api as project_api -from openstack_dashboard.dashboards.project.stacks \ - import forms as project_forms -from openstack_dashboard.dashboards.project.stacks \ - import tables as project_tables -from openstack_dashboard.dashboards.project.stacks \ - import tabs as project_tabs class IndexView(tables.DataTableView): diff --git a/heat_dashboard/content/template_versions/panel.py b/heat_dashboard/content/template_versions/panel.py index 3492d59..22ac7af 100644 --- a/heat_dashboard/content/template_versions/panel.py +++ b/heat_dashboard/content/template_versions/panel.py @@ -18,6 +18,6 @@ import horizon class TemplateVersions(horizon.Panel): name = _("Template Versions") - slug = "stacks.template_versions" + slug = "template_versions" permissions = ('openstack.services.orchestration',) policy_rules = (("orchestration", "stacks:list_template_versions"),) diff --git a/heat_dashboard/content/template_versions/tables.py b/heat_dashboard/content/template_versions/tables.py index 8c63d14..ba85c73 100644 --- a/heat_dashboard/content/template_versions/tables.py +++ b/heat_dashboard/content/template_versions/tables.py @@ -21,7 +21,7 @@ class TemplateVersionsTable(tables.DataTable): version = tables.Column( "version", verbose_name=_("Version"), - link="horizon:project:stacks.template_versions:details",) + link="horizon:project:template_versions:details",) type = tables.Column( "type", verbose_name=_("Type"), diff --git a/heat_dashboard/content/template_versions/tabs.py b/heat_dashboard/content/template_versions/tabs.py index 9cb9096..c44575e 100644 --- a/heat_dashboard/content/template_versions/tabs.py +++ b/heat_dashboard/content/template_versions/tabs.py @@ -18,14 +18,15 @@ from horizon import tabs from openstack_dashboard import api from openstack_dashboard import policy -from openstack_dashboard.dashboards.project.stacks.template_versions \ - import tables as project_tables +# from openstack_dashboard.dashboards.project.stacks.template_versions \ +# import tables as project_tables +from heat_dashboard.content.template_versions import tables as project_tables class TemplateFunctionsTab(tabs.Tab): name = _("Template Functions") slug = "template_functions" - template_name = "project/stacks.template_versions/_details.html" + template_name = "project/template_versions/_details.html" preload = False def allowed(self, request): diff --git a/heat_dashboard/content/template_versions/urls.py b/heat_dashboard/content/template_versions/urls.py index 5e2bbc2..e956926 100644 --- a/heat_dashboard/content/template_versions/urls.py +++ b/heat_dashboard/content/template_versions/urls.py @@ -13,8 +13,9 @@ from django.conf.urls import url -from openstack_dashboard.dashboards.project.stacks.template_versions \ - import views +# from openstack_dashboard.dashboards.project.stacks.template_versions \ +# import views +from heat_dashboard.content.template_versions import views urlpatterns = [ diff --git a/heat_dashboard/content/template_versions/views.py b/heat_dashboard/content/template_versions/views.py index 22eabd7..9a674be 100644 --- a/heat_dashboard/content/template_versions/views.py +++ b/heat_dashboard/content/template_versions/views.py @@ -18,16 +18,19 @@ from horizon import exceptions from horizon import tables from horizon import tabs -from openstack_dashboard import api -import openstack_dashboard.dashboards.project.stacks.template_versions.tables \ - as project_tables -import openstack_dashboard.dashboards.project.stacks.template_versions.tabs \ - as project_tabs +# from openstack_dashboard import api +# import openstack_dashboard.dashboards.project.\ +# stacks.template_versions.tables as project_tables +# import openstack_dashboard.dashboards.project.\ +# stacks.template_versions.tabs as project_tabs +from heat_dashboard import api +import heat_dashboard.content.template_versions.tables as project_tables +import heat_dashboard.content.template_versions.tabs as project_tabs class TemplateVersionsView(tables.DataTableView): table_class = project_tables.TemplateVersionsTable - template_name = 'project/stacks.template_versions/index.html' + template_name = 'project/template_versions/index.html' page_title = _("Template Versions") def get_data(self): diff --git a/heat_dashboard/enabled/_1620_project_stacks_panel.py b/heat_dashboard/enabled/_1620_project_stacks_panel.py index b044fcc..82791c3 100644 --- a/heat_dashboard/enabled/_1620_project_stacks_panel.py +++ b/heat_dashboard/enabled/_1620_project_stacks_panel.py @@ -1,3 +1,15 @@ +# 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 slug of the panel to be added to HORIZON_CONFIG. Required. PANEL = 'stacks' # The slug of the dashboard the PANEL associated with. Required. @@ -6,4 +18,9 @@ PANEL_DASHBOARD = 'project' PANEL_GROUP = 'orchestration' # Python panel class of the PANEL to be added. -ADD_PANEL = 'openstack_dashboard.dashboards.project.stacks.panel.Stacks' +ADD_PANEL = 'heat_dashboard.content.stacks.panel.Stacks' + +# Automatically discover static resources in installed apps +AUTO_DISCOVER_STATIC_FILES = True + +# ADD_INSTALLED_APPS = ['heat_dashboard.content.stacks', ] diff --git a/heat_dashboard/enabled/_1630_project_resource_types_panel.py b/heat_dashboard/enabled/_1630_project_resource_types_panel.py index 8b04892..8145b18 100644 --- a/heat_dashboard/enabled/_1630_project_resource_types_panel.py +++ b/heat_dashboard/enabled/_1630_project_resource_types_panel.py @@ -1,10 +1,27 @@ +# 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 slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'stacks.resource_types' +PANEL = 'resource_types' # The slug of the dashboard the PANEL associated with. Required. PANEL_DASHBOARD = 'project' # The slug of the panel group the PANEL is associated with. PANEL_GROUP = 'orchestration' # Python panel class of the PANEL to be added. -ADD_PANEL = ('openstack_dashboard.dashboards.project.' - 'stacks.resource_types.panel.ResourceTypes') +ADD_PANEL = 'heat_dashboard.content.resource_types.panel.ResourceTypes' + +# Automatically discover static resources in installed apps +AUTO_DISCOVER_STATIC_FILES = True + +# ADD_INSTALLED_APPS = ['heat_dashboard.content.resource_types', ] +DISABLED = False diff --git a/heat_dashboard/enabled/_1640_project_template_versions_panel.py b/heat_dashboard/enabled/_1640_project_template_versions_panel.py index f31e040..d914326 100644 --- a/heat_dashboard/enabled/_1640_project_template_versions_panel.py +++ b/heat_dashboard/enabled/_1640_project_template_versions_panel.py @@ -1,10 +1,26 @@ +# 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 slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'stacks.template_versions' +PANEL = 'template_versions' # The slug of the dashboard the PANEL associated with. Required. PANEL_DASHBOARD = 'project' # The slug of the panel group the PANEL is associated with. PANEL_GROUP = 'orchestration' # Python panel class of the PANEL to be added. -ADD_PANEL = ('openstack_dashboard.dashboards.project.' - 'stacks.template_versions.panel.TemplateVersions') +ADD_PANEL = 'heat_dashboard.content.template_versions.panel.TemplateVersions' + +# Automatically discover static resources in installed apps +AUTO_DISCOVER_STATIC_FILES = True + +# ADD_INSTALLED_APPS = ['heat_dashboard.content.template_versions', ] diff --git a/heat_dashboard/test/settings.py b/heat_dashboard/test/settings.py index 8b36dfd..ed94fd4 100644 --- a/heat_dashboard/test/settings.py +++ b/heat_dashboard/test/settings.py @@ -1,310 +1,24 @@ -# 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 +# 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 # -# 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. +# 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 os -import tempfile - -import six - -from django.utils.translation import pgettext_lazy -from horizon.test.settings import * # noqa: F403,H303 -from horizon.utils import secret_key -from openstack_dashboard import exceptions - -from horizon.utils.escape import monkeypatch_escape - -# this is used to protect from client XSS attacks, but it's worth -# enabling in our test setup to find any issues it might cause -monkeypatch_escape() - -from openstack_dashboard.utils import settings as settings_utils - -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/' -WEBROOT = '/' - -SECRET_KEY = secret_key.generate_or_read_from_file( - os.path.join(tempfile.gettempdir(), '.secret_key_store')) -ROOT_URLCONF = 'openstack_dashboard.test.urls' - -TEMPLATES[0]['DIRS'] = [ - os.path.join(TEST_DIR, 'templates') -] - -TEMPLATES[0]['OPTIONS']['context_processors'].append( - 'openstack_dashboard.context_processors.openstack' -) - -CUSTOM_THEME_PATH = 'themes/default' - -# 'key', 'label', 'path' -AVAILABLE_THEMES = [ - ( - 'default', - pgettext_lazy('Default style theme', 'Default'), - 'themes/default' - ), ( - 'material', - pgettext_lazy("Google's Material Design style theme", "Material"), - 'themes/material' - ), -] - -SELECTABLE_THEMES = [ - ( - 'default', - pgettext_lazy('Default style theme', 'Default'), - 'themes/default' - ), -] - -# Theme Static Directory -THEME_COLLECTION_DIR = 'themes' - -COMPRESS_OFFLINE = False - -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', -) - -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': [], -} - -ANGULAR_FEATURES = { - 'images_panel': False, # Use the legacy panel so unit tests are still run - 'flavors_panel': False, - 'roles_panel': False, -} - -STATICFILES_DIRS = settings_utils.get_xstatic_dirs( - settings_utils.BASE_XSTATIC_MODULES, HORIZON_CONFIG -) - -# Load the pluggable dashboard settings -import openstack_dashboard.enabled - -INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable -settings_utils.update_dashboards( - [ - openstack_dashboard.enabled, - ], - HORIZON_CONFIG, - INSTALLED_APPS, -) - -OPENSTACK_PROFILER = {'enabled': False} - -settings_utils.find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES, - THEME_COLLECTION_DIR, ROOT_PATH) - -# Set to 'legacy' or 'direct' to allow users to upload images to glance via -# Horizon server. When enabled, a file form field will appear on the create -# image form. If set to 'off', there will be no file form field on the create -# image form. See documentation for deployment considerations. -HORIZON_IMAGES_UPLOAD_MODE = 'legacy' - -AVAILABLE_REGIONS = [ - ('http://localhost:5000/v2.0', 'local'), - ('http://remote:5000/v2.0', 'remote'), -] - -OPENSTACK_API_VERSIONS = { - "identity": 3, - "image": 2 -} - -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_FEDERATION_MANAGEMENT = True - -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_router': True, - 'enable_quotas': False, # Enabled in specific tests only - 'enable_distributed_router': False, -} - -OPENSTACK_HYPERVISOR_FEATURES = { - 'can_set_mount_point': False, - 'can_set_password': True, -} - -OPENSTACK_IMAGE_BACKEND = { - 'image_formats': [ - ('', 'Select format'), - ('aki', 'AKI - Amazon Kernel Image'), - ('ami', 'AMI - Amazon Machine Image'), - ('ari', 'ARI - Amazon Ramdisk Image'), - ('iso', 'ISO - Optical Disk Image'), - ('ploop', 'PLOOP - Virtuozzo/Parallels Loopback Disk'), - ('qcow2', 'QCOW2 - QEMU Emulator'), - ('raw', 'Raw'), - ('vdi', 'VDI'), - ('vhd', 'VHD'), - ('vmdk', 'VMDK') - ] -} - -LOGGING['loggers'].update( - { - 'openstack_dashboard': { - 'handlers': ['test'], - 'propagate': False, - }, - 'openstack_auth': { - 'handlers': ['test'], - 'propagate': False, - }, - 'novaclient': { - 'handlers': ['test'], - 'propagate': False, - }, - 'keystoneclient': { - 'handlers': ['test'], - 'propagate': False, - }, - 'glanceclient': { - 'handlers': ['test'], - 'propagate': False, - }, - 'neutronclient': { - 'handlers': ['test'], - 'propagate': False, - }, - 'iso8601': { - 'handlers': ['null'], - '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'] -# TODO(amotoki): Need to investigate why --with-html-output -# is unavailable in python3. -# NOTE(amotoki): Most horizon plugins import this module in their test -# settings and they do not necessarily have nosehtmloutput in test-reqs. -# Assuming nosehtmloutput potentially breaks plugins tests, -# we check the availability of htmloutput module (from nosehtmloutput). -try: - import htmloutput # noqa: F401 - has_html_output = True -except ImportError: - has_html_output = False -if six.PY2 and has_html_output: - NOSE_ARGS += ['--with-html-output', - '--html-out-file=ut_openstack_dashboard_nose_results.html'] - -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' - -REST_API_SETTING_1 = 'foo' -REST_API_SETTING_2 = 'bar' -REST_API_SECURITY = 'SECURITY' -REST_API_REQUIRED_SETTINGS = ['REST_API_SETTING_1'] -REST_API_ADDITIONAL_SETTINGS = ['REST_API_SETTING_2'] - -ALLOWED_PRIVATE_SUBNET_CIDR = {'ipv4': [], 'ipv6': []} +from horizon.test.settings import * # noqa +from openstack_dashboard.test.settings import * # noqa -# -------------------- -# Test-only settings -# -------------------- -# TEST_GLOBAL_MOCKS_ON_PANELS: defines what and how methods should be -# mocked globally for unit tests and Selenium tests. -# 'method' is required. 'return_value' and 'side_effect' -# are optional and passed to mock.patch(). -TEST_GLOBAL_MOCKS_ON_PANELS = { - 'aggregates': { - 'method': ('openstack_dashboard.dashboards.admin' - '.aggregates.panel.Aggregates.can_access'), - 'return_value': True, - }, - 'trunk': { - 'method': ('openstack_dashboard.dashboards.project' - '.trunks.panel.Trunks.can_access'), - 'return_value': True, - }, - 'qos': { - 'method': ('openstack_dashboard.dashboards.project' - '.network_qos.panel.NetworkQoS.can_access'), - 'return_value': True, - }, -} +INSTALLED_APPS = list(INSTALLED_APPS) +INSTALLED_APPS.append('heat_dashboard.content.stacks') +INSTALLED_APPS.append('heat_dashboard.content.resource_types') +INSTALLED_APPS.append('heat_dashboard.content.template_versions') + +# further implementation +# INSTALLED_APPS.append('heat_dashboard.content.template_generator') diff --git a/heat_dashboard/test/tests/api/heat_rest_tests.py b/heat_dashboard/test/tests/api/heat_rest_tests.py index ef5cc0f..b8e4607 100644 --- a/heat_dashboard/test/tests/api/heat_rest_tests.py +++ b/heat_dashboard/test/tests/api/heat_rest_tests.py @@ -15,9 +15,11 @@ import json import mock +# from openstack_dashboard.api.rest import heat +# from openstack_dashboard.test import helpers as test +from heat_dashboard.api.rest import heat +from heat_dashboard.test import helpers as test from openstack_dashboard import api -from openstack_dashboard.api.rest import heat -from openstack_dashboard.test import helpers as test class ValidateRestTestCase(test.TestCase): diff --git a/heat_dashboard/test/tests/api/heat_tests.py b/heat_dashboard/test/tests/api/heat_tests.py index d241277..c58fe83 100644 --- a/heat_dashboard/test/tests/api/heat_tests.py +++ b/heat_dashboard/test/tests/api/heat_tests.py @@ -14,9 +14,12 @@ import six from django.conf import settings from django.test.utils import override_settings +# from openstack_dashboard import api +# from openstack_dashboard.test import helpers as test +from heat_dashboard import api +from heat_dashboard.test import helpers as test + from horizon import exceptions -from openstack_dashboard import api -from openstack_dashboard.test import helpers as test class HeatApiTests(test.APITestCase): diff --git a/heat_dashboard/test/tests/content/test_resource_types.py b/heat_dashboard/test/tests/content/test_resource_types.py index 4c73644..3022355 100644 --- a/heat_dashboard/test/tests/content/test_resource_types.py +++ b/heat_dashboard/test/tests/content/test_resource_types.py @@ -16,8 +16,9 @@ from django import http from mox3.mox import IsA -from openstack_dashboard import api -from openstack_dashboard.test import helpers as test +# from openstack_dashboard import api +from heat_dashboard import api +from heat_dashboard.test import helpers as test class ResourceTypesTests(test.TestCase): diff --git a/heat_dashboard/test/tests/content/test_stacks.py b/heat_dashboard/test/tests/content/test_stacks.py index d646a51..3f5f760 100644 --- a/heat_dashboard/test/tests/content/test_stacks.py +++ b/heat_dashboard/test/tests/content/test_stacks.py @@ -20,16 +20,23 @@ from django.core.urlresolvers import reverse from django import http from django.test.utils import override_settings from django.utils import html -from heatclient.common import template_format as hc_format + from mox3.mox import IsA import six -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.stacks import api as project_api -from openstack_dashboard.dashboards.project.stacks import forms -from openstack_dashboard.dashboards.project.stacks import mappings -from openstack_dashboard.dashboards.project.stacks import tables -from openstack_dashboard.test import helpers as test +from heatclient.common import template_format as hc_format + +from heat_dashboard import api +from heat_dashboard.test import helpers as test +from openstack_dashboard import api as dashboard_api + +# from openstack_dashboard.dashboards.project.stacks import api as project_api +# from openstack_dashboard.dashboards.project.stacks import forms +# from openstack_dashboard.dashboards.project.stacks import mappings +# from openstack_dashboard.dashboards.project.stacks import tables +from heat_dashboard.content.stacks import forms +from heat_dashboard.content.stacks import mappings +from heat_dashboard.content.stacks import tables INDEX_TEMPLATE = 'horizon/common/_data_table_view.html' @@ -234,7 +241,7 @@ class StackTests(test.TestCase): settings.API_RESULT_PAGE_SIZE) @test.create_stubs({api.heat: ('stack_create', 'template_validate'), - api.neutron: ('network_list_for_tenant', )}) + dashboard_api.neutron: ('network_list_for_tenant', )}) def test_launch_stack(self): template = self.stack_templates.first() stack = self.stacks.first() @@ -252,11 +259,11 @@ class StackTests(test.TestCase): parameters=IsA(dict), password='password', files=None) - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() @@ -292,7 +299,7 @@ class StackTests(test.TestCase): self.assertRedirectsNoFollow(res, INDEX_URL) @test.create_stubs({api.heat: ('stack_create', 'template_validate'), - api.neutron: ('network_list_for_tenant', )}) + dashboard_api.neutron: ('network_list_for_tenant', )}) def test_launch_stack_with_environment(self): template = self.stack_templates.first() environment = self.stack_environments.first() @@ -313,11 +320,11 @@ class StackTests(test.TestCase): parameters=IsA(dict), password='password', files=None) - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() @@ -384,10 +391,11 @@ class StackTests(test.TestCase): } } } - api.heat.template_validate(IsA(http.HttpRequest), - files={}, - template=hc_format.parse(template['data'])) \ - .AndReturn(template['validate']) + api.heat.template_validate( + IsA(http.HttpRequest), + files={}, + template=hc_format.parse(template['data']))\ + .AndReturn(template['validate']) self.mox.ReplayAll() @@ -471,10 +479,11 @@ class StackTests(test.TestCase): ] } } - api.heat.template_validate(IsA(http.HttpRequest), - files={}, - template=hc_format.parse(template['data'])) \ - .AndReturn(template['validate']) + api.heat.template_validate( + IsA(http.HttpRequest), + files={}, + template=hc_format.parse(template['data'])).\ + AndReturn(template['validate']) self.mox.ReplayAll() @@ -546,10 +555,11 @@ class StackTests(test.TestCase): } stack = self.stacks.first() - api.heat.template_validate(IsA(http.HttpRequest), - files={}, - template=hc_format.parse(template['data'])) \ - .AndReturn(template['validate']) + api.heat.template_validate( + IsA(http.HttpRequest), + files={}, + template=hc_format.parse(template['data']))\ + .AndReturn(template['validate']) api.heat.stack_create(IsA(http.HttpRequest), stack_name=stack.stack_name, @@ -587,10 +597,12 @@ class StackTests(test.TestCase): 'name="__param_param{0}" type="{1}"/>') self.assertContains(res, input_str.format(1, 'text'), html=True) - # the custom number spinner produces an input element - # that doesn't match the input_strs above - # validate with id alone - self.assertContains(res, 'id="id___param_param2"') + self.assertContains( + res, + '', + html=True) self.assertContains(res, input_str.format(3, 'text'), html=True) self.assertContains(res, input_str.format(4, 'text'), html=True) self.assertContains( @@ -619,7 +631,7 @@ class StackTests(test.TestCase): @test.create_stubs({api.heat: ('stack_update', 'stack_get', 'template_get', 'template_validate'), - api.neutron: ('network_list_for_tenant', )}) + dashboard_api.neutron: ('network_list_for_tenant', )}) def test_edit_stack_template(self): template = self.stack_templates.first() stack = self.stacks.first() @@ -656,8 +668,8 @@ class StackTests(test.TestCase): api.heat.stack_update(IsA(http.HttpRequest), stack_id=stack.id, **fields) - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() @@ -703,10 +715,10 @@ class StackTests(test.TestCase): def test_launch_stack_form_invalid_name_point(self): self._test_launch_stack_invalid_name('.StartWithPoint') - @test.create_stubs({api.neutron: ('network_list_for_tenant', )}) + @test.create_stubs({dashboard_api.neutron: ('network_list_for_tenant', )}) def _test_launch_stack_invalid_name(self, name): - api.neutron.network_list_for_tenant(IsA(http.HttpRequest), - self.tenant.id) \ + dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest), + self.tenant.id) \ .AndReturn(self.networks.list()) self.mox.ReplayAll() @@ -844,17 +856,21 @@ class StackTests(test.TestCase): self.assertIn('stack-green.svg', d3_data) self.assertIn('Create Complete', d3_data) - @test.create_stubs({api.heat: ('stack_get', 'template_get'), - project_api: ('d3_data',)}) + # @test.create_stubs({api.heat: ('stack_get', 'template_get'), + # project_api: ('d3_data',)}) + @test.create_stubs({api.heat: ('stack_get', 'template_get', + 'resources_list')}) def test_detail_stack_overview(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn(stack) + api.heat.resources_list(IsA(http.HttpRequest), stack.id) \ + .MultipleTimes().AndReturn([]) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) - project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ - .AndReturn(json.dumps({"nodes": [], "stack": {}})) + # project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ + # .AndReturn(json.dumps({"nodes": [], "stack": {}})) self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), @@ -866,17 +882,26 @@ class StackTests(test.TestCase): 'project/stacks/_detail_overview.html') self.assertEqual(stack.stack_name, overview_data.stack_name) - @test.create_stubs({api.heat: ('stack_get', 'template_get'), - project_api: ('d3_data',)}) + # @test.create_stubs({api.heat: ('stack_get', + # 'template_get', 'resources_list'), + # project_api: ('d3_data',)}) + @test.create_stubs({api.heat: ('stack_get', 'template_get', + 'resources_list')}) def test_detail_stack_resources(self): stack = self.stacks.first() template = self.stack_templates.first() api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ .MultipleTimes().AndReturn(stack) + api.heat.resources_list(IsA(http.HttpRequest), stack.id) \ + .MultipleTimes().AndReturn([]) api.heat.template_get(IsA(http.HttpRequest), stack.id) \ .AndReturn(json.loads(template.validate)) - project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ - .AndReturn(json.dumps({"nodes": [], "stack": {}})) + + # Needs to move into JSONView test + # because this part will be called from Ajax + # project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ + # .AndReturn(json.dumps({"nodes": [], "stack": {}})) + self.mox.ReplayAll() url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), diff --git a/heat_dashboard/test/tests/content/test_template_versions.py b/heat_dashboard/test/tests/content/test_template_versions.py index fcace15..cd31184 100644 --- a/heat_dashboard/test/tests/content/test_template_versions.py +++ b/heat_dashboard/test/tests/content/test_template_versions.py @@ -16,8 +16,10 @@ from django import http from mox3.mox import IsA -from openstack_dashboard import api -from openstack_dashboard.test import helpers as test +# from openstack_dashboard import api +# from openstack_dashboard.test import helpers as test +from heat_dashboard import api +from heat_dashboard.test import helpers as test class TemplateVersionsTests(test.TestCase):