vmware-nsx/vmware_nsx/services/lbaas/nsx_v3/lb_utils.py

181 lines
7.1 KiB
Python

# Copyright 2017 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.db import l3_db
from neutron.services.flavors import flavors_plugin
from neutron_lib import exceptions as n_exc
from vmware_nsx._i18n import _
from vmware_nsx.db import db as nsx_db
from vmware_nsx.services.lbaas import lb_const
from vmware_nsxlib.v3 import utils
def get_tags(plugin, resource_id, resource_type, project_id, project_name):
resource = {'project_id': project_id,
'id': resource_id}
tags = plugin.nsxlib.build_v3_tags_payload(
resource, resource_type=resource_type,
project_name=project_name)
return tags
def get_network_from_subnet(context, plugin, subnet_id):
subnet = plugin.get_subnet(context, subnet_id)
if subnet:
return plugin.get_network(context, subnet['network_id'])
def get_router_from_network(context, plugin, subnet_id):
subnet = plugin.get_subnet(context, subnet_id)
network_id = subnet['network_id']
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
'network_id': [network_id]}
ports = plugin.get_ports(context, filters=port_filters)
if ports:
return ports[0]['device_id']
def get_lb_router_id(context, plugin, lb):
router_client = plugin.nsxlib.logical_router
name = utils.get_name_and_uuid(lb.name or 'router', lb.id)
tags = get_tags(plugin, lb.id, lb_const.LB_LB_TYPE, lb.tenant_id,
context.project_name)
edge_cluster_uuid = plugin._get_edge_cluster(plugin._default_tier0_router)
lb_router = router_client.create(name, tags, edge_cluster_uuid)
return lb_router
def get_lb_flavor_size(flavor_plugin, context, flavor_id):
if not flavor_id:
return lb_const.DEFAULT_LB_SIZE
else:
flavor = flavors_plugin.FlavorsPlugin.get_flavor(
flavor_plugin, context, flavor_id)
flavor_size = flavor['name']
if flavor_size in lb_const.LB_FLAVOR_SIZES:
return flavor_size.upper()
else:
err_msg = (_("Invalid flavor size %(flavor)s, only 'small', "
"'medium', or 'large' are supported") %
{'flavor': flavor_size})
raise n_exc.InvalidInput(error_message=err_msg)
def validate_lb_subnet(context, plugin, subnet_id):
'''Validate LB subnet before creating loadbalancer on it.
To create a loadbalancer, the network has to be either an external
network or private network that connects to a tenant router. It will
throw exception if the network doesn't meet this requirement.
:param context: context
:param plugin: core plugin
:param subnet_id: loadbalancer's subnet id
:return: True if subnet meet requirement, otherwise return False
'''
network = get_network_from_subnet(context, plugin, subnet_id)
router_id = get_router_from_network(
context, plugin, subnet_id)
if network.get('router:external') or router_id:
return True
else:
return False
def get_rule_match_conditions(policy):
match_conditions = []
# values in rule have already been validated in LBaaS API,
# we won't need to valid anymore in driver, and just get
# the LB rule mapping from the dict.
for rule in policy.rules:
match_type = lb_const.LB_RULE_MATCH_TYPE[rule.compare_type]
if rule.type == lb_const.L7_RULE_TYPE_COOKIE:
header_value = rule.key + '=' + rule.value
match_conditions.append(
{'type': 'LbHttpRequestHeaderCondition',
'match_type': match_type,
'header_name': 'Cookie',
'header_value': header_value})
elif rule.type == lb_const.L7_RULE_TYPE_FILE_TYPE:
match_conditions.append(
{'type': 'LbHttpRequestUriCondition',
'match_type': match_type,
'uri': '*.' + rule.value})
elif rule.type == lb_const.L7_RULE_TYPE_HEADER:
match_conditions.append(
{'type': 'LbHttpRequestHeaderCondition',
'match_type': match_type,
'header_name': rule.key,
'header_value': rule.value})
elif rule.type == lb_const.L7_RULE_TYPE_HOST_NAME:
match_conditions.append(
{'type': 'LbHttpRequestHeaderCondition',
'match_type': match_type,
'header_name': 'Host',
'header_value': rule.value})
elif rule.type == lb_const.L7_RULE_TYPE_PATH:
match_conditions.append(
{'type': 'LbHttpRequestUriCondition',
'match_type': match_type,
'uri': rule.value})
else:
msg = (_('l7rule type %(type)s is not supported in LBaaS') %
{'type': rule.type})
raise n_exc.BadRequest(resource='lbaas-l7rule', msg=msg)
return match_conditions
def get_rule_actions(context, l7policy):
lb_id = l7policy.listener.loadbalancer_id
if l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_POOL:
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
context.session, lb_id, l7policy.redirect_pool_id)
if pool_binding:
lb_pool_id = pool_binding['lb_pool_id']
actions = [{'type': lb_const.LB_SELECT_POOL_ACTION,
'pool_id': lb_pool_id}]
else:
msg = _('Failed to get LB pool binding from nsx db')
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
msg=msg)
elif l7policy.action == lb_const.L7_POLICY_ACTION_REDIRECT_TO_URL:
actions = [{'type': lb_const.LB_HTTP_REDIRECT_ACTION,
'redirect_status': lb_const.LB_HTTP_REDIRECT_STATUS,
'redirect_url': l7policy.redirect_url}]
elif l7policy.action == lb_const.L7_POLICY_ACTION_REJECT:
actions = [{'type': lb_const.LB_REJECT_ACTION,
'reply_status': lb_const.LB_HTTP_REJECT_STATUS}]
else:
msg = (_('Invalid l7policy action: %(action)s') %
{'action': l7policy.action})
raise n_exc.BadRequest(resource='lbaas-l7rule-create',
msg=msg)
return actions
def convert_l7policy_to_lb_rule(context, policy):
return {
'match_conditions': get_rule_match_conditions(policy),
'actions': get_rule_actions(context, policy),
'phase': lb_const.LB_RULE_HTTP_FORWARDING,
'match_strategy': 'ALL'
}
def remove_rule_from_policy(rule):
l7rules = rule.policy.rules
rule.policy.rules = [r for r in l7rules if r.id != rule.id]