Added Goals and Strategies to Dashboard

In this changeset I added 2 new panels: Goals and Strategies.
I also update the Audit Template panel to take into account the
new model fields.

Partially Implements: get-goal-from-strategy

Change-Id: Ie8d8785ee0133650ac56c499abca0260309032eb
This commit is contained in:
Vincent Francoise 2016-04-05 10:36:33 +02:00 committed by David TARDIVEL
parent d5b54a8c5d
commit 387e51ee96
58 changed files with 1231 additions and 311 deletions

View File

@ -6,6 +6,7 @@ pbr>=1.8
Django>=1.8,<1.9 # BSD
django_compressor>=1.4 # MIT
django_openstack_auth>=2.0.0 # Apache-2.0
httplib2>=0.7.5 # MIT
python-keystoneclient>=1.6.0,!=1.8.0,!=2.1.0 # Apache-2.0
pytz>=2013.6 # MIT

View File

@ -343,7 +343,7 @@ function run_tests {
fi
if [ $with_selenium -eq 0 -a $integration -eq 0 ]; then
testopts="$testopts --exclude=watcher_dashboard/test/integration_tests/"
testopts="$testopts --exclude=watcher_dashboard/test/integration_tests/ "
fi
if [ $selenium_headless -eq 1 ]; then

View File

@ -22,7 +22,7 @@ deps = -r{toxinidir}/requirements.txt
commands =
python manage.py test --settings=watcher_dashboard.test.settings \
--exclude-dir=watcher_dashboard/test/integration_tests \
watcher_dashboard.test
watcher_dashboard
[testenv:pep8]
commands = flake8

View File

@ -46,7 +46,7 @@ def watcherclient(request, password=None):
return client
class Audit(base.APIResourceWrapper):
class Audit(base.APIDictWrapper):
_attrs = ('uuid', 'created_at', 'modified_at', 'deleted_at',
'deadline', 'state', 'type', 'audit_template_uuid',
'audit_template_name')
@ -62,8 +62,8 @@ class Audit(base.APIResourceWrapper):
:param request: request object
:type request: django.http.HttpRequest
:param audit_template: audit audit_template
:type audit_template: string
:param audit_template_uuid: related audit template UUID
:type audit_template_uuid: string
:param type: audit type
:type type: string
@ -72,12 +72,11 @@ class Audit(base.APIResourceWrapper):
:type deadline: string
:return: the created Audit object
:rtype: watcher_dashboard.api.watcher.Audit
:rtype: :py:class:`~.Audit`
"""
audit = watcherclient(request).audit.create(
return watcherclient(request).audit.create(
audit_template_uuid=audit_template_uuid, type=type,
deadline=deadline)
return cls(audit, request=request)
@classmethod
def list(cls, request, audit_template_filter):
@ -90,11 +89,10 @@ class Audit(base.APIResourceWrapper):
:type audit_template_filter: string
:return: list of audits, or an empty list if there are none
:rtype: list of watcher_dashboard.api.watcher.Audit
:rtype: list of :py:class:`~.Audit`
"""
audits = watcherclient(request).audit.list(
return watcherclient(request).audit.list(
audit_template=audit_template_filter)
return [cls(audit, request=request) for audit in audits]
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve audit"))
@ -109,10 +107,9 @@ class Audit(base.APIResourceWrapper):
:return: matching audit, or None if no audit matches
the ID
:rtype: watcher_dashboard.api.watcher.Audit
:rtype: :py:class:`~.Audit`
"""
audit = watcherclient(request).audit.get(audit_id=audit_id)
return cls(audit, request=request)
return watcherclient(request).audit.get(audit_id=audit_id)
@classmethod
def delete(cls, request, audit_id):
@ -134,14 +131,15 @@ class Audit(base.APIResourceWrapper):
class AuditTemplate(base.APIDictWrapper):
_attrs = ('uuid', 'created_at', 'updated_at', 'deleted_at',
'description', 'host_aggregate', 'name',
'extra', 'goal')
'extra', 'goal_uuid' 'strategy_uuid')
def __init__(self, apiresource, request=None):
super(AuditTemplate, self).__init__(apiresource)
self._request = request
@classmethod
def create(cls, request, name, goal, description, host_aggregate):
def create(cls, request, name, goal_uuid, strategy_uuid,
description, host_aggregate):
"""Create an audit template in Watcher
:param request: request object
@ -150,25 +148,29 @@ class AuditTemplate(base.APIDictWrapper):
:param name: Name for this audit template
:type name: string
:param goal: Goal Type associated to this audit template
:type goal: string
:param goal_uuid: Goal UUID associated to this audit template
:type goal_uuid: string
:param strategy_uuid: Strategy UUID associated to this audit template
:type strategy_uuid: string
:param description: Descrition of the audit template
:type description: string
:param host_aggregate: Name or ID of the host aggregate targeted\
by this audit template
:param host_aggregate: Name or UUID of the host aggregate targeted
by this audit template
:type host_aggregate: string
:param audit_template: audit audit_template
:param audit_template: audit template
:type audit_template: string
:return: the created Audit Template object
:rtype: watcher_dashboard.api.watcher.AuditTemplate
:rtype: :py:class:`~.AuditTemplate`
"""
audit_template = watcherclient(request).audit_template.create(
name=name,
goal=goal,
goal_uuid=goal_uuid,
strategy_uuid=strategy_uuid,
description=description,
host_aggregate=host_aggregate
)
@ -189,7 +191,7 @@ class AuditTemplate(base.APIDictWrapper):
:type parameters: dict
:return: the updated Audit Template object
:rtype: watcher_dashboard.api.watcher.AuditTemplate
:rtype: :py:class:`~.AuditTemplate`
"""
parameter_list = [{
'name': str(name),
@ -200,22 +202,18 @@ class AuditTemplate(base.APIDictWrapper):
return audit_template
@classmethod
def list(cls, request, filter):
def list(cls, request, **filters):
"""Return a list of audit templates in Watcher
:param request: request object
:type request: django.http.HttpRequest
:param filter: audit template filter
:type filter: string
:param filters: key/value kwargs used as filters
:return: list of audit templates, or an empty list if there are none
:rtype: list of watcher_dashboard.api.watcher.AuditTemplate
:rtype: list of :py:class:`~.AuditTemplate`
"""
audit_templates = watcherclient(request).audit_template.list(
name=filter)
return audit_templates
return watcherclient(request).audit_template.list(**filters)
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve audit template"))
@ -230,31 +228,10 @@ class AuditTemplate(base.APIDictWrapper):
:return: matching audit template, or None if no audit template matches
the ID
:rtype: watcher_dashboard.api.watcher.AuditTemplate
:rtype: :py:class:`~.AuditTemplate`
"""
audit_template = watcherclient(request).audit_template.get(
return watcherclient(request).audit_template.get(
audit_template_id=audit_template_id)
# return cls(audit, request=request)
return audit_template
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve audit template goal"))
def get_goals(cls, request):
"""Return the audit template goal that matches the ID
:param request: request object
:type request: django.http.HttpRequest
:param audit_template_id: id of audit template to be retrieved
:type audit_template_id: int
:return: matching audit template, or None if no audit template matches
the ID
:rtype: watcher_dashboard.api.watcher.AuditTemplate
"""
goals = watcherclient(request).goal.list()
return map(lambda goal: goal.name, goals)
@classmethod
def delete(cls, request, audit_template_id):
@ -274,7 +251,7 @@ class AuditTemplate(base.APIDictWrapper):
return self.uuid
class ActionPlan(base.APIResourceWrapper):
class ActionPlan(base.APIDictWrapper):
_attrs = ('uuid', 'created_at', 'updated_at', 'deleted_at',
'audit_uuid', 'state')
@ -293,12 +270,10 @@ class ActionPlan(base.APIResourceWrapper):
:type audit_filter: string
:return: list of action plans, or an empty list if there are none
:rtype: list of watcher_dashboard.api.watcher.ActionPlan
:rtype: list of :py:class:`~.ActionPlan`
"""
action_plans = watcherclient(request).action_plan.list(
return watcherclient(request).action_plan.list(
audit=audit_filter)
return [cls(action_plan, request=request)
for action_plan in action_plans]
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve action plan"))
@ -313,11 +288,10 @@ class ActionPlan(base.APIResourceWrapper):
:return: matching action plan, or None if no action plan matches
the ID
:rtype: watcher_dashboard.api.watcher.ActionPlan
:rtype: :py:class:`~.ActionPlan`
"""
action_plan = watcherclient(request).action_plan.get(
return watcherclient(request).action_plan.get(
action_plan_id=action_plan_id)
return cls(action_plan, request=request)
@classmethod
def delete(cls, request, action_plan_id):
@ -351,7 +325,7 @@ class ActionPlan(base.APIResourceWrapper):
return self.uuid
class Action(base.APIResourceWrapper):
class Action(base.APIDictWrapper):
_attrs = ('uuid', 'created_at', 'updated_at', 'deleted_at', 'next_uuid',
'description', 'state', 'action_plan_uuid',
'action_type', 'applies_to', 'src', 'dst', 'parameter')
@ -371,13 +345,11 @@ class Action(base.APIResourceWrapper):
:type action_plan_filter: string
:return: list of actions, or an empty list if there are none
:rtype: list of watcher_dashboard.api.watcher.Action
:rtype: list of :py:class:`~.Action`
"""
actions = watcherclient(request).action.list(
return watcherclient(request).action.list(
action_plan=action_plan_filter, detail=True)
return [cls(action, request=request)
for action in actions]
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve action"))
@ -392,11 +364,9 @@ class Action(base.APIResourceWrapper):
:return: matching action, or None if no action matches
the ID
:rtype: watcher_dashboard.api.watcher.Action
:rtype: :py:class:`~.Action`
"""
action = watcherclient(request).action.get(
action_id=action_id)
return cls(action, request=request)
return watcherclient(request).action.get(action_id=action_id)
@classmethod
def delete(cls, request, action_id):
@ -428,3 +398,94 @@ class Action(base.APIResourceWrapper):
@property
def id(self):
return self.uuid
class Goal(base.APIDictWrapper):
"""Goal resource."""
_attrs = ('uuid', 'name', 'display_name', 'created_at',
'updated_at', 'deleted_at')
def __init__(self, apiresource, request=None):
super(Goal, self).__init__(apiresource)
self._request = request
@classmethod
def list(cls, request, **filters):
"""Return a list of goals in Watcher
:param request: request object
:type request: django.http.HttpRequest
:return: list of goals, or an empty list if there are none
:rtype: list of :py:class:`~.Goal` instance
"""
return watcherclient(request).goal.list(detail=True, **filters)
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve goal"))
def get(cls, request, goal_uuid):
"""Return the goal that matches the ID
:param request: request object
:type request: django.http.HttpRequest
:param goal_uuid: uuid of goal to be retrieved
:type goal_uuid: int
:return: matching goal, or None if no goal matches the UUID
:rtype: :py:class:`~.Goal` instance
"""
return watcherclient(request).goal.get(goal_uuid)
@property
def id(self):
return self.uuid
class Strategy(base.APIDictWrapper):
"""Strategy resource."""
_attrs = ('uuid', 'name', 'display_name', 'goal_uuid', 'created_at',
'updated_at', 'deleted_at')
def __init__(self, apiresource, request=None):
super(Strategy, self).__init__(apiresource)
self._request = request
@classmethod
def list(cls, request, **filters):
"""Return a list of strategies in Watcher
:param request: request object
:type request: django.http.HttpRequest
:param goal_uuid: goal uuid filter
:type goal_uuid: string
:return: list of strategies, or an empty list if there are none
:rtype: list of :py:class:`~.Strategy` instances
"""
goal_uuid = filters.get('goal_uuid', None)
return watcherclient(request).strategy.list(
goal_uuid=goal_uuid, detail=True)
@classmethod
@errors_utils.handle_errors(_("Unable to retrieve strategy"))
def get(cls, request, strategy_uuid):
"""Return the strategy that matches the UUID
:param request: request object
:type request: django.http.HttpRequest
:param strategy_uuid: uuid of strategy to be retrieved
:type strategy_uuid: str
:return: matching strategy, or None if no strategy matches the UUID
:rtype: :py:class:`~.Strategy` instance
"""
return watcherclient(request).strategy.get(strategy_uuid)
@property
def id(self):
return self.uuid

View File

@ -32,7 +32,7 @@ LOG = logging.getLogger(__name__)
ACTION_PLAN_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("State of an action plan", u"No State")),
("ONGOING", pgettext_lazy("State of an action plan", u"On Going")),
("SUCCESS", pgettext_lazy("State of an action plan", u"Sucess")),
("SUCCEEDED", pgettext_lazy("State of an action plan", u"Succeeded")),
("SUBMITTED", pgettext_lazy("State of an action plan", u"Submitted")),
("FAILED", pgettext_lazy("State of an action plan", u"Failed")),
("DELETED", pgettext_lazy("State of an action plan", u"Deleted")),
@ -124,31 +124,10 @@ class UpdateRow(horizon.tables.Row):
return action_plan
# class CancelActionPlan(horizon.tables.DeleteAction):
# verbose_name = _(u"Cancel ActionPlans")
# icon = "trash"
# @staticmethod
# def action_present(count):
# return ungettext_lazy(
# u"Cancel ActionPlan",
# u"Cancel ActionPlans",
# count
# )
# @staticmethod
# def action_past(count):
# return ungettext_lazy(
# u"Canceled ActionPlan",
# u"canceled ActionPlans",
# count
# )
class ActionPlansTable(horizon.tables.DataTable):
name = horizon.tables.Column(
'id',
verbose_name=_("ID"),
'uuid',
verbose_name=_("UUID"),
link="horizon:admin:action_plans:detail")
audit = horizon.tables.Column(
'audit_uuid',
@ -165,6 +144,9 @@ class ActionPlansTable(horizon.tables.DataTable):
status=True,
status_choices=ACTION_PLAN_STATE_DISPLAY_CHOICES)
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
name = "action_plans"
verbose_name = _("ActionPlans")

View File

@ -19,12 +19,11 @@ from django.conf import urls
from watcher_dashboard.content.action_plans import views
urlpatterns = urls.patterns(
'watcher_dashboard.content.action_plans.views',
urlpatterns = [
urls.url(r'^$',
views.IndexView.as_view(), name='index'),
urls.url(r'^(?P<action_plan_id>[^/]+)/detail$',
urls.url(r'^(?P<action_plan_uuid>[^/]+)/detail$',
views.DetailView.as_view(), name='detail'),
urls.url(r'^archive/$',
views.ArchiveView.as_view(), name='archive'),
)
]

View File

@ -85,13 +85,14 @@ class DetailView(horizon.tables.MultiTableView):
@memoized.memoized_method
def _get_data(self):
action_plan_id = None
action_plan_uuid = None
try:
action_plan_id = self.kwargs['action_plan_id']
action_plan = watcher.ActionPlan.get(self.request, action_plan_id)
action_plan_uuid = self.kwargs['action_plan_uuid']
action_plan = watcher.ActionPlan.get(
self.request, action_plan_uuid)
except Exception:
msg = _('Unable to retrieve details for action_plan "%s".') \
% action_plan_id
% action_plan_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)

View File

@ -32,7 +32,7 @@ LOG = logging.getLogger(__name__)
ACTION_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("Power state of an Instance", u"No State")),
("ONGOING", pgettext_lazy("Power state of an Instance", u"On Going")),
("SUCCESS", pgettext_lazy("Power state of an Instance", u"Success")),
("SUCCEEDED", pgettext_lazy("Power state of an Instance", u"Succeeded")),
("CANCELLED", pgettext_lazy("Power state of an Instance", u"Cancelled")),
("FAILED", pgettext_lazy("Power state of an Instance", u"Failed")),
("DELETED", pgettext_lazy("Power state of an Instance", u"Deleted")),
@ -62,8 +62,8 @@ class ActionsFilterAction(horizon.tables.FilterAction):
class ActionsTable(horizon.tables.DataTable):
name = horizon.tables.Column(
'id',
verbose_name=_("ID"))
'uuid',
verbose_name=_("UUID"))
action_type = horizon.tables.Column(
'action_type',
verbose_name=_('Type'),
@ -81,6 +81,9 @@ class ActionsTable(horizon.tables.DataTable):
verbose_name=_('Next Action'))
ajax = True
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
name = "wactions"
verbose_name = _("Actions")

View File

@ -19,10 +19,9 @@ from django.conf import urls
from watcher_dashboard.content.actions import views
urlpatterns = urls.patterns(
'watcher_dashboard.content.actions.views',
urlpatterns = [
urls.url(r'^$',
views.IndexView.as_view(), name='index'),
urls.url(r'^(?P<action_id>[^/]+)/$',
urls.url(r'^(?P<action_uuid>[^/]+)/$',
views.DetailView.as_view(), name='details'),
)
]

View File

@ -70,13 +70,13 @@ class DetailView(horizon.tabs.TabbedTableView):
@memoized.memoized_method
def _get_data(self):
action_plan_id = None
action_plan_uuid = None
try:
action_plan_id = self.kwargs['action_plan_id']
action = watcher.Action.get(self.request, action_plan_id)
action_plan_uuid = self.kwargs['action_plan_uuid']
action = watcher.Action.get(self.request, action_plan_uuid)
except Exception:
msg = _('Unable to retrieve details for action "%s".') \
% action_plan_id
% action_plan_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)

View File

@ -34,23 +34,29 @@ class CreateForm(forms.SelfHandlingForm):
name = forms.CharField(max_length=255, label=_("Name"))
description = forms.CharField(max_length=255, label=_("Description"),
required=False)
goal = forms.ChoiceField(label=_('Goal'),
required=True,
)
goal_uuid = forms.ChoiceField(label=_('Goal'), required=True)
strategy_uuid = forms.ChoiceField(label=_('Strategy'), required=False)
failure_url = 'horizon:admin:audit_templates:index'
def __init__(self, request, *args, **kwargs):
super(CreateForm, self).__init__(request, *args, **kwargs)
goals = self._get_goal_list(request)
strategies = self._get_strategy_list(request, goals)
if goals:
self.fields['goal'].choices = goals
self.fields['goal_uuid'].choices = goals
else:
del self.fields['goal']
del self.fields['goal_uuid']
if strategies:
self.fields['strategy_uuid'].choices = strategies
else:
del self.fields['strategy_uuid']
def _get_goal_list(self, request):
try:
goals = watcher.AuditTemplate.get_goals(self.request)
goals = watcher.Goal.list(self.request)
except Exception as exc:
msg = _('Failed to get goals list.')
LOG.info(msg)
@ -59,7 +65,7 @@ class CreateForm(forms.SelfHandlingForm):
goals = []
choices = [
(goal, goal)
(goal.uuid, goal.display_name)
for goal in goals
]
@ -67,16 +73,41 @@ class CreateForm(forms.SelfHandlingForm):
choices.insert(0, ("", _("Select Goal")))
return choices
def _get_strategy_list(self, request, goals):
try:
strategies = watcher.Strategy.list(self.request)
except Exception as exc:
msg = _('Failed to get the list of available strategies.')
LOG.info(msg)
messages.warning(request, msg)
messages.warning(request, exc)
strategies = []
_goals = {}
for goal in goals:
_goals[goal[0]] = goal[1]
choices = [
(strategy.uuid, strategy.display_name +
' (GOAL: ' + _goals[strategy.goal_uuid] + ')')
for strategy in strategies
]
if choices:
choices.insert(0, ("", _("Select Strategy")))
return choices
def handle(self, request, data):
try:
params = {'name': data['name']}
params['goal'] = data['goal']
params['description'] = data['description']
params['goal_uuid'] = data['goal_uuid']
params['strategy_uuid'] = data['strategy_uuid'] or None
params['host_aggregate'] = None
audit_temp = watcher.AuditTemplate.create(request, **params)
audit_tpl = watcher.AuditTemplate.create(request, **params)
message = _('Audit Template was successfully created.')
messages.success(request, message)
return audit_temp
return audit_tpl
except Exception as exc:
msg = _('Failed to create audit template"%s".') % data['name']
LOG.info(exc)

View File

@ -16,7 +16,6 @@
from __future__ import unicode_literals
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
import horizon.exceptions
@ -26,25 +25,6 @@ import horizon.tables
from watcher_dashboard.api import watcher
AUDIT_TEMPLATE_GOAL_DISPLAY_CHOICES = (
("BASIC_CONSOLIDATION", pgettext_lazy(
"Goal of an Audit",
"Consolidate Servers")),
("MINIMIZE_ENERGY_CONSUMPTION", pgettext_lazy(
"Goal of an Audit",
"Minimize Energy")),
("BALANCE_LOAD", pgettext_lazy(
"Goal of an Audit",
"Load Balancing")),
("MINIMIZE_LICENSING_COST", pgettext_lazy(
"Goal of an Audit",
"Minimize Licensing Cost")),
("PREPARED_PLAN_OPERATION", pgettext_lazy(
"Goal of an Audit",
"Prepared Plan Operation")),
)
class CreateAuditTemplates(horizon.tables.LinkAction):
name = "create"
verbose_name = _("Create Template")
@ -55,7 +35,9 @@ class CreateAuditTemplates(horizon.tables.LinkAction):
class AuditTemplatesFilterAction(horizon.tables.FilterAction):
filter_type = "server"
filter_choices = (
('name', _("Template Name ="), True),
('name', _("Name ="), True),
('goal_uuid', _("Goal ="), True),
('strategy_uuid', _("Strategy ="), True),
)
@ -65,8 +47,6 @@ class LaunchAudit(horizon.tables.BatchAction):
data_type_singular = _("Launch Audit")
data_type_plural = _("Launch Audits")
success_url = "horizon:admin:audits:index"
# icon = "cloud-upload"
# policy_rules = (("compute", "compute:create"),)
@staticmethod
def action_present(count):
@ -120,10 +100,14 @@ class AuditTemplatesTable(horizon.tables.DataTable):
verbose_name=_("Name"),
link="horizon:admin:audit_templates:detail")
goal = horizon.tables.Column(
'goal',
'goal_uuid',
verbose_name=_('Goal'),
status=True,
status_choices=AUDIT_TEMPLATE_GOAL_DISPLAY_CHOICES
)
strategy = horizon.tables.Column(
'strategy_uuid',
verbose_name=_('Strategy'),
status=True,
)
def get_object_id(self, datum):
@ -136,10 +120,7 @@ class AuditTemplatesTable(horizon.tables.DataTable):
CreateAuditTemplates,
DeleteAuditTemplates,
AuditTemplatesFilterAction,
# LaunchAuditTemplates,
)
row_actions = (
LaunchAudit,
# CreateAuditTemplates,
# DeleteAuditTemplates,
)

View File

@ -34,20 +34,17 @@ DETAILS_VIEW = 'horizon:admin:audit_templates:detail'
class AuditTemplatesTest(test.BaseAdminViewTests):
goal_list = [
'BASIC_CONSOLIDATION',
'MINIMIZE_ENERGY_CONSUMPTION',
'BALANCE_LOAD',
'MINIMIZE_LICENSING_COST',
'PREPARED_PLAN_OPERATION',
]
def setUp(self):
super(AuditTemplatesTest, self).setUp()
self.goal_list = self.goals.list()
self.strategy_list = self.strategies.list()
@test.create_stubs({api.watcher.AuditTemplate: ('list',)})
def test_index(self):
search_opts = None
search_opts = {}
api.watcher.AuditTemplate.list(
IsA(http.HttpRequest),
filter=search_opts).MultipleTimes().AndReturn(
**search_opts).MultipleTimes().AndReturn(
self.audit_templates.list())
self.mox.ReplayAll()
@ -68,34 +65,45 @@ class AuditTemplatesTest(test.BaseAdminViewTests):
resp = self.client.get(INDEX_URL)
self.assertMessageCount(resp, error=1, warning=0)
@test.create_stubs({api.watcher.AuditTemplate: ('get_goals',)})
@test.create_stubs({api.watcher.Strategy: ('list',)})
@test.create_stubs({api.watcher.Goal: ('list',)})
def test_create_get(self):
api.watcher.AuditTemplate.get_goals(
api.watcher.Goal.list(
IsA(http.HttpRequest)).AndReturn(self.goal_list)
api.watcher.Strategy.list(
IsA(http.HttpRequest)).AndReturn(self.strategy_list)
self.mox.ReplayAll()
res = self.client.get(CREATE_URL)
self.assertTemplateUsed(res, 'infra_optim/audit_templates/create.html')
@test.create_stubs({api.watcher.AuditTemplate: ('create',
'get_goals')})
@test.create_stubs({api.watcher.Strategy: ('list',)})
@test.create_stubs({api.watcher.Goal: ('list',)})
@test.create_stubs({api.watcher.AuditTemplate: ('create',)})
def test_create_post(self):
at = self.audit_templates.first()
api.watcher.AuditTemplate.get_goals(
params = {
'name': at.name,
'goal_uuid': at.goal_uuid,
'strategy_uuid': at.strategy_uuid,
'description': at.description,
'host_aggregate': at.host_aggregate,
}
api.watcher.Goal.list(
IsA(http.HttpRequest)).AndReturn(self.goal_list)
params = {'name': at.name,
'goal': at.goal,
'description': at.description,
'host_aggregate': at.host_aggregate,
}
api.watcher.Strategy.list(
IsA(http.HttpRequest)).AndReturn(self.strategy_list)
api.watcher.AuditTemplate.create(
IsA(http.HttpRequest), **params).AndReturn(at)
self.mox.ReplayAll()
form_data = {'name': at.name,
'goal': at.goal,
'description': at.description,
'host_aggregate': at.host_aggregate,
}
form_data = {
'name': at.name,
'goal_uuid': at.goal_uuid,
'strategy_uuid': at.strategy_uuid,
'description': at.description,
'host_aggregate': at.host_aggregate,
}
res = self.client.post(CREATE_URL, form_data)
self.assertNoFormErrors(res)
self.assertRedirectsNoFollow(res, INDEX_URL)
@ -130,14 +138,13 @@ class AuditTemplatesTest(test.BaseAdminViewTests):
@test.create_stubs({api.watcher.AuditTemplate: ('delete', 'list')})
def test_delete(self):
search_opts = None
search_opts = {}
at_list = self.audit_templates.list()
at = self.audit_templates.first()
at_id = at.uuid
api.watcher.AuditTemplate.list(
IsA(http.HttpRequest),
filter=search_opts).MultipleTimes().AndReturn(
at_list)
**search_opts).MultipleTimes().AndReturn(at_list)
api.watcher.AuditTemplate.delete(IsA(http.HttpRequest), at_id)
self.mox.ReplayAll()

View File

@ -19,11 +19,10 @@ from django.conf import urls
from watcher_dashboard.content.audit_templates import views
urlpatterns = urls.patterns(
'watcher_dashboard.content.audit_templates.views',
urlpatterns = [
urls.url(r'^$', views.IndexView.as_view(), name='index'),
urls.url(r'^create/$', views.CreateView.as_view(), name='create'),
urls.url(r'^(?P<audit_template_id>[^/]+)/detail$',
urls.url(r'^(?P<audit_template_uuid>[^/]+)/detail$',
views.DetailView.as_view(),
name='detail'),
)
]

View File

@ -44,8 +44,8 @@ class IndexView(horizon.tables.DataTableView):
audit_templates = []
search_opts = self.get_filters()
try:
audit_templates = watcher.AuditTemplate.list(self.request,
filter=search_opts)
audit_templates = watcher.AuditTemplate.list(
self.request, **search_opts)
except Exception:
horizon.exceptions.handle(
self.request,
@ -56,15 +56,15 @@ class IndexView(horizon.tables.DataTableView):
return len(self.get_data())
def get_filters(self):
filter = None
filters = {}
filter_action = self.table._meta._filter_action
if filter_action:
filter_field = self.table.get_filter_field()
if filter_action.is_api_filter(filter_field):
filter_string = self.table.get_filter_string()
if filter_field and filter_string:
filter = filter_string
return filter
filters[filter_field] = filter_string
return filters
class CreateView(forms.ModalFormView):
@ -85,15 +85,15 @@ class DetailView(horizon.tabs.TabbedTableView):
page_title = _("Audit Template Details: {{ audit_template.name }}")
def _get_data(self):
audit_template_id = None
audit_template_uuid = None
try:
LOG.info(self.kwargs)
audit_template_id = self.kwargs['audit_template_id']
audit_template = watcher.AuditTemplate.get(self.request,
audit_template_id)
audit_template_uuid = self.kwargs['audit_template_uuid']
audit_template = watcher.AuditTemplate.get(
self.request, audit_template_uuid)
except Exception:
msg = _('Unable to retrieve details for audit template "%s".') \
% audit_template_id
% audit_template_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)

View File

@ -45,7 +45,7 @@ class CreateForm(forms.SelfHandlingForm):
def _get_audit_template_list(self, request):
try:
audit_templates = watcher.AuditTemplate.list(self.request, None)
audit_templates = watcher.AuditTemplate.list(self.request)
except Exception:
msg = _('Failed to get audit template list.')
LOG.info(msg)

View File

@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from django.core import urlresolvers
from django import shortcuts
from django.template.defaultfilters import title # noqa
@ -23,15 +25,15 @@ import horizon.exceptions
import horizon.messages
import horizon.tables
from horizon.utils import filters
from watcher_dashboard.api import watcher
import logging
LOG = logging.getLogger(__name__)
AUDIT_STATE_DISPLAY_CHOICES = (
("NO STATE", pgettext_lazy("State of an audit", u"No State")),
("ONGOING", pgettext_lazy("State of an audit", u"On Going")),
("SUCCESS", pgettext_lazy("State of an audit", u"Sucess")),
("SUCCEEDED", pgettext_lazy("State of an audit", u"Succeeeded")),
("SUBMITTED", pgettext_lazy("State of an audit", u"Submitted")),
("FAILED", pgettext_lazy("State of an audit", u"Failed")),
("DELETED", pgettext_lazy("State of an audit", u"Deleted")),
@ -55,19 +57,10 @@ class CreateAudit(horizon.tables.LinkAction):
# policy_rules = (("compute", "compute:create"),)
# class ArchiveAudits(horizon.tables.LinkAction):
# name = "archive_audits"
# verbose_name = _("Archive Audits")
# url = "horizon:project:instances:launch"
# classes = ("ajax-modal", "btn-launch")
# icon = "folder-open"
class GoToActionPlan(horizon.tables.Action):
name = "go_to_action_plan"
verbose_name = _("Go to Action Plan")
url = "horizon:admin:action_plans:detail"
# classes = ("ajax-modal", "btn-launch")
# icon = "send"
def allowed(self, request, audit):
return ((audit is None) or
@ -117,8 +110,8 @@ class GoToAuditTemplate(horizon.tables.Action):
class AuditsTable(horizon.tables.DataTable):
name = horizon.tables.Column(
'id',
verbose_name=_("ID"),
'uuid',
verbose_name=_("UUID"),
link="horizon:admin:audits:detail")
audit_template = horizon.tables.Column(
'audit_template_name',
@ -130,6 +123,9 @@ class AuditsTable(horizon.tables.DataTable):
status=True,
status_choices=AUDIT_STATE_DISPLAY_CHOICES)
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
name = "audits"
verbose_name = _("Audits")

View File

@ -19,12 +19,11 @@ from django.conf import urls
from watcher_dashboard.content.audits import views
urlpatterns = urls.patterns(
'watcher_dashboard.audits.views',
urlpatterns = [
urls.url(r'^$',
views.IndexView.as_view(), name='index'),
urls.url(r'^create/$',
views.CreateView.as_view(), name='create'),
urls.url(r'^(?P<audit_id>[^/]+)/detail$',
urls.url(r'^(?P<audit_uuid>[^/]+)/detail$',
views.DetailView.as_view(), name='detail'),
)
]

View File

@ -91,13 +91,13 @@ class DetailView(horizon.tabs.TabbedTableView):
@memoized.memoized_method
def _get_data(self):
audit_id = None
audit_uuid = None
try:
audit_id = self.kwargs['audit_id']
audit = watcher.Audit.get(self.request, audit_id)
audit_uuid = self.kwargs['audit_uuid']
audit = watcher.Audit.get(self.request, audit_uuid)
except Exception:
msg = _('Unable to retrieve details for audit "%s".') \
% audit_id
% audit_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)

View File

View File

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 Goals(horizon.Panel):
name = _("Goals")
slug = "goals"

View File

@ -0,0 +1,38 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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.template.defaultfilters import title # noqa
from django.utils.translation import ugettext_lazy as _
import horizon.exceptions
import horizon.messages
import horizon.tables
class GoalsTable(horizon.tables.DataTable):
uuid = horizon.tables.Column(
'uuid',
verbose_name=_("UUID"),
link="horizon:admin:goals:detail")
display_name = horizon.tables.Column(
'display_name',
verbose_name=_('Name'))
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
name = "goals"
verbose_name = _("Goals")

View File

@ -0,0 +1,33 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 tabs
class OverviewTab(tabs.Tab):
name = _("Overview")
slug = "overview"
template_name = "infra_optim/goals/_detail_overview.html"
def get_context_data(self, request):
return {"goal": self.tab_group.kwargs['goal']}
class GoalDetailTabs(tabs.TabGroup):
slug = "goal_details"
tabs = (OverviewTab,)
sticky = True

View File

@ -0,0 +1,82 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 logging
from django.core import urlresolvers
from django import http
from mox3.mox import IsA # noqa
from watcher_dashboard import api
from watcher_dashboard.test import helpers as test
LOG = logging.getLogger(__name__)
INDEX_URL = urlresolvers.reverse('horizon:admin:goals:index')
DETAILS_VIEW = 'horizon:admin:goals:detail'
class GoalsTest(test.BaseAdminViewTests):
@test.create_stubs({api.watcher.Goal: ('list',)})
def test_index(self):
search_opts = {}
api.watcher.Goal.list(
IsA(http.HttpRequest), **search_opts
).MultipleTimes().AndReturn(self.goals.list())
self.mox.ReplayAll()
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, 'infra_optim/goals/index.html')
goals = res.context['goals_table'].data
self.assertItemsEqual(goals, self.goals.list())
@test.create_stubs({api.watcher.Goal: ('list',)})
def test_goal_list_unavailable(self):
search_opts = {}
api.watcher.Goal.list(
IsA(http.HttpRequest), **search_opts
).MultipleTimes().AndRaise(self.exceptions.watcher)
self.mox.ReplayAll()
resp = self.client.get(INDEX_URL)
self.assertMessageCount(resp, error=1, warning=0)
@test.create_stubs({api.watcher.Goal: ('get',)})
def test_details(self):
goal = self.goals.first()
goal_id = goal.uuid
api.watcher.Goal.get(
IsA(http.HttpRequest), goal_id).MultipleTimes().AndReturn(goal)
self.mox.ReplayAll()
DETAILS_URL = urlresolvers.reverse(DETAILS_VIEW, args=[goal_id])
res = self.client.get(DETAILS_URL)
self.assertTemplateUsed(res, 'infra_optim/goals/details.html')
goals = res.context['goal']
self.assertItemsEqual([goals], [goal])
@test.create_stubs({api.watcher.Goal: ('get',)})
def test_details_exception(self):
at = self.goals.first()
at_id = at.uuid
api.watcher.Goal.get(IsA(http.HttpRequest), at_id) \
.AndRaise(self.exceptions.watcher)
self.mox.ReplayAll()
DETAILS_URL = urlresolvers.reverse(DETAILS_VIEW, args=[at_id])
res = self.client.get(DETAILS_URL)
self.assertRedirectsNoFollow(res, INDEX_URL)

View File

@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 import urls
from watcher_dashboard.content.goals import views
urlpatterns = [
urls.url(r'^$',
views.IndexView.as_view(), name='index'),
urls.url(r'^(?P<goal_uuid>[^/]+)/detail$',
views.DetailView.as_view(), name='detail'),
]

View File

@ -0,0 +1,95 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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.exceptions
import horizon.tables
import horizon.tabs
from horizon.utils import memoized
import horizon.workflows
from watcher_dashboard.api import watcher
from watcher_dashboard.content.goals import tables
from watcher_dashboard.content.goals import tabs as wtabs
class IndexView(horizon.tables.DataTableView):
table_class = tables.GoalsTable
template_name = 'infra_optim/goals/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['goals_count'] = self.get_goals_count()
return context
def get_data(self):
goals = []
search_opts = self.get_filters()
try:
goals = watcher.Goal.list(self.request, **search_opts)
except Exception:
horizon.exceptions.handle(
self.request,
_("Unable to retrieve goal information."))
return goals
def get_goals_count(self):
return len(self.get_data())
def get_filters(self):
filters = {}
filter_action = self.table._meta._filter_action
if filter_action:
filter_field = self.table.get_filter_field()
if filter_action.is_api_filter(filter_field):
filter_string = self.table.get_filter_string()
if filter_field and filter_string:
filters[filter_field] = filter_string
return filters
class DetailView(horizon.tabs.TabbedTableView):
tab_group_class = wtabs.GoalDetailTabs
template_name = 'infra_optim/goals/details.html'
redirect_url = 'horizon:admin:goals:index'
page_title = _("Goal Details: {{ goal.name }}")
@memoized.memoized_method
def _get_data(self):
goal_uuid = None
try:
goal_uuid = self.kwargs['goal_uuid']
goal = watcher.Goal.get(self.request, goal_uuid)
except Exception:
msg = _('Unable to retrieve details for goal "%s".') \
% goal_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)
return goal
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
goal = self._get_data()
context["goal"] = goal
return context
def get_tabs(self, request, *args, **kwargs):
goal = self._get_data()
# ports = self._get_ports()
return self.tab_group_class(request, goal=goal,
# ports=ports,
**kwargs)

View File

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 Strategies(horizon.Panel):
name = _("Strategies")
slug = "strategies"

View File

@ -0,0 +1,44 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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.template.defaultfilters import title # noqa
from django.utils.translation import ugettext_lazy as _
import horizon.exceptions
import horizon.messages
import horizon.tables
from horizon.utils import filters
class StrategiesTable(horizon.tables.DataTable):
uuid = horizon.tables.Column(
'uuid',
verbose_name=_("UUID"),
link="horizon:admin:strategies:detail")
display_name = horizon.tables.Column(
'display_name',
verbose_name=_('Name'),
filters=(title, filters.replace_underscores))
goal_uuid = horizon.tables.Column(
'goal_uuid',
verbose_name=_("Goal UUID"),
)
def get_object_id(self, datum):
return datum.uuid
class Meta(object):
name = "strategies"
verbose_name = _("Strategies")

View File

@ -0,0 +1,33 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 tabs
class OverviewTab(tabs.Tab):
name = _("Overview")
slug = "overview"
template_name = "infra_optim/strategies/_detail_overview.html"
def get_context_data(self, request):
return {"strategy": self.tab_group.kwargs['strategy']}
class StrategyDetailTabs(tabs.TabGroup):
slug = "strategy_details"
tabs = (OverviewTab,)
sticky = True

View File

@ -0,0 +1,93 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 logging
from django.core import urlresolvers
from django import http
from mox3.mox import IsA # noqa
from watcher_dashboard import api
from watcher_dashboard.test import helpers as test
LOG = logging.getLogger(__name__)
INDEX_URL = urlresolvers.reverse(
'horizon:admin:strategies:index')
DETAILS_VIEW = 'horizon:admin:strategies:detail'
class StrategiesTest(test.BaseAdminViewTests):
goal_list = [
'BASIC_CONSOLIDATION',
'MINIMIZE_ENERGY_CONSUMPTION',
'BALANCE_LOAD',
'MINIMIZE_LICENSING_COST',
'PREPARED_PLAN_OPERATION',
]
@test.create_stubs({api.watcher.Strategy: ('list',)})
def test_index(self):
search_opts = {}
api.watcher.Strategy.list(
IsA(http.HttpRequest), **search_opts
).MultipleTimes().AndReturn(self.strategies.list())
self.mox.ReplayAll()
res = self.client.get(INDEX_URL)
self.assertTemplateUsed(res, 'infra_optim/strategies/index.html')
strategies = res.context['strategies_table'].data
self.assertItemsEqual(strategies, self.strategies.list())
@test.create_stubs({api.watcher.Strategy: ('list',)})
def test_strategy_list_unavailable(self):
search_opts = {}
api.watcher.Strategy.list(
IsA(http.HttpRequest), **search_opts).MultipleTimes().AndRaise(
self.exceptions.watcher)
self.mox.ReplayAll()
resp = self.client.get(INDEX_URL)
self.assertMessageCount(resp, error=1, warning=0)
@test.create_stubs({api.watcher.Strategy: ('get',)})
def test_details(self):
at = self.strategies.first()
at_id = at.uuid
api.watcher.Strategy.get(
IsA(http.HttpRequest), at_id).\
MultipleTimes().AndReturn(at)
self.mox.ReplayAll()
DETAILS_URL = urlresolvers.reverse(DETAILS_VIEW, args=[at_id])
res = self.client.get(DETAILS_URL)
self.assertTemplateUsed(res,
'infra_optim/strategies/details.html')
strategies = res.context['strategy']
self.assertItemsEqual([strategies], [at])
@test.create_stubs({api.watcher.Strategy: ('get',)})
def test_details_exception(self):
at = self.strategies.first()
at_id = at.uuid
api.watcher.Strategy.get(IsA(http.HttpRequest), at_id) \
.AndRaise(self.exceptions.watcher)
self.mox.ReplayAll()
DETAILS_URL = urlresolvers.reverse(DETAILS_VIEW, args=[at_id])
res = self.client.get(DETAILS_URL)
self.assertRedirectsNoFollow(res, INDEX_URL)

View File

@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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 import urls
from watcher_dashboard.content.strategies import views
urlpatterns = [
urls.url(r'^$',
views.IndexView.as_view(), name='index'),
urls.url(r'^(?P<strategy_uuid>[^/]+)/detail$',
views.DetailView.as_view(), name='detail'),
]

View File

@ -0,0 +1,95 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2016 b<>com
#
# 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.exceptions
import horizon.tables
import horizon.tabs
from horizon.utils import memoized
import horizon.workflows
from watcher_dashboard.api import watcher
from watcher_dashboard.content.strategies import tables
from watcher_dashboard.content.strategies import tabs as wtabs
class IndexView(horizon.tables.DataTableView):
table_class = tables.StrategiesTable
template_name = 'infra_optim/strategies/index.html'
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['strategies_count'] = self.get_strategies_count()
return context
def get_data(self):
strategies = []
search_opts = self.get_filters()
try:
strategies = watcher.Strategy.list(self.request, **search_opts)
except Exception:
horizon.exceptions.handle(
self.request,
_("Unable to retrieve strategy information."))
return strategies
def get_strategies_count(self):
return len(self.get_data())
def get_filters(self):
filters = {}
filter_action = self.table._meta._filter_action
if filter_action:
filter_field = self.table.get_filter_field()
if filter_action.is_api_filter(filter_field):
filter_string = self.table.get_filter_string()
if filter_field and filter_string:
filters[filter_field] = filter_string
return filters
class DetailView(horizon.tabs.TabbedTableView):
tab_group_class = wtabs.StrategyDetailTabs
template_name = 'infra_optim/strategies/details.html'
redirect_url = 'horizon:admin:strategies:index'
page_title = _("Strategy Details: {{ strategy.name }}")
@memoized.memoized_method
def _get_data(self):
strategy_uuid = None
try:
strategy_uuid = self.kwargs['strategy_uuid']
strategy = watcher.Strategy.get(self.request, strategy_uuid)
except Exception:
msg = _('Unable to retrieve details for strategy "%s".') \
% strategy_uuid
horizon.exceptions.handle(
self.request, msg,
redirect=self.redirect_url)
return strategy
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
strategy = self._get_data()
context["strategy"] = strategy
return context
def get_tabs(self, request, *args, **kwargs):
strategy = self._get_data()
# ports = self._get_ports()
return self.tab_group_class(request, strategy=strategy,
# ports=ports,
**kwargs)

View File

@ -0,0 +1,21 @@
# 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 = 'goals'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.goals.panel.Goals'

View File

@ -0,0 +1,21 @@
# 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 = 'strategies'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.strategies.panel.Strategies'

View File

@ -16,8 +16,6 @@ PANEL = 'audit_templates'
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# If set, it will update the default panel of the PANEL_DASHBOARD.
DEFAULT_PANEL = 'audit_templates'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.audit_templates.panel.AuditTemplates'

View File

@ -16,8 +16,6 @@ PANEL = 'audits'
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# If set, it will update the default panel of the PANEL_DASHBOARD.
DEFAULT_PANEL = 'audits'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.audits.panel.Audits'

View File

@ -16,8 +16,6 @@ PANEL = 'action_plans'
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# If set, it will update the default panel of the PANEL_DASHBOARD.
DEFAULT_PANEL = 'action_plans'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.action_plans.panel.ActionPlans'

View File

@ -16,8 +16,6 @@ PANEL = 'actions'
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'watcher'
# If set, it will update the default panel of the PANEL_DASHBOARD.
DEFAULT_PANEL = 'actions'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'watcher_dashboard.content.actions.panel.Actions'

View File

@ -1,3 +1,3 @@
/* Additional CSS for infra_optim. */
@import "/dashboard/scss/variables";
@import "/bootstrap/scss/bootstrap/variables";
// /* Additional CSS for infra_optim. */
// @import "/dashboard/scss/variables";
// @import "/bootstrap/scss/bootstrap/variables";

View File

@ -11,7 +11,7 @@
<div class="detail col-md-6">
<h4>{% trans "Audit Info" %}</h4>
<dl class="dl-horizontal">
<dt>{% trans "ID" %}</dt>
<dt>{% trans "UUID" %}</dt>
<dd>{{ action.uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Type" %}</dt>
<dd>{{ action.type|default:"&mdash;" }}</dd>

View File

@ -4,4 +4,7 @@
{% block modal-body-right %}
<h3>{% trans "Description:" %}</h3>
<p>{% trans "Creates an audit template with specified parameters." %}</p>
<p>
<span>{% trans "Define the optimization goal to achieve, among those which are available." %}</span>
<span>{% trans "Optionaly, you can select the strategy used to achieve your goal. If not set, a strategy will be automatically selected among those which can be used for your goal" %}</span></p>
{% endblock %}

View File

@ -1,11 +1,11 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% block title %}{% trans 'Audit Templates: ' %}{{ audit_template.name }}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Audit Templates: ')|add:audit_template.name %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="detail col-md-6">
@ -13,10 +13,12 @@
<dl class="dl-horizontal">
<dt>{% trans "Name" %}</dt>
<dd>{{ audit_template.name|default:"&mdash;" }}</dd>
<dt>{% trans "Id" %}</dt>
<dt>{% trans "UUID" %}</dt>
<dd>{{ audit_template.uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Goal" %}</dt>
<dd>{{ audit_template.goal|default:"&mdash;" }}</dd>
<dt>{% trans "Goal UUID" %}</dt>
<dd>{{ audit_template.goal_uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Strategy UUID" %}</dt>
<dd>{{ audit_template.strategy_uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Created At" %}</dt>
<dd>{{ audit_template.created_at|default:"&mdash;" }}</dd>
<dt>{% trans "Update At" %}</dt>
@ -31,5 +33,5 @@
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -1,17 +1,17 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% block title %}{% trans 'Audits: ' %}{{ audit.uuid }}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Audits: ')|add:audit.uuid %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="detail col-md-6">
<h4>{% trans "Audit Info" %}</h4>
<dl class="dl-horizontal">
<dt>{% trans "ID" %}</dt>
<dt>{% trans "UUID" %}</dt>
<dd>{{ audit.uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Type" %}</dt>
<dd>{{ audit.type|default:"&mdash;" }}</dd>
@ -34,5 +34,5 @@
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,31 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% block title %}{% trans 'Goals: ' %}{{ goal.display_name }}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Goals: ')|add:goal.display_name %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="detail col-md-6">
<h4>{% trans "Goal Info" %}</h4>
<dl class="dl-horizontal">
<dt>{% trans "UUID" %}</dt>
<dd>{{ goal.uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Name" %}</dt>
<dd>{{ goal.display_name|default:"&mdash;" }}</dd>
<dt>{% trans "Created At" %}</dt>
<dd>{{ goal.created_at|default:"&mdash;" }}</dd>
<dt>{% trans "Update At" %}</dt>
<dd>{{ goal.updated_at|default:"&mdash;" }}</dd>
</dl>
</div>
</div>
<div class="row">
<div class="col-xs-12">
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans 'Goals' %}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Goals') items_count=goal_count %}
{% endblock page_header %}
{% block main %}
<div id="goals">
{{ goals_table.render }}
</div>
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% block title %}{% trans 'Strategies: ' %}{{ strategy.display_name }}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Strategies: ')|add:strategy.display_name %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="detail col-md-6">
<h4>{% trans "Strategy Info" %}</h4>
<dl class="dl-horizontal">
<dt>{% trans "UUID" %}</dt>
<dd>{{ strategy.uuid|default:"&mdash;" }}</dd>
<dt>{% trans "Name" %}</dt>
<dd>{{ strategy.display_name|default:"&mdash;" }}</dd>
<dt>{% trans "Goal UUID" %}</dt>
{% url 'horizon:admin:goals:detail' strategy.goal_uuid as goal_url %}
<dd><a href="{{ goal_url }}">{{ strategy.goal_uuid|default:"&mdash;" }}</a></dd>
<dt>{% trans "Created At" %}</dt>
<dd>{{ strategy.created_at|default:"&mdash;" }}</dd>
<dt>{% trans "Update At" %}</dt>
<dd>{{ strategy.updated_at|default:"&mdash;" }}</dd>
</dl>
</div>
</div>
<div class="row">
<div class="col-xs-12">
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends 'infra_optim/base.html' %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans 'Strategies' %}{% endblock %}
{% block page_header %}
{% include 'horizon/common/_page_header.html' with title=_('Strategies') items_count=strategy_count %}
{% endblock page_header %}
{% block main %}
<div id="goals">
{{ strategies_table.render }}
</div>
{% endblock %}

View File

@ -21,37 +21,95 @@ from watcher_dashboard.test import helpers as test
class WatcherAPITests(test.APITestCase):
def test_goal_list(self):
goals = {'goals': self.api_goals.list()}
watcherclient = self.stub_watcherclient()
watcherclient.goal = self.mox.CreateMockAnything()
watcherclient.goal.list(detail=True).AndReturn(goals)
self.mox.ReplayAll()
ret_val = api.watcher.Goal.list(self.request)
self.assertIsInstance(ret_val, dict)
self.assertIn('goals', ret_val)
for n in ret_val['goals']:
self.assertIsInstance(n, dict)
def test_goal_get(self):
goal = self.api_goals.first()
goal_id = self.api_goals.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.goal = self.mox.CreateMockAnything()
watcherclient.goal.get(goal_id).AndReturn(goal)
self.mox.ReplayAll()
ret_val = api.watcher.Goal.get(self.request, goal_id)
self.assertIsInstance(ret_val, dict)
def test_strategy_list(self):
strategies = {'strategies': self.api_strategies.list()}
watcherclient = self.stub_watcherclient()
watcherclient.strategy = self.mox.CreateMockAnything()
watcherclient.strategy.list(
goal_uuid=None, detail=True).AndReturn(strategies)
self.mox.ReplayAll()
ret_val = api.watcher.Strategy.list(self.request)
self.assertIn('strategies', ret_val)
for n in ret_val['strategies']:
self.assertIsInstance(n, dict)
def test_strategy_get(self):
strategy = self.api_strategies.first()
strategy_id = self.api_strategies.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.strategy = self.mox.CreateMockAnything()
watcherclient.strategy.get(strategy_id).AndReturn(strategy)
self.mox.ReplayAll()
ret_val = api.watcher.Strategy.get(self.request, strategy_id)
self.assertIsInstance(ret_val, dict)
def test_audit_template_list(self):
audit_templates = {'audit_templates': self.api_audit_templates.list()}
watcherclient = self.stub_watcherclient()
watcherclient.audit_template = self.mox.CreateMockAnything()
watcherclient.audit_template.list(name=None).AndReturn(audit_templates)
watcherclient.audit_template.list().AndReturn(audit_templates)
self.mox.ReplayAll()
ret_val = api.watcher.AuditTemplate.list(self.request, filter=None)
for n in ret_val:
self.assertTrue(type(n), 'dict')
ret_val = api.watcher.AuditTemplate.list(self.request)
self.assertIn('audit_templates', ret_val)
for n in ret_val['audit_templates']:
self.assertIsInstance(n, dict)
def test_audit_template_list_with_filters(self):
search_opts = 'Audit Template 1'
audit_templates = self.api_audit_templates.filter(name=search_opts)
search_opts = {'name': 'Audit Template 1'}
audit_templates = {
'audit_templates': self.api_audit_templates.filter(**search_opts)}
watcherclient = self.stub_watcherclient()
watcherclient.audit_template = self.mox.CreateMockAnything()
watcherclient.audit_template.list(name=search_opts)\
.AndReturn(audit_templates)
watcherclient.audit_template.list(
**search_opts).AndReturn(audit_templates)
self.mox.ReplayAll()
ret_val = api.watcher.AuditTemplate\
.list(self.request, filter=search_opts)
for n in ret_val:
self.assertTrue(type(n), 'dict')
ret_val = api.watcher.AuditTemplate.list(
self.request, **search_opts)
self.assertIn('audit_templates', ret_val)
for n in ret_val['audit_templates']:
self.assertIsInstance(n, dict)
self.assertEqual(ret_val, audit_templates)
def test_audit_template_get(self):
audit_template = {'audit_template': self.api_audit_templates.first()}
audit_template = self.api_audit_templates.first()
audit_template_id = self.api_audit_templates.first()['uuid']
watcherclient = self.stub_watcherclient()
@ -62,30 +120,33 @@ class WatcherAPITests(test.APITestCase):
ret_val = api.watcher.AuditTemplate.get(self.request,
audit_template_id)
self.assertTrue(type(ret_val), 'dict')
self.assertIsInstance(ret_val, dict)
def test_audit_template_create(self):
audit_template = {'audit_template': self.api_audit_templates.first()}
name = self.api_audit_templates.first()['name']
goal = self.api_audit_templates.first()['goal']
description = self.api_audit_templates.first()['description']
host_aggregate = self.api_audit_templates.first()['host_aggregate']
audit_template = self.api_audit_templates.first()
name = audit_template['name']
goal_uuid = audit_template['goal_uuid']
strategy_uuid = audit_template['strategy_uuid']
description = audit_template['description']
host_aggregate = audit_template['host_aggregate']
watcherclient = self.stub_watcherclient()
watcherclient.audit_template = self.mox.CreateMockAnything()
watcherclient.audit_template.create(
name=name,
goal=goal,
goal_uuid=goal_uuid,
strategy_uuid=strategy_uuid,
description=description,
host_aggregate=host_aggregate).AndReturn(audit_template)
self.mox.ReplayAll()
ret_val = api.watcher.AuditTemplate.create(
self.request, name, goal, description, host_aggregate)
self.assertTrue(type(ret_val), 'dict')
self.request, name, goal_uuid, strategy_uuid,
description, host_aggregate)
self.assertIsInstance(ret_val, dict)
def test_audit_template_patch(self):
audit_template = {'audit_template': self.api_audit_templates.first()}
audit_template = self.api_audit_templates.first()
audit_template_id = self.api_audit_templates.first()['uuid']
form_data = {'name': 'new Audit Template 1'}
@ -100,7 +161,7 @@ class WatcherAPITests(test.APITestCase):
ret_val = api.watcher.AuditTemplate.patch(
self.request, audit_template_id,
form_data)
self.assertTrue(type(ret_val), 'dict')
self.assertIsInstance(ret_val, dict)
def test_audit_template_delete(self):
audit_template_list = self.api_audit_templates.list()
@ -127,26 +188,26 @@ class WatcherAPITests(test.APITestCase):
self.mox.ReplayAll()
ret_val = api.watcher.Audit.list(
self.request,
audit_template_filter=None)
for n in ret_val:
self.assertIsInstance(n, api.watcher.Audit)
self.request, audit_template_filter=None)
self.assertIn('audits', ret_val)
for n in ret_val['audits']:
self.assertIsInstance(n, dict)
def test_audit_get(self):
audit = {'audit': self.api_audits.first()}
audit_id = self.api_audits.first()['id']
audit = self.api_audits.first()
audit_id = self.api_audits.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.audit = self.mox.CreateMockAnything()
watcherclient.audit.get(
audit_id=audit_id).AndReturn(audit)
watcherclient.audit.get(audit_id=audit_id).AndReturn(audit)
self.mox.ReplayAll()
ret_val = api.watcher.Audit.get(self.request, audit_id)
self.assertIsInstance(ret_val, api.watcher.Audit)
self.assertIsInstance(ret_val, dict)
def test_audit_create(self):
audit = {'audit': self.api_audits.first()}
audit = self.api_audits.first()
audit_template_id = self.api_audit_templates.first()['uuid']
deadline = self.api_audits.first()['deadline']
@ -163,10 +224,10 @@ class WatcherAPITests(test.APITestCase):
ret_val = api.watcher.Audit.create(
self.request, audit_template_uuid, _type, deadline)
self.assertIsInstance(ret_val, api.watcher.Audit)
self.assertIsInstance(ret_val, dict)
def test_audit_delete(self):
audit_id = self.api_audits.first()['id']
audit_id = self.api_audits.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.audit = self.mox.CreateMockAnything()
@ -185,15 +246,15 @@ class WatcherAPITests(test.APITestCase):
watcherclient.action_plan.list(audit=None).AndReturn(action_plans)
self.mox.ReplayAll()
ret_val = api.watcher.ActionPlan.list(
self.request,
audit_filter=None)
for n in ret_val:
self.assertIsInstance(n, api.watcher.ActionPlan)
ret_val = api.watcher.ActionPlan.list(self.request, audit_filter=None)
self.assertIn('action_plans', ret_val)
for n in ret_val['action_plans']:
self.assertIsInstance(n, dict)
def test_action_plan_get(self):
action_plan = {'action_plan': self.api_action_plans.first()}
action_plan_id = self.api_action_plans.first()['id']
action_plan = self.api_action_plans.first()
action_plan_id = self.api_action_plans.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.action_plan = self.mox.CreateMockAnything()
@ -202,10 +263,10 @@ class WatcherAPITests(test.APITestCase):
self.mox.ReplayAll()
ret_val = api.watcher.ActionPlan.get(self.request, action_plan_id)
self.assertIsInstance(ret_val, api.watcher.ActionPlan)
self.assertIsInstance(ret_val, dict)
def test_action_plan_start(self):
action_plan_id = self.api_action_plans.first()['id']
action_plan_id = self.api_action_plans.first()['uuid']
patch = []
patch.append({'path': '/state', 'value': 'PENDING', 'op': 'replace'})
@ -217,7 +278,7 @@ class WatcherAPITests(test.APITestCase):
api.watcher.ActionPlan.start(self.request, action_plan_id)
def test_action_plan_delete(self):
action_plan_id = self.api_action_plans.first()['id']
action_plan_id = self.api_action_plans.first()['uuid']
watcherclient = self.stub_watcherclient()
watcherclient.action_plan = self.mox.CreateMockAnything()
@ -237,7 +298,8 @@ class WatcherAPITests(test.APITestCase):
self.mox.ReplayAll()
ret_val = api.watcher.Action.list(
self.request,
action_plan_filter=None)
for n in ret_val:
self.assertIsInstance(n, api.watcher.Action)
self.request, action_plan_filter=None)
self.assertIn('actions', ret_val)
for n in ret_val['actions']:
self.assertIsInstance(n, dict)

View File

@ -223,7 +223,7 @@ class TestCase(horizon_helpers.TestCase):
Asserts that the given response issued a 302 redirect without
processing the view which is redirected to.
"""
assert (response.status_code / 100 == 3), \
assert (300 <= response.status_code < 400), \
"The response did not return a redirect."
self.assertEqual(response._headers.get('location', None),
('Location', settings.TESTSERVER + expected_url))

View File

@ -29,7 +29,7 @@ class AuditsTable(tables.TableRegion):
launch_button.click()
return forms.BaseFormRegion(self.driver, self.conf)
@tables.bind_row_action('go_to_action_plan', primary=True)
@tables.bind_row_action('go_to_action_plan')
def go_to_action_plan(self, goto_button):
goto_button.click()
return forms.BaseFormRegion(self.driver, self.conf)

View File

@ -21,7 +21,8 @@ class AuditTemplatesTable(tables.TableRegion):
name = 'audit_templates'
CREATE_AUDIT_TEMPLATE_FORM_FIELDS = ("name", "description", "goal")
CREATE_AUDIT_TEMPLATE_FORM_FIELDS = ("name", "description",
"goal_id", "strategy_id")
@tables.bind_table_action('create')
def create_audit_template(self, create_button):
@ -35,7 +36,7 @@ class AuditTemplatesTable(tables.TableRegion):
delete_button.click()
return forms.BaseFormRegion(self.driver, self.conf, None)
@tables.bind_row_action('launch_audit', primary=True)
@tables.bind_row_action('launch_audit')
def launch_audit(self, launch_button, row):
launch_button.click()
return forms.BaseFormRegion(self.driver, self.conf)
@ -44,7 +45,7 @@ class AuditTemplatesTable(tables.TableRegion):
class AudittemplatesPage(basepage.BaseNavigationPage):
DEFAULT_DESCRIPTION = "Fake description from integration tests"
DEFAULT_GOAL = "BASIC_CONSOLIDATION"
DEFAULT_GOAL = "SERVER_CONSOLIDATION"
AUDITS_PAGE_TITLE = "Audits - OpenStack Dashboard"
@ -86,11 +87,11 @@ class AudittemplatesPage(basepage.BaseNavigationPage):
def create_audit_template(self,
name,
description=DEFAULT_DESCRIPTION,
goal=DEFAULT_GOAL):
goal_id=DEFAULT_GOAL):
self.audittemplates_table.create_audit_template()
self.audit_templates__action_create_form.name.text = name
self.audit_templates__action_create_form.description.text = description
self.audit_templates__action_create_form.goal.value = goal
self.audit_templates__action_create_form.goal_id.value = goal_id
self.audit_templates__action_create_form.submit()
def is_audit_template_present(self, name):

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import unittest
import uuid
from openstack_dashboard.test.integration_tests import helpers
@ -66,7 +65,6 @@ class AuditTemplatePanelTests(helpers.AdminTestCase):
audit_template_page.show_audit_template_info(
self.audit_template_name))
@unittest.skip(reason="https://bugs.launchpad.net/horizon/+bug/1537526")
def test_launch_audit(self):
"""Test the audit template panel "Launch Audit" row button

View File

@ -34,6 +34,50 @@ def data(TEST):
"publicURL": "http://public.watcher2.example.com:9322"}]},
)
TEST.goals = utils.TestDataContainer()
TEST.api_goals = utils.TestDataContainer()
goal_dict1 = {
'uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
'name': 'MINIMIZE_LICENSING_COST',
'display_name': 'Dummy',
}
goal_dict2 = {
'uuid': 'gggggggg-2222-2222-2222-gggggggggggg',
'name': 'SERVER_CONSOLIDATION',
'display_name': 'Server consolidation',
}
TEST.api_goals.add(goal_dict1)
TEST.api_goals.add(goal_dict2)
_goal_dict1 = copy.deepcopy(goal_dict1)
_goal_dict2 = copy.deepcopy(goal_dict2)
TEST.strategies = utils.TestDataContainer()
TEST.api_strategies = utils.TestDataContainer()
strategy_dict1 = {
'uuid': 'ssssssss-1111-1111-1111-ssssssssssss',
'name': 'minimize_licensing_cost1',
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
'display_name': 'Fake licensing cost strategy1',
}
strategy_dict2 = {
'uuid': 'ssssssss-2222-2222-2222-ssssssssssss',
'name': 'minimize_licensing_cost2',
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
'display_name': 'Fake licensing cost strategy2',
}
strategy_dict3 = {
'uuid': 'ssssssss-3333-3333-3333-ssssssssssss',
'name': 'sercon',
'goal_uuid': 'gggggggg-2222-2222-2222-gggggggggggg',
'display_name': 'Fake Sercon',
}
TEST.api_strategies.add(strategy_dict1)
TEST.api_strategies.add(strategy_dict2)
TEST.api_strategies.add(strategy_dict3)
_strategy_dict1 = copy.deepcopy(strategy_dict1)
_strategy_dict2 = copy.deepcopy(strategy_dict2)
_strategy_dict3 = copy.deepcopy(strategy_dict3)
TEST.audit_templates = utils.TestDataContainer()
TEST.api_audit_templates = utils.TestDataContainer()
audit_template_dict = {
@ -42,7 +86,8 @@ def data(TEST):
'description': 'Audit Template 1 description',
'host_aggregate': None,
'extra': {'automatic': False},
'goal': 'MINIMIZE_LICENSING_COST'
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
'strategy_uuid': 'ssssssss-1111-1111-1111-ssssssssssss',
}
audit_template_dict2 = {
'uuid': '11111111-2222-2222-2222-111111111111',
@ -50,7 +95,8 @@ def data(TEST):
'description': 'Audit Template 2 description',
'host_aggregate': None,
'extra': {'automatic': False},
'goal': 'MINIMIZE_LICENSING_COST'
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
'strategy_uuid': 'ssssssss-2222-2222-2222-ssssssssssss',
}
audit_template_dict3 = {
'uuid': '11111111-3333-3333-3333-111111111111',
@ -58,7 +104,8 @@ def data(TEST):
'description': 'Audit Template 3 description',
'host_aggregate': None,
'extra': {'automatic': False},
'goal': 'MINIMIZE_LICENSING_COST'
'goal_uuid': 'gggggggg-2222-2222-2222-gggggggggggg',
'strategy_uuid': None,
}
TEST.api_audit_templates.add(audit_template_dict)
TEST.api_audit_templates.add(audit_template_dict2)
@ -67,13 +114,10 @@ def data(TEST):
_audit_template_dict2 = copy.deepcopy(audit_template_dict2)
_audit_template_dict3 = copy.deepcopy(audit_template_dict3)
TEST.goals = utils.TestDataContainer()
TEST.api_goals = utils.TestDataContainer()
TEST.audits = utils.TestDataContainer()
TEST.api_audits = utils.TestDataContainer()
audit_dict = {
'id': '22222222-2222-2222-2222-222222222222',
'uuid': '22222222-2222-2222-2222-222222222222',
'deadline': None,
'type': 'ONESHOT',
'audit_template_uuid': '11111111-1111-1111-1111-111111111111'
@ -84,7 +128,7 @@ def data(TEST):
TEST.action_plans = utils.TestDataContainer()
TEST.api_action_plans = utils.TestDataContainer()
action_plan_dict = {
'id': '33333333-3333-3333-3333-333333333333',
'uuid': '33333333-3333-3333-3333-333333333333',
'state': 'RECOMMENDED',
'first_action_uuid': '44444444-4444-4444-4444-111111111111',
'audit_uuid': '22222222-2222-2222-2222-222222222222'
@ -95,7 +139,7 @@ def data(TEST):
TEST.actions = utils.TestDataContainer()
TEST.api_actions = utils.TestDataContainer()
action_dict1 = {
'id': '44444444-4444-4444-4444-111111111111',
'uuid': '44444444-4444-4444-4444-111111111111',
'state': 'PENDING',
'next_uuid': '44444444-4444-4444-4444-222222222222',
'action_plan_uuid': '33333333-3333-3333-3333-333333333333'
@ -103,7 +147,7 @@ def data(TEST):
TEST.api_actions.add(action_dict1)
action_dict2 = {
'id': '44444444-4444-4444-4444-222222222222',
'uuid': '44444444-4444-4444-4444-222222222222',
'state': 'PENDING',
'next_uuid': None,
'action_plan_uuid': '33333333-3333-3333-3333-333333333333'
@ -121,11 +165,23 @@ def data(TEST):
_audit_dict['action_plans'] = [action_plan]
audit = watcher.Audit(_audit_dict)
# _audit_template_dict['audits'] = [audit]
goal1 = watcher.Goal(_goal_dict1)
goal2 = watcher.Goal(_goal_dict2)
strategy1 = watcher.Strategy(_strategy_dict1)
strategy2 = watcher.Strategy(_strategy_dict2)
strategy3 = watcher.Strategy(_strategy_dict3)
audit_template1 = watcher.AuditTemplate(_audit_template_dict)
audit_template2 = watcher.AuditTemplate(_audit_template_dict2)
audit_template3 = watcher.AuditTemplate(_audit_template_dict3)
TEST.goals.add(goal1)
TEST.goals.add(goal2)
TEST.strategies.add(strategy1)
TEST.strategies.add(strategy2)
TEST.strategies.add(strategy3)
TEST.audit_templates.add(audit_template1)
TEST.audit_templates.add(audit_template2)
TEST.audit_templates.add(audit_template3)

View File

@ -14,7 +14,6 @@
from django.conf import urls
import openstack_dashboard.urls
urlpatterns = urls.patterns(
'',
urlpatterns = [
urls.url(r'', urls.include(openstack_dashboard.urls))
)
]