update files by working files.

This commit is contained in:
Keiichi Hikita 2017-10-06 14:44:50 +09:00
parent 2865d31cb4
commit 6e046521a0
29 changed files with 358 additions and 450 deletions

112
.gitignore vendored Normal file
View File

@ -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

View File

@ -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 shouldn't need to understand the finer details of APIs for
Keystone/Nova/Glance/Swift et. al. 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 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__ = [ __all__ = [
"base",
"cinder",
"glance",
"heat", "heat",
"keystone",
"network",
"neutron",
"nova",
"swift",
] ]

View File

@ -12,15 +12,17 @@
import contextlib import contextlib
import six
from six.moves.urllib import request
from django.conf import settings from django.conf import settings
from oslo_serialization import jsonutils
from heatclient import client as heat_client from heatclient import client as heat_client
from heatclient.common import template_format from heatclient.common import template_format
from heatclient.common import template_utils from heatclient.common import template_utils
from heatclient.common import utils as heat_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 import exceptions
from horizon.utils import functions as utils from horizon.utils import functions as utils
from horizon.utils.memoized import memoized from horizon.utils.memoized import memoized

View File

@ -13,7 +13,8 @@
from django.views import generic 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 urls
from openstack_dashboard.api.rest import utils as rest_utils from openstack_dashboard.api.rest import utils as rest_utils

View File

@ -18,6 +18,6 @@ import horizon
class ResourceTypes(horizon.Panel): class ResourceTypes(horizon.Panel):
name = _("Resource Types") name = _("Resource Types")
slug = "stacks.resource_types" slug = "resource_types"
permissions = ('openstack.services.orchestration',) permissions = ('openstack.services.orchestration',)
policy_rules = (("orchestration", "stacks:list_resource_types"),) policy_rules = (("orchestration", "stacks:list_resource_types"),)

View File

@ -24,7 +24,7 @@ class ResourceTypesFilterAction(tables.FilterAction):
class ResourceTypesTable(tables.DataTable): class ResourceTypesTable(tables.DataTable):
name = tables.Column("resource_type", name = tables.Column("resource_type",
verbose_name=_("Type"), verbose_name=_("Type"),
link="horizon:project:stacks.resource_types:details",) link="horizon:project:resource_types:details",)
def get_object_id(self, resource): def get_object_id(self, resource):
return resource.resource_type return resource.resource_type

View File

