OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

372 lines
14 KiB

# Copyright (c) 2015 Thales Services SAS
# 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
# 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.
import functools
import fixtures
import netaddr
from neutron_lib.api.definitions import portbindings
from neutron_lib import constants
from neutronclient.common import exceptions
from neutron.common import utils
def _safe_method(f):
def delete(*args, **kwargs):
return f(*args, **kwargs)
except exceptions.NotFound:
return delete
class ClientFixture(fixtures.Fixture):
"""Manage and cleanup neutron resources."""
def __init__(self, client):
super(ClientFixture, self).__init__()
self.client = client
def _create_resource(self, resource_type, spec):
create = getattr(self.client, 'create_%s' % resource_type)
delete = getattr(self.client, 'delete_%s' % resource_type)
body = {resource_type: spec}
resp = create(body=body)
data = resp[resource_type]
self.addCleanup(_safe_method(delete), data['id'])
return data
def _update_resource(self, resource_type, id, spec):
update = getattr(self.client, 'update_%s' % resource_type)
body = {resource_type: spec}
resp = update(id, body=body)
return resp[resource_type]
def _delete_resource(self, resource_type, id):
delete = getattr(self.client, 'delete_%s' % resource_type)
return delete(id)
def create_router(self, tenant_id, name=None, ha=False,
external_network=None, external_subnet=None):
resource_type = 'router'
name = name or utils.get_rand_name(prefix=resource_type)
spec = {'tenant_id': tenant_id, 'name': name, 'ha': ha}
if external_network:
spec['external_gateway_info'] = {"network_id": external_network}
if external_subnet:
spec['external_gateway_info']['external_fixed_ips'] = (
[{"subnet_id": external_subnet}])
return self._create_resource(resource_type, spec)
def update_router(self, router_id, **kwargs):
return self._update_resource('router', router_id, kwargs)
def create_segment(self, project_id, network, name, network_type=None,
segmentation_id=None, physical_network=None):
resource_type = 'segment'
name = name or utils.get_rand_name(prefix=resource_type)
spec = {'project_id': project_id, 'name': name, 'network_id': network,
'network_type': network_type,
'physical_network': physical_network,
'segmentation_id': segmentation_id}
return self._create_resource(resource_type, spec)
def create_network(self, tenant_id, name=None, external=False,
network_type=None, segmentation_id=None,
physical_network=None, mtu=None, qos_policy_id=None):
resource_type = 'network'
name = name or utils.get_rand_name(prefix=resource_type)
spec = {'tenant_id': tenant_id, 'name': name}
spec['router:external'] = external
if segmentation_id is not None:
spec['provider:segmentation_id'] = segmentation_id
if network_type is not None:
spec['provider:network_type'] = network_type
if physical_network is not None:
spec['provider:physical_network'] = physical_network
if mtu is not None:
spec['mtu'] = mtu
if qos_policy_id is not None:
spec['qos_policy_id'] = qos_policy_id
return self._create_resource(resource_type, spec)
def update_network(self, id, **kwargs):
return self._update_resource('network', id, kwargs)
def delete_network(self, id):
return self._delete_resource('network', id)
def create_subnet(self, tenant_id, network_id,
cidr, gateway_ip=None, name=None, enable_dhcp=True,
ipv6_address_mode='slaac', ipv6_ra_mode='slaac',
subnetpool_id=None, ip_version=None):
resource_type = 'subnet'
name = name or utils.get_rand_name(prefix=resource_type)
if cidr and not ip_version:
ip_version = netaddr.IPNetwork(cidr).version
spec = {'tenant_id': tenant_id, 'network_id': network_id, 'name': name,
'enable_dhcp': enable_dhcp, 'ip_version': ip_version}
if ip_version == constants.IP_VERSION_6:
spec['ipv6_address_mode'] = ipv6_address_mode
spec['ipv6_ra_mode'] = ipv6_ra_mode
if gateway_ip:
spec['gateway_ip'] = gateway_ip
if subnetpool_id:
spec['subnetpool_id'] = subnetpool_id
if cidr:
spec['cidr'] = cidr
return self._create_resource(resource_type, spec)
def list_subnets(self, retrieve_all=True, **kwargs):
resp = self.client.list_subnets(retrieve_all=retrieve_all, **kwargs)
return resp['subnets']
def list_ports(self, retrieve_all=True, **kwargs):
resp = self.client.list_ports(retrieve_all=retrieve_all, **kwargs)
return resp['ports']
def create_port(self, tenant_id, network_id, hostname=None,
qos_policy_id=None, security_groups=None, **kwargs):
spec = {
'network_id': network_id,
'tenant_id': tenant_id,
if hostname is not None:
spec[portbindings.HOST_ID] = hostname
if qos_policy_id:
spec['qos_policy_id'] = qos_policy_id
if security_groups:
spec['security_groups'] = security_groups
return self._create_resource('port', spec)
def update_port(self, port_id, **kwargs):
return self._update_resource('port', port_id, kwargs)
def create_floatingip(self, tenant_id, floating_network_id,
fixed_ip_address, port_id, qos_policy_id=None):
spec = {
'floating_network_id': floating_network_id,
'tenant_id': tenant_id,
'fixed_ip_address': fixed_ip_address,
'port_id': port_id
if qos_policy_id:
spec['qos_policy_id'] = qos_policy_id
return self._create_resource('floatingip', spec)
def add_router_interface(self, router_id, subnet_id):
body = {'subnet_id': subnet_id}
router_interface_info = self.client.add_interface_router(
router=router_id, body=body)
router=router_id, body=body)
return router_interface_info
def create_qos_policy(self, tenant_id, name, description, shared,
policy = self.client.create_qos_policy(
body={'policy': {'name': name,
'description': description,
'shared': shared,
'tenant_id': tenant_id,
'is_default': is_default}})
def detach_and_delete_policy():
qos_policy_id = policy['policy']['id']
ports_with_policy = self.client.list_ports()['ports']
for port in ports_with_policy:
if qos_policy_id == port['qos_policy_id']:
body={'port': {'qos_policy_id': None}})
# NOTE: We'll need to add support for detaching from network once
# create_network() supports qos_policy_id.
return policy['policy']
def create_bandwidth_limit_rule(self, tenant_id, qos_policy_id, limit=None,
burst=None, direction=None):
rule = {'tenant_id': tenant_id}
if limit:
rule['max_kbps'] = limit
if burst:
rule['max_burst_kbps'] = burst
if direction:
rule['direction'] = direction
rule = self.client.create_bandwidth_limit_rule(
body={'bandwidth_limit_rule': rule})
return rule['bandwidth_limit_rule']
def create_minimum_bandwidth_rule(self, tenant_id, qos_policy_id,
min_bw, direction=None):
rule = {'tenant_id': tenant_id,
'min_kbps': min_bw}
if direction:
rule['direction'] = direction
rule = self.client.create_minimum_bandwidth_rule(
body={'minimum_bandwidth_rule': rule})
rule['minimum_bandwidth_rule']['id'], qos_policy_id)
return rule['minimum_bandwidth_rule']
def create_dscp_marking_rule(self, tenant_id, qos_policy_id, dscp_mark=0):
rule = {'tenant_id': tenant_id}
if dscp_mark:
rule['dscp_mark'] = dscp_mark
rule = self.client.create_dscp_marking_rule(
body={'dscp_marking_rule': rule})
return rule['dscp_marking_rule']
def create_trunk(self, tenant_id, port_id, name=None,
admin_state_up=None, sub_ports=None):
"""Create a trunk via API.
:param tenant_id: ID of the tenant.
:param port_id: Parent port of trunk.
:param name: Name of the trunk.
:param admin_state_up: Admin state of the trunk.
:param sub_ports: List of subport dictionaries in format
{'port_id': <ID of neutron port for subport>,
'segmentation_type': 'vlan',
'segmentation_id': <VLAN tag>}
:return: Dictionary with trunk's data returned from Neutron API.
spec = {
'port_id': port_id,
'tenant_id': tenant_id,
if name is not None:
spec['name'] = name
if sub_ports is not None:
spec['sub_ports'] = sub_ports
if admin_state_up is not None:
spec['admin_state_up'] = admin_state_up
trunk = self.client.create_trunk({'trunk': spec})['trunk']
if sub_ports:
tenant_id, trunk['id'], trunk['sub_ports'])
self.addCleanup(_safe_method(self.client.delete_trunk), trunk['id'])
return trunk
def trunk_add_subports(self, tenant_id, trunk_id, sub_ports):
"""Add subports to the trunk.
:param tenant_id: ID of the tenant.
:param trunk_id: ID of the trunk.
:param sub_ports: List of subport dictionaries to be added in format
{'port_id': <ID of neutron port for subport>,
'segmentation_type': 'vlan',
'segmentation_id': <VLAN tag>}
spec = {
'tenant_id': tenant_id,
'sub_ports': sub_ports,
trunk = self.client.trunk_add_subports(trunk_id, spec)
sub_ports_to_remove = [
sub_port for sub_port in trunk['sub_ports']
if sub_port in sub_ports]
_safe_method(self.trunk_remove_subports), tenant_id, trunk_id,
def trunk_remove_subports(self, tenant_id, trunk_id, sub_ports):
"""Remove subports from the trunk.
:param trunk_id: ID of the trunk.
:param sub_ports: List of subport port IDs.
spec = {
'tenant_id': tenant_id,
'sub_ports': sub_ports,
return self.client.trunk_remove_subports(trunk_id, spec)
def create_security_group(self, tenant_id, name=None, stateful=True):
resource_type = 'security_group'
name = name or utils.get_rand_name(prefix=resource_type)
spec = {'tenant_id': tenant_id, 'name': name, 'stateful': stateful}
return self._create_resource(resource_type, spec)
def update_security_group(self, security_group_id, **kwargs):
return self._update_resource('security_group', security_group_id,
def create_security_group_rule(self, tenant_id, security_group_id,
resource_type = 'security_group_rule'
spec = {'tenant_id': tenant_id,
'security_group_id': security_group_id}
return self._create_resource(resource_type, spec)
def create_network_log(self, tenant_id, resource_type,
enabled=True, **kwargs):
spec = {'project_id': tenant_id,
'resource_type': resource_type,
'enabled': enabled}
net_log = self.client.create_network_log({'log': spec})
_safe_method(self.client.delete_network_log), net_log['log']['id'])
return net_log
def update_quota(self, project_id, tracked_resource, quota):
self._update_resource('quota', project_id, {tracked_resource: quota})