Boden R 22618a005b nsx v3 lport refactor
this patch refactors the nsx v3 logical switch port functions
into the rest client/resource model and updates all refs
to these functions to use an nsx v3 client. the patch also
adds support for passing switch profile ids to the lport create.
this functionality will be leveraged in subsequent port
security change sets.

Change-Id: I1cf86a7f3127f637735560f1ad60eb36edac7500
2015-09-21 13:34:15 -06:00

324 lines
12 KiB
Python

# Copyright 2015 OpenStack Foundation
# 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 oslo_config import cfg
from oslo_log import log
from neutron.i18n import _LW
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import nsx_constants
from vmware_nsx.common import utils
from vmware_nsx.nsxlib.v3 import client
LOG = log.getLogger(__name__)
# TODO(berlin): move them to nsx_constants file
# Router logical port types
LROUTERPORT_UPLINK = "LogicalRouterUplinkPort"
LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort"
LROUTERPORT_LINK = "LogicalRouterLinkPort"
LROUTER_TYPES = [LROUTERPORT_UPLINK,
LROUTERPORT_DOWNLINK,
LROUTERPORT_LINK]
def get_edge_cluster(edge_cluster_uuid):
resource = "edge-clusters/%s" % edge_cluster_uuid
return client.get_resource(resource)
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision)
def update_resource_with_retry(resource, payload):
revised_payload = client.get_resource(resource)
for key_name in payload.keys():
revised_payload[key_name] = payload[key_name]
return client.update_resource(resource, revised_payload)
def delete_resource_by_values(resource, res_id='id', skip_not_found=True,
**kwargs):
resources_get = client.get_resource(resource)
for res in resources_get['results']:
is_matched = True
for (key, value) in kwargs.items():
if res.get(key) != value:
is_matched = False
break
if is_matched:
LOG.debug("Deleting %s from resource %s", res, resource)
delete_resource = resource + "/" + str(res[res_id])
client.delete_resource(delete_resource)
return
if skip_not_found:
LOG.warning(_LW("No resource in %(res)s matched for values: "
"%(values)s"), {'res': resource,
'values': kwargs})
else:
err_msg = (_("No resource in %(res)s matched for values: %(values)s") %
{'res': resource,
'values': kwargs})
raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(),
operation=err_msg)
def create_logical_switch(display_name, transport_zone_id, tags,
replication_mode=nsx_constants.MTEP,
admin_state=True, vlan_id=None):
# TODO(salv-orlando): Validate Replication mode and admin_state
# NOTE: These checks might be moved to the API client library if one that
# performs such checks in the client is available
resource = 'logical-switches'
body = {'transport_zone_id': transport_zone_id,
'replication_mode': replication_mode,
'display_name': display_name,
'tags': tags}
if admin_state:
body['admin_state'] = nsx_constants.ADMIN_STATE_UP
else:
body['admin_state'] = nsx_constants.ADMIN_STATE_DOWN
if vlan_id:
body['vlan'] = vlan_id
return client.create_resource(resource, body)
def delete_logical_switch(lswitch_id):
resource = 'logical-switches/%s?detach=true&cascade=true' % lswitch_id
client.delete_resource(resource)
def get_logical_switch(logical_switch_id):
resource = "logical-switches/%s" % logical_switch_id
return client.get_resource(resource)
@utils.retry_upon_exception_nsxv3(nsx_exc.StaleRevision,
max_attempts=cfg.CONF.nsx_v3.retries)
def update_logical_switch(lswitch_id, name=None, admin_state=None):
resource = "logical-switches/%s" % lswitch_id
lswitch = get_logical_switch(lswitch_id)
if name is not None:
lswitch['display_name'] = name
if admin_state is not None:
if admin_state:
lswitch['admin_state'] = nsx_constants.ADMIN_STATE_UP
else:
lswitch['admin_state'] = nsx_constants.ADMIN_STATE_DOWN
return client.update_resource(resource, lswitch)
def create_logical_router(display_name, tags,
edge_cluster_uuid=None, tier_0=False):
# TODO(salv-orlando): If possible do not manage edge clusters in the main
# plugin logic.
router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else
nsx_constants.ROUTER_TYPE_TIER1)
resource = 'logical-routers'
body = {'display_name': display_name,
'router_type': router_type,
'tags': tags}
if edge_cluster_uuid:
body['edge_cluster_id'] = edge_cluster_uuid
return client.create_resource(resource, body)
def get_logical_router(lrouter_id):
resource = 'logical-routers/%s' % lrouter_id
return client.get_resource(resource)
def update_logical_router(lrouter_id, **kwargs):
resource = 'logical-routers/%s' % lrouter_id
return update_resource_with_retry(resource, kwargs)
def delete_logical_router(lrouter_id):
# TODO(berlin): need to verify whether cascade prefix is valid to delete
# router link port and its relative nat rules
resource = 'logical-routers/%s/' % lrouter_id
# TODO(salv-orlando): Must handle connection exceptions
return client.delete_resource(resource)
def get_logical_router_port_by_ls_id(logical_switch_id):
resource = 'logical-router-ports?logical_switch_id=%s' % logical_switch_id
router_ports = client.get_resource(resource)
if int(router_ports['result_count']) >= 2:
raise nsx_exc.NsxPluginException(
err_msg=_("Can't support more than one logical router ports "
"on same logical switch %s ") % logical_switch_id)
elif int(router_ports['result_count']) == 1:
return router_ports['results'][0]
else:
err_msg = (_("Logical router link port not found on logical "
"switch %s") % logical_switch_id)
raise nsx_exc.ResourceNotFound(manager=client._get_manager_ip(),
operation=err_msg)
def create_logical_router_port(logical_router_id,
display_name,
resource_type,
logical_port_id,
address_groups,
edge_cluster_member_index=None):
resource = 'logical-router-ports'
body = {'display_name': display_name,
'resource_type': resource_type,
'logical_router_id': logical_router_id}
if address_groups:
body['subnets'] = address_groups
if resource_type in [LROUTERPORT_UPLINK,
LROUTERPORT_DOWNLINK]:
body['linked_logical_switch_port_id'] = logical_port_id
elif logical_port_id:
body['linked_logical_router_port_id'] = logical_port_id
if edge_cluster_member_index:
body['edge_cluster_member_index'] = edge_cluster_member_index
return client.create_resource(resource, body)
def update_logical_router_port_by_ls_id(logical_router_id, ls_id,
**payload):
port = get_logical_router_port_by_ls_id(ls_id)
return update_logical_router_port(port['id'], **payload)
def update_logical_router_port(logical_port_id, **kwargs):
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
return update_resource_with_retry(resource, kwargs)
def delete_logical_router_port_by_ls_id(ls_id):
port = get_logical_router_port_by_ls_id(ls_id)
delete_logical_router_port(port['id'])
def delete_logical_router_port(logical_port_id):
resource = 'logical-router-ports/%s?detach=true' % logical_port_id
client.delete_resource(resource)
def get_logical_router_ports_by_router_id(logical_router_id):
resource = 'logical-router-ports'
logical_router_ports = client.get_resource(
resource, logical_router_id=logical_router_id)
return logical_router_ports['results']
def get_tier1_logical_router_link_port(logical_router_id):
logical_router_ports = get_logical_router_ports_by_router_id(
logical_router_id)
for port in logical_router_ports:
if port['resource_type'] == LROUTERPORT_LINK:
return port
raise nsx_exc.ResourceNotFound(
manager=client._get_manager_ip(),
operation="get router link port")
def add_nat_rule(logical_router_id, action, translated_network,
source_net=None, dest_net=None,
enabled=True, rule_priority=None):
resource = 'logical-routers/%s/nat/rules' % logical_router_id
body = {'action': action,
'enabled': enabled,
'translated_network': translated_network}
if source_net:
body['match_source_network'] = source_net
if dest_net:
body['match_destination_network'] = dest_net
if rule_priority:
body['rule_priority'] = rule_priority
return client.create_resource(resource, body)
def delete_nat_rule(logical_router_id, nat_rule_id):
resource = 'logical-routers/%s/nat/rules/%s' % (logical_router_id,
nat_rule_id)
client.delete_resource(resource)
def delete_nat_rule_by_values(logical_router_id, **kwargs):
resource = 'logical-routers/%s/nat/rules' % logical_router_id
return delete_resource_by_values(resource, res_id='rule_id', **kwargs)
def update_logical_router_advertisement(logical_router_id, **kwargs):
resource = 'logical-routers/%s/routing/advertisement' % logical_router_id
return update_resource_with_retry(resource, kwargs)
def create_qos_switching_profile(tags, qos_marking=None, dscp=None, name=None,
description=None):
resource = 'switching-profiles'
body = {"resource_type": "QosSwitchingProfile",
"tags": tags}
# TODO(abhide): Add TrafficShaper configuration.
if qos_marking:
body["dscp"] = {}
body["dscp"]["mode"] = qos_marking.upper()
if dscp:
body["dscp"]["priority"] = dscp
if name:
body["display_name"] = name
if description:
body["description"] = description
return client.create_resource(resource, body)
def get_qos_switching_profile(profile_id):
resource = 'switching-profiles/%s' % profile_id
return client.get_resource(resource)
def delete_qos_switching_profile(profile_id):
resource = 'switching-profiles/%s' % profile_id
client.delete_resource(resource)
def create_bridge_endpoint(device_name, seg_id, tags):
"""Create a bridge endpoint on the backend.
Create a bridge endpoint resource on a bridge cluster for the L2 gateway
network connection.
:param device_name: device_name actually refers to the bridge cluster's
UUID.
:param seg_id: integer representing the VLAN segmentation ID.
:param tags: nsx backend specific tags.
"""
resource = 'bridge-endpoints'
body = {'bridge_cluster_id': device_name,
'tags': tags,
'vlan': seg_id}
return client.create_resource(resource, body)
def delete_bridge_endpoint(bridge_endpoint_id):
"""Delete a bridge endpoint on the backend.
:param bridge_endpoint_id: string representing the UUID of the bridge
endpoint to be deleted.
"""
resource = 'bridge-endpoints/%s' % bridge_endpoint_id
client.delete_resource(resource)