@ -19,7 +19,8 @@ from horizon import tabs
class ResourceTypeOverviewTab(tabs.Tab): class ResourceTypeOverviewTab(tabs.Tab):
name = _("Overview") name = _("Overview")
slug = "resource_type_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): def get_context_data(self, request):
return {"r_type": self.tab_group.kwargs['rt'], return {"r_type": self.tab_group.kwargs['rt'],

View File

@ -13,7 +13,7 @@
from django.conf.urls import url 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 = [ urlpatterns = [
url(r'^$', views.ResourceTypesView.as_view(), name='index'), url(r'^$', views.ResourceTypesView.as_view(), name='index'),

View File

@ -20,11 +20,14 @@ from horizon import exceptions
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from openstack_dashboard import api # from openstack_dashboard import api
import openstack_dashboard.dashboards.project.stacks.resource_types.tables \ # import openstack_dashboard.dashboards.project.stacks.resource_types.tables \
as project_tables # as project_tables
import openstack_dashboard.dashboards.project.stacks.resource_types.tabs \ # import openstack_dashboard.dashboards.project.stacks.resource_types.tabs \
as project_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): class ResourceTypesView(tables.DataTableView):
@ -75,4 +78,4 @@ class DetailView(tabs.TabView):
@staticmethod @staticmethod
def get_redirect_url(): def get_redirect_url():
return reverse('horizon:project:stacks.resources:index') return reverse('horizon:project:resource_types:index')

View File

@ -26,7 +26,8 @@ from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import messages 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 \ from openstack_dashboard.dashboards.project.images \
import utils as image_utils import utils as image_utils
from openstack_dashboard.dashboards.project.instances \ from openstack_dashboard.dashboards.project.instances \

View File

@ -142,7 +142,9 @@ def stack_output(output):
output = json.dumps(output, indent=2) output = json.dumps(output, indent=2)
return safestring.mark_safe(u'<pre>%s</pre>' % html.escape(output)) return safestring.mark_safe(u'<pre>%s</pre>' % html.escape(output))
static_url = getattr(settings, "STATIC_URL", "/static/") static_url = getattr(settings, "STATIC_URL", "/static/")
resource_images = { resource_images = {
'LB_FAILED': static_url + 'dashboard/img/lb-red.svg', 'LB_FAILED': static_url + 'dashboard/img/lb-red.svg',
'LB_DELETE': static_url + 'dashboard/img/lb-red.svg', 'LB_DELETE': static_url + 'dashboard/img/lb-red.svg',

View File

@ -16,15 +16,17 @@ from django.template.defaultfilters import title
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy from django.utils.translation import ungettext_lazy
from heatclient import exc
from horizon import exceptions
from horizon import messages from horizon import messages
from horizon import tables from horizon import tables
from horizon.utils import filters from horizon.utils import filters
from openstack_dashboard import api from heatclient import exc
from openstack_dashboard.dashboards.project.stacks import mappings
# 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): class LaunchStack(tables.LinkAction):
@ -96,11 +98,8 @@ class SuspendStack(tables.BatchAction):
) )
def action(self, request, stack_id): def action(self, request, stack_id):
try: # api.heat.action_suspend(request, stack_id)
api.heat.action_suspend(request, stack_id) api.heat.action_suspend(request, stack_id)
except Exception:
msg = _('Failed to suspend stack.')
exceptions.handle(request, msg)
class ResumeStack(tables.BatchAction): class ResumeStack(tables.BatchAction):
@ -126,11 +125,8 @@ class ResumeStack(tables.BatchAction):
) )
def action(self, request, stack_id): def action(self, request, stack_id):
try: # api.heat.action_resume(request, stack_id)
api.heat.action_resume(request, stack_id) api.heat.action_resume(request, stack_id)
except Exception:
msg = _('Failed to resume stack.')
exceptions.handle(request, msg)
class ChangeStackTemplate(tables.LinkAction): class ChangeStackTemplate(tables.LinkAction):
@ -164,11 +160,8 @@ class DeleteStack(tables.DeleteAction):
policy_rules = (("orchestration", "stacks:delete"),) policy_rules = (("orchestration", "stacks:delete"),)
def delete(self, request, stack_id): def delete(self, request, stack_id):
try: # api.heat.stack_delete(request, stack_id)
api.heat.stack_delete(request, stack_id) api.heat.stack_delete(request, stack_id)
except Exception:
msg = _('Failed to delete stack.')
exceptions.handle(request, msg)
def allowed(self, request, stack): def allowed(self, request, stack):
if stack is not None: if stack is not None:
@ -184,6 +177,7 @@ class StacksUpdateRow(tables.Row):
def get_data(self, request, stack_id): def get_data(self, request, stack_id):
try: try:
# stack = api.heat.stack_get(request, stack_id)
stack = api.heat.stack_get(request, stack_id) stack = api.heat.stack_get(request, stack_id)
if stack.stack_status == 'DELETE_COMPLETE': if stack.stack_status == 'DELETE_COMPLETE':
# returning 404 to the ajax call removes the # returning 404 to the ajax call removes the
@ -351,8 +345,11 @@ class ResourcesUpdateRow(tables.Row):
try: try:
stack = self.table.stack stack = self.table.stack
stack_identifier = '%s/%s' % (stack.stack_name, stack.id) stack_identifier = '%s/%s' % (stack.stack_name, stack.id)
return api.heat.resource_get( # return api.heat.resource_get(
request, stack_identifier, resource_name) # request, stack_identifier, resource_name)
return api.heat.resource_get(request,
stack_identifier,
resource_name)
except exc.HTTPNotFound: except exc.HTTPNotFound:
# returning 404 to the ajax call removes the # returning 404 to the ajax call removes the
# row from the table on the ui # row from the table on the ui

View File

@ -16,14 +16,13 @@ from django.utils.translation import ugettext_lazy as _
from horizon import messages from horizon import messages
from horizon import tabs from horizon import tabs
from openstack_dashboard import api
from openstack_dashboard import policy
from openstack_dashboard.dashboards.project.stacks \ from heat_dashboard import api
import api as project_api from heat_dashboard.content.stacks import api as project_api
from openstack_dashboard.dashboards.project.stacks import mappings from heat_dashboard.content.stacks import mappings
from openstack_dashboard.dashboards.project.stacks \ from heat_dashboard.content.stacks import tables as project_tables
import tables as project_tables
from openstack_dashboard import policy
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -33,6 +32,7 @@ class StackTopologyTab(tabs.Tab):
name = _("Topology") name = _("Topology")
slug = "topology" slug = "topology"
template_name = "project/stacks/_detail_topology.html" template_name = "project/stacks/_detail_topology.html"
# template_name = "stacks/_detail_topology.html"
preload = False preload = False
def allowed(self, request): def allowed(self, request):
@ -55,6 +55,7 @@ class StackOverviewTab(tabs.Tab):
name = _("Overview") name = _("Overview")
slug = "overview" slug = "overview"
template_name = "project/stacks/_detail_overview.html" template_name = "project/stacks/_detail_overview.html"
# template_name = "stacks/_detail_overview.html"
def allowed(self, request): def allowed(self, request):
return policy.check( return policy.check(
@ -71,6 +72,7 @@ class ResourceOverviewTab(tabs.Tab):
name = _("Overview") name = _("Overview")
slug = "resource_overview" slug = "resource_overview"
template_name = "project/stacks/_resource_overview.html" template_name = "project/stacks/_resource_overview.html"
# template_name = "stacks/_resource_overview.html"
def get_context_data(self, request): def get_context_data(self, request):
resource = self.tab_group.kwargs['resource'] resource = self.tab_group.kwargs['resource']
@ -85,6 +87,7 @@ class StackEventsTab(tabs.Tab):
name = _("Events") name = _("Events")
slug = "events" slug = "events"
template_name = "project/stacks/_detail_events.html" template_name = "project/stacks/_detail_events.html"
# template_name = "stacks/_detail_events.html"
preload = False preload = False
def allowed(self, request): def allowed(self, request):
@ -116,6 +119,7 @@ class StackResourcesTab(tabs.Tab):
name = _("Resources") name = _("Resources")
slug = "resources" slug = "resources"
template_name = "project/stacks/_detail_resources.html" template_name = "project/stacks/_detail_resources.html"
# template_name = "stacks/_detail_resources.html"
preload = False preload = False
def allowed(self, request): def allowed(self, request):
@ -148,6 +152,7 @@ class StackTemplateTab(tabs.Tab):
name = _("Template") name = _("Template")
slug = "stack_template" slug = "stack_template"
template_name = "project/stacks/_stack_template.html" template_name = "project/stacks/_stack_template.html"
# template_name = "stacks/_stack_template.html"
def allowed(self, request): def allowed(self, request):
return policy.check( return policy.check(

View File

@ -12,7 +12,7 @@
from django.conf.urls import url from django.conf.urls import url
from openstack_dashboard.dashboards.project.stacks import views from heat_dashboard.content.stacks import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'), url(r'^$', views.IndexView.as_view(), name='index'),

View File

@ -19,23 +19,21 @@ from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django.views.generic 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 exceptions
from horizon import forms from horizon import forms
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from horizon.utils import memoized from horizon.utils import memoized
from horizon import views 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): class IndexView(tables.DataTableView):

View File

@ -18,6 +18,6 @@ import horizon
class TemplateVersions(horizon.Panel): class TemplateVersions(horizon.Panel):
name = _("Template Versions") name = _("Template Versions")
slug = "stacks.template_versions" slug = "template_versions"
permissions = ('openstack.services.orchestration',) permissions = ('openstack.services.orchestration',)
policy_rules = (("orchestration", "stacks:list_template_versions"),) policy_rules = (("orchestration", "stacks:list_template_versions"),)

View File

@ -21,7 +21,7 @@ class TemplateVersionsTable(tables.DataTable):
version = tables.Column( version = tables.Column(
"version", "version",
verbose_name=_("Version"), verbose_name=_("Version"),
link="horizon:project:stacks.template_versions:details",) link="horizon:project:template_versions:details",)
type = tables.Column( type = tables.Column(
"type", "type",
verbose_name=_("Type"), verbose_name=_("Type"),

View File

@ -18,14 +18,15 @@ from horizon import tabs
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard import policy from openstack_dashboard import policy
from openstack_dashboard.dashboards.project.stacks.template_versions \ # from openstack_dashboard.dashboards.project.stacks.template_versions \
import tables as project_tables # import tables as project_tables
from heat_dashboard.content.template_versions import tables as project_tables
class TemplateFunctionsTab(tabs.Tab): class TemplateFunctionsTab(tabs.Tab):
name = _("Template Functions") name = _("Template Functions")
slug = "template_functions" slug = "template_functions"
template_name = "project/stacks.template_versions/_details.html" template_name = "project/template_versions/_details.html"
preload = False preload = False
def allowed(self, request): def allowed(self, request):

View File

@ -13,8 +13,9 @@
from django.conf.urls import url from django.conf.urls import url
from openstack_dashboard.dashboards.project.stacks.template_versions \ # from openstack_dashboard.dashboards.project.stacks.template_versions \
import views # import views
from heat_dashboard.content.template_versions import views
urlpatterns = [ urlpatterns = [

View File

@ -18,16 +18,19 @@ from horizon import exceptions
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from openstack_dashboard import api # from openstack_dashboard import api
import openstack_dashboard.dashboards.project.stacks.template_versions.tables \ # import openstack_dashboard.dashboards.project.\
as project_tables # stacks.template_versions.tables as project_tables
import openstack_dashboard.dashboards.project.stacks.template_versions.tabs \ # import openstack_dashboard.dashboards.project.\
as project_tabs # 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): class TemplateVersionsView(tables.DataTableView):
table_class = project_tables.TemplateVersionsTable table_class = project_tables.TemplateVersionsTable
template_name = 'project/stacks.template_versions/index.html' template_name = 'project/template_versions/index.html'
page_title = _("Template Versions") page_title = _("Template Versions")
def get_data(self): def get_data(self):

View File

@ -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. # The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'stacks' PANEL = 'stacks'
# The slug of the dashboard the PANEL associated with. Required. # The slug of the dashboard the PANEL associated with. Required.
@ -6,4 +18,9 @@ PANEL_DASHBOARD = 'project'
PANEL_GROUP = 'orchestration' PANEL_GROUP = 'orchestration'
# Python panel class of the PANEL to be added. # 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', ]

View File

@ -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. # 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. # The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'project' PANEL_DASHBOARD = 'project'
# The slug of the panel group the PANEL is associated with. # The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'orchestration' PANEL_GROUP = 'orchestration'
# Python panel class of the PANEL to be added. # Python panel class of the PANEL to be added.
ADD_PANEL = ('openstack_dashboard.dashboards.project.' ADD_PANEL = 'heat_dashboard.content.resource_types.panel.ResourceTypes'
'stacks.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

View File

@ -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. # 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. # The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'project' PANEL_DASHBOARD = 'project'
# The slug of the panel group the PANEL is associated with. # The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'orchestration' PANEL_GROUP = 'orchestration'
# Python panel class of the PANEL to be added. # Python panel class of the PANEL to be added.
ADD_PANEL = ('openstack_dashboard.dashboards.project.' ADD_PANEL = 'heat_dashboard.content.template_versions.panel.TemplateVersions'
'stacks.template_versions.panel.TemplateVersions')
# Automatically discover static resources in installed apps
AUTO_DISCOVER_STATIC_FILES = True
# ADD_INSTALLED_APPS = ['heat_dashboard.content.template_versions', ]

View File

@ -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 # http://www.apache.org/licenses/LICENSE-2.0
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT #
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # Unless required by applicable law or agreed to in writing, software
# License for the specific language governing permissions and limitations # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# under the License. # 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 from horizon.test.settings import * # noqa
import tempfile from openstack_dashboard.test.settings import * # noqa
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': []}
# -------------------- INSTALLED_APPS = list(INSTALLED_APPS)
# Test-only settings INSTALLED_APPS.append('heat_dashboard.content.stacks')
# -------------------- INSTALLED_APPS.append('heat_dashboard.content.resource_types')
# TEST_GLOBAL_MOCKS_ON_PANELS: defines what and how methods should be INSTALLED_APPS.append('heat_dashboard.content.template_versions')
# mocked globally for unit tests and Selenium tests.
# 'method' is required. 'return_value' and 'side_effect' # further implementation
# are optional and passed to mock.patch(). # INSTALLED_APPS.append('heat_dashboard.content.template_generator')
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,
},
}

View File

@ -15,9 +15,11 @@ import json
import mock 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 import api
from openstack_dashboard.api.rest import heat
from openstack_dashboard.test import helpers as test
class ValidateRestTestCase(test.TestCase): class ValidateRestTestCase(test.TestCase):

View File

@ -14,9 +14,12 @@ import six
from django.conf import settings from django.conf import settings
from django.test.utils import override_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 horizon import exceptions
from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
class HeatApiTests(test.APITestCase): class HeatApiTests(test.APITestCase):

View File

@ -16,8 +16,9 @@ from django import http
from mox3.mox import IsA from mox3.mox import IsA
from openstack_dashboard import api # 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 ResourceTypesTests(test.TestCase): class ResourceTypesTests(test.TestCase):

View File

@ -20,16 +20,23 @@ from django.core.urlresolvers import reverse
from django import http from django import http
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils import html from django.utils import html
from heatclient.common import template_format as hc_format
from mox3.mox import IsA from mox3.mox import IsA
import six import six
from openstack_dashboard import api from heatclient.common import template_format as hc_format
from openstack_dashboard.dashboards.project.stacks import api as project_api
from openstack_dashboard.dashboards.project.stacks import forms from heat_dashboard import api
from openstack_dashboard.dashboards.project.stacks import mappings from heat_dashboard.test import helpers as test
from openstack_dashboard.dashboards.project.stacks import tables from openstack_dashboard import api as dashboard_api
from openstack_dashboard.test import helpers as test
# 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' INDEX_TEMPLATE = 'horizon/common/_data_table_view.html'
@ -234,7 +241,7 @@ class StackTests(test.TestCase):
settings.API_RESULT_PAGE_SIZE) settings.API_RESULT_PAGE_SIZE)
@test.create_stubs({api.heat: ('stack_create', 'template_validate'), @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): def test_launch_stack(self):
template = self.stack_templates.first() template = self.stack_templates.first()
stack = self.stacks.first() stack = self.stacks.first()
@ -252,11 +259,11 @@ class StackTests(test.TestCase):
parameters=IsA(dict), parameters=IsA(dict),
password='password', password='password',
files=None) files=None)
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -292,7 +299,7 @@ class StackTests(test.TestCase):
self.assertRedirectsNoFollow(res, INDEX_URL) self.assertRedirectsNoFollow(res, INDEX_URL)
@test.create_stubs({api.heat: ('stack_create', 'template_validate'), @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): def test_launch_stack_with_environment(self):
template = self.stack_templates.first() template = self.stack_templates.first()
environment = self.stack_environments.first() environment = self.stack_environments.first()
@ -313,11 +320,11 @@ class StackTests(test.TestCase):
parameters=IsA(dict), parameters=IsA(dict),
password='password', password='password',
files=None) files=None)
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -384,10 +391,11 @@ class StackTests(test.TestCase):
} }
} }
} }
api.heat.template_validate(IsA(http.HttpRequest), api.heat.template_validate(
files={}, IsA(http.HttpRequest),
template=hc_format.parse(template['data'])) \ files={},
.AndReturn(template['validate']) template=hc_format.parse(template['data']))\
.AndReturn(template['validate'])
self.mox.ReplayAll() self.mox.ReplayAll()
@ -471,10 +479,11 @@ class StackTests(test.TestCase):
] ]
} }
} }
api.heat.template_validate(IsA(http.HttpRequest), api.heat.template_validate(
files={}, IsA(http.HttpRequest),
template=hc_format.parse(template['data'])) \ files={},
.AndReturn(template['validate']) template=hc_format.parse(template['data'])).\
AndReturn(template['validate'])
self.mox.ReplayAll() self.mox.ReplayAll()
@ -546,10 +555,11 @@ class StackTests(test.TestCase):
} }
stack = self.stacks.first() stack = self.stacks.first()
api.heat.template_validate(IsA(http.HttpRequest), api.heat.template_validate(
files={}, IsA(http.HttpRequest),
template=hc_format.parse(template['data'])) \ files={},
.AndReturn(template['validate']) template=hc_format.parse(template['data']))\
.AndReturn(template['validate'])
api.heat.stack_create(IsA(http.HttpRequest), api.heat.stack_create(IsA(http.HttpRequest),
stack_name=stack.stack_name, stack_name=stack.stack_name,
@ -587,10 +597,12 @@ class StackTests(test.TestCase):
'name="__param_param{0}" type="{1}"/>') 'name="__param_param{0}" type="{1}"/>')
self.assertContains(res, input_str.format(1, 'text'), html=True) self.assertContains(res, input_str.format(1, 'text'), html=True)
# the custom number spinner produces an input element self.assertContains(
# that doesn't match the input_strs above res,
# validate with id alone '<input autocomplete="off" class="form-control" '
self.assertContains(res, 'id="id___param_param2"') 'id="id___param_param2" name="__param_param2" '
'type="number"/>',
html=True)
self.assertContains(res, input_str.format(3, 'text'), html=True) self.assertContains(res, input_str.format(3, 'text'), html=True)
self.assertContains(res, input_str.format(4, 'text'), html=True) self.assertContains(res, input_str.format(4, 'text'), html=True)
self.assertContains( self.assertContains(
@ -619,7 +631,7 @@ class StackTests(test.TestCase):
@test.create_stubs({api.heat: ('stack_update', 'stack_get', 'template_get', @test.create_stubs({api.heat: ('stack_update', 'stack_get', 'template_get',
'template_validate'), 'template_validate'),
api.neutron: ('network_list_for_tenant', )}) dashboard_api.neutron: ('network_list_for_tenant', )})
def test_edit_stack_template(self): def test_edit_stack_template(self):
template = self.stack_templates.first() template = self.stack_templates.first()
stack = self.stacks.first() stack = self.stacks.first()
@ -656,8 +668,8 @@ class StackTests(test.TestCase):
api.heat.stack_update(IsA(http.HttpRequest), api.heat.stack_update(IsA(http.HttpRequest),
stack_id=stack.id, stack_id=stack.id,
**fields) **fields)
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -703,10 +715,10 @@ class StackTests(test.TestCase):
def test_launch_stack_form_invalid_name_point(self): def test_launch_stack_form_invalid_name_point(self):
self._test_launch_stack_invalid_name('.StartWithPoint') 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): def _test_launch_stack_invalid_name(self, name):
api.neutron.network_list_for_tenant(IsA(http.HttpRequest), dashboard_api.neutron.network_list_for_tenant(IsA(http.HttpRequest),
self.tenant.id) \ self.tenant.id) \
.AndReturn(self.networks.list()) .AndReturn(self.networks.list())
self.mox.ReplayAll() self.mox.ReplayAll()
@ -844,17 +856,21 @@ class StackTests(test.TestCase):
self.assertIn('stack-green.svg', d3_data) self.assertIn('stack-green.svg', d3_data)
self.assertIn('Create Complete', d3_data) self.assertIn('Create Complete', d3_data)
@test.create_stubs({api.heat: ('stack_get', 'template_get'), # @test.create_stubs({api.heat: ('stack_get', 'template_get'),
project_api: ('d3_data',)}) # project_api: ('d3_data',)})
@test.create_stubs({api.heat: ('stack_get', 'template_get',
'resources_list')})
def test_detail_stack_overview(self): def test_detail_stack_overview(self):
stack = self.stacks.first() stack = self.stacks.first()
template = self.stack_templates.first() template = self.stack_templates.first()
api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ api.heat.stack_get(IsA(http.HttpRequest), stack.id) \
.MultipleTimes().AndReturn(stack) .MultipleTimes().AndReturn(stack)
api.heat.resources_list(IsA(http.HttpRequest), stack.id) \
.MultipleTimes().AndReturn([])
api.heat.template_get(IsA(http.HttpRequest), stack.id) \ api.heat.template_get(IsA(http.HttpRequest), stack.id) \
.AndReturn(json.loads(template.validate)) .AndReturn(json.loads(template.validate))
project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \ # project_api.d3_data(IsA(http.HttpRequest), stack_id=stack.id) \
.AndReturn(json.dumps({"nodes": [], "stack": {}})) # .AndReturn(json.dumps({"nodes": [], "stack": {}}))
self.mox.ReplayAll() self.mox.ReplayAll()
url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), url = '?'.join([reverse(DETAIL_URL, args=[stack.id]),
@ -866,17 +882,26 @@ class StackTests(test.TestCase):
'project/stacks/_detail_overview.html') 'project/stacks/_detail_overview.html')
self.assertEqual(stack.stack_name, overview_data.stack_name) self.assertEqual(stack.stack_name, overview_data.stack_name)
@test.create_stubs({api.heat: ('stack_get', 'template_get'), # @test.create_stubs({api.heat: ('stack_get',
project_api: ('d3_data',)}) # '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): def test_detail_stack_resources(self):
stack = self.stacks.first() stack = self.stacks.first()
template = self.stack_templates.first() template = self.stack_templates.first()
api.heat.stack_get(IsA(http.HttpRequest), stack.id) \ api.heat.stack_get(IsA(http.HttpRequest), stack.id) \
.MultipleTimes().AndReturn(stack) .MultipleTimes().AndReturn(stack)
api.heat.resources_list(IsA(http.HttpRequest), stack.id) \
.MultipleTimes().AndReturn([])
api.heat.template_get(IsA(http.HttpRequest), stack.id) \ api.heat.template_get(IsA(http.HttpRequest), stack.id) \
.AndReturn(json.loads(template.validate)) .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() self.mox.ReplayAll()
url = '?'.join([reverse(DETAIL_URL, args=[stack.id]), url = '?'.join([reverse(DETAIL_URL, args=[stack.id]),

View File

@ -16,8 +16,10 @@ from django import http
from mox3.mox import IsA from mox3.mox import IsA
from openstack_dashboard import api # from openstack_dashboard import api
from openstack_dashboard.test import helpers as test # 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): class TemplateVersionsTests(test.TestCase):