From 5b7326405aab97fe8c976d1dc16ff8c2a65fa788 Mon Sep 17 00:00:00 2001
From: Jacky Hu
Date: Mon, 12 Mar 2018 18:14:23 +0800
Subject: [PATCH] Add l7 support
Enable users to create l7 policies and rules on a listener.
Change-Id: I29130311346c8627473222491a76777a9dc95f52
---
octavia_dashboard/api/rest/lbaasv2.py | 227 ++++++++++++++++
.../openstack-service-api/lbaasv2.service.js | 210 ++++++++++++++-
.../lbaasv2.service.spec.js | 101 +++++++
.../actions/create/create.action.service.js | 74 ++++++
.../create/create.action.service.spec.js | 65 +++++
.../actions/create/wizard.controller.js | 45 ++++
.../actions/create/wizard.controller.spec.js | 63 +++++
.../actions/delete/delete.action.service.js | 135 ++++++++++
.../delete/delete.action.service.spec.js | 103 ++++++++
.../actions/edit/edit.action.service.js | 69 +++++
.../actions/edit/edit.action.service.spec.js | 55 ++++
.../actions/edit/wizard.controller.js | 60 +++++
.../actions/edit/wizard.controller.spec.js | 77 ++++++
.../l7policies/details/detail.controller.js | 109 ++++++++
.../details/detail.controller.spec.js | 112 ++++++++
.../lbaasv2/l7policies/details/detail.html | 61 +++++
.../lbaasv2/l7policies/details/drawer.html | 9 +
.../lbaasv2/l7policies/l7policies.module.js | 177 +++++++++++++
.../l7policies/l7policies.module.spec.js | 67 +++++
.../actions/create/create.action.service.js | 74 ++++++
.../create/create.action.service.spec.js | 65 +++++
.../actions/create/wizard.controller.js | 45 ++++
.../actions/create/wizard.controller.spec.js | 63 +++++
.../actions/delete/delete.action.service.js | 137 ++++++++++
.../delete/delete.action.service.spec.js | 103 ++++++++
.../actions/edit/edit.action.service.js | 69 +++++
.../actions/edit/edit.action.service.spec.js | 55 ++++
.../l7rules/actions/edit/wizard.controller.js | 60 +++++
.../actions/edit/wizard.controller.spec.js | 77 ++++++
.../l7rules/details/detail.controller.js | 119 +++++++++
.../l7rules/details/detail.controller.spec.js | 114 ++++++++
.../lbaasv2/l7rules/details/detail.html | 54 ++++
.../lbaasv2/l7rules/details/drawer.html | 8 +
.../project/lbaasv2/l7rules/l7rules.module.js | 181 +++++++++++++
.../lbaasv2/l7rules/l7rules.module.spec.js | 67 +++++
.../project/lbaasv2/lbaasv2.module.js | 103 ++++++++
.../project/lbaasv2/lbaasv2.module.spec.js | 115 ++++++++
.../lbaasv2/listeners/details/detail.html | 6 +
.../actions/create/wizard.controller.js | 6 +-
.../loadbalancers/loadbalancers.service.js | 83 ++++++
.../loadbalancers.service.spec.js | 55 ++++
.../workflow/l7policy/l7policy.controller.js | 52 ++++
.../l7policy/l7policy.controller.spec.js | 37 +++
.../workflow/l7policy/l7policy.help.html | 38 +++
.../lbaasv2/workflow/l7policy/l7policy.html | 104 ++++++++
.../workflow/l7rule/l7rule.controller.js | 49 ++++
.../workflow/l7rule/l7rule.controller.spec.js | 37 +++
.../lbaasv2/workflow/l7rule/l7rule.help.html | 76 ++++++
.../lbaasv2/workflow/l7rule/l7rule.html | 92 +++++++
.../project/lbaasv2/workflow/model.service.js | 110 ++++++++
.../lbaasv2/workflow/model.service.spec.js | 250 +++++++++++++++++-
.../lbaasv2/workflow/workflow.service.js | 14 +
.../lbaasv2/workflow/workflow.service.spec.js | 4 +-
.../add-l7-support-05a790bc2965c38f.yaml | 4 +
54 files changed, 4338 insertions(+), 7 deletions(-)
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/drawer.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.spec.js
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html
create mode 100644 octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html
create mode 100644 releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml
diff --git a/octavia_dashboard/api/rest/lbaasv2.py b/octavia_dashboard/api/rest/lbaasv2.py
index c5ca48e5..71fd373c 100644
--- a/octavia_dashboard/api/rest/lbaasv2.py
+++ b/octavia_dashboard/api/rest/lbaasv2.py
@@ -180,6 +180,47 @@ def create_listener(request, **kwargs):
return _get_sdk_object_dict(listener)
+def create_l7_policy(request, **kwargs):
+ """Create a new l7 policy.
+
+ """
+ data = request.DATA
+
+ conn = _get_sdk_connection(request)
+ l7_policy = conn.load_balancer.create_l7_policy(
+ action=data['l7policy']['action'],
+ admin_state_up=data['l7policy'].get('admin_state_up'),
+ description=data['l7policy'].get('description'),
+ listener_id=kwargs['listener_id'],
+ name=data['l7policy'].get('name'),
+ position=data['l7policy'].get('position'),
+ redirect_pool_id=data['l7policy'].get('redirect_pool_id'),
+ redirect_url=data['l7policy'].get('redirect_url'),
+ )
+
+ return _get_sdk_object_dict(l7_policy)
+
+
+def create_l7_rule(request, **kwargs):
+ """Create a new l7 rule.
+
+ """
+ data = request.DATA
+
+ conn = _get_sdk_connection(request)
+ l7_rule = conn.load_balancer.create_l7_rule(
+ admin_state_up=data['l7rule'].get('admin_state_up'),
+ compare_type=data['l7rule']['compare_type'],
+ invert=data['l7rule'].get('invert'),
+ key=data['l7rule'].get('key'),
+ l7_policy=kwargs['l7_policy_id'],
+ type=data['l7rule']['type'],
+ rule_value=data['l7rule']['rule_value'],
+ )
+
+ return _get_sdk_object_dict(l7_rule)
+
+
def create_pool(request, **kwargs):
"""Create a new pool.
@@ -369,6 +410,50 @@ def update_listener(request, **kwargs):
return _get_sdk_object_dict(listener)
+def update_l7_policy(request, **kwargs):
+ """Update a l7 policy.
+
+ """
+ data = request.DATA
+ l7_policy_id = data['l7policy'].get('id')
+
+ conn = _get_sdk_connection(request)
+ l7_policy = conn.load_balancer.update_l7_policy(
+ action=data['l7policy']['action'],
+ admin_state_up=data['l7policy'].get('admin_state_up'),
+ description=data['l7policy'].get('description'),
+ l7_policy=l7_policy_id,
+ name=data['l7policy'].get('name'),
+ position=data['l7policy'].get('position'),
+ redirect_pool_id=data['l7policy'].get('redirect_pool_id'),
+ redirect_url=data['l7policy'].get('redirect_url'),
+ )
+
+ return _get_sdk_object_dict(l7_policy)
+
+
+def update_l7_rule(request, **kwargs):
+ """Update a l7 rule.
+
+ """
+ data = request.DATA
+ l7_rule_id = data['l7rule'].get('id')
+
+ conn = _get_sdk_connection(request)
+ l7_rule = conn.load_balancer.update_l7_rule(
+ admin_state_up=data['l7rule'].get('admin_state_up'),
+ compare_type=data['l7rule']['compare_type'],
+ invert=data['l7rule'].get('invert'),
+ key=data['l7rule'].get('key'),
+ l7_policy=kwargs['l7_policy_id'],
+ l7rule=l7_rule_id,
+ type=data['l7rule']['type'],
+ rule_value=data['l7rule']['rule_value'],
+ )
+
+ return _get_sdk_object_dict(l7_rule)
+
+
def update_pool(request, **kwargs):
"""Update a pool.
@@ -674,6 +759,148 @@ class Listener(generic.View):
conn.load_balancer.delete_listener(listener_id, ignore_missing=True)
+@urls.register
+class L7Policies(generic.View):
+ """API for load balancer l7 policies.
+
+ """
+ url_regex = r'lbaas/l7policies/$'
+
+ @rest_utils.ajax()
+ def get(self, request):
+ """List of l7 policies for the current project.
+
+ The listing result is an object with property "items".
+ """
+ listener_id = request.GET.get('listenerId')
+ conn = _get_sdk_connection(request)
+ l7_policy_list = _sdk_object_to_list(conn.load_balancer.l7_policies(
+ listener_id=listener_id))
+ return {'items': l7_policy_list}
+
+ @rest_utils.ajax()
+ def post(self, request):
+ """Create a new l7 policy.
+
+ Creates a new l7 policy as well as other optional resources such as
+ l7 rules.
+ """
+ kwargs = {'listener_id': request.DATA.get('parentResourceId')}
+ return create_l7_policy(request, **kwargs)
+
+
+@urls.register
+class L7Policy(generic.View):
+ """API for retrieving a single l7 policy.
+
+ """
+ url_regex = r'lbaas/l7policies/(?P[^/]+)/$'
+
+ @rest_utils.ajax()
+ def get(self, request, l7_policy_id):
+ """Get a specific l7 policy.
+
+ If the param 'includeChildResources' is passed in as a truthy value,
+ the details of all resources that exist under the l7 policy will be
+ returned along with the l7 policy details.
+
+ http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915
+ """
+ conn = _get_sdk_connection(request)
+ l7_policy = conn.load_balancer.find_l7_policy(l7_policy_id)
+ l7_policy = _get_sdk_object_dict(l7_policy)
+
+ if request.GET.get('includeChildResources'):
+ resources = {}
+
+ if l7_policy.get('rules'):
+ l7_rules_list = _sdk_object_to_list(
+ conn.load_balancer.l7_rules(l7_policy_id))
+ l7_policy['rules'] = l7_rules_list
+
+ resources['l7policy'] = l7_policy
+
+ return resources
+ else:
+ return l7_policy
+
+ @rest_utils.ajax()
+ def put(self, request, l7_policy_id):
+ """Edit a l7 policy as well as any resources below it.
+
+ """
+ kwargs = {'l7_policy_id': l7_policy_id}
+ update_l7_policy(request, **kwargs)
+
+ @rest_utils.ajax()
+ def delete(self, request, l7_policy_id):
+ """Delete a specific l7 policy.
+
+ http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915
+ """
+ conn = _get_sdk_connection(request)
+ conn.load_balancer.delete_l7_policy(l7_policy_id)
+
+
+@urls.register
+class L7Rules(generic.View):
+ """API for load balancer l7 rules.
+
+ """
+ url_regex = r'lbaas/l7policies/(?P[^/]+)/l7rules/$'
+
+ @rest_utils.ajax()
+ def get(self, request, l7_policy_id):
+ """List of l7 rules for the current project.
+
+ The listing result is an object with property "items".
+ """
+ conn = _get_sdk_connection(request)
+ l7_rule_list = _sdk_object_to_list(conn.load_balancer.l7_rules(
+ l7_policy_id))
+ return {'items': l7_rule_list}
+
+ @rest_utils.ajax()
+ def post(self, request, l7_policy_id):
+ """Create a new l7 rule.
+
+ Creates a new l7 rule as well as other optional resources such as
+ l7 rules.
+ """
+ kwargs = {'l7_policy_id': l7_policy_id}
+ return create_l7_rule(request, **kwargs)
+
+
+@urls.register
+class L7Rule(generic.View):
+ """API for retrieving a single l7 rule.
+
+ """
+ url_regex = (
+ r'lbaas/l7policies/(?P[^/]+)'
+ r'/l7rules/(?P[^/]+)/$'
+ )
+
+ @rest_utils.ajax()
+ def get(self, request, l7_rule_id, l7_policy_id):
+ """Get a specific l7 rule."""
+ conn = _get_sdk_connection(request)
+ l7_rule = conn.load_balancer.find_l7_rule(l7_rule_id, l7_policy_id)
+ return _get_sdk_object_dict(l7_rule)
+
+ @rest_utils.ajax()
+ def put(self, request, l7_rule_id, l7_policy_id):
+ """Edit a specific l7 rule."""
+ kwargs = {'l7_rule_id': l7_rule_id, 'l7_policy_id': l7_policy_id}
+ update_l7_rule(request, **kwargs)
+
+ @rest_utils.ajax()
+ def delete(self, request, l7_rule_id, l7_policy_id):
+ """Delete a specific l7 rule."""
+ conn = _get_sdk_connection(request)
+ conn.load_balancer.delete_l7_rule(l7_rule_id, l7_policy_id)
+
+
@urls.register
class Pools(generic.View):
"""API for load balancer pools.
diff --git a/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js b/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js
index 6ebd55c4..ae2d410c 100644
--- a/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js
+++ b/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js
@@ -46,6 +46,16 @@
createListener: createListener,
editListener: editListener,
deleteListener: deleteListener,
+ getL7Policies: getL7Policies,
+ getL7Policy: getL7Policy,
+ createL7Policy: createL7Policy,
+ editL7Policy: editL7Policy,
+ deleteL7Policy: deleteL7Policy,
+ getL7Rules: getL7Rules,
+ getL7Rule: getL7Rule,
+ createL7Rule: createL7Rule,
+ editL7Rule: editL7Rule,
+ deleteL7Rule: deleteL7Rule,
getPools: getPools,
getPool: getPool,
createPool: createPool,
@@ -108,8 +118,8 @@
* @description
* Delete a single load balancer by ID
* @param {string} id
- * @param {boolean} quiet
* Specifies the id of the load balancer to delete.
+ * @param {boolean} quiet
*/
function deleteLoadBalancer(id, quiet) {
@@ -231,8 +241,8 @@
* @description
* Delete a single listener by ID
* @param {string} id
- * @param {boolean} quiet
* Specifies the id of the listener to delete.
+ * @param {boolean} quiet
*/
function deleteListener(id, quiet) {
@@ -333,8 +343,8 @@
* @description
* Delete a single pool by ID
* @param {string} id
- * @param {boolean} quiet
* Specifies the id of the pool to delete.
+ * @param {boolean} quiet
*/
function deletePool(id, quiet) {
@@ -344,6 +354,198 @@
});
}
+ // L7 Policies
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Policies
+ * @description
+ * Get the list of l7 policies.
+ * If a listener ID is passed as a parameter, the returning list of
+ * l7 policies will be filtered to include only those l7 policies under the
+ * specified listener.
+ * @param {string} listenerId
+ * Specifies the id of the listener to request l7policies for.
+ *
+ * The listing result is an object with property "items". Each item is
+ * a l7 policy.
+ */
+
+ function getL7Policies(listenerId) {
+ var params = $.extend({},
+ {
+ listenerId: listenerId
+ }
+ );
+ if (!$.isEmptyObject(params)) {
+ params = { params: params };
+ }
+ return apiService.get('/api/lbaas/l7policies/', params)
+ .error(function () {
+ toastService.add('error', gettext('Unable to retrieve l7 policies.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Policy
+ * @description
+ * Get a single L7Policy by ID.
+ * @param {string} id
+ * Specifies the id of the l7 policy to request.
+ * @param {boolean} includeChildResources
+ * If truthy, all child resources below the l7 policy will be included in the response.
+ */
+
+ function getL7Policy(id, includeChildResources) {
+ var params = includeChildResources
+ ? {params: {includeChildResources: includeChildResources}}
+ : {};
+ return apiService.get('/api/lbaas/l7policies/' + id + '/', params)
+ .error(function () {
+ toastService.add('error', gettext('Unable to retrieve l7 policy.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.createL7Policy
+ * @description
+ * Create a new l7 policy
+ * @param {object} spec
+ * Specifies the data used to create the new l7 policy.
+ */
+
+ function createL7Policy(spec) {
+ return apiService.post('/api/lbaas/l7policies/', spec)
+ .error(function () {
+ toastService.add('error', gettext('Unable to create l7 policy.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.editL7Policy
+ * @description
+ * Edit a l7 policy
+ * @param {string} id
+ * Specifies the id of the l7 policy to update.
+ * @param {object} spec
+ * Specifies the data used to update the l7 policy.
+ */
+
+ function editL7Policy(id, spec) {
+ return apiService.put('/api/lbaas/l7policies/' + id + '/', spec)
+ .error(function () {
+ toastService.add('error', gettext('Unable to update l7 policy.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.deleteL7Policy
+ * @description
+ * Delete a single l7 policy by ID
+ * @param {string} id
+ * Specifies the id of the l7 policy to delete.
+ * @param {boolean} quiet
+ */
+
+ function deleteL7Policy(id, quiet) {
+ var promise = apiService.delete('/api/lbaas/l7policies/' + id + '/');
+ return quiet ? promise : promise.error(function () {
+ toastService.add('error', gettext('Unable to delete l7 policy.'));
+ });
+ }
+
+ // L7 Rules
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Rules
+ * @description
+ * Get the list of l7 rules under the specified l7 policy.
+ * @param {string} l7policyId
+ * Specifies the id of the l7 policy to request l7rules for.
+ *
+ * The listing result is an object with property "items".
+ * Each item is a l7 rule.
+ */
+
+ function getL7Rules(l7policyId) {
+ return apiService.get('/api/lbaas/l7policies/' + l7policyId + '/l7rules/')
+ .error(function () {
+ toastService.add('error', gettext('Unable to retrieve l7 rules.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Rule
+ * @description
+ * Get a single L7Rule by ID.
+ * @param {string} l7policyId
+ * Specifies the id of the l7 policy the l7 rule belongs to.
+ * @param {string} l7ruleId
+ * Specifies the id of the l7 rule to request.
+ */
+
+ function getL7Rule(l7policyId, l7ruleId) {
+ return apiService.get('/api/lbaas/l7policies/' + l7policyId + '/l7rules/' + l7ruleId + '/')
+ .error(function () {
+ toastService.add('error', gettext('Unable to retrieve l7 rule.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.createL7Rule
+ * @description
+ * Create a new l7 rule
+ * @param {string} l7policyId
+ * Specifies the id of the l7 policy the l7 rule belongs to.
+ * @param {object} spec
+ * Specifies the data used to create the new l7 rule.
+ */
+
+ function createL7Rule(l7policyId, spec) {
+ return apiService.post('/api/lbaas/l7policies/' + l7policyId + '/l7rules/', spec)
+ .error(function () {
+ toastService.add('error', gettext('Unable to create l7 rule.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.editL7Rule
+ * @description
+ * Edit a l7 rule
+ * @param {string} l7policyId
+ * Specifies the id of the l7 policy the l7 rule belongs to.
+ * @param {string} l7ruleId
+ * Specifies the id of the l7 rule to update.
+ * @param {object} spec
+ * Specifies the data used to update the l7 rule.
+ */
+
+ function editL7Rule(l7policyId, l7ruleId, spec) {
+ return apiService.put('/api/lbaas/l7policies/' + l7policyId +
+ '/l7rules/' + l7ruleId + '/', spec)
+ .error(function () {
+ toastService.add('error', gettext('Unable to update l7 rule.'));
+ });
+ }
+
+ /**
+ * @name horizon.app.core.openstack-service-api.lbaasv2.deleteL7Rule
+ * @description
+ * Delete a single l7 rule by ID
+ * @param {string} l7policyId
+ * Specifies the id of the l7 policy the l7 rule belongs to.
+ * @param {string} l7ruleId
+ * Specifies the id of the l7 rule to delete.
+ * @param {boolean} quiet
+ */
+
+ function deleteL7Rule(l7policyId, l7ruleId, quiet) {
+ var promise = apiService.delete('/api/lbaas/l7policies/' + l7policyId +
+ '/l7rules/' + l7ruleId + '/');
+ return quiet ? promise : promise.error(function () {
+ toastService.add('error', gettext('Unable to delete l7 rule.'));
+ });
+ }
+
// Members
/**
@@ -493,8 +695,8 @@
* @description
* Delete a single health monitor by ID
* @param {string} id
- * @param {boolean} quiet
* Specifies the id of the health monitor to delete.
+ * @param {boolean} quiet
*/
function deleteHealthMonitor(id, quiet) {
diff --git a/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js b/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js
index 118b83fd..4a6e4e86 100644
--- a/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js
+++ b/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js
@@ -90,6 +90,65 @@
error: 'Unable to retrieve listener.',
testInput: [ '1234', false ]
},
+ {
+ func: 'getL7Policies',
+ method: 'get',
+ path: '/api/lbaas/l7policies/',
+ error: 'Unable to retrieve l7 policies.',
+ testInput: [ '1234' ],
+ data: { params: { listenerId: '1234' } }
+ },
+ {
+ func: 'getL7Policies',
+ method: 'get',
+ path: '/api/lbaas/l7policies/',
+ data: {},
+ error: 'Unable to retrieve l7 policies.'
+ },
+ {
+ func: 'getL7Policy',
+ method: 'get',
+ path: '/api/lbaas/l7policies/1234/',
+ data: { params: { includeChildResources: true } },
+ error: 'Unable to retrieve l7 policy.',
+ testInput: [ '1234', true ]
+ },
+ {
+ func: 'getL7Policy',
+ method: 'get',
+ path: '/api/lbaas/l7policies/1234/',
+ data: {},
+ error: 'Unable to retrieve l7 policy.',
+ testInput: [ '1234', false ]
+ },
+ {
+ func: 'deleteL7Policy',
+ method: 'delete',
+ path: '/api/lbaas/l7policies/1234/',
+ error: 'Unable to delete l7 policy.',
+ testInput: [ '1234' ]
+ },
+ {
+ func: 'getL7Rules',
+ method: 'get',
+ path: '/api/lbaas/l7policies/1234/l7rules/',
+ error: 'Unable to retrieve l7 rules.',
+ testInput: [ '1234' ]
+ },
+ {
+ func: 'getL7Rule',
+ method: 'get',
+ path: '/api/lbaas/l7policies/1234/l7rules/5678/',
+ error: 'Unable to retrieve l7 rule.',
+ testInput: [ '1234', '5678' ]
+ },
+ {
+ func: 'deleteL7Rule',
+ method: 'delete',
+ path: '/api/lbaas/l7policies/1234/l7rules/5678/',
+ error: 'Unable to delete l7 rule.',
+ testInput: [ '1234', '5678' ]
+ },
{
func: 'getPools',
method: 'get',
@@ -249,6 +308,38 @@
error: 'Unable to delete listener.',
testInput: [ '1234' ]
},
+ {
+ func: 'createL7Policy',
+ method: 'post',
+ path: '/api/lbaas/l7policies/',
+ error: 'Unable to create l7 policy.',
+ data: { name: 'l7policy-1' },
+ testInput: [ { name: 'l7policy-1' } ]
+ },
+ {
+ func: 'editL7Policy',
+ method: 'put',
+ path: '/api/lbaas/l7policies/1234/',
+ error: 'Unable to update l7 policy.',
+ data: { name: 'l7policy-1' },
+ testInput: [ '1234', { name: 'l7policy-1' } ]
+ },
+ {
+ func: 'createL7Rule',
+ method: 'post',
+ path: '/api/lbaas/l7policies/1234/l7rules/',
+ error: 'Unable to create l7 rule.',
+ data: { name: 'l7rule-1' },
+ testInput: [ '1234', { name: 'l7rule-1' } ]
+ },
+ {
+ func: 'editL7Rule',
+ method: 'put',
+ path: '/api/lbaas/l7policies/1234/l7rules/5678/',
+ error: 'Unable to update l7 rule.',
+ data: { name: 'l7rule-1' },
+ testInput: [ '1234', '5678', { name: 'l7rule-1' } ]
+ },
{
func: 'createPool',
method: 'post',
@@ -301,6 +392,16 @@
expect(service.deleteListener("whatever", true)).toBe("promise");
});
+ it('supresses the error if instructed for deleteL7Policy', function() {
+ spyOn(apiService, 'delete').and.returnValue("promise");
+ expect(service.deleteL7Policy("whatever", true)).toBe("promise");
+ });
+
+ it('supresses the error if instructed for deleteL7Rule', function() {
+ spyOn(apiService, 'delete').and.returnValue("promise");
+ expect(service.deleteL7Rule("whatever", "whatever", true)).toBe("promise");
+ });
+
it('supresses the error if instructed for deletePool', function() {
spyOn(apiService, 'delete').and.returnValue("promise");
expect(service.deletePool("whatever", true)).toBe("promise");
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js
new file mode 100644
index 00000000..b0800cab
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies')
+ .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.create', createService);
+
+ createService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ '$q',
+ 'horizon.dashboard.project.lbaasv2.workflow.modal',
+ 'horizon.app.core.openstack-service-api.policy',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7policies.actions.createService
+ *
+ * @description
+ * Provides the service for creating a l7policy resource.
+ *
+ * @param resourceType The l7policy resource type.
+ * @param actionResultService The horizon action result service.
+ * @param $q The angular service for promises.
+ * @param workflowModal The LBaaS workflow modal service.
+ * @param policy The horizon policy service.
+ * @param gettext The horizon gettext function for translation.
+ *
+ * @returns The l7policy create service.
+ */
+
+ function createService(
+ resourceType, actionResultService,
+ $q, workflowModal, policy, gettext
+ ) {
+ return workflowModal.init({
+ controller: 'CreateL7PolicyWizardController',
+ message: gettext('A new l7 policy is being created.'),
+ handle: handle,
+ allowed: allowed
+ });
+
+ //////////////
+
+ function allowed() {
+ return $q.all([
+ policy.ifAllowed({ rules: [['neutron', 'create_l7policy']] })
+ ]);
+ }
+
+ function handle(response) {
+ return actionResultService.getActionResult()
+ .created(resourceType, response.data.id)
+ .result;
+ }
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js
new file mode 100644
index 00000000..2d7ccd64
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 Create l7policy Action Service', function() {
+ var policy, service;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$modal', {
+ open: function() {
+ return {
+ result: {
+ then: function(func) {
+ func({ data: { id: 'listener1' } });
+ }
+ }
+ };
+ }
+ });
+ $provide.value('$routeParams', {});
+ }));
+
+ beforeEach(inject(function ($injector) {
+ policy = $injector.get('horizon.app.core.openstack-service-api.policy');
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.create');
+ }));
+
+ it('should not allow creating a l7policy if listenerId is not present', function() {
+ spyOn(policy, 'ifAllowed').and.returnValue(true);
+ var allowed = service.allowed();
+ permissionShouldFail(allowed);
+ });
+
+ it('should handle the action result properly', function() {
+ var result = service.handle({data: {id: 1}});
+ expect(result.created[0].id).toBe(1);
+ });
+
+ function permissionShouldFail(permissions) {
+ permissions.then(
+ function() {
+ expect(false).toBe(true);
+ },
+ function() {
+ expect(true).toBe(true);
+ });
+ }
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js
new file mode 100644
index 00000000..05d2160f
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies')
+ .controller('CreateL7PolicyWizardController', CreateL7PolicyWizardController);
+
+ CreateL7PolicyWizardController.$inject = [
+ '$scope',
+ '$routeParams',
+ 'horizon.dashboard.project.lbaasv2.workflow.model',
+ 'horizon.dashboard.project.lbaasv2.workflow.workflow',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ function CreateL7PolicyWizardController($scope, $routeParams, model, workflowService, gettext) {
+ var loadbalancerId = $routeParams.loadbalancerId;
+ var listenerId = $routeParams.listenerId;
+ var scope = $scope;
+ scope.model = model;
+ scope.submit = scope.model.submit;
+ scope.workflow = workflowService(
+ gettext('Create L7 Policy'),
+ 'fa fa-cloud-download',
+ ['l7policy']
+ );
+ scope.model.initialize('l7policy', false, loadbalancerId, listenerId);
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js
new file mode 100644
index 00000000..6dede502
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ describe('LBaaS v2 Create L7Policy Wizard Controller', function() {
+ var ctrl;
+ var model = {
+ submit: function() {
+ return 'created';
+ },
+ initialize: angular.noop
+ };
+ var workflow = function() {
+ return 'foo';
+ };
+ var scope = {
+ launchContext: {id: '1234'}
+ };
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module(function ($provide) {
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow);
+ }));
+ beforeEach(inject(function ($controller) {
+ spyOn(model, 'initialize');
+ ctrl = $controller('CreateL7PolicyWizardController', { $scope: scope });
+ }));
+
+ it('defines the controller', function() {
+ expect(ctrl).toBeDefined();
+ });
+
+ it('calls initialize on the given model', function() {
+ expect(model.initialize).toHaveBeenCalled();
+ });
+
+ it('sets scope.workflow to the given workflow', function() {
+ expect(scope.workflow).toBe('foo');
+ });
+
+ it('defines scope.submit', function() {
+ expect(scope.submit).toBeDefined();
+ expect(scope.submit()).toBe('created');
+ });
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js
new file mode 100644
index 00000000..d1260653
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies')
+ .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.delete', deleteService);
+
+ deleteService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ '$location',
+ 'horizon.framework.widgets.modal.deleteModalService',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ 'horizon.framework.util.i18n.gettext',
+ 'horizon.app.core.openstack-service-api.policy'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7policies.actions.deleteService
+ *
+ * @description
+ * Brings up the delete l7policy confirmation modal dialog.
+ * On submit, deletes selected l7policy.
+ * On cancel, does nothing.
+ *
+ * @param resourceType The l7policy resource type.
+ * @param actionResultService The horizon action result service.
+ * @param $location The angular $location service.
+ * @param deleteModal The horizon delete modal service.
+ * @param api The LBaaS v2 API service.
+ * @param gettext The horizon gettext function for translation.
+ * @param policy The horizon policy service.
+ *
+ * @returns The l7policy delete service.
+ */
+
+ function deleteService(
+ resourceType, actionResultService, $location,
+ deleteModal, api, gettext, policy
+ ) {
+ var loadbalancerId, listenerId;
+
+ var service = {
+ perform: perform,
+ allowed: allowed,
+ deleteResult: deleteResult // exposed just for testing
+ };
+
+ return service;
+
+ //////////////
+
+ function allowed(/*item*/) {
+ // This rule is made up and should therefore always pass. I assume at some point there
+ // will be a valid rule similar to this that we will want to use.
+ return policy.ifAllowed({ rules: [['neutron', 'delete_l7policy']] });
+ }
+
+ function perform(items, scope) {
+ var context = { };
+ var l7policies = angular.isArray(items) ? items : [items];
+ context.labels = labelize(l7policies.length);
+ context.deleteEntity = deleteItem;
+ l7policies.map(function(item) {
+ loadbalancerId = item.loadbalancerId;
+ listenerId = item.listenerId;
+ });
+ return deleteModal.open(scope, l7policies, context).then(deleteResult);
+ }
+
+ function labelize(count) {
+ return {
+ title: ngettext(
+ 'Confirm Delete L7 Policy',
+ 'Confirm Delete L7 Policies', count),
+
+ message: ngettext(
+ 'You have selected "%s". Deleted L7 Policy is not recoverable.',
+ 'You have selected "%s". Deleted L7 Policies are not recoverable.', count),
+
+ submit: ngettext(
+ 'Delete L7 Policy',
+ 'Delete L7 Policies', count),
+
+ success: ngettext(
+ 'Deleted L7 Policy: %s.',
+ 'Deleted L7 Policies: %s.', count),
+
+ error: ngettext(
+ 'Unable to delete L7 Policy: %s.',
+ 'Unable to delete L7 Policies: %s.', count)
+ };
+ }
+
+ function deleteResult(deleteModalResult) {
+ // To make the result of this action generically useful, reformat the return
+ // from the deleteModal into a standard form
+ var actionResult = actionResultService.getActionResult();
+ deleteModalResult.pass.forEach(function markDeleted(item) {
+ actionResult.deleted(resourceType, item.context.id);
+ });
+ deleteModalResult.fail.forEach(function markFailed(item) {
+ actionResult.failed(resourceType, item.context.id);
+ });
+
+ if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) {
+ var path = 'project/load_balancer/' + loadbalancerId +
+ '/listeners/' + listenerId;
+ $location.path(path);
+ }
+ return actionResult.result;
+ }
+
+ function deleteItem(id) {
+ return api.deleteL7Policy(id, true);
+ }
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js
new file mode 100644
index 00000000..ed59d3fe
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Policy Delete Service', function() {
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module('horizon.framework'));
+
+ var deleteModalService, service, lbaasv2API, policyAPI, $location;
+
+ beforeEach(inject(function($injector) {
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.delete');
+ lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
+ deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService');
+ policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy');
+ $location = $injector.get('$location');
+ }));
+
+ describe('perform method', function() {
+ beforeEach(function () {
+ // just need for this to return something that looks like a promise but does nothing
+ spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop});
+ });
+
+ it('should open the modal with correct label', function () {
+ service.perform({name: 'spam'});
+ var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
+ expect(deleteModalService.open).toHaveBeenCalled();
+ angular.forEach(labels, function eachLabel(label) {
+ expect(label.toLowerCase()).toContain('l7 policy');
+ });
+ });
+
+ it('should open the delete modal with correct entities', function () {
+ service.perform([{name: 'one'}, {name: 'two'}]);
+ var entities = deleteModalService.open.calls.argsFor(0)[1];
+ expect(deleteModalService.open).toHaveBeenCalled();
+ expect(entities.length).toEqual(2);
+ });
+
+ it('should pass in a function that deletes a l7 policy', function () {
+ spyOn(lbaasv2API, 'deleteL7Policy').and.callFake(angular.noop);
+ service.perform({id: 1, name: 'one'});
+ var contextArg = deleteModalService.open.calls.argsFor(0)[2];
+ var deleteFunction = contextArg.deleteEntity;
+ deleteFunction(1);
+ expect(lbaasv2API.deleteL7Policy).toHaveBeenCalledWith(1, true);
+ });
+ });
+
+ it('should handle the action result properly', function() {
+ spyOn($location, 'path');
+ spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop});
+ spyOn(lbaasv2API, 'deleteL7Policy').and.callFake(angular.noop);
+ service.perform({loadbalancerId: 1, listenerId: 2, id: 1, name: 'one'});
+ var result = service.deleteResult({
+ fail: [],
+ pass: [{
+ context: {
+ id: 1
+ }
+ }]
+ });
+ var path = 'project/load_balancer/1/listeners/2';
+ expect($location.path).toHaveBeenCalledWith(path);
+ expect(result.deleted[0].id).toBe(1);
+ result = service.deleteResult({
+ pass: [],
+ fail: [{
+ context: {
+ id: 1
+ }
+ }]
+ });
+ expect(result.failed[0].id).toBe(1);
+ });
+
+ describe('allow method', function() {
+ it('should use default policy if batch action', function () {
+ spyOn(policyAPI, 'ifAllowed');
+ service.allowed();
+ expect(policyAPI.ifAllowed).toHaveBeenCalled();
+ });
+ }); // end of allowed
+
+ }); // end of delete
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js
new file mode 100644
index 00000000..963f4cf3
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies')
+ .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.edit', editService);
+
+ editService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ 'horizon.dashboard.project.lbaasv2.workflow.modal',
+ 'horizon.app.core.openstack-service-api.policy',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7policies.actions.editService
+ *
+ * @description
+ * Provides the service for editing a l7policy resource.
+ *
+ * @param resourceType The l7policy resource type.
+ * @param actionResultService The horizon action result service.
+ * @param workflowModal The LBaaS workflow modal service.
+ * @param policy The horizon policy service.
+ * @param gettext The horizon gettext function for translation.
+ *
+ * @returns The l7policy edit service.
+ */
+
+ function editService(
+ resourceType, actionResultService, workflowModal, policy, gettext
+ ) {
+
+ return workflowModal.init({
+ controller: 'EditL7PolicyWizardController',
+ message: gettext('The l7policy has been updated.'),
+ handle: handle,
+ allowed: allowed
+ });
+
+ function allowed(/*item*/) {
+ return policy.ifAllowed({ rules: [['neutron', 'update_l7policy']] });
+ }
+
+ function handle(response) {
+ return actionResultService.getActionResult()
+ .updated(resourceType, response.config.data.l7policy.id)
+ .result;
+ }
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js
new file mode 100644
index 00000000..89d7fe90
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 Edit L7Policy Action Service', function() {
+ var policy, service;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$modal', {
+ open: function() {
+ return {
+ result: {
+ then: function(func) {
+ func({ data: { id: 'l7policy1' } });
+ }
+ }
+ };
+ }
+ });
+ }));
+
+ beforeEach(inject(function ($injector) {
+ policy = $injector.get('horizon.app.core.openstack-service-api.policy');
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.edit');
+ }));
+
+ it('should check policy to allow editing a l7policy', function() {
+ spyOn(policy, 'ifAllowed').and.returnValue(true);
+ expect(service.allowed()).toBe(true);
+ expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7policy']]});
+ });
+
+ it('should handle the action result properly', function() {
+ var result = service.handle({config: {data: {l7policy: {id: 1}}}});
+ expect(result.updated[0].id).toBe(1);
+ });
+
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js
new file mode 100644
index 00000000..b1a4f1c7
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.loadbalancers')
+ .controller('EditL7PolicyWizardController', EditL7PolicyWizardController);
+
+ EditL7PolicyWizardController.$inject = [
+ '$scope',
+ '$routeParams',
+ '$q',
+ 'horizon.dashboard.project.lbaasv2.workflow.model',
+ 'horizon.dashboard.project.lbaasv2.workflow.workflow',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name EditL7PolicyWizardController
+ *
+ * @description
+ * Controller for the LBaaS v2 edit l7policy wizard.
+ *
+ * @param $scope The angular scope object.
+ * @param $routeParams The angular $routeParams service.
+ * @param $q The angular service for promises.
+ * @param model The LBaaS V2 workflow model service.
+ * @param workflowService The LBaaS V2 workflow service.
+ * @param gettext The horizon gettext function for translation.
+ * @returns undefined
+ */
+
+ function EditL7PolicyWizardController($scope, $routeParams, $q, model, workflowService, gettext) {
+ var scope = $scope;
+ var loadbalancerId = $routeParams.loadbalancerId;
+ var listenerId = $routeParams.listenerId;
+ scope.model = model;
+ scope.submit = scope.model.submit;
+ scope.workflow = workflowService(
+ gettext('Update L7 Policy'),
+ 'fa fa-pencil', ['l7policy']);
+ scope.model.initialize('l7policy', scope.launchContext.id, loadbalancerId, listenerId);
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js
new file mode 100644
index 00000000..a985d954
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ describe('LBaaS v2 Edit L7Policy Wizard Controller', function() {
+ var ctrl, workflowSpy, $q, scope;
+ var model = {
+ submit: function() {
+ return 'updated';
+ },
+ initialize: function() {
+ var defer = $q.defer();
+ defer.resolve();
+ return defer.promise;
+ }
+ };
+ var workflow = {
+ steps: [{id: 'l7policy'}],
+ append: angular.noop
+ };
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module(function ($provide) {
+ workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy);
+ }));
+ beforeEach(inject(function ($controller, $injector) {
+ $q = $injector.get('$q');
+ scope = $injector.get('$rootScope').$new();
+ scope.launchContext = { id: 'l7policyId' };
+ spyOn(model, 'initialize').and.callThrough();
+ ctrl = $controller('EditL7PolicyWizardController', {
+ $scope: scope,
+ $routeParams: {loadbalancerId: 'loadbalancerId', listenerId: 'listenerId'}});
+ }));
+
+ it('defines the controller', function() {
+ expect(ctrl).toBeDefined();
+ });
+
+ it('calls initialize on the given model', function() {
+ expect(model.initialize).toHaveBeenCalledWith(
+ 'l7policy', 'l7policyId', 'loadbalancerId', 'listenerId');
+ });
+
+ it('sets scope.workflow to the given workflow', function() {
+ expect(scope.workflow).toBe(workflow);
+ });
+
+ it('initializes workflow with correct properties', function() {
+ expect(workflowSpy).toHaveBeenCalledWith('Update L7 Policy',
+ 'fa fa-pencil', ['l7policy']);
+ });
+
+ it('defines scope.submit', function() {
+ expect(scope.submit).toBe(model.submit);
+ expect(scope.submit()).toBe('updated');
+ });
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js
new file mode 100644
index 00000000..b120648f
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies')
+ .controller('L7PolicyDetailController', L7PolicyDetailController);
+
+ L7PolicyDetailController.$inject = [
+ 'loadbalancer',
+ 'listener',
+ 'l7policy',
+ 'horizon.dashboard.project.lbaasv2.loadbalancers.service',
+ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType',
+ 'horizon.framework.conf.resource-type-registry.service',
+ 'horizon.framework.widgets.modal-wait-spinner.service',
+ '$q'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name L7PolicyDetailController
+ *
+ * @description
+ * Controller for the LBaaS v2 l7policy detail page.
+ *
+ * @param loadbalancer The loadbalancer object.
+ * @param listener The listener object.
+ * @param l7policy The l7policy object.
+ * @param loadBalancersService The LBaaS v2 load balancers service.
+ * @param resourceType The load balancer resource type.
+ * @param typeRegistry The horizon type registry service.
+ * @param spinnerService The horizon modal wait spinner service.
+ * @param $q The angular service for promises.
+ *
+ * @returns undefined
+ */
+
+ function L7PolicyDetailController(
+ loadbalancer, listener, l7policy, loadBalancersService,
+ resourceType, typeRegistry, spinnerService, $q
+ ) {
+ var ctrl = this;
+
+ ctrl.operatingStatus = loadBalancersService.operatingStatus;
+ ctrl.provisioningStatus = loadBalancersService.provisioningStatus;
+ ctrl.l7policyAction = loadBalancersService.l7policyAction;
+ ctrl.loadbalancer = loadbalancer;
+ ctrl.listener = listener;
+ ctrl.l7policy = l7policy;
+ ctrl.listFunctionExtraParams = {
+ loadbalancerId: ctrl.loadbalancer.id,
+ listenerId: ctrl.listener.id,
+ l7policyId: ctrl.l7policy.id
+ };
+ ctrl.resourceType = typeRegistry.getResourceType(resourceType);
+ ctrl.context = {};
+ ctrl.context.identifier = l7policy.id;
+
+ ctrl.resultHandler = actionResultHandler;
+
+ function actionResultHandler(returnValue) {
+ return $q.when(returnValue, actionSuccessHandler);
+ }
+
+ function loadData(response) {
+ spinnerService.hideModalSpinner();
+ ctrl.showDetails = true;
+ ctrl.resourceType.initActions();
+ ctrl.l7policy = response.data;
+ ctrl.l7policy.loadbalancerId = ctrl.loadbalancer.id;
+ ctrl.l7policy.listenerId = ctrl.listener.id;
+ }
+
+ function actionSuccessHandler(result) {
+ // The action has completed (for whatever "complete" means to that
+ // action. Notice the view doesn't really need to know the semantics of the
+ // particular action because the actions return data in a standard form.
+ // That return includes the id and type of each created, updated, deleted
+ // and failed item.
+ // Currently just refreshes the display each time.
+ if (result) {
+ if (result.failed.length === 0 && result.deleted.length > 0) {
+ // handle a race condition where the resource is already deleted
+ return;
+ }
+ spinnerService.showModalSpinner(gettext('Please Wait'));
+ ctrl.showDetails = false;
+ ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier);
+ ctrl.context.loadPromise.then(loadData);
+ }
+ }
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js
new file mode 100644
index 00000000..92caada1
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Policy Detail Controller', function() {
+ var deferred, service, ctrl, scope, $timeout, $q, actionResultService;
+
+ ///////////////////////
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$uibModal', {});
+ }));
+
+ beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) {
+ $q = _$q_;
+ deferred = $q.defer();
+ service = {
+ getResourceType: function() {
+ return {
+ load: function() { return deferred.promise; },
+ parsePath: function() { return 'my-context'; },
+ itemName: function() { return 'A name'; },
+ initActions: angular.noop
+ };
+ },
+ getDefaultDetailsTemplateUrl: angular.noop
+ };
+ actionResultService = {
+ getIdsOfType: function() { return []; }
+ };
+ $timeout = _$timeout_;
+ scope = $rootScope.$new();
+ ctrl = $controller('L7PolicyDetailController', {
+ $scope: scope,
+ loadbalancer: { id: '123' },
+ listener: { id: '123' },
+ l7policy: { id: '123' },
+ 'horizon.framework.conf.resource-type-registry.service': service,
+ 'horizon.framework.util.actions.action-result.service': actionResultService,
+ 'horizon.framework.widgets.modal-wait-spinner.service': {
+ showModalSpinner: angular.noop,
+ hideModalSpinner: angular.noop
+ }
+ });
+ }));
+
+ it('should create a controller', function() {
+ expect(ctrl).toBeDefined();
+ expect(ctrl.loadbalancer).toBeDefined();
+ expect(ctrl.listener).toBeDefined();
+ expect(ctrl.l7policy).toBeDefined();
+ });
+
+ describe('resultHandler', function() {
+
+ it('handles empty results', function() {
+ var result = $q.defer();
+ result.resolve({failed: [], deleted: []});
+ ctrl.resultHandler(result.promise);
+ $timeout.flush();
+ expect(ctrl.showDetails).not.toBe(true);
+ });
+
+ it('handles falsy results', function() {
+ var result = $q.defer();
+ result.resolve(false);
+ ctrl.resultHandler(result.promise);
+ $timeout.flush();
+ expect(ctrl.showDetails).not.toBe(true);
+ });
+
+ it('handles matched results', function() {
+ spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]);
+ var result = $q.defer();
+ result.resolve({some: 'thing', failed: [], deleted: []});
+ ctrl.resultHandler(result.promise);
+ deferred.resolve({data: {some: 'data'}});
+ $timeout.flush();
+ expect(ctrl.showDetails).toBe(true);
+ });
+
+ it('handles delete race condition', function() {
+ spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]);
+ var result = $q.defer();
+ result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]});
+ ctrl.resultHandler(result.promise);
+ deferred.resolve({data: {some: 'data'}});
+ $timeout.flush();
+ expect(ctrl.showDetails).toBe(undefined);
+ });
+
+ });
+
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html
new file mode 100644
index 00000000..b7ce90cf
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html
new file mode 100644
index 00000000..86b3251a
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html
@@ -0,0 +1,9 @@
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js
new file mode 100644
index 00000000..9a28f8ff
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ /**
+ * @ngdoc overview
+ * @ngname horizon.dashboard.project.lbaasv2.l7policies
+ *
+ * @description
+ * Provides the services and widgets required to support and display the project l7 policies
+ * for the load balancers v2 panel.
+ */
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7policies', [])
+ .constant('horizon.dashboard.project.lbaasv2.l7policies.resourceType',
+ 'OS::Octavia::L7Policy')
+ .run(run);
+
+ run.$inject = [
+ 'horizon.framework.conf.resource-type-registry.service',
+ 'horizon.dashboard.project.lbaasv2.basePath',
+ 'horizon.dashboard.project.lbaasv2.loadbalancers.service',
+ 'horizon.dashboard.project.lbaasv2.l7policies.actions.create',
+ 'horizon.dashboard.project.lbaasv2.l7policies.actions.edit',
+ 'horizon.dashboard.project.lbaasv2.l7policies.actions.delete',
+ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType'
+ ];
+
+ function run(
+ registry,
+ basePath,
+ loadBalancerService,
+ createService,
+ editService,
+ deleteService,
+ resourceType
+ ) {
+ var l7policyResourceType = registry.getResourceType(resourceType);
+
+ l7policyResourceType
+ .setNames(gettext('L7 Policy'), gettext('L7 Policies'))
+ .setSummaryTemplateUrl(basePath + 'l7policies/details/drawer.html')
+ .setProperties(l7policyProperties(loadBalancerService))
+ .setListFunction(loadBalancerService.getL7PoliciesPromise)
+ .setLoadFunction(loadBalancerService.getL7PolicyPromise)
+ .tableColumns
+ .append({
+ id: 'name',
+ priority: 1,
+ urlFunction: loadBalancerService.getL7PolicyDetailsPath
+ })
+ .append({
+ id: 'position',
+ sortDefault: true,
+ priority: 1
+ })
+ .append({
+ id: 'action',
+ priority: 1
+ })
+ .append({
+ id: 'operating_status',
+ priority: 1
+ })
+ .append({
+ id: 'provisioning_status',
+ priority: 1
+ })
+ .append({
+ id: 'admin_state_up',
+ priority: 1
+ });
+
+ l7policyResourceType.itemActions
+ .append({
+ id: 'l7policyEdit',
+ service: editService,
+ template: {
+ text: gettext('Edit L7 Policy')
+ }
+ })
+ .append({
+ id: 'l7policyDelete',
+ service: deleteService,
+ template: {
+ text: gettext('Delete L7 Policy'),
+ type: 'delete'
+ }
+ });
+
+ l7policyResourceType.globalActions
+ .append({
+ id: 'l7policyCreate',
+ service: createService,
+ template: {
+ type: 'create',
+ text: gettext('Create L7 Policy')
+ }
+ });
+
+ l7policyResourceType.batchActions
+ .append({
+ id: 'l7policyBatchDelete',
+ service: deleteService,
+ template: {
+ text: gettext('Delete L7 Policies'),
+ type: 'delete-selected'
+ }
+ });
+ }
+
+ function l7policyProperties(loadBalancerService) {
+ return {
+ id: gettext('ID'),
+ name: {
+ label: gettext('Name'),
+ filters: ['noName']
+ },
+ description: {
+ label: gettext('Description'),
+ filters: ['noValue']
+ },
+ provisioning_status: {
+ label: gettext('Provisioning Status'),
+ values: loadBalancerService.provisioningStatus
+ },
+ operating_status: {
+ label: gettext('Operating Status'),
+ values: loadBalancerService.operatingStatus
+ },
+ admin_state_up: {
+ label: gettext('Admin State Up'),
+ filters: ['yesno']
+ },
+ action: {
+ label: gettext('Action'),
+ values: loadBalancerService.l7policyAction
+ },
+ redirect_url: {
+ label: gettext('Redirect URL'),
+ filters: ['noName']
+ },
+ redirect_pool_id: {
+ label: gettext('Redirect Pool ID'),
+ filters: ['noName']
+ },
+ project_id: gettext('Project ID'),
+ created_at: {
+ label: gettext('Created At'),
+ filters: ['noValue']
+ },
+ updated_at: {
+ label: gettext('Updated At'),
+ filters: ['noValue']
+ },
+ position: gettext('Position'),
+ listener_id: gettext('Listener ID'),
+ rules: gettext('Rules')
+ };
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js
new file mode 100644
index 00000000..9a33b1ff
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Policies Module', function() {
+ it('should exist', function() {
+ expect(angular.module('horizon.dashboard.project.lbaasv2.l7policies')).toBeDefined();
+ });
+ });
+
+ describe('LBaaS v2 L7Policies Registry', function () {
+ var registry, resourceType;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(inject(function($injector) {
+ resourceType = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.resourceType');
+ registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
+ }));
+
+ it('should define resourceType', function () {
+ expect(resourceType).toBeDefined();
+ });
+
+ it('should register item actions', function () {
+ var actions = registry.getResourceType(resourceType).itemActions;
+ expect(actionHasId(actions, 'l7policyEdit')).toBe(true);
+ expect(actionHasId(actions, 'l7policyDelete')).toBe(true);
+ });
+
+ it('should register global actions', function () {
+ var actions = registry.getResourceType(resourceType).globalActions;
+ expect(actionHasId(actions, 'l7policyCreate')).toBe(true);
+ });
+
+ it('should register batch actions', function () {
+ var actions = registry.getResourceType(resourceType).batchActions;
+ expect(actionHasId(actions, 'l7policyBatchDelete')).toBe(true);
+ });
+
+ function actionHasId(list, value) {
+ return list.filter(matchesId).length === 1;
+
+ function matchesId(action) {
+ if (action.id === value) {
+ return true;
+ }
+ }
+ }
+
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js
new file mode 100644
index 00000000..aa452427
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules')
+ .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.create', createService);
+
+ createService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ '$q',
+ 'horizon.dashboard.project.lbaasv2.workflow.modal',
+ 'horizon.app.core.openstack-service-api.policy',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7rules.actions.createService
+ *
+ * @description
+ * Provides the service for creating a l7rule resource.
+ *
+ * @param resourceType The l7rule resource type.
+ * @param actionResultService The horizon action result service.
+ * @param $q The angular service for promises.
+ * @param workflowModal The LBaaS workflow modal service.
+ * @param policy The horizon policy service.
+ * @param gettext The horizon gettext function for translation.
+ *
+ * @returns The l7rule create service.
+ */
+
+ function createService(
+ resourceType, actionResultService,
+ $q, workflowModal, policy, gettext
+ ) {
+ return workflowModal.init({
+ controller: 'CreateL7RuleWizardController',
+ message: gettext('A new l7 policy is being created.'),
+ handle: handle,
+ allowed: allowed
+ });
+
+ //////////////
+
+ function allowed() {
+ return $q.all([
+ policy.ifAllowed({ rules: [['neutron', 'create_l7rule']] })
+ ]);
+ }
+
+ function handle(response) {
+ return actionResultService.getActionResult()
+ .created(resourceType, response.data.id)
+ .result;
+ }
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js
new file mode 100644
index 00000000..8416d1a5
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 Create l7rule Action Service', function() {
+ var policy, service;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$modal', {
+ open: function() {
+ return {
+ result: {
+ then: function(func) {
+ func({ data: { id: 'listener1' } });
+ }
+ }
+ };
+ }
+ });
+ $provide.value('$routeParams', {});
+ }));
+
+ beforeEach(inject(function ($injector) {
+ policy = $injector.get('horizon.app.core.openstack-service-api.policy');
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.create');
+ }));
+
+ it('should not allow creating a l7rule if listenerId is not present', function() {
+ spyOn(policy, 'ifAllowed').and.returnValue(true);
+ var allowed = service.allowed();
+ permissionShouldFail(allowed);
+ });
+
+ it('should handle the action result properly', function() {
+ var result = service.handle({data: {id: 1}});
+ expect(result.created[0].id).toBe(1);
+ });
+
+ function permissionShouldFail(permissions) {
+ permissions.then(
+ function() {
+ expect(false).toBe(true);
+ },
+ function() {
+ expect(true).toBe(true);
+ });
+ }
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js
new file mode 100644
index 00000000..ca7ee7e9
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules')
+ .controller('CreateL7RuleWizardController', CreateL7RuleWizardController);
+
+ CreateL7RuleWizardController.$inject = [
+ '$scope',
+ '$routeParams',
+ 'horizon.dashboard.project.lbaasv2.workflow.model',
+ 'horizon.dashboard.project.lbaasv2.workflow.workflow',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ function CreateL7RuleWizardController($scope, $routeParams, model, workflowService, gettext) {
+ var loadbalancerId = $routeParams.loadbalancerId;
+ var l7policyId = $routeParams.l7policyId;
+ var scope = $scope;
+ scope.model = model;
+ scope.submit = scope.model.submit;
+ scope.workflow = workflowService(
+ gettext('Create L7 Rule'),
+ 'fa fa-cloud-download',
+ ['l7rule']
+ );
+ scope.model.initialize('l7rule', false, loadbalancerId, l7policyId);
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js
new file mode 100644
index 00000000..700a1c50
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ describe('LBaaS v2 Create L7Rule Wizard Controller', function() {
+ var ctrl;
+ var model = {
+ submit: function() {
+ return 'created';
+ },
+ initialize: angular.noop
+ };
+ var workflow = function() {
+ return 'foo';
+ };
+ var scope = {
+ launchContext: {id: '1234'}
+ };
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module(function ($provide) {
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow);
+ }));
+ beforeEach(inject(function ($controller) {
+ spyOn(model, 'initialize');
+ ctrl = $controller('CreateL7RuleWizardController', { $scope: scope });
+ }));
+
+ it('defines the controller', function() {
+ expect(ctrl).toBeDefined();
+ });
+
+ it('calls initialize on the given model', function() {
+ expect(model.initialize).toHaveBeenCalled();
+ });
+
+ it('sets scope.workflow to the given workflow', function() {
+ expect(scope.workflow).toBe('foo');
+ });
+
+ it('defines scope.submit', function() {
+ expect(scope.submit).toBeDefined();
+ expect(scope.submit()).toBe('created');
+ });
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js
new file mode 100644
index 00000000..54db1b10
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules')
+ .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.delete', deleteService);
+
+ deleteService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ '$location',
+ 'horizon.framework.widgets.modal.deleteModalService',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ 'horizon.framework.util.i18n.gettext',
+ 'horizon.app.core.openstack-service-api.policy'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7rules.actions.deleteService
+ *
+ * @description
+ * Brings up the delete l7rule confirmation modal dialog.
+ * On submit, deletes selected l7rule.
+ * On cancel, does nothing.
+ *
+ * @param resourceType The l7rule resource type.
+ * @param actionResultService The horizon action result service.
+ * @param $location The angular $location service.
+ * @param deleteModal The horizon delete modal service.
+ * @param api The LBaaS v2 API service.
+ * @param gettext The horizon gettext function for translation.
+ * @param policy The horizon policy service.
+ *
+ * @returns The l7rule delete service.
+ */
+
+ function deleteService(
+ resourceType, actionResultService, $location,
+ deleteModal, api, gettext, policy
+ ) {
+ var loadbalancerId, listenerId, l7policyId;
+
+ var service = {
+ perform: perform,
+ allowed: allowed,
+ deleteResult: deleteResult // exposed just for testing
+ };
+
+ return service;
+
+ //////////////
+
+ function allowed(/*item*/) {
+ // This rule is made up and should therefore always pass. I assume at some point there
+ // will be a valid rule similar to this that we will want to use.
+ return policy.ifAllowed({ rules: [['neutron', 'delete_l7rule']] });
+ }
+
+ function perform(items, scope) {
+ var context = { };
+ var l7rules = angular.isArray(items) ? items : [items];
+ context.labels = labelize(l7rules.length);
+ context.deleteEntity = deleteItem;
+ l7rules.map(function(item) {
+ loadbalancerId = item.loadbalancerId;
+ listenerId = item.listenerId;
+ l7policyId = item.l7policyId;
+ });
+ return deleteModal.open(scope, l7rules, context).then(deleteResult);
+ }
+
+ function labelize(count) {
+ return {
+ title: ngettext(
+ 'Confirm Delete L7 Rule',
+ 'Confirm Delete L7 Rules', count),
+
+ message: ngettext(
+ 'You have selected "%s". Deleted L7 Rule is not recoverable.',
+ 'You have selected "%s". Deleted L7 Rules are not recoverable.', count),
+
+ submit: ngettext(
+ 'Delete L7 Rule',
+ 'Delete L7 Rules', count),
+
+ success: ngettext(
+ 'Deleted L7 Rule: %s.',
+ 'Deleted L7 Rules: %s.', count),
+
+ error: ngettext(
+ 'Unable to delete L7 Rule: %s.',
+ 'Unable to delete L7 Rules: %s.', count)
+ };
+ }
+
+ function deleteResult(deleteModalResult) {
+ // To make the result of this action generically useful, reformat the return
+ // from the deleteModal into a standard form
+ var actionResult = actionResultService.getActionResult();
+ deleteModalResult.pass.forEach(function markDeleted(item) {
+ actionResult.deleted(resourceType, item.context.id);
+ });
+ deleteModalResult.fail.forEach(function markFailed(item) {
+ actionResult.failed(resourceType, item.context.id);
+ });
+
+ if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) {
+ var path = 'project/load_balancer/' + loadbalancerId +
+ '/listeners/' + listenerId +
+ '/l7policies/' + l7policyId;
+ $location.path(path);
+ }
+ return actionResult.result;
+ }
+
+ function deleteItem(id) {
+ return api.deleteL7Rule(l7policyId, id, true);
+ }
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js
new file mode 100644
index 00000000..5aae2df8
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Rule Delete Service', function() {
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module('horizon.framework'));
+
+ var deleteModalService, service, lbaasv2API, policyAPI, $location;
+
+ beforeEach(inject(function($injector) {
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.delete');
+ lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
+ deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService');
+ policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy');
+ $location = $injector.get('$location');
+ }));
+
+ describe('perform method', function() {
+ beforeEach(function () {
+ // just need for this to return something that looks like a promise but does nothing
+ spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop});
+ });
+
+ it('should open the modal with correct label', function () {
+ service.perform({name: 'spam'});
+ var labels = deleteModalService.open.calls.argsFor(0)[2].labels;
+ expect(deleteModalService.open).toHaveBeenCalled();
+ angular.forEach(labels, function eachLabel(label) {
+ expect(label.toLowerCase()).toContain('l7 rule');
+ });
+ });
+
+ it('should open the delete modal with correct entities', function () {
+ service.perform([{name: 'one'}, {name: 'two'}]);
+ var entities = deleteModalService.open.calls.argsFor(0)[1];
+ expect(deleteModalService.open).toHaveBeenCalled();
+ expect(entities.length).toEqual(2);
+ });
+
+ it('should pass in a function that deletes a l7 rule', function () {
+ spyOn(lbaasv2API, 'deleteL7Rule').and.callFake(angular.noop);
+ service.perform({l7policyId: 2, id: 1, name: 'one'});
+ var contextArg = deleteModalService.open.calls.argsFor(0)[2];
+ var deleteFunction = contextArg.deleteEntity;
+ deleteFunction(1);
+ expect(lbaasv2API.deleteL7Rule).toHaveBeenCalledWith(2, 1, true);
+ });
+ });
+
+ it('should handle the action result properly', function() {
+ spyOn($location, 'path');
+ spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop});
+ spyOn(lbaasv2API, 'deleteL7Rule').and.callFake(angular.noop);
+ service.perform({loadbalancerId: 1, listenerId: 2, l7policyId: 3, id: 1, name: 'one'});
+ var result = service.deleteResult({
+ fail: [],
+ pass: [{
+ context: {
+ id: 1
+ }
+ }]
+ });
+ var path = 'project/load_balancer/1/listeners/2/l7policies/3';
+ expect($location.path).toHaveBeenCalledWith(path);
+ expect(result.deleted[0].id).toBe(1);
+ result = service.deleteResult({
+ pass: [],
+ fail: [{
+ context: {
+ id: 1
+ }
+ }]
+ });
+ expect(result.failed[0].id).toBe(1);
+ });
+
+ describe('allow method', function() {
+ it('should use default policy if batch action', function () {
+ spyOn(policyAPI, 'ifAllowed');
+ service.allowed();
+ expect(policyAPI.ifAllowed).toHaveBeenCalled();
+ });
+ }); // end of allowed
+
+ }); // end of delete
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js
new file mode 100644
index 00000000..9daced27
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules')
+ .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.edit', editService);
+
+ editService.$inject = [
+ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType',
+ 'horizon.framework.util.actions.action-result.service',
+ 'horizon.dashboard.project.lbaasv2.workflow.modal',
+ 'horizon.app.core.openstack-service-api.policy',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngDoc factory
+ * @name horizon.dashboard.project.lbaasv2.l7rules.actions.editService
+ *
+ * @description
+ * Provides the service for editing a l7rule resource.
+ *
+ * @param resourceType The l7rule resource type.
+ * @param actionResultService The horizon action result service.
+ * @param workflowModal The LBaaS workflow modal service.
+ * @param policy The horizon policy service.
+ * @param gettext The horizon gettext function for translation.
+ *
+ * @returns The l7rule edit service.
+ */
+
+ function editService(
+ resourceType, actionResultService, workflowModal, policy, gettext
+ ) {
+
+ return workflowModal.init({
+ controller: 'EditL7RuleWizardController',
+ message: gettext('The l7rule has been updated.'),
+ handle: handle,
+ allowed: allowed
+ });
+
+ function allowed(/*item*/) {
+ return policy.ifAllowed({ rules: [['neutron', 'update_l7rule']] });
+ }
+
+ function handle(response) {
+ return actionResultService.getActionResult()
+ .updated(resourceType, response.config.data.l7rule.id)
+ .result;
+ }
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js
new file mode 100644
index 00000000..922bc3d2
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 Edit L7Rule Action Service', function() {
+ var policy, service;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$modal', {
+ open: function() {
+ return {
+ result: {
+ then: function(func) {
+ func({ data: { id: 'l7rule1' } });
+ }
+ }
+ };
+ }
+ });
+ }));
+
+ beforeEach(inject(function ($injector) {
+ policy = $injector.get('horizon.app.core.openstack-service-api.policy');
+ service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.edit');
+ }));
+
+ it('should check policy to allow editing a l7rule', function() {
+ spyOn(policy, 'ifAllowed').and.returnValue(true);
+ expect(service.allowed()).toBe(true);
+ expect(policy.ifAllowed).toHaveBeenCalledWith({rules: [['neutron', 'update_l7rule']]});
+ });
+
+ it('should handle the action result properly', function() {
+ var result = service.handle({config: {data: {l7rule: {id: 1}}}});
+ expect(result.updated[0].id).toBe(1);
+ });
+
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js
new file mode 100644
index 00000000..ef98331d
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.loadbalancers')
+ .controller('EditL7RuleWizardController', EditL7RuleWizardController);
+
+ EditL7RuleWizardController.$inject = [
+ '$scope',
+ '$routeParams',
+ '$q',
+ 'horizon.dashboard.project.lbaasv2.workflow.model',
+ 'horizon.dashboard.project.lbaasv2.workflow.workflow',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name EditL7RuleWizardController
+ *
+ * @description
+ * Controller for the LBaaS v2 edit l7rule wizard.
+ *
+ * @param $scope The angular scope object.
+ * @param $routeParams The angular $routeParams service.
+ * @param $q The angular service for promises.
+ * @param model The LBaaS V2 workflow model service.
+ * @param workflowService The LBaaS V2 workflow service.
+ * @param gettext The horizon gettext function for translation.
+ * @returns undefined
+ */
+
+ function EditL7RuleWizardController($scope, $routeParams, $q, model, workflowService, gettext) {
+ var scope = $scope;
+ var loadbalancerId = $routeParams.loadbalancerId;
+ var l7policyId = $routeParams.l7policyId;
+ scope.model = model;
+ scope.submit = scope.model.submit;
+ scope.workflow = workflowService(
+ gettext('Update L7 Rule'),
+ 'fa fa-pencil', ['l7rule']);
+ scope.model.initialize('l7rule', scope.launchContext.id, loadbalancerId, l7policyId);
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js
new file mode 100644
index 00000000..dc04135d
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ describe('LBaaS v2 Edit L7Rule Wizard Controller', function() {
+ var ctrl, workflowSpy, $q, scope;
+ var model = {
+ submit: function() {
+ return 'updated';
+ },
+ initialize: function() {
+ var defer = $q.defer();
+ defer.resolve();
+ return defer.promise;
+ }
+ };
+ var workflow = {
+ steps: [{id: 'l7rule'}],
+ append: angular.noop
+ };
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+ beforeEach(module(function ($provide) {
+ workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model);
+ $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy);
+ }));
+ beforeEach(inject(function ($controller, $injector) {
+ $q = $injector.get('$q');
+ scope = $injector.get('$rootScope').$new();
+ scope.launchContext = { id: 'l7ruleId' };
+ spyOn(model, 'initialize').and.callThrough();
+ ctrl = $controller('EditL7RuleWizardController', {
+ $scope: scope,
+ $routeParams: {loadbalancerId: 'loadbalancerId', l7policyId: 'l7policyId'}});
+ }));
+
+ it('defines the controller', function() {
+ expect(ctrl).toBeDefined();
+ });
+
+ it('calls initialize on the given model', function() {
+ expect(model.initialize).toHaveBeenCalledWith(
+ 'l7rule', 'l7ruleId', 'loadbalancerId', 'l7policyId');
+ });
+
+ it('sets scope.workflow to the given workflow', function() {
+ expect(scope.workflow).toBe(workflow);
+ });
+
+ it('initializes workflow with correct properties', function() {
+ expect(workflowSpy).toHaveBeenCalledWith('Update L7 Rule',
+ 'fa fa-pencil', ['l7rule']);
+ });
+
+ it('defines scope.submit', function() {
+ expect(scope.submit).toBe(model.submit);
+ expect(scope.submit()).toBe('updated');
+ });
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js
new file mode 100644
index 00000000..d1f4e09f
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules')
+ .controller('L7RuleDetailController', L7RuleDetailController);
+
+ L7RuleDetailController.$inject = [
+ 'loadbalancer',
+ 'listener',
+ 'l7policy',
+ 'l7rule',
+ 'horizon.dashboard.project.lbaasv2.loadbalancers.service',
+ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType',
+ 'horizon.framework.conf.resource-type-registry.service',
+ 'horizon.framework.widgets.modal-wait-spinner.service',
+ '$q'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name L7RuleDetailController
+ *
+ * @description
+ * Controller for the LBaaS v2 l7rule detail page.
+ *
+ * @param loadbalancer The loadbalancer object.
+ * @param listener The listener object.
+ * @param l7policy The l7policy object.
+ * @param l7rule The l7rule object.
+ * @param loadBalancersService The LBaaS v2 load balancers service.
+ * @param resourceType The load balancer resource type.
+ * @param typeRegistry The horizon type registry service.
+ * @param spinnerService The horizon modal wait spinner service.
+ * @param $q The angular service for promises.
+ *
+ * @returns undefined
+ */
+
+ function L7RuleDetailController(
+ loadbalancer, listener, l7policy, l7rule, loadBalancersService,
+ resourceType, typeRegistry, spinnerService, $q
+ ) {
+ var ctrl = this;
+
+ ctrl.operatingStatus = loadBalancersService.operatingStatus;
+ ctrl.provisioningStatus = loadBalancersService.provisioningStatus;
+ ctrl.l7ruleType = loadBalancersService.l7ruleType;
+ ctrl.l7ruleCompareType = loadBalancersService.l7ruleCompareType;
+ ctrl.loadbalancer = loadbalancer;
+ ctrl.listener = listener;
+ ctrl.l7policy = l7policy;
+ ctrl.l7rule = l7rule;
+ ctrl.listFunctionExtraParams = {
+ loadbalancerId: ctrl.loadbalancer.id,
+ listenerId: ctrl.listener.id,
+ l7policyId: ctrl.l7policy.id,
+ l7ruleId: ctrl.l7rule.id
+ };
+ ctrl.resourceType = typeRegistry.getResourceType(resourceType);
+ ctrl.context = {};
+ ctrl.context.l7policyId = l7policy.id;
+ ctrl.context.l7ruleId = l7rule.id;
+
+ ctrl.resultHandler = actionResultHandler;
+
+ function actionResultHandler(returnValue) {
+ return $q.when(returnValue, actionSuccessHandler);
+ }
+
+ function loadData(response) {
+ spinnerService.hideModalSpinner();
+ ctrl.showDetails = true;
+ ctrl.resourceType.initActions();
+ ctrl.l7rule = response.data;
+ ctrl.l7rule.loadbalancerId = ctrl.loadbalancer.id;
+ ctrl.l7rule.listenerId = ctrl.listener.id;
+ ctrl.l7rule.l7policyId = ctrl.l7policy.id;
+ }
+
+ function actionSuccessHandler(result) {
+ // The action has completed (for whatever "complete" means to that
+ // action. Notice the view doesn't really need to know the semantics of the
+ // particular action because the actions return data in a standard form.
+ // That return includes the id and type of each created, updated, deleted
+ // and failed item.
+ // Currently just refreshes the display each time.
+ if (result) {
+ if (result.failed.length === 0 && result.deleted.length > 0) {
+ // handle a race condition where the resource is already deleted
+ return;
+ }
+ spinnerService.showModalSpinner(gettext('Please Wait'));
+ ctrl.showDetails = false;
+ ctrl.context.loadPromise = ctrl.resourceType.load(
+ ctrl.context.l7policyId,
+ ctrl.context.l7ruleId
+ );
+ ctrl.context.loadPromise.then(loadData);
+ }
+ }
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js
new file mode 100644
index 00000000..e37e256c
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Rule Detail Controller', function() {
+ var deferred, service, ctrl, scope, $timeout, $q, actionResultService;
+
+ ///////////////////////
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(module(function($provide) {
+ $provide.value('$uibModal', {});
+ }));
+
+ beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) {
+ $q = _$q_;
+ deferred = $q.defer();
+ service = {
+ getResourceType: function() {
+ return {
+ load: function() { return deferred.promise; },
+ parsePath: function() { return 'my-context'; },
+ itemName: function() { return 'A name'; },
+ initActions: angular.noop
+ };
+ },
+ getDefaultDetailsTemplateUrl: angular.noop
+ };
+ actionResultService = {
+ getIdsOfType: function() { return []; }
+ };
+ $timeout = _$timeout_;
+ scope = $rootScope.$new();
+ ctrl = $controller('L7RuleDetailController', {
+ $scope: scope,
+ loadbalancer: { id: '123' },
+ listener: { id: '123' },
+ l7policy: { id: '123' },
+ l7rule: { id: '123' },
+ 'horizon.framework.conf.resource-type-registry.service': service,
+ 'horizon.framework.util.actions.action-result.service': actionResultService,
+ 'horizon.framework.widgets.modal-wait-spinner.service': {
+ showModalSpinner: angular.noop,
+ hideModalSpinner: angular.noop
+ }
+ });
+ }));
+
+ it('should create a controller', function() {
+ expect(ctrl).toBeDefined();
+ expect(ctrl.loadbalancer).toBeDefined();
+ expect(ctrl.listener).toBeDefined();
+ expect(ctrl.l7policy).toBeDefined();
+ expect(ctrl.l7rule).toBeDefined();
+ });
+
+ describe('resultHandler', function() {
+
+ it('handles empty results', function() {
+ var result = $q.defer();
+ result.resolve({failed: [], deleted: []});
+ ctrl.resultHandler(result.promise);
+ $timeout.flush();
+ expect(ctrl.showDetails).not.toBe(true);
+ });
+
+ it('handles falsy results', function() {
+ var result = $q.defer();
+ result.resolve(false);
+ ctrl.resultHandler(result.promise);
+ $timeout.flush();
+ expect(ctrl.showDetails).not.toBe(true);
+ });
+
+ it('handles matched results', function() {
+ spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]);
+ var result = $q.defer();
+ result.resolve({some: 'thing', failed: [], deleted: []});
+ ctrl.resultHandler(result.promise);
+ deferred.resolve({data: {some: 'data'}});
+ $timeout.flush();
+ expect(ctrl.showDetails).toBe(true);
+ });
+
+ it('handles delete race condition', function() {
+ spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]);
+ var result = $q.defer();
+ result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]});
+ ctrl.resultHandler(result.promise);
+ deferred.resolve({data: {some: 'data'}});
+ $timeout.flush();
+ expect(ctrl.showDetails).toBe(undefined);
+ });
+
+ });
+
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html
new file mode 100644
index 00000000..97368df7
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html
@@ -0,0 +1,54 @@
+
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js
new file mode 100644
index 00000000..3a512cbe
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ /**
+ * @ngdoc overview
+ * @ngname horizon.dashboard.project.lbaasv2.l7rules
+ *
+ * @description
+ * Provides the services and widgets required to support and display the project l7 rules
+ * for the load balancers v2 panel.
+ */
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2.l7rules', [])
+ .constant('horizon.dashboard.project.lbaasv2.l7rules.resourceType',
+ 'OS::Octavia::L7Rule')
+ .run(run);
+
+ run.$inject = [
+ 'horizon.framework.conf.resource-type-registry.service',
+ 'horizon.dashboard.project.lbaasv2.basePath',
+ 'horizon.dashboard.project.lbaasv2.loadbalancers.service',
+ 'horizon.dashboard.project.lbaasv2.l7rules.actions.create',
+ 'horizon.dashboard.project.lbaasv2.l7rules.actions.edit',
+ 'horizon.dashboard.project.lbaasv2.l7rules.actions.delete',
+ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType'
+ ];
+
+ function run(
+ registry,
+ basePath,
+ loadBalancerService,
+ createService,
+ editService,
+ deleteService,
+ resourceType
+ ) {
+ var l7ruleResourceType = registry.getResourceType(resourceType);
+
+ l7ruleResourceType
+ .setNames(gettext('L7 Rule'), gettext('L7 Rules'))
+ .setSummaryTemplateUrl(basePath + 'l7rules/details/drawer.html')
+ .setProperties(l7ruleProperties(loadBalancerService))
+ .setListFunction(loadBalancerService.getL7RulesPromise)
+ .setLoadFunction(loadBalancerService.getL7RulePromise)
+ .tableColumns
+ .append({
+ id: 'type',
+ priority: 1,
+ urlFunction: loadBalancerService.getL7RuleDetailsPath
+ })
+ .append({
+ id: 'compare_type',
+ priority: 1
+ })
+ .append({
+ id: 'key',
+ priority: 1
+ })
+ .append({
+ id: 'rule_value',
+ priority: 1
+ })
+ .append({
+ id: 'invert',
+ priority: 1
+ })
+ .append({
+ id: 'operating_status',
+ priority: 1
+ })
+ .append({
+ id: 'provisioning_status',
+ priority: 1
+ })
+ .append({
+ id: 'admin_state_up',
+ priority: 1
+ });
+
+ l7ruleResourceType.itemActions
+ .append({
+ id: 'l7ruleEdit',
+ service: editService,
+ template: {
+ text: gettext('Edit L7 Rule')
+ }
+ })
+ .append({
+ id: 'l7ruleDelete',
+ service: deleteService,
+ template: {
+ text: gettext('Delete L7 Rule'),
+ type: 'delete'
+ }
+ });
+
+ l7ruleResourceType.globalActions
+ .append({
+ id: 'l7ruleCreate',
+ service: createService,
+ template: {
+ type: 'create',
+ text: gettext('Create L7 Rule')
+ }
+ });
+
+ l7ruleResourceType.batchActions
+ .append({
+ id: 'l7ruleBatchDelete',
+ service: deleteService,
+ template: {
+ text: gettext('Delete L7 Rules'),
+ type: 'delete-selected'
+ }
+ });
+ }
+
+ function l7ruleProperties(loadBalancerService) {
+ return {
+ id: gettext('ID'),
+ type: {
+ label: gettext('Type'),
+ values: loadBalancerService.l7ruleType
+ },
+ compare_type: {
+ label: gettext('Compare Type'),
+ values: loadBalancerService.l7ruleCompareType
+ },
+ provisioning_status: {
+ label: gettext('Provisioning Status'),
+ values: loadBalancerService.provisioningStatus
+ },
+ operating_status: {
+ label: gettext('Operating Status'),
+ values: loadBalancerService.operatingStatus
+ },
+ admin_state_up: {
+ label: gettext('Admin State Up'),
+ filters: ['yesno']
+ },
+ key: {
+ label: gettext('Key'),
+ filters: ['noName']
+ },
+ rule_value: {
+ label: gettext('Value'),
+ filters: ['noName']
+ },
+ invert: {
+ label: gettext('Invert'),
+ filters: ['yesno']
+ },
+ project_id: gettext('Project ID'),
+ created_at: {
+ label: gettext('Created At'),
+ filters: ['noValue']
+ },
+ updated_at: {
+ label: gettext('Updated At'),
+ filters: ['noValue']
+ }
+ };
+ }
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js
new file mode 100644
index 00000000..6fc42122
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('LBaaS v2 L7Rules Module', function() {
+ it('should exist', function() {
+ expect(angular.module('horizon.dashboard.project.lbaasv2.l7rules')).toBeDefined();
+ });
+ });
+
+ describe('LBaaS v2 L7Rules Registry', function () {
+ var registry, resourceType;
+
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ beforeEach(inject(function($injector) {
+ resourceType = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.resourceType');
+ registry = $injector.get('horizon.framework.conf.resource-type-registry.service');
+ }));
+
+ it('should define resourceType', function () {
+ expect(resourceType).toBeDefined();
+ });
+
+ it('should register item actions', function () {
+ var actions = registry.getResourceType(resourceType).itemActions;
+ expect(actionHasId(actions, 'l7ruleEdit')).toBe(true);
+ expect(actionHasId(actions, 'l7ruleDelete')).toBe(true);
+ });
+
+ it('should register global actions', function () {
+ var actions = registry.getResourceType(resourceType).globalActions;
+ expect(actionHasId(actions, 'l7ruleCreate')).toBe(true);
+ });
+
+ it('should register batch actions', function () {
+ var actions = registry.getResourceType(resourceType).batchActions;
+ expect(actionHasId(actions, 'l7ruleBatchDelete')).toBe(true);
+ });
+
+ function actionHasId(list, value) {
+ return list.filter(matchesId).length === 1;
+
+ function matchesId(action) {
+ if (action.id === value) {
+ return true;
+ }
+ }
+ }
+
+ });
+
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js b/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js
index f1f8d482..e10aa289 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js
@@ -28,6 +28,8 @@
.module('horizon.dashboard.project.lbaasv2', [
'horizon.dashboard.project.lbaasv2.loadbalancers',
'horizon.dashboard.project.lbaasv2.listeners',
+ 'horizon.dashboard.project.lbaasv2.l7policies',
+ 'horizon.dashboard.project.lbaasv2.l7rules',
'horizon.dashboard.project.lbaasv2.pools',
'horizon.dashboard.project.lbaasv2.members',
'horizon.dashboard.project.lbaasv2.healthmonitors',
@@ -68,6 +70,8 @@
var loadbalancers = '/project/load_balancer';
var listener = loadbalancers + '/:loadbalancerId/listeners/:listenerId';
+ var listenerL7Policy = listener + '/l7policies/:l7policyId';
+ var listenerL7Rule = listenerL7Policy + '/l7rules/:l7ruleId';
var listenerPool = listener + '/pools/:poolId';
var listenerPoolMember = listenerPool + '/members/:memberId';
var listenerPoolHealthmonitor = listenerPool + '/healthmonitors/:healthmonitorId';
@@ -129,6 +133,105 @@
controller: 'ListenerDetailController',
controllerAs: 'ctrl'
})
+ .when(listenerL7Policy, {
+ templateUrl: basePath + 'l7policies/details/detail.html',
+ resolve: {
+ loadbalancer: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getLoadBalancer($route.current.params.loadbalancerId, true).then(
+ function success(response) {
+ response.data.floating_ip_address = response.data.floating_ip.ip;
+ return response.data;
+ }
+ );
+ }
+ ],
+ listener: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getListener($route.current.params.listenerId).then(
+ function success(response) {
+ return response.data;
+ }
+ );
+ }
+ ],
+ l7policy: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getL7Policy($route.current.params.l7policyId).then(
+ function success(response) {
+ response.data.loadbalancerId = $route.current.params.loadbalancerId;
+ response.data.listenerId = $route.current.params.listenerId;
+ return response.data;
+ }
+ );
+ }
+ ]
+ },
+ controller: 'L7PolicyDetailController',
+ controllerAs: 'ctrl'
+ })
+ .when(listenerL7Rule, {
+ templateUrl: basePath + 'l7rules/details/detail.html',
+ resolve: {
+ loadbalancer: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getLoadBalancer($route.current.params.loadbalancerId, true).then(
+ function success(response) {
+ response.data.floating_ip_address = response.data.floating_ip.ip;
+ return response.data;
+ }
+ );
+ }
+ ],
+ listener: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getListener($route.current.params.listenerId).then(
+ function success(response) {
+ return response.data;
+ }
+ );
+ }
+ ],
+ l7policy: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getL7Policy($route.current.params.l7policyId).then(
+ function success(response) {
+ return response.data;
+ }
+ );
+ }
+ ],
+ l7rule: [
+ '$route',
+ 'horizon.app.core.openstack-service-api.lbaasv2',
+ function($route, api) {
+ return api.getL7Rule($route.current.params.l7policyId,
+ $route.current.params.l7ruleId).then(
+ function success(response) {
+ response.data.loadbalancerId = $route.current.params.loadbalancerId;
+ response.data.listenerId = $route.current.params.listenerId;
+ response.data.l7policyId = $route.current.params.l7policyId;
+ return response.data;
+ }
+ );
+ }
+ ]
+ },
+ controller: 'L7RuleDetailController',
+ controllerAs: 'ctrl'
+ })
.when(listenerPool, {
templateUrl: basePath + 'pools/details/detail.html',
resolve: {
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js
index 174ec00c..45e53f16 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js
@@ -233,6 +233,121 @@
});
}));
+ it('should route resolved listener l7 policy detail', inject(function($injector) {
+ function loadbalancerAPI() {
+ var loadbalancer = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(loadbalancer);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1, floating_ip: {}}});
+ }
+ };
+ }
+
+ function listenerAPI() {
+ var listener = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(listener);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1}});
+ }
+ };
+ }
+
+ function l7policyAPI() {
+ var l7policy = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(l7policy);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1}});
+ }
+ };
+ }
+
+ var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
+ spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
+ spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI);
+ spyOn(lbaasv2API, 'getL7Policy').and.callFake(l7policyAPI);
+ inject(function($route, $location, $rootScope, $httpBackend) {
+ $httpBackend.expectGET(
+ '/static/dashboard/project/lbaasv2/l7policies/details/detail.html'
+ ).respond({});
+ $location.path('/project/load_balancer/1/listeners/2/l7policies/3');
+ $rootScope.$digest();
+ expect($route.current).toBeDefined();
+ });
+ }));
+
+ it('should route resolved listener l7 rule detail', inject(function($injector) {
+ function loadbalancerAPI() {
+ var loadbalancer = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(loadbalancer);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1, floating_ip: {}}});
+ }
+ };
+ }
+
+ function listenerAPI() {
+ var listener = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(listener);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1}});
+ }
+ };
+ }
+
+ function l7policyAPI() {
+ var l7policy = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(l7policy);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1}});
+ }
+ };
+ }
+
+ function l7ruleAPI() {
+ var l7rule = { provisioning_status: 'ACTIVE' };
+ return {
+ success: function(callback) {
+ callback(l7rule);
+ },
+ then: function(callback) {
+ callback({ data: { id: 1}});
+ }
+ };
+ }
+
+ var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
+ spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
+ spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI);
+ spyOn(lbaasv2API, 'getL7Policy').and.callFake(l7policyAPI);
+ spyOn(lbaasv2API, 'getL7Rule').and.callFake(l7ruleAPI);
+ inject(function($route, $location, $rootScope, $httpBackend) {
+ $httpBackend.expectGET(
+ '/static/dashboard/project/lbaasv2/l7rules/details/detail.html'
+ ).respond({});
+ $location.path('/project/load_balancer/1/listeners/2/l7policies/3/l7rules/4');
+ $rootScope.$digest();
+ expect($route.current).toBeDefined();
+ });
+ }));
+
it('should route resolved listener pool member detail', inject(function($injector) {
function loadbalancerAPI() {
var loadbalancer = { provisioning_status: 'ACTIVE' };
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html b/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html
index 7a4a2ce7..f810dde1 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html
@@ -61,4 +61,10 @@
list-function-extra-params="ctrl.listFunctionExtraParams">
+
+
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js
index 3a99c6b0..daf16765 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js
@@ -33,7 +33,11 @@
// the wizard continues to work. Using local var to appease eslint angular/ng_controller_as.
scope.model = model;
scope.submit = scope.model.submit;
- scope.workflow = workflowService(gettext('Create Load Balancer'), 'fa fa-cloud-download');
+ scope.workflow = workflowService(
+ gettext('Create Load Balancer'),
+ 'fa fa-cloud-download',
+ ['loadbalancer', 'listener', 'certificates', 'pool', 'members', 'monitor']
+ );
scope.model.initialize('loadbalancer');
}
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js
index 54fdf3db..1302e1d1 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js
@@ -64,6 +64,28 @@
SOURCE_IP: gettext('Source IP')
};
+ var l7policyAction = {
+ REJECT: gettext('Reject'),
+ REDIRECT_TO_URL: gettext('Redirect to URL'),
+ REDIRECT_TO_POOL: gettext('Redirect to Pool')
+ };
+
+ var l7ruleType = {
+ HOST_NAME: gettext('Host Name'),
+ PATH: gettext('Path'),
+ FILE_TYPE: gettext('File Type'),
+ HEADER: gettext('Header'),
+ COOKIE: gettext('Cookie')
+ };
+
+ var l7ruleCompareType = {
+ REGEX: gettext('Regex'),
+ STARTS_WITH: gettext('Starts With'),
+ ENDS_WITH: gettext('Ends With'),
+ CONTAINS: gettext('Contains'),
+ EQUAL_TO: gettext('Equal To')
+ };
+
var none = {
null: gettext('None')
};
@@ -72,6 +94,9 @@
operatingStatus: operatingStatus,
provisioningStatus: provisioningStatus,
loadBalancerAlgorithm: loadBalancerAlgorithm,
+ l7policyAction: l7policyAction,
+ l7ruleType: l7ruleType,
+ l7ruleCompareType: l7ruleCompareType,
none: none,
nullFilter: nullFilter,
getLoadBalancersPromise: getLoadBalancersPromise,
@@ -80,6 +105,12 @@
getListenersPromise: getListenersPromise,
getListenerPromise: getListenerPromise,
getListenerDetailsPath: getListenerDetailsPath,
+ getL7PoliciesPromise: getL7PoliciesPromise,
+ getL7PolicyPromise: getL7PolicyPromise,
+ getL7PolicyDetailsPath: getL7PolicyDetailsPath,
+ getL7RulesPromise: getL7RulesPromise,
+ getL7RulePromise: getL7RulePromise,
+ getL7RuleDetailsPath: getL7RuleDetailsPath,
getPoolsPromise: getPoolsPromise,
getPoolPromise: getPoolPromise,
getPoolDetailsPath: getPoolDetailsPath,
@@ -200,6 +231,58 @@
}
}
+ function getL7RulesPromise(params) {
+ return api.getL7Rules(params.l7policyId).then(modifyResponse);
+
+ function modifyResponse(response) {
+ return {data: {items: response.data.items.map(modifyItem)}};
+
+ function modifyItem(item) {
+ item.trackBy = item.id + item.updated_at;
+ item.loadbalancerId = params.loadbalancerId;
+ item.listenerId = params.listenerId;
+ item.l7policyId = params.l7policyId;
+ return item;
+ }
+ }
+ }
+
+ function getL7RulePromise(l7policyId, l7ruleId) {
+ return api.getL7Rule(l7policyId, l7ruleId);
+ }
+
+ function getL7RuleDetailsPath(item) {
+ return 'project/load_balancer/' +
+ item.loadbalancerId + '/listeners/' +
+ item.listenerId + '/l7policies/' +
+ item.l7policyId + '/l7rules/' + item.id;
+ }
+
+ function getL7PoliciesPromise(params) {
+ return api.getL7Policies(params.listenerId).then(modifyResponse);
+
+ function modifyResponse(response) {
+ return {data: {items: response.data.items.map(modifyItem)}};
+
+ function modifyItem(item) {
+ item.trackBy = item.id + item.updated_at;
+ item.loadbalancerId = params.loadbalancerId;
+ item.listenerId = params.listenerId;
+ return item;
+ }
+ }
+ }
+
+ function getL7PolicyPromise(identifier) {
+ return api.getL7Policy(identifier);
+ }
+
+ function getL7PolicyDetailsPath(item) {
+ return 'project/load_balancer/' +
+ item.loadbalancerId + '/listeners/' +
+ item.listenerId + '/l7policies/' + item.id;
+ }
+
function getListenersPromise(params) {
return api.getListeners(params.loadbalancerId).then(modifyResponse);
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js
index e5222821..4f05316d 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js
@@ -91,6 +91,61 @@
expect(result.$$state.value.data.updated_at).toBe('feb8');
}));
+ it('getL7PolicyDetailsPath creates urls using the item\'s ID', function() {
+ var myItem = {loadbalancerId: '123', id: '789', listenerId: '456'};
+ expect(service.getL7PolicyDetailsPath(myItem))
+ .toBe('project/load_balancer/123/listeners/456/l7policies/789');
+ });
+
+ it("getL7PoliciesPromise provides a promise", inject(function($timeout) {
+ var deferred = $q.defer();
+ spyOn(api, 'getL7Policies').and.returnValue(deferred.promise);
+ var result = service.getL7PoliciesPromise({listenerId: 3});
+ deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}});
+ $timeout.flush();
+ expect(result.$$state.value.data.items[0].id).toBe(1);
+ expect(result.$$state.value.data.items[0].updated_at).toBe('feb8');
+ expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8');
+ expect(result.$$state.value.data.items[0].listenerId).toBe(3);
+ }));
+
+ it("getL7PolicyPromise provides a promise", inject(function() {
+ var deferred = $q.defer();
+ spyOn(api, 'getL7Policy').and.returnValue(deferred.promise);
+ var result = service.getL7PolicyPromise(1);
+ deferred.resolve({data: {id: 1, updated_at: 'feb8'}});
+ expect(result.$$state.value.data.id).toBe(1);
+ expect(result.$$state.value.data.updated_at).toBe('feb8');
+ }));
+
+ it('getL7RuleDetailsPath creates urls using the item\'s ID', function() {
+ var myItem = {loadbalancerId: '1', id: '5', listenerId: '2', l7policyId: '3'};
+ expect(service.getL7RuleDetailsPath(myItem))
+ .toBe('project/load_balancer/1/listeners/2/l7policies/3/l7rules/5');
+ });
+
+ it("getL7RulesPromise provides a promise", inject(function($timeout) {
+ var deferred = $q.defer();
+ spyOn(api, 'getL7Rules').and.returnValue(deferred.promise);
+ var result = service.getL7RulesPromise({listenerId: 3, l7policyId: 5});
+ deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}});
+ $timeout.flush();
+ expect(result.$$state.value.data.items[0].id).toBe(1);
+ expect(result.$$state.value.data.items[0].updated_at).toBe('feb8');
+ expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8');
+ expect(result.$$state.value.data.items[0].listenerId).toBe(3);
+ expect(result.$$state.value.data.items[0].l7policyId).toBe(5);
+ }));
+
+ it("getL7RulePromise provides a promise", inject(function() {
+ var deferred = $q.defer();
+ spyOn(api, 'getL7Rule').and.returnValue(deferred.promise);
+ var result = service.getL7RulePromise(2, 1);
+ deferred.resolve({data: {id: 1, updated_at: 'feb8'}});
+ expect(result.$$state.value.data.id).toBe(1);
+ expect(result.$$state.value.data.updated_at).toBe('feb8');
+ }));
+
it('getPoolDetailsPath creates urls using the item\'s ID', function() {
var myItem = {loadbalancerId: '123', id: '789', listeners: [{id: '456'}]};
expect(service.getPoolDetailsPath(myItem))
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js
new file mode 100644
index 00000000..6a552dd9
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2')
+ .controller('L7PolicyDetailsController', L7PolicyDetailsController);
+
+ L7PolicyDetailsController.$inject = [
+ 'horizon.dashboard.project.lbaasv2.patterns',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name L7PolicyDetailsController
+ * @description
+ * The `L7PolicyDetailsController` controller provides functions for
+ * configuring the l7policy step of the LBaaS wizard.
+ * @param patterns The LBaaS v2 patterns constant.
+ * @param gettext The horizon gettext function for translation.
+ * @returns undefined
+ */
+
+ function L7PolicyDetailsController(patterns, gettext) {
+
+ var ctrl = this;
+
+ ctrl.adminStateUpOptions = [
+ { label: gettext('Yes'), value: true },
+ { label: gettext('No'), value: false }
+ ];
+
+ ctrl.redirectUrlError = gettext('The redirect url must be a valid http or https url.');
+ ctrl.positionError = gettext('The position must be a number between 1 and 2147483647.');
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js
new file mode 100644
index 00000000..7c4dfb21
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('L7Policy Details Step', function() {
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ describe('L7PolicyDetailsController', function() {
+ var ctrl;
+
+ beforeEach(inject(function($controller) {
+ ctrl = $controller('L7PolicyDetailsController');
+ }));
+
+ it('should define adminStateUpOptions', function() {
+ expect(ctrl.adminStateUpOptions).toBeDefined();
+ });
+
+ });
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html
new file mode 100644
index 00000000..4b1459c5
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html
@@ -0,0 +1,38 @@
+
+ An L7 Policy is a collection of L7 rules associated with a Listener, and which may also have an association to a back-end pool
+
+
+ Action:
+
+ The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL.
+
+
+
+ REJECT: The request is denied with an appropriate response code, and not forwarded on to any back-end pool.
+
+
+ REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in the redirect_url parameter.
+
+
+ REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated with the L7 policy.
+
+
+
+
+ Position:
+
+ The position of this policy on the listener. Positions start at 1.
+
+
+
+ Redirect Pool ID:
+
+ Requests matching this policy will be redirected to the pool with this ID. Only valid if action is REDIRECT_TO_POOL.
+
+
+
+ Redirect URL:
+
+ Requests matching this policy will be redirected to this URL. Only valid if action is REDIRECT_TO_URL.
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html
new file mode 100644
index 00000000..a9962bd7
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html
@@ -0,0 +1,104 @@
+
+
Provide the details for the l7 policy.
+
+
+
+
+
+
+
+
+
+
+ Redirect URL
+
+
+
+
+ {$ ::ctrl.redirectUrlError $}
+
+
+
+
+
+
+
+ Redirect Pool ID
+
+
+
+
+ {$ pool_id $}
+
+
+
+
+
+
+
+
+
+
+
+ Position
+
+
+ {$ ::ctrl.positionError $}
+
+
+
+
+
+
+
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.js
new file mode 100644
index 00000000..d98971e7
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function () {
+ 'use strict';
+
+ angular
+ .module('horizon.dashboard.project.lbaasv2')
+ .controller('L7RuleDetailsController', L7RuleDetailsController);
+
+ L7RuleDetailsController.$inject = [
+ 'horizon.dashboard.project.lbaasv2.patterns',
+ 'horizon.framework.util.i18n.gettext'
+ ];
+
+ /**
+ * @ngdoc controller
+ * @name L7RuleDetailsController
+ * @description
+ * The `L7RuleDetailsController` controller provides functions for
+ * configuring the l7rule step of the LBaaS wizard.
+ * @param patterns The LBaaS v2 patterns constant.
+ * @param gettext The horizon gettext function for translation.
+ * @returns undefined
+ */
+
+ function L7RuleDetailsController(patterns, gettext) {
+
+ var ctrl = this;
+
+ ctrl.adminStateUpOptions = [
+ { label: gettext('Yes'), value: true },
+ { label: gettext('No'), value: false }
+ ];
+
+ }
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.spec.js
new file mode 100644
index 00000000..9eb3a6ff
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.controller.spec.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Walmart.
+ *
+ * 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.
+ */
+(function() {
+ 'use strict';
+
+ describe('L7Rule Details Step', function() {
+
+ beforeEach(module('horizon.framework.util'));
+ beforeEach(module('horizon.dashboard.project.lbaasv2'));
+
+ describe('L7RuleDetailsController', function() {
+ var ctrl;
+
+ beforeEach(inject(function($controller) {
+ ctrl = $controller('L7RuleDetailsController');
+ }));
+
+ it('should define adminStateUpOptions', function() {
+ expect(ctrl.adminStateUpOptions).toBeDefined();
+ });
+
+ });
+ });
+})();
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html
new file mode 100644
index 00000000..a68f12d1
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html
@@ -0,0 +1,76 @@
+
+An L7 Rule is a single, simple logical test which returns either true or
+false.
+
+
+ Type:
+
+ The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH.
+
+
+
+ COOKIE: The rule looks for a cookie named by the key parameter and
+ compares it against the value parameter in the rule.
+
+
+ HEADER: The rule looks for a header defined in the key parameter
+ and compares it against the value parameter in the rule.
+
+
+ FILE_TYPE: The rule compares the last portion of the URI against
+ the value parameter in the rule. (eg. “txt”, “jpg”, etc.)
+
+
+ PATH: The rule compares the path portion of the HTTP URI against
+ the value parameter in the rule.
+
+
+ HOST_NAME: The rule does a comparison between the HTTP/1.1
+ hostname in the request against the value parameter in the rule.
+
+
+
+
+ Compare Type:
+
+ The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,
+ EQUAL_TO, REGEX, or STARTS_WITH.
+
+
+
+ REGEX: Perl type regular expression matching.
+
+
+ STARTS_WITH: String starts with.
+
+
+ ENDS_WITH: String ends with.
+
+
+ CONTAINS: String contains.
+
+
+ EQUAL_TO: String is equal to.
+
+
+
+
+ Key:
+
+ The key to use for the comparison. For example, the name of the cookie
+ to evaluate.
+
+
+
+ Value:
+
+ The value to use for the comparison. For example, the file type to compare.
+
+
+
+ Invert:
+
+ When true the logic of the rule is inverted. For example, with invert
+ true, equal to would become not equal to.
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html
new file mode 100644
index 00000000..b5b637f0
--- /dev/null
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html
@@ -0,0 +1,92 @@
+
+
Provide the details for the l7 rule.
+
+
+
+
+
+
+
+
+
+
+ Compare Type
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js
index a329604b..e7533683 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js
@@ -86,6 +86,9 @@
subnets: [],
members: [],
listenerProtocols: ['HTTP', 'TCP', 'TERMINATED_HTTPS', 'HTTPS'],
+ l7policyActions: ['REJECT', 'REDIRECT_TO_URL', 'REDIRECT_TO_POOL'],
+ l7ruleTypes: ['HOST_NAME', 'PATH', 'FILE_TYPE', 'HEADER', 'COOKIE'],
+ l7ruleCompareTypes: ['REGEX', 'STARTS_WITH', 'ENDS_WITH', 'CONTAINS', 'EQUAL_TO'],
poolProtocols: ['HTTP', 'HTTPS', 'PROXY', 'TCP'],
methods: ['LEAST_CONNECTIONS', 'ROUND_ROBIN', 'SOURCE_IP'],
types: ['SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE'],
@@ -153,6 +156,25 @@
admin_state_up: true,
default_pool_id: null
},
+ l7policy: {
+ id: null,
+ name: gettext('L7 Policy 1'),
+ description: null,
+ action: null,
+ position: null,
+ redirect_pool_id: null,
+ redirect_url: null,
+ admin_state_up: true
+ },
+ l7rule: {
+ id: null,
+ type: null,
+ compare_type: null,
+ key: null,
+ rule_value: null,
+ invert: false,
+ admin_state_up: true
+ },
pool: {
id: null,
name: gettext('Pool 1'),
@@ -198,11 +220,15 @@
var promise = {
createloadbalancer: initCreateLoadBalancer,
createlistener: initCreateListener,
+ createl7policy: initCreateL7Policy,
+ createl7rule: initCreateL7Rule,
createpool: initCreatePool,
createmonitor: initCreateMonitor,
createmembers: initUpdateMemberList,
editloadbalancer: initEditLoadBalancer,
editlistener: initEditListener,
+ editl7policy: initEditL7Policy,
+ editl7rule: initEditL7Rule,
editpool: initEditPool,
editmonitor: initEditMonitor
}[type](keymanagerPromise);
@@ -242,6 +268,17 @@
]).then(initMemberAddresses);
}
+ function initCreateL7Policy() {
+ model.context.submit = createL7Policy;
+ return lbaasv2API.getListener(model.spec.parentResourceId)
+ .then(onGetListener).then(getPools).then(onGetPools);
+ }
+
+ function initCreateL7Rule() {
+ model.context.submit = createL7Rule;
+ return $q.when();
+ }
+
function initCreatePool() {
model.context.submit = createPool;
// We get the listener details here because we need to know the listener protocol
@@ -295,6 +332,19 @@
]).then(initMemberAddresses);
}
+ function initEditL7Policy() {
+ model.context.submit = editL7Policy;
+ return lbaasv2API
+ .getListener(model.spec.parentResourceId).then(onGetListener)
+ .then(getPools).then(onGetPools)
+ .then(getL7Policy).then(onGetL7Policy);
+ }
+
+ function initEditL7Rule() {
+ model.context.submit = editL7Rule;
+ return getL7Rule().then(onGetL7Rule);
+ }
+
function initEditPool() {
model.context.submit = editPool;
return $q.all([
@@ -339,6 +389,14 @@
return lbaasv2API.createListener(spec);
}
+ function createL7Policy(spec) {
+ return lbaasv2API.createL7Policy(spec);
+ }
+
+ function createL7Rule(spec) {
+ return lbaasv2API.createL7Rule(model.spec.parentResourceId, spec);
+ }
+
function createPool(spec) {
return lbaasv2API.createPool(spec);
}
@@ -355,6 +413,14 @@
return lbaasv2API.editListener(model.context.id, spec);
}
+ function editL7Policy(spec) {
+ return lbaasv2API.editL7Policy(model.context.id, spec);
+ }
+
+ function editL7Rule(spec) {
+ return lbaasv2API.editL7Rule(model.spec.parentResourceId, model.context.id, spec);
+ }
+
function editPool(spec) {
return lbaasv2API.editPool(model.context.id, spec);
}
@@ -576,6 +642,15 @@
return lbaasv2API.getListener(model.context.id, true);
}
+ function getL7Policy() {
+ return lbaasv2API.getL7Policy(model.context.id, true);
+ }
+
+ function getL7Rule() {
+ return lbaasv2API.getL7Rule(model.spec.parentResourceId,
+ model.context.id);
+ }
+
function getPool() {
return lbaasv2API.getPool(model.context.id, true);
}
@@ -633,6 +708,18 @@
}
}
+ function onGetL7Policy(response) {
+ var result = response.data;
+
+ setL7PolicySpec(result.l7policy || result);
+ }
+
+ function onGetL7Rule(response) {
+ var result = response.data;
+
+ setL7RuleSpec(result.l7rule || result);
+ }
+
function onGetPool(response) {
var result = response.data;
@@ -674,6 +761,29 @@
spec.default_pool_id = listener.default_pool_id;
}
+ function setL7PolicySpec(l7policy) {
+ var spec = model.spec.l7policy;
+ spec.id = l7policy.id;
+ spec.name = l7policy.name;
+ spec.description = l7policy.description;
+ spec.action = l7policy.action;
+ spec.position = l7policy.position;
+ spec.redirect_pool_id = l7policy.redirect_pool_id;
+ spec.redirect_url = l7policy.redirect_url;
+ spec.admin_state_up = l7policy.admin_state_up;
+ }
+
+ function setL7RuleSpec(l7rule) {
+ var spec = model.spec.l7rule;
+ spec.id = l7rule.id;
+ spec.type = l7rule.type;
+ spec.compare_type = l7rule.compare_type;
+ spec.key = l7rule.key;
+ spec.rule_value = l7rule.rule_value;
+ spec.invert = l7rule.invert;
+ spec.admin_state_up = l7rule.admin_state_up;
+ }
+
function setPoolSpec(pool) {
var spec = model.spec.pool;
spec.id = pool.id;
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js
index 731679c4..eec254be 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js
@@ -141,6 +141,37 @@
deferred.resolve({ data: listenerData });
return deferred.promise;
},
+ getL7Policy: function() {
+ var l7policy = {
+ admin_state_up: true,
+ id: '1234',
+ name: 'L7 Policy 1',
+ description: 'l7 policy description',
+ action: 'REDIRECT_TO_URL',
+ position: 1,
+ redirect_url: 'http://example.com'
+ };
+
+ var deferred = $q.defer();
+ deferred.resolve({ data: l7policy });
+
+ return deferred.promise;
+ },
+ getL7Rule: function() {
+ var l7rule = {
+ admin_state_up: true,
+ id: '1234',
+ type: 'HOST_NAME',
+ compare_type: 'EQUAL_TO',
+ value: 'api.example.com',
+ invert: false
+ };
+
+ var deferred = $q.defer();
+ deferred.resolve({ data: l7rule });
+
+ return deferred.promise;
+ },
getPool: function() {
var poolResources = angular.copy(listenerResources);
delete poolResources.listener;
@@ -202,6 +233,18 @@
editListener: function(id, spec) {
return spec;
},
+ createL7Policy: function(spec) {
+ return spec;
+ },
+ editL7Policy: function(id, spec) {
+ return spec;
+ },
+ createL7Rule: function(l7policyId, spec) {
+ return spec;
+ },
+ editL7Rule: function(l7policyId, l7ruleId, spec) {
+ return spec;
+ },
createPool: function(spec) {
return spec;
},
@@ -463,6 +506,82 @@
});
});
+ describe('Post initialize model (create l7 policy)', function() {
+
+ beforeEach(function() {
+ includeChildResources = false;
+ model.initialize('l7policy', false, '1234', '5678');
+ scope.$apply();
+ });
+
+ it('should initialize model properties', function() {
+ expect(model.initializing).toBe(false);
+ expect(model.initialized).toBe(true);
+ expect(model.subnets.length).toBe(0);
+ expect(model.members.length).toBe(0);
+ expect(model.certificates.length).toBe(0);
+ expect(model.listenerPorts.length).toBe(0);
+ expect(model.spec).toBeDefined();
+ expect(model.spec.loadbalancer_id).toBe('1234');
+ expect(model.spec.parentResourceId).toBe('5678');
+ expect(model.spec.loadbalancer).toBeDefined();
+ expect(model.spec.listener).toBeDefined();
+ expect(model.spec.pool).toBeDefined();
+ expect(model.spec.members.length).toBe(0);
+ expect(model.spec.certificates).toEqual([]);
+ expect(model.spec.monitor).toBeDefined();
+ expect(model.certificatesError).toBe(false);
+ });
+
+ it('should initialize names', function() {
+ expect(model.spec.l7policy.name).toBe('L7 Policy 1');
+ });
+
+ it('should initialize context properties', function() {
+ expect(model.context.resource).toBe('l7policy');
+ expect(model.context.id).toBeFalsy();
+ expect(model.context.submit).toBeDefined();
+ });
+ });
+
+ describe('Post initialize model (create l7 rule)', function() {
+
+ beforeEach(function() {
+ includeChildResources = false;
+ model.initialize('l7rule', false, '1234', '5678');
+ scope.$apply();
+ });
+
+ it('should initialize model properties', function() {
+ expect(model.initializing).toBe(false);
+ expect(model.initialized).toBe(true);
+ expect(model.subnets.length).toBe(0);
+ expect(model.members.length).toBe(0);
+ expect(model.certificates.length).toBe(0);
+ expect(model.listenerPorts.length).toBe(0);
+ expect(model.spec).toBeDefined();
+ expect(model.spec.loadbalancer_id).toBe('1234');
+ expect(model.spec.parentResourceId).toBe('5678');
+ expect(model.spec.loadbalancer).toBeDefined();
+ expect(model.spec.listener).toBeDefined();
+ expect(model.spec.pool).toBeDefined();
+ expect(model.spec.members.length).toBe(0);
+ expect(model.spec.certificates).toEqual([]);
+ expect(model.spec.monitor).toBeDefined();
+ expect(model.certificatesError).toBe(false);
+ });
+
+ it('should initialize invert', function() {
+ expect(model.spec.l7rule.invert).toBe(false);
+ });
+
+ it('should initialize context properties', function() {
+ expect(model.context.resource).toBe('l7rule');
+ expect(model.context.id).toBeFalsy();
+ expect(model.context.submit).toBeDefined();
+ });
+ });
+
describe('Post initialize model (create pool with listener)', function() {
beforeEach(function() {
@@ -794,6 +913,53 @@
});
});
+ describe('Post initialize model (edit l7 policy)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7policy', '1234', 'loadbalancerId', 'listenerId');
+ scope.$apply();
+ });
+
+ it('should initialize model properties', function() {
+ expect(model.initializing).toBe(false);
+ expect(model.initialized).toBe(true);
+ expect(model.spec).toBeDefined();
+ expect(model.spec.loadbalancer_id).toBeDefined();
+ expect(model.spec.l7policy.id).toBe('1234');
+ expect(model.spec.l7policy.name).toBe('L7 Policy 1');
+ expect(model.spec.l7policy.description).toBe('l7 policy description');
+ });
+
+ it('should initialize context', function() {
+ expect(model.context.resource).toBe('l7policy');
+ expect(model.context.id).toBeDefined();
+ expect(model.context.submit).toBeDefined();
+ });
+ });
+
+ describe('Post initialize model (edit l7 rule)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7rule', '1234', 'loadbalancerId', 'l7policyId');
+ scope.$apply();
+ });
+
+ it('should initialize model properties', function() {
+ expect(model.initializing).toBe(false);
+ expect(model.initialized).toBe(true);
+ expect(model.spec).toBeDefined();
+ expect(model.spec.loadbalancer_id).toBeDefined();
+ expect(model.spec.l7rule.id).toBe('1234');
+ expect(model.spec.l7rule.type).toBe('HOST_NAME');
+ });
+
+ it('should initialize context', function() {
+ expect(model.context.resource).toBe('l7rule');
+ expect(model.context.id).toBeDefined();
+ expect(model.context.submit).toBeDefined();
+ });
+ });
+
describe('Post initialize model (edit pool)', function() {
beforeEach(function() {
@@ -1005,9 +1171,11 @@
// This is here to ensure that as people add/change spec properties, they don't forget
// to implement tests for them.
it('has the right number of properties', function() {
- expect(Object.keys(model.spec).length).toBe(9);
+ expect(Object.keys(model.spec).length).toBe(11);
expect(Object.keys(model.spec.loadbalancer).length).toBe(5);
expect(Object.keys(model.spec.listener).length).toBe(8);
+ expect(Object.keys(model.spec.l7policy).length).toBe(8);
+ expect(Object.keys(model.spec.l7rule).length).toBe(7);
expect(Object.keys(model.spec.pool).length).toBe(8);
expect(Object.keys(model.spec.monitor).length).toBe(10);
expect(model.spec.members).toEqual([]);
@@ -1716,6 +1884,47 @@
});
});
+ describe('Model submit function (create l7 policy)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7policy', null, '1234', 'listener1');
+ scope.$apply();
+ });
+
+ it('should set final spec properties', function() {
+ model.spec.l7policy.action = 'REJECT';
+
+ var finalSpec = model.submit();
+
+ expect(finalSpec.loadbalancer_id).toBe('1234');
+ expect(finalSpec.parentResourceId).toBe('listener1');
+ expect(finalSpec.loadbalancer).toBeUndefined();
+ expect(finalSpec.listener).toBeDefined();
+
+ expect(finalSpec.l7policy.action).toBe('REJECT');
+ });
+ });
+
+ describe('Model submit function (create l7 rule)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7rule', null, '1234', 'l7policy1');
+ scope.$apply();
+ });
+
+ it('should set final spec properties', function() {
+ model.spec.l7rule.type = 'PATH';
+
+ var finalSpec = model.submit();
+
+ expect(finalSpec.loadbalancer_id).toBe('1234');
+ expect(finalSpec.parentResourceId).toBe('l7policy1');
+ expect(finalSpec.loadbalancer).toBeUndefined();
+
+ expect(finalSpec.l7rule.type).toBe('PATH');
+ });
+ });
+
describe('Model submit function (create pool)', function() {
beforeEach(function() {
@@ -1977,6 +2186,45 @@
});
});
+ describe('Model submit function (edit l7 policy)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7policy', 'l7policy1', '1234', '1234');
+ scope.$apply();
+ });
+
+ it('should set final spec properties', function() {
+ var finalSpec = model.submit();
+
+ expect(finalSpec.loadbalancer_id).toBe('1234');
+ expect(finalSpec.parentResourceId).toBe('1234');
+ expect(finalSpec.loadbalancer).toBeUndefined();
+ expect(finalSpec.listener).toBeDefined();
+
+ expect(finalSpec.l7policy.action).toBe('REDIRECT_TO_URL');
+ });
+
+ });
+
+ describe('Model submit function (edit l7 rule)', function() {
+
+ beforeEach(function() {
+ model.initialize('l7rule', '1234', '1234', '1234');
+ scope.$apply();
+ });
+
+ it('should set final spec properties', function() {
+ var finalSpec = model.submit();
+
+ expect(finalSpec.loadbalancer_id).toBe('1234');
+ expect(finalSpec.parentResourceId).toBe('1234');
+ expect(finalSpec.loadbalancer).toBeUndefined();
+
+ expect(finalSpec.l7rule.type).toBe('HOST_NAME');
+ });
+
+ });
+
describe('Model submit function (edit pool)', function() {
beforeEach(function() {
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js
index 10ae18e6..e04f312c 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js
@@ -42,6 +42,20 @@
helpUrl: basePath + 'workflow/listener/listener.help.html',
formName: 'listenerDetailsForm'
},
+ {
+ id: 'l7policy',
+ title: gettext('L7 Policy Details'),
+ templateUrl: basePath + 'workflow/l7policy/l7policy.html',
+ helpUrl: basePath + 'workflow/l7policy/l7policy.help.html',
+ formName: 'l7policyDetailsForm'
+ },
+ {
+ id: 'l7rule',
+ title: gettext('L7 Rule Details'),
+ templateUrl: basePath + 'workflow/l7rule/l7rule.html',
+ helpUrl: basePath + 'workflow/l7rule/l7rule.help.html',
+ formName: 'l7ruleDetailsForm'
+ },
{
id: 'pool',
title: gettext('Pool Details'),
diff --git a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js
index 14ad72cc..22e73c02 100644
--- a/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js
+++ b/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js
@@ -44,11 +44,13 @@
it('should have default steps defined', function () {
var workflow = workflowService('My Workflow');
expect(workflow.steps).toBeDefined();
- expect(workflow.steps.length).toBe(6);
+ expect(workflow.steps.length).toBe(8);
var forms = [
'loadBalancerDetailsForm',
'listenerDetailsForm',
+ 'l7policyDetailsForm',
+ 'l7ruleDetailsForm',
'poolDetailsForm',
'memberDetailsForm',
'monitorDetailsForm',
diff --git a/releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml b/releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml
new file mode 100644
index 00000000..5f19cd27
--- /dev/null
+++ b/releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Adds L7 policy support to the dashboard.