Merge "Remove HyperVNeutronPlugin"

This commit is contained in:
Jenkins 2015-03-05 01:12:13 +00:00 committed by Gerrit Code Review
commit 0f04be6e5e
12 changed files with 150 additions and 1052 deletions

View File

@ -1,63 +0,0 @@
[hyperv]
# (StrOpt) Type of network to allocate for tenant networks. The
# default value 'local' is useful only for single-box testing and
# provides no connectivity between hosts. You MUST either change this
# to 'vlan' and configure network_vlan_ranges below or to 'flat'.
# Set to 'none' to disable creation of tenant networks.
#
# tenant_network_type = local
# Example: tenant_network_type = vlan
# (ListOpt) Comma-separated list of
# <physical_network>[:<vlan_min>:<vlan_max>] tuples enumerating ranges
# of VLAN IDs on named physical networks that are available for
# allocation. All physical networks listed are available for flat and
# VLAN provider network creation. Specified ranges of VLAN IDs are
# available for tenant network allocation if tenant_network_type is
# 'vlan'. If empty, only gre and local networks may be created.
#
# network_vlan_ranges =
# Example: network_vlan_ranges = physnet1:1000:2999
[agent]
# Agent's polling interval in seconds
# polling_interval = 2
# (ListOpt) Comma separated list of <physical_network>:<vswitch>
# where the physical networks can be expressed with wildcards,
# e.g.: ."*:external".
# The referred external virtual switches need to be already present on
# the Hyper-V server.
# If a given physical network name will not match any value in the list
# the plugin will look for a virtual switch with the same name.
#
# physical_network_vswitch_mappings = *:external
# Example: physical_network_vswitch_mappings = net1:external1,net2:external2
# (StrOpt) Private virtual switch name used for local networking.
#
# local_network_vswitch = private
# Example: local_network_vswitch = custom_vswitch
# (BoolOpt) Enables metrics collections for switch ports by using Hyper-V's
# metric APIs. Collected data can by retrieved by other apps and services,
# e.g.: Ceilometer. Requires Hyper-V / Windows Server 2012 and above.
#
# enable_metrics_collection = False
#-----------------------------------------------------------------------------
# Sample Configurations.
#-----------------------------------------------------------------------------
#
# Neutron server:
#
# [HYPERV]
# tenant_network_type = vlan
# network_vlan_ranges = default:2000:3999
#
# Agent running on Hyper-V node:
#
# [AGENT]
# polling_interval = 2
# physical_network_vswitch_mappings = *:external
# local_network_vswitch = private

View File

