b6bd7e49d1
Change-Id: I6909c10471039f1e68224679ceeb2867ab5a3a47
203 lines
8.3 KiB
Python
203 lines
8.3 KiB
Python
# Copyright 2014 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_lib import exceptions as exception
|
|
from oslo_config import cfg
|
|
from oslo_log import log
|
|
from oslo_serialization import jsonutils
|
|
|
|
from vmware_nsx.api_client import exception as api_exc
|
|
from vmware_nsx.common import utils
|
|
from vmware_nsx.nsxlib import mh as nsxlib
|
|
|
|
HTTP_GET = "GET"
|
|
HTTP_POST = "POST"
|
|
HTTP_DELETE = "DELETE"
|
|
HTTP_PUT = "PUT"
|
|
|
|
LSWITCH_RESOURCE = "lswitch"
|
|
LSWITCHPORT_RESOURCE = "lport/%s" % LSWITCH_RESOURCE
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
def _configure_extensions(lport_obj, mac_address, fixed_ips,
|
|
port_security_enabled, security_profiles,
|
|
queue_id, mac_learning_enabled,
|
|
allowed_address_pairs):
|
|
lport_obj['allowed_address_pairs'] = []
|
|
if port_security_enabled:
|
|
for fixed_ip in fixed_ips:
|
|
ip_address = fixed_ip.get('ip_address')
|
|
if ip_address:
|
|
lport_obj['allowed_address_pairs'].append(
|
|
{'mac_address': mac_address, 'ip_address': ip_address})
|
|
# add address pair allowing src_ip 0.0.0.0 to leave
|
|
# this is required for outgoing dhcp request
|
|
lport_obj["allowed_address_pairs"].append(
|
|
{"mac_address": mac_address,
|
|
"ip_address": "0.0.0.0"})
|
|
lport_obj['security_profiles'] = list(security_profiles or [])
|
|
lport_obj['queue_uuid'] = queue_id
|
|
if mac_learning_enabled is not None:
|
|
lport_obj["mac_learning"] = mac_learning_enabled
|
|
lport_obj["type"] = "LogicalSwitchPortConfig"
|
|
for address_pair in list(allowed_address_pairs or []):
|
|
lport_obj['allowed_address_pairs'].append(
|
|
{'mac_address': address_pair['mac_address'],
|
|
'ip_address': address_pair['ip_address']})
|
|
|
|
|
|
def get_lswitches(cluster, neutron_net_id):
|
|
|
|
def lookup_switches_by_tag():
|
|
# Fetch extra logical switches
|
|
lswitch_query_path = nsxlib._build_uri_path(
|
|
LSWITCH_RESOURCE,
|
|
fields="uuid,display_name,tags,lport_count",
|
|
relations="LogicalSwitchStatus",
|
|
filters={'tag': neutron_net_id,
|
|
'tag_scope': 'quantum_net_id'})
|
|
return nsxlib.get_all_query_pages(lswitch_query_path, cluster)
|
|
|
|
lswitch_uri_path = nsxlib._build_uri_path(LSWITCH_RESOURCE, neutron_net_id,
|
|
relations="LogicalSwitchStatus")
|
|
results = []
|
|
try:
|
|
ls = nsxlib.do_request(HTTP_GET, lswitch_uri_path, cluster=cluster)
|
|
results.append(ls)
|
|
for tag in ls['tags']:
|
|
if (tag['scope'] == "multi_lswitch" and
|
|
tag['tag'] == "True"):
|
|
results.extend(lookup_switches_by_tag())
|
|
except exception.NotFound:
|
|
# This is legit if the neutron network was created using
|
|
# a post-Havana version of the plugin
|
|
results.extend(lookup_switches_by_tag())
|
|
if results:
|
|
return results
|
|
raise exception.NetworkNotFound(net_id=neutron_net_id)
|
|
|
|
|
|
# This api is currently used only for unittests
|
|
def create_lswitch(cluster, neutron_net_id, tenant_id, display_name,
|
|
transport_zones_config,
|
|
shared=None,
|
|
**kwargs):
|
|
# The tag scope adopts a slightly different naming convention for
|
|
# historical reasons
|
|
lswitch_obj = {"display_name": utils.check_and_truncate(display_name),
|
|
"transport_zones": transport_zones_config,
|
|
"replication_mode": cfg.CONF.NSX.replication_mode,
|
|
"tags": utils.get_tags(os_tid=tenant_id,
|
|
quantum_net_id=neutron_net_id)}
|
|
# TODO(salv-orlando): Now that we have async status synchronization
|
|
# this tag is perhaps not needed anymore
|
|
if shared:
|
|
lswitch_obj["tags"].append({"tag": "true",
|
|
"scope": "shared"})
|
|
if "tags" in kwargs:
|
|
lswitch_obj["tags"].extend(kwargs["tags"])
|
|
uri = nsxlib._build_uri_path(LSWITCH_RESOURCE)
|
|
lswitch = nsxlib.do_request(HTTP_POST, uri, jsonutils.dumps(lswitch_obj),
|
|
cluster=cluster)
|
|
LOG.debug("Created logical switch: %s", lswitch['uuid'])
|
|
return lswitch
|
|
|
|
|
|
def delete_port(cluster, switch, port):
|
|
uri = "/ws.v1/lswitch/" + switch + "/lport/" + port
|
|
try:
|
|
nsxlib.do_request(HTTP_DELETE, uri, cluster=cluster)
|
|
except exception.NotFound as e:
|
|
LOG.error("Port or Network not found, Error: %s", str(e))
|
|
raise exception.PortNotFoundOnNetwork(
|
|
net_id=switch, port_id=port)
|
|
except api_exc.NsxApiException:
|
|
raise exception.NeutronException()
|
|
|
|
|
|
def get_port_by_neutron_tag(cluster, lswitch_uuid, neutron_port_id):
|
|
"""Get port by neutron tag.
|
|
|
|
Returns the NSX UUID of the logical port with tag q_port_id equal to
|
|
neutron_port_id or None if the port is not Found.
|
|
"""
|
|
uri = nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
|
|
parent_resource_id=lswitch_uuid,
|
|
fields='uuid',
|
|
filters={'tag': neutron_port_id,
|
|
'tag_scope': 'q_port_id'})
|
|
LOG.debug("Looking for port with q_port_id tag '%(neutron_port_id)s' "
|
|
"on: '%(lswitch_uuid)s'",
|
|
{'neutron_port_id': neutron_port_id,
|
|
'lswitch_uuid': lswitch_uuid})
|
|
res = nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
|
|
num_results = len(res["results"])
|
|
if num_results >= 1:
|
|
if num_results > 1:
|
|
LOG.warning("Found '%(num_ports)d' ports with "
|
|
"q_port_id tag: '%(neutron_port_id)s'. "
|
|
"Only 1 was expected.",
|
|
{'num_ports': num_results,
|
|
'neutron_port_id': neutron_port_id})
|
|
return res["results"][0]
|
|
|
|
|
|
# This api is currently used only for unittests
|
|
def get_port(cluster, network, port, relations=None):
|
|
LOG.info("get_port() %(network)s %(port)s",
|
|
{'network': network, 'port': port})
|
|
uri = "/ws.v1/lswitch/" + network + "/lport/" + port + "?"
|
|
if relations:
|
|
uri += "relations=%s" % relations
|
|
try:
|
|
return nsxlib.do_request(HTTP_GET, uri, cluster=cluster)
|
|
except exception.NotFound as e:
|
|
LOG.error("Port or Network not found, Error: %s", str(e))
|
|
raise exception.PortNotFoundOnNetwork(
|
|
port_id=port, net_id=network)
|
|
|
|
|
|
def create_lport(cluster, lswitch_uuid, tenant_id, neutron_port_id,
|
|
display_name, device_id, admin_status_enabled,
|
|
mac_address=None, fixed_ips=None, port_security_enabled=None,
|
|
security_profiles=None, queue_id=None,
|
|
mac_learning_enabled=None, allowed_address_pairs=None):
|
|
"""Creates a logical port on the assigned logical switch."""
|
|
display_name = utils.check_and_truncate(display_name)
|
|
lport_obj = dict(
|
|
admin_status_enabled=admin_status_enabled,
|
|
display_name=display_name,
|
|
tags=utils.get_tags(os_tid=tenant_id,
|
|
q_port_id=neutron_port_id,
|
|
vm_id=utils.device_id_to_vm_id(device_id))
|
|
)
|
|
|
|
_configure_extensions(lport_obj, mac_address, fixed_ips,
|
|
port_security_enabled, security_profiles,
|
|
queue_id, mac_learning_enabled,
|
|
allowed_address_pairs)
|
|
|
|
path = nsxlib._build_uri_path(LSWITCHPORT_RESOURCE,
|
|
parent_resource_id=lswitch_uuid)
|
|
result = nsxlib.do_request(HTTP_POST, path, jsonutils.dumps(lport_obj),
|
|
cluster=cluster)
|
|
|
|
LOG.debug("Created logical port %(result)s on logical switch %(uuid)s",
|
|
{'result': result['uuid'], 'uuid': lswitch_uuid})
|
|
return result
|