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
changes/16/301516/5 0.3.0
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