@ -0,0 +1,149 @@
# Copyright 2015 OpenStack Foundation
#
# 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.
#
"""Remove Hyper-V Neutron Plugin
Migrates the contents of the tables 'hyperv_vlan_allocations' and
'hyperv_network_bindings' to 'ml2_vlan_allocations' and 'ml2_network_segments'
respectively, and then removes the tables.
Thse tables are used by HyperVNeutronPlugin, which will be removed.
Revision ID: 2b801560a332
Revises: 4119216b7365
Create Date: 2015-02-12 09:23:40.346104
"""
# revision identifiers, used by Alembic.
revision = '2b801560a332'
down_revision = '2d2a8a565438'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import expression as sa_expr
from neutron.extensions import portbindings
from neutron.openstack.common import uuidutils
from neutron.plugins.common import constants as p_const
FLAT_VLAN_ID = -1
LOCAL_VLAN_ID = -2
HYPERV = 'hyperv'
# Duplicated from neutron.plugins.linuxbridge.common.constants to
# avoid being dependent on it, as it will eventually be removed.
def _interpret_vlan_id(vlan_id):
"""Return (network_type, segmentation_id) tuple for encoded vlan_id."""
if vlan_id == LOCAL_VLAN_ID:
return (p_const.TYPE_LOCAL, None)
elif vlan_id == FLAT_VLAN_ID:
return (p_const.TYPE_FLAT, None)
else:
return (p_const.TYPE_VLAN, vlan_id)
def _migrate_segment_dict(binding):
binding['id'] = uuidutils.generate_uuid()
vlan_id = binding.pop('segmentation_id')
network_type, segmentation_id = _interpret_vlan_id(vlan_id)
binding['network_type'] = network_type
binding['segmentation_id'] = segmentation_id
def _migrate_vlan_allocations():
# Code similar to migrate_to_ml2.BaseMigrateToMl2.migrate_vlan_allocations
op.execute('INSERT INTO ml2_vlan_allocations '
'SELECT physical_network, vlan_id, allocated '
'FROM hyperv_vlan_allocations '
'WHERE allocated = TRUE')
def _migrate_network_segments(engine):
# Code similar to migrate_to_ml2.BaseMigrateToMl2.migrate_network_segments
source_table = sa_expr.table('hyperv_network_bindings')
source_segments = engine.execute(
sa_expr.select(['*'], from_obj=source_table))
ml2_segments = [dict(x) for x in source_segments]
for segment in ml2_segments:
_migrate_segment_dict(segment)
if ml2_segments:
ml2_network_segments = sa_expr.table('ml2_network_segments')
op.execute(ml2_network_segments.insert(), ml2_segments)
def _get_port_segment_map(engine):
# Code from migrate_to_ml2.BaseMigrateToMl2.get_port_segment_map
port_segments = engine.execute("""
SELECT ports_network.port_id, ml2_network_segments.id AS segment_id
FROM ml2_network_segments, (
SELECT portbindingports.port_id, ports.network_id
FROM portbindingports, ports
WHERE portbindingports.port_id = ports.id
) AS ports_network
WHERE ml2_network_segments.network_id = ports_network.network_id
""")
return dict(x for x in port_segments)
def _migrate_port_bindings(engine):
# Code similar to migrate_to_ml2.BaseMigrateToMl2.migrate_port_bindings
port_segment_map = _get_port_segment_map(engine)
port_binding_ports = sa_expr.table('portbindingports')
source_bindings = engine.execute(
sa_expr.select(['*'], from_obj=port_binding_ports))
ml2_bindings = [dict(x) for x in source_bindings]
for binding in ml2_bindings:
binding['vif_type'] = portbindings.VIF_TYPE_HYPERV
binding['driver'] = HYPERV
segment = port_segment_map.get(binding['port_id'])
if segment:
binding['segment'] = segment
if ml2_bindings:
ml2_port_bindings = sa_expr.table('ml2_port_bindings')
op.execute(ml2_port_bindings.insert(), ml2_bindings)
def upgrade():
bind = op.get_bind()
_migrate_vlan_allocations()
_migrate_network_segments(bind)
_migrate_port_bindings(bind)
op.drop_table('hyperv_vlan_allocations')
op.drop_table('hyperv_network_bindings')
def downgrade():
op.create_table(
'hyperv_vlan_allocations',
sa.Column('physical_network', sa.String(length=64), nullable=False),
sa.Column('vlan_id', sa.Integer(), autoincrement=False,
nullable=False),
sa.Column('allocated', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('physical_network', 'vlan_id'))
op.create_table(
'hyperv_network_bindings',
sa.Column('network_id', sa.String(length=36), nullable=False),
sa.Column('network_type', sa.String(length=32), nullable=False),
sa.Column('physical_network', sa.String(length=64), nullable=True),
sa.Column('segmentation_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['network_id'], ['networks.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('network_id'))

View File

@ -1 +1 @@
2d2a8a565438
2b801560a332

View File

@ -48,7 +48,6 @@ from neutron.plugins.brocade.db import models as brocade_models # noqa
from neutron.plugins.cisco.db.l3 import l3_models # noqa
from neutron.plugins.cisco.db import n1kv_models_v2 # noqa
from neutron.plugins.cisco.db import network_models_v2 # noqa
from neutron.plugins.hyperv import model # noqa
from neutron.plugins.linuxbridge.db import l2network_models_v2 # noqa
from neutron.plugins.metaplugin import meta_models_v2 # noqa
from neutron.plugins.ml2.drivers.arista import db # noqa

View File

@ -1,70 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# 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.
import oslo_messaging
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.plugins.hyperv.common import constants
class AgentNotifierApi(object):
'''Agent side of the openvswitch rpc API.
API version history:
1.0 - Initial version.
'''
def __init__(self, topic):
self.topic = topic
self.topic_network_delete = topics.get_topic_name(topic,
topics.NETWORK,
topics.DELETE)
self.topic_port_update = topics.get_topic_name(topic,
topics.PORT,
topics.UPDATE)
self.topic_port_delete = topics.get_topic_name(topic,
topics.PORT,
topics.DELETE)
self.topic_tunnel_update = topics.get_topic_name(topic,
constants.TUNNEL,
topics.UPDATE)
target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
def network_delete(self, context, network_id):
cctxt = self.client.prepare(topic=self.topic_network_delete,
fanout=True)
cctxt.cast(context, 'network_delete', network_id=network_id)
def port_update(self, context, port, network_type, segmentation_id,
physical_network):
cctxt = self.client.prepare(topic=self.topic_port_update,
fanout=True)
cctxt.cast(context, 'port_update', port=port,
network_type=network_type, segmentation_id=segmentation_id,
physical_network=physical_network)
def port_delete(self, context, port_id):
cctxt = self.client.prepare(topic=self.topic_port_delete,
fanout=True)
cctxt.cast(context, 'port_delete', port_id=port_id)
def tunnel_update(self, context, tunnel_ip, tunnel_id):
cctxt = self.client.prepare(topic=self.topic_tunnel_update,
fanout=True)
cctxt.cast(context, 'tunnel_update', tunnel_ip=tunnel_ip,
tunnel_id=tunnel_id)

View File

@ -1,214 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# 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 six import moves
from sqlalchemy.orm import exc
from neutron.common import exceptions as n_exc
import neutron.db.api as db_api
from neutron.db import models_v2
from neutron.i18n import _LW
from neutron.openstack.common import log as logging
from neutron.plugins.hyperv.common import constants
from neutron.plugins.hyperv import model as hyperv_model
LOG = logging.getLogger(__name__)
class HyperVPluginDB(object):
def reserve_vlan(self, session):
with session.begin(subtransactions=True):
alloc_q = session.query(hyperv_model.VlanAllocation)
alloc_q = alloc_q.filter_by(allocated=False)
alloc = alloc_q.first()
if alloc:
LOG.debug("Reserving vlan %(vlan_id)s on physical network "
"%(physical_network)s from pool",
{'vlan_id': alloc.vlan_id,
'physical_network': alloc.physical_network})
alloc.allocated = True
return (alloc.physical_network, alloc.vlan_id)
raise n_exc.NoNetworkAvailable()
def reserve_flat_net(self, session):
with session.begin(subtransactions=True):
alloc_q = session.query(hyperv_model.VlanAllocation)
alloc_q = alloc_q.filter_by(allocated=False,
vlan_id=constants.FLAT_VLAN_ID)
alloc = alloc_q.first()
if alloc:
LOG.debug("Reserving flat physical network "
"%(physical_network)s from pool",
{'physical_network': alloc.physical_network})
alloc.allocated = True
return alloc.physical_network
raise n_exc.NoNetworkAvailable()
def reserve_specific_vlan(self, session, physical_network, vlan_id):
with session.begin(subtransactions=True):
try:
alloc_q = session.query(hyperv_model.VlanAllocation)
alloc_q = alloc_q.filter_by(
physical_network=physical_network,
vlan_id=vlan_id)
alloc = alloc_q.one()
if alloc.allocated:
if vlan_id == constants.FLAT_VLAN_ID:
raise n_exc.FlatNetworkInUse(
physical_network=physical_network)
else:
raise n_exc.VlanIdInUse(
vlan_id=vlan_id,
physical_network=physical_network)
LOG.debug("Reserving specific vlan %(vlan_id)s on physical "
"network %(physical_network)s from pool",
{'vlan_id': vlan_id,
'physical_network': physical_network})
alloc.allocated = True
except exc.NoResultFound:
raise n_exc.NoNetworkAvailable()
def reserve_specific_flat_net(self, session, physical_network):
return self.reserve_specific_vlan(session, physical_network,
constants.FLAT_VLAN_ID)
def add_network_binding(self, session, network_id, network_type,
physical_network, segmentation_id):
with session.begin(subtransactions=True):
binding = hyperv_model.NetworkBinding(
network_id, network_type,
physical_network,
segmentation_id)
session.add(binding)
def get_port(self, port_id):
session = db_api.get_session()
try:
port = session.query(models_v2.Port).filter_by(id=port_id).one()
except exc.NoResultFound:
port = None
return port
def get_network_binding(self, session, network_id):
session = session or db_api.get_session()
try:
binding_q = session.query(hyperv_model.NetworkBinding)
binding_q = binding_q.filter_by(network_id=network_id)
return binding_q.one()
except exc.NoResultFound:
return
def set_port_status(self, port_id, status):
session = db_api.get_session()
try:
port = session.query(models_v2.Port).filter_by(id=port_id).one()
port['status'] = status
session.merge(port)
session.flush()
except exc.NoResultFound:
raise n_exc.PortNotFound(port_id=port_id)
def release_vlan(self, session, physical_network, vlan_id):
with session.begin(subtransactions=True):
try:
alloc_q = session.query(hyperv_model.VlanAllocation)
alloc_q = alloc_q.filter_by(physical_network=physical_network,
vlan_id=vlan_id)
alloc = alloc_q.one()
alloc.allocated = False
#session.delete(alloc)
LOG.debug("Releasing vlan %(vlan_id)s on physical network "
"%(physical_network)s",
{'vlan_id': vlan_id,
'physical_network': physical_network})
except exc.NoResultFound:
LOG.warning(_LW("vlan_id %(vlan_id)s on physical network "
"%(physical_network)s not found"),
{'vlan_id': vlan_id,
'physical_network': physical_network})
def _add_missing_allocatable_vlans(self, session, vlan_ids,
physical_network):
for vlan_id in sorted(vlan_ids):
alloc = hyperv_model.VlanAllocation(
physical_network, vlan_id)
session.add(alloc)
def _remove_non_allocatable_vlans(self, session,
physical_network,
vlan_ids,
allocations):
if physical_network in allocations:
for alloc in allocations[physical_network]:
try:
# see if vlan is allocatable
vlan_ids.remove(alloc.vlan_id)
except KeyError:
# it's not allocatable, so check if its allocated
if not alloc.allocated:
# it's not, so remove it from table
LOG.debug(
"Removing vlan %(vlan_id)s on physical network "
"%(physical_network)s from pool",
{'vlan_id': alloc.vlan_id,
'physical_network': physical_network})
session.delete(alloc)
del allocations[physical_network]
def _remove_unconfigured_vlans(self, session, allocations):
for allocs in allocations.itervalues():
for alloc in allocs:
if not alloc.allocated:
LOG.debug("Removing vlan %(vlan_id)s on physical "
"network %(physical_network)s from pool",
{'vlan_id': alloc.vlan_id,
'physical_network': alloc.physical_network})
session.delete(alloc)
def sync_vlan_allocations(self, network_vlan_ranges):
"""Synchronize vlan_allocations table with configured VLAN ranges."""
session = db_api.get_session()
with session.begin():
# get existing allocations for all physical networks
allocations = dict()
allocs_q = session.query(hyperv_model.VlanAllocation)
for alloc in allocs_q:
allocations.setdefault(alloc.physical_network,
set()).add(alloc)
# process vlan ranges for each configured physical network
for physical_network, vlan_ranges in network_vlan_ranges.items():
# determine current configured allocatable vlans for this
# physical network
vlan_ids = set()
for vlan_range in vlan_ranges:
vlan_ids |= set(moves.xrange(vlan_range[0],
vlan_range[1] + 1))
# remove from table unallocated vlans not currently allocatable
self._remove_non_allocatable_vlans(session,
physical_network,
vlan_ids,
allocations)
# add missing allocatable vlans to table
self._add_missing_allocatable_vlans(session, vlan_ids,
physical_network)
# remove from table unallocated vlans for any unconfigured physical
# networks
self._remove_unconfigured_vlans(session, allocations)

View File

@ -1,336 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# 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 neutron.api.rpc.handlers import dhcp_rpc
from neutron.api.rpc.handlers import l3_rpc
from neutron.api.rpc.handlers import metadata_rpc
from neutron.api.v2 import attributes
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.db import agents_db
from neutron.db import db_base_plugin_v2
from neutron.db import external_net_db
from neutron.db import l3_gwmode_db
from neutron.db import portbindings_base
from neutron.db import quota_db # noqa
from neutron.extensions import portbindings
from neutron.extensions import providernet as provider
from neutron.i18n import _LI
from neutron.openstack.common import log as logging
from neutron.plugins.common import constants as svc_constants
from neutron.plugins.common import utils as plugin_utils
from neutron.plugins.hyperv import agent_notifier_api
from neutron.plugins.hyperv.common import constants
from neutron.plugins.hyperv import db as hyperv_db
from neutron.plugins.hyperv import rpc_callbacks
DEFAULT_VLAN_RANGES = []
hyperv_opts = [
cfg.StrOpt('tenant_network_type', default='local',
help=_("Network type for tenant networks "
"(local, flat, vlan or none)")),
cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES,
help=_("List of <physical_network>:<vlan_min>:<vlan_max> "
"or <physical_network>")),
]
cfg.CONF.register_opts(hyperv_opts, "HYPERV")
LOG = logging.getLogger(__name__)
class BaseNetworkProvider(object):
def __init__(self):
self._db = hyperv_db.HyperVPluginDB()
def create_network(self, session, attrs):
pass
def delete_network(self, session, binding):
pass
def extend_network_dict(self, network, binding):
pass
class LocalNetworkProvider(BaseNetworkProvider):
def create_network(self, session, attrs):
network_type = attrs.get(provider.NETWORK_TYPE)
segmentation_id = attrs.get(provider.SEGMENTATION_ID)
if attributes.is_attr_set(segmentation_id):
msg = _("segmentation_id specified "
"for %s network") % network_type
raise n_exc.InvalidInput(error_message=msg)
attrs[provider.SEGMENTATION_ID] = None
physical_network = attrs.get(provider.PHYSICAL_NETWORK)
if attributes.is_attr_set(physical_network):
msg = _("physical_network specified "
"for %s network") % network_type
raise n_exc.InvalidInput(error_message=msg)
attrs[provider.PHYSICAL_NETWORK] = None
def extend_network_dict(self, network, binding):
network[provider.PHYSICAL_NETWORK] = None
network[provider.SEGMENTATION_ID] = None
class FlatNetworkProvider(BaseNetworkProvider):
def create_network(self, session, attrs):
network_type = attrs.get(provider.NETWORK_TYPE)
segmentation_id = attrs.get(provider.SEGMENTATION_ID)
if attributes.is_attr_set(segmentation_id):
msg = _("segmentation_id specified "
"for %s network") % network_type
raise n_exc.InvalidInput(error_message=msg)
segmentation_id = constants.FLAT_VLAN_ID
attrs[provider.SEGMENTATION_ID] = segmentation_id
physical_network = attrs.get(provider.PHYSICAL_NETWORK)
if not attributes.is_attr_set(physical_network):
physical_network = self._db.reserve_flat_net(session)
attrs[provider.PHYSICAL_NETWORK] = physical_network
else:
self._db.reserve_specific_flat_net(session, physical_network)
def delete_network(self, session, binding):
self._db.release_vlan(session, binding.physical_network,
constants.FLAT_VLAN_ID)
def extend_network_dict(self, network, binding):
network[provider.PHYSICAL_NETWORK] = binding.physical_network
class VlanNetworkProvider(BaseNetworkProvider):
def create_network(self, session, attrs):
segmentation_id = attrs.get(provider.SEGMENTATION_ID)
if attributes.is_attr_set(segmentation_id):
physical_network = attrs.get(provider.PHYSICAL_NETWORK)
if not attributes.is_attr_set(physical_network):
msg = _("physical_network not provided")
raise n_exc.InvalidInput(error_message=msg)
self._db.reserve_specific_vlan(session, physical_network,
segmentation_id)
else:
(physical_network,
segmentation_id) = self._db.reserve_vlan(session)
attrs[provider.SEGMENTATION_ID] = segmentation_id
attrs[provider.PHYSICAL_NETWORK] = physical_network
def delete_network(self, session, binding):
self._db.release_vlan(
session, binding.physical_network,
binding.segmentation_id)
def extend_network_dict(self, network, binding):
network[provider.PHYSICAL_NETWORK] = binding.physical_network
network[provider.SEGMENTATION_ID] = binding.segmentation_id
class HyperVNeutronPlugin(agents_db.AgentDbMixin,
db_base_plugin_v2.NeutronDbPluginV2,
external_net_db.External_net_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_base.PortBindingBaseMixin):
# This attribute specifies whether the plugin supports or not
# bulk operations. Name mangling is used in order to ensure it
# is qualified by class
__native_bulk_support = True
supported_extension_aliases = ["provider", "external-net", "router",
"agent", "ext-gw-mode", "binding", "quotas"]
def __init__(self, configfile=None):
self._db = hyperv_db.HyperVPluginDB()
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_HYPERV}
portbindings_base.register_port_dict_function()
self._set_tenant_network_type()
self._parse_network_vlan_ranges()
self._create_network_providers_map()
self._db.sync_vlan_allocations(self._network_vlan_ranges)
self._setup_rpc()
def _set_tenant_network_type(self):
tenant_network_type = cfg.CONF.HYPERV.tenant_network_type
if tenant_network_type not in [svc_constants.TYPE_LOCAL,
svc_constants.TYPE_FLAT,
svc_constants.TYPE_VLAN,
svc_constants.TYPE_NONE]:
msg = _(
"Invalid tenant_network_type: %s. "
"Agent terminated!") % tenant_network_type
raise n_exc.InvalidInput(error_message=msg)
self._tenant_network_type = tenant_network_type
def _setup_rpc(self):
# RPC support
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
self.conn = n_rpc.create_connection(new=True)
self.notifier = agent_notifier_api.AgentNotifierApi(
topics.AGENT)
self.endpoints = [rpc_callbacks.HyperVRpcCallbacks(self.notifier),
dhcp_rpc.DhcpRpcCallback(),
l3_rpc.L3RpcCallback(),
agents_db.AgentExtRpcCallback(),
metadata_rpc.MetadataRpcCallback()]
for svc_topic in self.service_topics.values():
self.conn.create_consumer(svc_topic, self.endpoints, fanout=False)
# Consume from all consumers in threads
self.conn.consume_in_threads()
def _parse_network_vlan_ranges(self):
self._network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
cfg.CONF.HYPERV.network_vlan_ranges)
LOG.info(_LI("Network VLAN ranges: %s"), self._network_vlan_ranges)
def _check_vlan_id_in_range(self, physical_network, vlan_id):
for r in self._network_vlan_ranges[physical_network]:
if vlan_id >= r[0] and vlan_id <= r[1]:
return True
return False
def _create_network_providers_map(self):
self._network_providers_map = {
svc_constants.TYPE_LOCAL: LocalNetworkProvider(),
svc_constants.TYPE_FLAT: FlatNetworkProvider(),
svc_constants.TYPE_VLAN: VlanNetworkProvider()
}
def _process_provider_create(self, context, session, attrs):
network_type = attrs.get(provider.NETWORK_TYPE)
network_type_set = attributes.is_attr_set(network_type)
if not network_type_set:
if self._tenant_network_type == svc_constants.TYPE_NONE:
raise n_exc.TenantNetworksDisabled()
network_type = self._tenant_network_type
attrs[provider.NETWORK_TYPE] = network_type
if network_type not in self._network_providers_map:
msg = _("Network type %s not supported") % network_type
raise n_exc.InvalidInput(error_message=msg)
p = self._network_providers_map[network_type]
# Provider specific network creation
p.create_network(session, attrs)
def create_network(self, context, network):
session = context.session
with session.begin(subtransactions=True):
network_attrs = network['network']
self._process_provider_create(context, session, network_attrs)
net = super(HyperVNeutronPlugin, self).create_network(
context, network)
network_type = network_attrs[provider.NETWORK_TYPE]
physical_network = network_attrs[provider.PHYSICAL_NETWORK]
segmentation_id = network_attrs[provider.SEGMENTATION_ID]
self._db.add_network_binding(
session, net['id'], network_type,
physical_network, segmentation_id)
self._process_l3_create(context, net, network['network'])
self._extend_network_dict_provider(context, net)
LOG.debug("Created network: %s", net['id'])
return net
def _extend_network_dict_provider(self, context, network):
binding = self._db.get_network_binding(
context.session, network['id'])
network[provider.NETWORK_TYPE] = binding.network_type
p = self._network_providers_map[binding.network_type]
p.extend_network_dict(network, binding)
def update_network(self, context, id, network):
provider._raise_if_updates_provider_attributes(network['network'])
session = context.session
with session.begin(subtransactions=True):
net = super(HyperVNeutronPlugin, self).update_network(context, id,
network)
self._process_l3_update(context, net, network['network'])
self._extend_network_dict_provider(context, net)
return net
def delete_network(self, context, id):
session = context.session
with session.begin(subtransactions=True):
binding = self._db.get_network_binding(session, id)
self._process_l3_delete(context, id)
super(HyperVNeutronPlugin, self).delete_network(context, id)
p = self._network_providers_map[binding.network_type]
p.delete_network(session, binding)
# the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary
self.notifier.network_delete(context, id)
def get_network(self, context, id, fields=None):
net = super(HyperVNeutronPlugin, self).get_network(context, id, None)
self._extend_network_dict_provider(context, net)
return self._fields(net, fields)
def get_networks(self, context, filters=None, fields=None):
nets = super(HyperVNeutronPlugin, self).get_networks(
context, filters, None)
for net in nets:
self._extend_network_dict_provider(context, net)
return [self._fields(net, fields) for net in nets]
def create_port(self, context, port):
port_data = port['port']
port = super(HyperVNeutronPlugin, self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
return port
def update_port(self, context, id, port):
original_port = super(HyperVNeutronPlugin, self).get_port(
context, id)
port_data = port['port']
port = super(HyperVNeutronPlugin, self).update_port(context, id, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
if original_port['admin_state_up'] != port['admin_state_up']:
binding = self._db.get_network_binding(
None, port['network_id'])
self.notifier.port_update(context, port,
binding.network_type,
binding.segmentation_id,
binding.physical_network)
return port
def delete_port(self, context, id, l3_port_check=True):
# if needed, check to see if this is a port owned by
# and l3-router. If so, we should prevent deletion.
if l3_port_check:
self.prevent_l3_port_deletion(context, id)
self.disassociate_floatingips(context, id)
super(HyperVNeutronPlugin, self).delete_port(context, id)
self.notifier.port_delete(context, id)

View File

@ -1,52 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# 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 sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from neutron.db import model_base
class VlanAllocation(model_base.BASEV2):
"""Represents allocation state of vlan_id on physical network."""
__tablename__ = 'hyperv_vlan_allocations'
physical_network = Column(String(64), nullable=False, primary_key=True)
vlan_id = Column(Integer, nullable=False, primary_key=True,
autoincrement=False)
allocated = Column(Boolean, nullable=False)
def __init__(self, physical_network, vlan_id):
self.physical_network = physical_network
self.vlan_id = vlan_id
self.allocated = False
class NetworkBinding(model_base.BASEV2):
"""Represents binding of virtual network to physical realization."""
__tablename__ = 'hyperv_network_bindings'
network_id = Column(String(36),
ForeignKey('networks.id', ondelete="CASCADE"),
primary_key=True)
network_type = Column(String(32), nullable=False)
physical_network = Column(String(64))
segmentation_id = Column(Integer)
def __init__(self, network_id, network_type, physical_network,
segmentation_id):
self.network_id = network_id
self.network_type = network_type
self.physical_network = physical_network
self.segmentation_id = segmentation_id

View File

@ -1,99 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# 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.
import oslo_messaging
from neutron.common import constants as q_const
from neutron.openstack.common import log as logging
from neutron.plugins.hyperv import db as hyperv_db
LOG = logging.getLogger(__name__)
class HyperVRpcCallbacks(object):
# history
# 1.1 Support Security Group RPC
# 1.2 Support get_devices_details_list
target = oslo_messaging.Target(version='1.2')
def __init__(self, notifier):
super(HyperVRpcCallbacks, self).__init__()
self.notifier = notifier
self._db = hyperv_db.HyperVPluginDB()
def get_device_details(self, rpc_context, **kwargs):
"""Agent requests device details."""
agent_id = kwargs.get('agent_id')
device = kwargs.get('device')
LOG.debug("Device %(device)s details requested from %(agent_id)s",
{'device': device, 'agent_id': agent_id})
port = self._db.get_port(device)
if port:
binding = self._db.get_network_binding(None, port['network_id'])
entry = {'device': device,
'network_id': port['network_id'],
'port_id': port['id'],
'admin_state_up': port['admin_state_up'],
'network_type': binding.network_type,
'segmentation_id': binding.segmentation_id,
'physical_network': binding.physical_network}
# Set the port status to UP
self._db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE)
else:
entry = {'device': device}
LOG.debug("%s can not be found in database", device)
return entry
def get_devices_details_list(self, rpc_context, **kwargs):
return [
self.get_device_details(
rpc_context,
device=device,
**kwargs
)
for device in kwargs.pop('devices', [])
]
def update_device_down(self, rpc_context, **kwargs):
"""Device no longer exists on agent."""
# TODO(garyk) - live migration and port status
agent_id = kwargs.get('agent_id')
device = kwargs.get('device')
LOG.debug("Device %(device)s no longer exists on %(agent_id)s",
{'device': device, 'agent_id': agent_id})
port = self._db.get_port(device)
if port:
entry = {'device': device,
'exists': True}
# Set port status to DOWN
self._db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN)
else:
entry = {'device': device,
'exists': False}
LOG.debug("%s can not be found in database", device)
return entry
def tunnel_sync(self, rpc_context, **kwargs):
"""Tunnel sync.
Dummy function for ovs agent running on Linux to
work with Hyper-V plugin and agent.
"""
entry = dict()
entry['tunnels'] = {}
# Return the list of tunnels IP's to the agent
return entry

