group-based-policy-ui/gbpui/panels/application_policy/workflows.py
Marek Lycka cf76c87cc7 Replaces multi select combos with transfer tables
Implements an angular-python bridge that allows django/horizon forms
to use transfer tables (as seen in other parts of horizon, e.g.:
computes launch instance dialog) as form fields. These fields are
then used to replace the multi select combos boxes in the different
GBPUI dialogs/forms.

Note 1: The add and remove policy rule set actions in group details
"Provided Policy Rule Set" and "Consumed Policy Rule Set" are currently
unaffected. These two tabs do not follow the "standard" horizon method
of adding and removing items through one transfer table; instead,
it uses two different dialogs to carry out each operation separately.
This should be addressed in a separate patchset.

Note 2: This is a bit of a stop gap measure, as horizon is slowly moving
away from native django based dialogs and wizards to AngularJS. The goal
should ultimately be to do the same in GBPUI.

Change-Id: I01c9dc08b1bc35309d62eb3da0bd26f3795867ab
Partial-Bug: 1712814
2017-09-18 14:04:34 +02:00

355 lines
13 KiB
Python

# 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.core.urlresolvers import reverse
from django.utils import html
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import workflows
from gbpui import client
from gbpui import fields
ADD_POLICY_ACTION_URL = "horizon:project:application_policy:addpolicyaction"
ADD_POLICY_CLASSIFIER_URL = "horizon:project:application_policy:"
ADD_POLICY_CLASSIFIER_URL = ADD_POLICY_CLASSIFIER_URL + "addpolicyclassifier"
ADD_POLICY_RULE_URL = "horizon:project:application_policy:addpolicyrule"
class SelectPolicyRuleAction(workflows.Action):
policy_rules = fields.TransferTableField(
label=_("Policy Rules"),
required=False,
add_item_link=ADD_POLICY_RULE_URL,
help_text=_("Create a policy rule set with selected rules.")
)
class Meta(object):
name = _("Rules")
help_text = _("Select policy rules for your policy rule set.")
def populate_policy_rules_choices(self, request, context):
try:
rules = client.policyrule_list(request,
tenant_id=request.user.tenant_id)
for r in rules:
r.set_id_as_name_if_empty()
rules = sorted(rules,
key=lambda rule: rule.name)
rule_list = [(rule.id, rule.name) for rule in rules]
except Exception as e:
rule_list = []
exceptions.handle(request,
_('Unable to retrieve rules (%(error)s).') % {
'error': str(e)})
return rule_list
class SelectPolicyRuleStep(workflows.Step):
action_class = SelectPolicyRuleAction
contributes = ("policy_rules",)
def contribute(self, data, context):
if data:
rules = self.workflow.request.POST.getlist("policy_rules")
if rules:
rules = [r for r in rules if r != '']
context['policy_rules'] = rules
return context
class AddContractAction(workflows.Action):
name = forms.CharField(max_length=80,
label=_("Name"),
required=False)
description = forms.CharField(max_length=80,
label=_("Description"),
required=False)
shared = forms.BooleanField(label=_("Shared"),
initial=False, required=False)
def __init__(self, request, *args, **kwargs):
super(AddContractAction, self).__init__(request, *args, **kwargs)
class Meta(object):
name = _("Create Policy Rule Set")
help_text = _("Create a new Policy Rule Set")
class AddContractStep(workflows.Step):
action_class = AddContractAction
contributes = ("name", "description", "shared")
def contribute(self, data, context):
context = super(AddContractStep, self).contribute(data, context)
return context
class AddContract(workflows.Workflow):
slug = "addpolicy_rule_set"
name = _("Create Policy Rule Set")
finalize_button_name = _("Create")
success_message = _('Created Policy Rule Set "%s".')
failure_message = _('Unable to create Policy Rule Set "%s".')
default_steps = (AddContractStep,
SelectPolicyRuleStep)
wizard = True
def get_success_url(self):
return reverse("horizon:project:application_policy:index")
def format_status_message(self, message):
return message % self.context.get('name')
def _create_policy_rule_set(self, request, context):
try:
if context.get('name'):
context['name'] = html.escape(context['name'])
if context.get('description'):
context['description'] = html.escape(context['description'])
return client.policy_rule_set_create(request, **context)
except Exception as e:
msg = self.format_status_message(self.failure_message) + str(e)
exceptions.handle(request, msg)
return False
def handle(self, request, context):
if context.get('name'):
context['name'] = html.escape(context['name'])
if context.get('description'):
context['description'] = html.escape(context['description'])
policy_rule_set = self._create_policy_rule_set(request, context)
self.object = policy_rule_set
return policy_rule_set
class SelectPolicyClassifierAction(workflows.Action):
classifier = forms.DynamicChoiceField(
label=_("Policy Classifier"),
required=False,
help_text=_("Create a policy with selected classifier."),
add_item_link=ADD_POLICY_CLASSIFIER_URL)
class Meta(object):
name = _("Classifiers")
help_text = _("Select classifiers for your policy-rule.")
def populate_classifier_choices(self, request, context):
try:
classifiers = client.policyclassifier_list(request,
tenant_id=request.user.tenant_id)
for classifier in classifiers:
classifier.set_id_as_name_if_empty()
classifiers = sorted(classifiers,
key=lambda classifier: classifier.name)
classifier_list = [(c.id, c.name) for c in classifiers]
except Exception as e:
classifier_list = []
exceptions.handle(request,
_('Unable to retrieve classifiers (%(error)s).')
% {'error': str(e)})
return classifier_list
class SelectPolicyActionAction(workflows.Action):
actions = fields.TransferTableField(
label=_("Policy Action"),
required=False,
add_item_link=ADD_POLICY_ACTION_URL,
help_text=_("Create a policy-rule with selected action.")
)
def __init__(self, request, context, *args, **kwargs):
super(SelectPolicyActionAction, self).__init__(
request, context, *args, **kwargs
)
class Meta(object):
name = _("actions")
help_text = _("Select actions for your policy-rule.")
def populate_actions_choices(self, request, context):
try:
actions = client.policyaction_list(request,
tenant_id=request.user.tenant_id)
for action in actions:
action.set_id_as_name_if_empty()
actions = sorted(actions,
key=lambda action: action.name)
action_list = [(a.id, a.name) for a in actions]
except Exception as e:
action_list = []
exceptions.handle(request,
_('Unable to retrieve actions (%(error)s).')
% {'error': str(e)})
return action_list
class SelectPolicyActionStep(workflows.Step):
action_class = SelectPolicyActionAction
contributes = ("policy_actions",)
def contribute(self, data, context):
if data:
actions = self.workflow.request.POST.getlist(
"actions")
if actions:
actions = [a for a in actions if a != '']
context['policy_actions'] = actions
return context
class SelectPolicyClassifierStep(workflows.Step):
action_class = SelectPolicyClassifierAction
contributes = ("policy_classifier_id",)
def contribute(self, data, context):
context = super(SelectPolicyClassifierStep, self).contribute(data,
context)
if data:
context['policy_classifier_id'] = data['classifier']
return context
class AddPolicyRuleAction(workflows.Action):
name = forms.CharField(max_length=80,
label=_("Name"))
description = forms.CharField(max_length=80,
label=_("Description"),
required=False)
shared = forms.BooleanField(label=_("Shared"),
initial=False, required=False)
def __init__(self, request, *args, **kwargs):
super(AddPolicyRuleAction, self).__init__(request, *args, **kwargs)
class Meta(object):
name = _("Create Policy-Rule")
help_text = _("Create a new Policy-Rule")
class AddPolicyRuleStep(workflows.Step):
action_class = AddPolicyRuleAction
contributes = ("name", "description", "shared")
def contribute(self, data, context):
context = super(AddPolicyRuleStep, self).contribute(data, context)
return context
class AddPolicyRule(workflows.Workflow):
slug = "addpolicyrule"
name = _("Create Policy-Rule")
finalize_button_name = _("Create")
success_message = _('Created Policy-Rule "%s".')
failure_message = _('Unable to create Policy-Rule "%s".')
default_steps = (AddPolicyRuleStep,
SelectPolicyClassifierStep,
SelectPolicyActionStep)
wizard = True
def get_success_url(self):
return reverse("horizon:project:application_policy:index")
def format_status_message(self, message):
return message % self.context.get('name')
def handle(self, request, context):
try:
if context.get('name'):
context['name'] = html.escape(context['name'])
if context.get('description'):
context['description'] = html.escape(context['description'])
rule = client.policyrule_create(request, **context)
self.object = rule
return rule
except Exception as e:
msg = self.format_status_message(self.failure_message) + str(e)
exceptions.handle(request, msg)
return False
class AddClassifierAction(workflows.Action):
name = forms.CharField(max_length=80, label=_("Name"), required=False)
protocol = forms.ChoiceField(
label=_("Protocol"),
choices=[('tcp', _('TCP')),
('udp', _('UDP')),
('icmp', _('ICMP')),
('any', _('ANY'))],)
port_range = forms.CharField(
max_length=80,
label=_("Port/Range(min:max)"),
required=False)
direction = forms.ChoiceField(
label=_("Direction"),
choices=[('in', _('IN')),
('out', _('OUT')),
('bi', _('BI'))])
shared = forms.BooleanField(label=_("Shared"),
initial=False, required=False)
def __init__(self, request, *args, **kwargs):
super(AddClassifierAction, self).__init__(request, *args, **kwargs)
class Meta(object):
name = _("Create Classifier")
help_text = _("Create a new Classifier")
class AddClassifierStep(workflows.Step):
action_class = AddClassifierAction
contributes = ("name", "protocol", "port_range", "direction", "shared")
def contribute(self, data, context):
context = super(AddClassifierStep, self).contribute(data, context)
return context
class AddPolicyClassifier(workflows.Workflow):
slug = "addpolicyclassifier"
name = _("Create Classifier")
finalize_button_name = _("Create")
success_message = _('Created Classifier "%s".')
failure_message = _('Unable to create Classifier "%s".')
success_url = "horizon:project:application_policy:index"
default_steps = (AddClassifierStep,)
def format_status_message(self, message):
return message % self.context.get('name')
def _create_classifer(self, request, context):
try:
if context.get('name'):
context['name'] = html.escape(context['name'])
if context.get('description'):
context['description'] = html.escape(context['description'])
client.policyclassifier_create(request, **context)
return True
except Exception as e:
msg = self.format_status_message(self.failure_message) + str(e)
exceptions.handle(request, msg)
return False
def handle(self, request, context):
if context.get('name'):
context['name'] = html.escape(context['name'])
if context.get('description'):
context['description'] = html.escape(context['description'])
classifier = self._create_classifer(request, context)
if not classifier:
return False
return classifier