Added the audit scope field in dashboard
In this changeset, I added the scope field in the dashboard using a textarea that verifies that the given audit scope is a valid YAML/JSON data structure. I also removed obsolete object fields: deadline in Audit object and extra in Audit Template object. Partially Implements: blueprint define-the-audit-scope Change-Id: Icb30557a6a4b3a698f3a6f9ccec57223b60b0b53
This commit is contained in:
parent
b7a2b73dfd
commit
1a900cfbf6
@ -10,6 +10,7 @@ django-openstack-auth>=2.4.0 # Apache-2.0
|
||||
httplib2>=0.7.5 # MIT
|
||||
python-keystoneclient!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
pytz>=2013.6 # MIT
|
||||
PyYAML>=3.10.0 # MIT
|
||||
|
||||
# Watcher-specific requirements
|
||||
python-watcherclient>=0.23.0 # Apache-2.0
|
||||
|
@ -56,7 +56,7 @@ def insert_watcher_policy_file():
|
||||
|
||||
class Audit(base.APIDictWrapper):
|
||||
_attrs = ('uuid', 'created_at', 'modified_at', 'deleted_at',
|
||||
'deadline', 'state', 'audit_type', 'audit_template_uuid',
|
||||
'state', 'audit_type', 'audit_template_uuid',
|
||||
'audit_template_name', 'interval')
|
||||
|
||||
def __init__(self, apiresource, request=None):
|
||||
@ -65,7 +65,7 @@ class Audit(base.APIDictWrapper):
|
||||
|
||||
@classmethod
|
||||
def create(cls, request, audit_template_uuid,
|
||||
audit_type, deadline, interval=None):
|
||||
audit_type, interval=None):
|
||||
|
||||
"""Create an audit in Watcher
|
||||
|
||||
@ -78,9 +78,6 @@ class Audit(base.APIDictWrapper):
|
||||
:param audit_type: audit type
|
||||
:type audit_type: string
|
||||
|
||||
:param deadline: audit deadline:
|
||||
:type deadline: string
|
||||
|
||||
:param interval: Audit interval (default: None)
|
||||
:type interval: int
|
||||
|
||||
@ -91,11 +88,10 @@ class Audit(base.APIDictWrapper):
|
||||
if interval:
|
||||
return watcherclient(request).audit.create(
|
||||
audit_template_uuid=audit_template_uuid, audit_type=audit_type,
|
||||
deadline=deadline, interval=interval)
|
||||
interval=interval)
|
||||
else:
|
||||
return watcherclient(request).audit.create(
|
||||
audit_template_uuid=audit_template_uuid, audit_type=audit_type,
|
||||
deadline=deadline)
|
||||
audit_template_uuid=audit_template_uuid, audit_type=audit_type)
|
||||
|
||||
@classmethod
|
||||
def list(cls, request, **filters):
|
||||
@ -147,9 +143,9 @@ class Audit(base.APIDictWrapper):
|
||||
|
||||
|
||||
class AuditTemplate(base.APIDictWrapper):
|
||||
_attrs = ('uuid', 'description', 'host_aggregate', 'name', 'extra',
|
||||
'goal_uuid', 'goal_name', 'strategy_uuid', 'strategy_name',
|
||||
'created_at', 'updated_at', 'deleted_at')
|
||||
_attrs = ('uuid', 'description', 'scope', 'name', 'goal_uuid', 'goal_name',
|
||||
'strategy_uuid', 'strategy_name', 'created_at', 'updated_at',
|
||||
'deleted_at')
|
||||
|
||||
def __init__(self, apiresource, request=None):
|
||||
super(AuditTemplate, self).__init__(apiresource)
|
||||
@ -157,7 +153,7 @@ class AuditTemplate(base.APIDictWrapper):
|
||||
|
||||
@classmethod
|
||||
def create(cls, request, name, goal, strategy,
|
||||
description, host_aggregate):
|
||||
description, scope):
|
||||
"""Create an audit template in Watcher
|
||||
|
||||
:param request: request object
|
||||
@ -176,9 +172,8 @@ class AuditTemplate(base.APIDictWrapper):
|
||||
:param description: Descrition of the audit template
|
||||
:type description: string
|
||||
|
||||
:param host_aggregate: Name or UUID of the host aggregate targeted
|
||||
by this audit template
|
||||
:type host_aggregate: string
|
||||
:param scope: Audit scope
|
||||
:type scope: list of list of dict
|
||||
|
||||
:param audit_template: audit template
|
||||
:type audit_template: string
|
||||
@ -191,7 +186,7 @@ class AuditTemplate(base.APIDictWrapper):
|
||||
goal=goal,
|
||||
strategy=strategy,
|
||||
description=description,
|
||||
host_aggregate=host_aggregate
|
||||
scope=scope,
|
||||
)
|
||||
|
||||
return audit_template
|
||||
|
@ -18,24 +18,45 @@ Forms for starting Watcher Audit Templates.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.core import exceptions as core_exc
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
import yaml
|
||||
|
||||
from watcher_dashboard.api import watcher
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class YamlValidator(object):
|
||||
message = _('Enter a valid YAML or JSON value.')
|
||||
code = 'invalid'
|
||||
|
||||
def __init__(self, message=None):
|
||||
if message:
|
||||
self.message = message
|
||||
|
||||
def __call__(self, value):
|
||||
try:
|
||||
yaml.load(value)
|
||||
except Exception:
|
||||
raise core_exc.ValidationError(self.message, code=self.code)
|
||||
|
||||
|
||||
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)
|
||||
strategy = forms.ChoiceField(label=_('Strategy'), required=False)
|
||||
strategy = forms.DynamicChoiceField(label=_('Strategy'), required=False)
|
||||
|
||||
scope = forms.CharField(
|
||||
label=_('Scope'), required=False,
|
||||
widget=forms.widgets.Textarea,
|
||||
validators=[YamlValidator()])
|
||||
|
||||
failure_url = 'horizon:admin:audit_templates:index'
|
||||
|
||||
@ -103,7 +124,8 @@ class CreateForm(forms.SelfHandlingForm):
|
||||
params['description'] = data['description']
|
||||
params['goal'] = data['goal']
|
||||
params['strategy'] = data['strategy'] or None
|
||||
params['host_aggregate'] = None
|
||||
params['scope'] = [] if not data['scope'] else yaml.load(
|
||||
data['scope'])
|
||||
audit_tpl = watcher.AuditTemplate.create(request, **params)
|
||||
message = _('Audit Template was successfully created.')
|
||||
messages.success(request, message)
|
||||
|
@ -69,7 +69,6 @@ class LaunchAudit(horizon.tables.BatchAction):
|
||||
def action(self, request, obj_id):
|
||||
params = {'audit_template_uuid': obj_id}
|
||||
params['audit_type'] = 'ONESHOT'
|
||||
params['deadline'] = None
|
||||
watcher.Audit.create(request, **params)
|
||||
|
||||
|
||||
|
@ -86,7 +86,7 @@ class AuditTemplatesTest(test.BaseAdminViewTests):
|
||||
'goal': at.goal_uuid,
|
||||
'strategy': at.strategy_uuid,
|
||||
'description': at.description,
|
||||
'host_aggregate': at.host_aggregate,
|
||||
'scope': at.scope,
|
||||
}
|
||||
api.watcher.Goal.list(
|
||||
IsA(http.HttpRequest)).AndReturn(self.goal_list)
|
||||
|
@ -14,6 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
@ -94,6 +95,9 @@ class DetailView(horizon.tabs.TabbedTableView):
|
||||
audit_template_uuid = self.kwargs['audit_template_uuid']
|
||||
audit_template = watcher.AuditTemplate.get(
|
||||
self.request, audit_template_uuid)
|
||||
if audit_template.scope:
|
||||
audit_template.scope = json.dumps(audit_template.scope)
|
||||
|
||||
except Exception as exc:
|
||||
LOG.exception(exc)
|
||||
msg = _('Unable to retrieve details for audit template "%s".') \
|
||||
|
@ -89,7 +89,6 @@ class CreateForm(forms.SelfHandlingForm):
|
||||
params['interval'] = int(data['interval'].total_seconds())
|
||||
else:
|
||||
params['interval'] = None
|
||||
params['deadline'] = None
|
||||
audit = watcher.Audit.create(request, **params)
|
||||
message = _('Audit was successfully created.')
|
||||
messages.success(request, message)
|
||||
|
@ -25,8 +25,6 @@
|
||||
<dd><a href="{{ next_action_url }}">{{ action.next_uuid|default:_("—") }}</a></dd>
|
||||
<dt>{% trans "State" %}</dt>
|
||||
<dd>{{ action.state|default:"—" }}</dd>
|
||||
<dt>{% trans "Deadline" %}</dt>
|
||||
<dd>{{ action.deadline|default:"—" }}</dd>
|
||||
<dt>{% trans "Created At" %}</dt>
|
||||
<dd>{{ action.created_at|default:"—" }}</dd>
|
||||
<dt>{% trans "Update At" %}</dt>
|
||||
|
@ -6,5 +6,46 @@
|
||||
<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 "Optionally, 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>
|
||||
<span>{% trans "Optionally, 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>
|
||||
<h3>{% trans "Audit scope:" %}</h3>
|
||||
<p>{% trans "Creates an audit template with specified parameters." %}</p>
|
||||
<p>{% trans "Creates an audit template with specified parameters." %}</p>
|
||||
|
||||
<p class="scope-example-yaml">
|
||||
{% trans "YAML example:" %}
|
||||
---
|
||||
- host_aggregates:
|
||||
- id: 1
|
||||
- id: 2
|
||||
- id: 3
|
||||
- availability_zones:
|
||||
- name: AZ1
|
||||
- name: AZ2
|
||||
- exclude:
|
||||
- instances:
|
||||
- uuid: UUID1
|
||||
- uuid: UUID2
|
||||
- compute_nodes:
|
||||
- name: compute1
|
||||
</p>
|
||||
<p>
|
||||
{% trans "JSON example:" %}
|
||||
[{'host_aggregates': [
|
||||
{'id': 1},
|
||||
{'id': 2},
|
||||
{'id': 3}]},
|
||||
{'availability_zones': [
|
||||
{'name': 'AZ1'},
|
||||
{'name': 'AZ2'}]},
|
||||
{'exclude': [
|
||||
{'instances': [
|
||||
{'uuid': 'UUID1'},
|
||||
{'uuid': 'UUID2'}
|
||||
]},
|
||||
{'compute_nodes': [
|
||||
{'name': 'compute1'}
|
||||
]}
|
||||
]}]
|
||||
</p>
|
||||
{% endblock %}
|
||||
|
@ -19,6 +19,8 @@
|
||||
<dd>{{ audit_template.goal_name|default:"—" }}</dd>
|
||||
<dt>{% trans "Strategy" %}</dt>
|
||||
<dd>{{ audit_template.strategy_name|default:"—" }}</dd>
|
||||
<dt>{% trans "Audit Scope" %}</dt>
|
||||
<dd><code>{{ audit_template.scope|linebreaks }}</code></dd>
|
||||
<dt>{% trans "Created At" %}</dt>
|
||||
<dd>{{ audit_template.created_at|default:"—" }}</dd>
|
||||
<dt>{% trans "Update At" %}</dt>
|
||||
|
@ -22,8 +22,6 @@
|
||||
{% url 'horizon:admin:audit_templates:detail' audit.audit_template_uuid as audit_template_url %}
|
||||
<dt>{% trans "State" %}</dt>
|
||||
<dd>{{ audit.state|default:"—" }}</dd>
|
||||
<dt>{% trans "Deadline" %}</dt>
|
||||
<dd>{{ audit.deadline|default:"—" }}</dd>
|
||||
<dt>{% trans "Created At" %}</dt>
|
||||
<dd>{{ audit.created_at|default:"—" }}</dd>
|
||||
<dt>{% trans "Update At" %}</dt>
|
||||
|
@ -129,7 +129,7 @@ class WatcherAPITests(test.APITestCase):
|
||||
goal = audit_template['goal_uuid']
|
||||
strategy = audit_template['strategy_uuid']
|
||||
description = audit_template['description']
|
||||
host_aggregate = audit_template['host_aggregate']
|
||||
scope = audit_template['scope']
|
||||
|
||||
watcherclient = self.stub_watcherclient()
|
||||
watcherclient.audit_template = self.mox.CreateMockAnything()
|
||||
@ -138,12 +138,12 @@ class WatcherAPITests(test.APITestCase):
|
||||
goal=goal,
|
||||
strategy=strategy,
|
||||
description=description,
|
||||
host_aggregate=host_aggregate).AndReturn(audit_template)
|
||||
scope=scope).AndReturn(audit_template)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
ret_val = api.watcher.AuditTemplate.create(
|
||||
self.request, name, goal, strategy,
|
||||
description, host_aggregate)
|
||||
description, scope)
|
||||
self.assertIsInstance(ret_val, dict)
|
||||
|
||||
def test_audit_template_patch(self):
|
||||
@ -210,7 +210,6 @@ class WatcherAPITests(test.APITestCase):
|
||||
audit = self.api_audits.first()
|
||||
audit_template_id = self.api_audit_templates.first()['uuid']
|
||||
|
||||
deadline = self.api_audits.first()['deadline']
|
||||
audit_type = self.api_audits.first()['audit_type']
|
||||
audit_template_uuid = audit_template_id
|
||||
|
||||
@ -218,19 +217,17 @@ class WatcherAPITests(test.APITestCase):
|
||||
watcherclient.audit = self.mox.CreateMockAnything()
|
||||
watcherclient.audit.create(
|
||||
audit_template_uuid=audit_template_uuid,
|
||||
audit_type=audit_type,
|
||||
deadline=deadline).AndReturn(audit)
|
||||
audit_type=audit_type).AndReturn(audit)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
ret_val = api.watcher.Audit.create(
|
||||
self.request, audit_template_uuid, audit_type, deadline)
|
||||
self.request, audit_template_uuid, audit_type)
|
||||
self.assertIsInstance(ret_val, dict)
|
||||
|
||||
def test_audit_create_with_interval(self):
|
||||
audit = self.api_audits.list()[1]
|
||||
audit_template_id = self.api_audit_templates.first()['uuid']
|
||||
|
||||
deadline = self.api_audits.first()['deadline']
|
||||
audit_type = self.api_audits.first()['audit_type']
|
||||
interval = audit['interval']
|
||||
audit_template_uuid = audit_template_id
|
||||
@ -240,12 +237,11 @@ class WatcherAPITests(test.APITestCase):
|
||||
watcherclient.audit.create(
|
||||
audit_template_uuid=audit_template_uuid,
|
||||
audit_type=audit_type,
|
||||
deadline=deadline,
|
||||
interval=interval).AndReturn(audit)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
ret_val = api.watcher.Audit.create(
|
||||
self.request, audit_template_uuid, audit_type, deadline, interval)
|
||||
self.request, audit_template_uuid, audit_type, interval)
|
||||
self.assertIsInstance(ret_val, dict)
|
||||
|
||||
def test_audit_delete(self):
|
||||
|
@ -117,6 +117,7 @@ AVAILABLE_THEMES, DEFAULT_THEME = theme_settings.get_available_themes(
|
||||
# Dictionary of currently available angular features
|
||||
ANGULAR_FEATURES = {
|
||||
'images_panel': False,
|
||||
'flavors_panel': False,
|
||||
}
|
||||
|
||||
# Notice all customizable configurations should be above this line
|
||||
|
@ -84,8 +84,7 @@ def data(TEST):
|
||||
'uuid': '11111111-1111-1111-1111-111111111111',
|
||||
'name': 'Audit Template 1',
|
||||
'description': 'Audit Template 1 description',
|
||||
'host_aggregate': None,
|
||||
'extra': {'automatic': False},
|
||||
'scope': None,
|
||||
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
|
||||
'strategy_uuid': 'ssssssss-1111-1111-1111-ssssssssssss',
|
||||
}
|
||||
@ -93,8 +92,7 @@ def data(TEST):
|
||||
'uuid': '11111111-2222-2222-2222-111111111111',
|
||||
'name': 'Audit Template 2',
|
||||
'description': 'Audit Template 2 description',
|
||||
'host_aggregate': None,
|
||||
'extra': {'automatic': False},
|
||||
'scope': None,
|
||||
'goal_uuid': 'gggggggg-1111-1111-1111-gggggggggggg',
|
||||
'strategy_uuid': 'ssssssss-2222-2222-2222-ssssssssssss',
|
||||
}
|
||||
@ -102,8 +100,7 @@ def data(TEST):
|
||||
'uuid': '11111111-3333-3333-3333-111111111111',
|
||||
'name': 'Audit Template 1',
|
||||
'description': 'Audit Template 3 description',
|
||||
'host_aggregate': None,
|
||||
'extra': {'automatic': False},
|
||||
'scope': None,
|
||||
'goal_uuid': 'gggggggg-2222-2222-2222-gggggggggggg',
|
||||
'strategy_uuid': None,
|
||||
}
|
||||
@ -118,14 +115,12 @@ def data(TEST):
|
||||
TEST.api_audits = utils.TestDataContainer()
|
||||
audit_dict = {
|
||||
'uuid': '22222222-2222-2222-2222-222222222222',
|
||||
'deadline': None,
|
||||
'audit_type': 'ONESHOT',
|
||||
'audit_template_uuid': '11111111-1111-1111-1111-111111111111',
|
||||
'interval': None,
|
||||
}
|
||||
audit_dict2 = {
|
||||
'uuid': '33333333-3333-3333-3333-333333333333',
|
||||
'deadline': None,
|
||||
'audit_type': 'CONTINUOUS',
|
||||
'audit_template_uuid': '11111111-1111-1111-1111-111111111111',
|
||||
'interval': 60,
|
||||
|
Loading…
x
Reference in New Issue
Block a user