View File

@ -1,67 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# Copyright 2013 Pedro Navarro Perez
# 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.
import contextlib
from oslo_config import cfg
from neutron import context
from neutron.extensions import portbindings
from neutron import manager
from neutron.tests.unit import test_db_plugin as test_plugin
class HyperVNeutronPluginTestCase(test_plugin.NeutronDbPluginV2TestCase):
_plugin_name = ('neutron.plugins.hyperv.'
'hyperv_neutron_plugin.HyperVNeutronPlugin')
def setUp(self):
super(HyperVNeutronPluginTestCase, self).setUp(self._plugin_name)
class TestHyperVVirtualSwitchBasicGet(
test_plugin.TestBasicGet, HyperVNeutronPluginTestCase):
pass
class TestHyperVVirtualSwitchV2HTTPResponse(
test_plugin.TestV2HTTPResponse, HyperVNeutronPluginTestCase):
pass
class TestHyperVVirtualSwitchPortsV2(
test_plugin.TestPortsV2, HyperVNeutronPluginTestCase):
def test_port_vif_details(self):
with self.port(name='name') as port:
self.assertEqual(port['port']['binding:vif_type'],
portbindings.VIF_TYPE_HYPERV)
def test_ports_vif_details(self):
cfg.CONF.set_default('allow_overlapping_ips', True)
plugin = manager.NeutronManager.get_plugin()
with contextlib.nested(self.port(), self.port()) as (port1, port2):
ctx = context.get_admin_context()
ports = plugin.get_ports(ctx)
self.assertEqual(len(ports), 2)
for port in ports:
self.assertEqual(port['binding:vif_type'],
portbindings.VIF_TYPE_HYPERV)
class TestHyperVVirtualSwitchNetworksV2(
test_plugin.TestNetworksV2, HyperVNeutronPluginTestCase):
pass

View File

@ -1,147 +0,0 @@
# Copyright 2013 Cloudbase Solutions SRL
# Copyright 2013 Pedro Navarro Perez
# 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.
"""
Unit Tests for hyperv neutron rpc
"""
import contextlib
import mock
from oslo_context import context as oslo_context
from neutron.agent import rpc as agent_rpc
from neutron.common import topics
from neutron.plugins.hyperv import agent_notifier_api as ana
from neutron.plugins.hyperv.common import constants
from neutron.tests import base
class rpcHyperVApiTestCase(base.BaseTestCase):
def _test_hyperv_neutron_api(
self, rpcapi, topic, method, rpc_method, **kwargs):
ctxt = oslo_context.RequestContext('fake_user', 'fake_project')
expected_retval = 'foo' if rpc_method == 'call' else None
expected_version = kwargs.pop('version', None)
fanout = kwargs.pop('fanout', False)
with contextlib.nested(
mock.patch.object(rpcapi.client, rpc_method),
mock.patch.object(rpcapi.client, 'prepare'),
) as (
rpc_mock, prepare_mock
):
prepare_mock.return_value = rpcapi.client
rpc_mock.return_value = expected_retval
retval = getattr(rpcapi, method)(ctxt, **kwargs)
self.assertEqual(retval, expected_retval)
prepare_args = {}
if expected_version:
prepare_args['version'] = expected_version
if fanout:
prepare_args['fanout'] = True
if topic:
prepare_args['topic'] = topic
prepare_mock.assert_called_once_with(**prepare_args)
rpc_mock.assert_called_once_with(ctxt, method, **kwargs)
def test_delete_network(self):
rpcapi = ana.AgentNotifierApi(topics.AGENT)
self._test_hyperv_neutron_api(
rpcapi,
topics.get_topic_name(
topics.AGENT,
topics.NETWORK,
topics.DELETE),
'network_delete', rpc_method='cast', fanout=True,
network_id='fake_request_spec')
def test_port_update(self):
rpcapi = ana.AgentNotifierApi(topics.AGENT)
self._test_hyperv_neutron_api(
rpcapi,
topics.get_topic_name(
topics.AGENT,
topics.PORT,
topics.UPDATE),
'port_update', rpc_method='cast', fanout=True,
port='fake_port',
network_type='fake_network_type',
segmentation_id='fake_segmentation_id',
physical_network='fake_physical_network')
def test_port_delete(self):
rpcapi = ana.AgentNotifierApi(topics.AGENT)
self._test_hyperv_neutron_api(
rpcapi,
topics.get_topic_name(
topics.AGENT,
topics.PORT,
topics.DELETE),
'port_delete', rpc_method='cast', fanout=True,
port_id='port_id')
def test_tunnel_update(self):
rpcapi = ana.AgentNotifierApi(topics.AGENT)
self._test_hyperv_neutron_api(
rpcapi,
topics.get_topic_name(
topics.AGENT,
constants.TUNNEL,
topics.UPDATE),
'tunnel_update', rpc_method='cast', fanout=True,
tunnel_ip='fake_ip', tunnel_id='fake_id')
def test_device_details(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_hyperv_neutron_api(
rpcapi, None,
'get_device_details', rpc_method='call',
device='fake_device',
agent_id='fake_agent_id',
host='fake_host')
def test_devices_details_list(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_hyperv_neutron_api(
rpcapi, None,
'get_devices_details_list', rpc_method='call',
devices=['fake_device1', 'fake_device2'],
agent_id='fake_agent_id', host='fake_host',
version='1.3')
def test_update_device_down(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_hyperv_neutron_api(
rpcapi, None,
'update_device_down', rpc_method='call',
device='fake_device',
agent_id='fake_agent_id',
host='fake_host')
def test_tunnel_sync(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
self._test_hyperv_neutron_api(
rpcapi, None,
'tunnel_sync', rpc_method='call',
tunnel_ip='fake_tunnel_ip',
tunnel_type=None,
host='fake_host',
version='1.4')

View File

@ -54,7 +54,6 @@ data_files =
etc/neutron/plugins/cisco/cisco_router_plugin.ini
etc/neutron/plugins/cisco/cisco_vpn_agent.ini
etc/neutron/plugins/embrane = etc/neutron/plugins/embrane/heleos_conf.ini
etc/neutron/plugins/hyperv = etc/neutron/plugins/hyperv/hyperv_neutron_plugin.ini
etc/neutron/plugins/ibm = etc/neutron/plugins/ibm/sdnve_neutron_plugin.ini
etc/neutron/plugins/linuxbridge = etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini
etc/neutron/plugins/metaplugin = etc/neutron/plugins/metaplugin/metaplugin.ini
@ -121,7 +120,6 @@ neutron.core_plugins =
brocade = neutron.plugins.brocade.NeutronPlugin:BrocadePluginV2
cisco = neutron.plugins.cisco.network_plugin:PluginV2
embrane = neutron.plugins.embrane.plugins.embrane_ml2_plugin:EmbraneMl2Plugin
hyperv = neutron.plugins.hyperv.hyperv_neutron_plugin:HyperVNeutronPlugin
ibm = neutron.plugins.ibm.sdnve_neutron_plugin:SdnvePluginV2
midonet = neutron.plugins.midonet.plugin:MidonetPluginV2
ml2 = neutron.plugins.ml2.plugin:Ml2Plugin