summaryrefslogtreecommitdiffstats
path: root/networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py
diff options
context:
space:
mode:
Diffstat (limited to 'networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py')
-rw-r--r--networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py263
1 files changed, 0 insertions, 263 deletions
diff --git a/networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py b/networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py
deleted file mode 100644
index d24bd55..0000000
--- a/networking-odl/networking_odl/ml2/pseudo_agentdb_binding.py
+++ /dev/null
@@ -1,263 +0,0 @@
-# Copyright (c) 2016 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.
-
-import logging
-from neutron_lib import constants as nl_const
-from requests import exceptions
-import six.moves.urllib.parse as urlparse
-from string import Template
-
-from oslo_config import cfg
-from oslo_log import log
-from oslo_serialization import jsonutils
-
-from neutron import context
-from neutron.extensions import portbindings
-from neutron import manager
-from neutron.plugins.ml2 import driver_api
-
-from networking_odl._i18n import _LE, _LI, _LW
-from networking_odl.common import client as odl_client
-from networking_odl.journal import maintenance as mt
-from networking_odl.ml2 import port_binding
-
-cfg.CONF.import_group('ml2_odl', 'networking_odl.common.config')
-LOG = log.getLogger(__name__)
-
-
-class PseudoAgentDBBindingController(port_binding.PortBindingController):
- """Switch agnostic Port binding controller for OpenDayLight."""
-
- AGENTDB_BINARY = 'neutron-odlagent-portbinding'
- L2_TYPE = "ODL L2"
-
- # TODO(mzmalick): binary, topic and resource_versions to be provided
- # by ODL, Pending ODL NB patches.
- agentdb_row = {
- 'binary': AGENTDB_BINARY,
- 'host': '',
- 'topic': nl_const.L2_AGENT_TOPIC,
- 'configurations': {},
- 'resource_versions': '',
- 'agent_type': L2_TYPE,
- 'start_flag': True}
- # We are not running host agents, so above start_flag is redundant
-
- def __init__(self, hostconf_uri=None, db_plugin=None):
- """Initialization."""
- LOG.debug("Initializing ODL Port Binding Controller")
-
- if not hostconf_uri:
- # extract host/port from ODL URL and append hostconf_uri path
- hostconf_uri = self._make_hostconf_uri(
- cfg.CONF.ml2_odl.url, cfg.CONF.ml2_odl.odl_hostconf_uri)
-
- LOG.debug("ODLPORTBINDING hostconfigs URI: %s", hostconf_uri)
-
- # TODO(mzmalick): disable port-binding for ODL lightweight testing
- self.odl_rest_client = odl_client.OpenDaylightRestClient.create_client(
- url=hostconf_uri)
-
- # Neutron DB plugin instance
- self.agents_db = db_plugin
-
- # Start polling ODL restconf using maintenance thread.
- # default: 30s (should be <= agent keep-alive poll interval)
- self._start_maintenance_thread(cfg.CONF.ml2_odl.restconf_poll_interval)
-
- def _make_hostconf_uri(self, odl_url=None, path=''):
- """Make ODL hostconfigs URI with host/port extraced from ODL_URL."""
- # NOTE(yamahata): for unit test.
- odl_url = odl_url or 'http://localhost:8080/'
-
- # extract ODL_IP and ODL_PORT from ODL_ENDPOINT and append path
- # urlsplit and urlunparse don't throw exceptions
- purl = urlparse.urlsplit(odl_url)
- return urlparse.urlunparse((purl.scheme, purl.netloc,
- path, '', '', ''))
- #
- # TODO(mzmalick):
- # 1. implement websockets for ODL hostconfig events
- #
-
- def _start_maintenance_thread(self, poll_interval):
- self._mainth = mt.MaintenanceThread()
- self._mainth.maintenance_interval = poll_interval
- self._mainth.register_operation(self._get_and_update_hostconfigs)
- self._mainth.start()
-
- def _rest_get_hostconfigs(self):
- try:
- response = self.odl_rest_client.get()
- response.raise_for_status()
- hostconfigs = response.json()['hostconfigs']['hostconfig']
- except exceptions.ConnectionError:
- LOG.error(_LE("Cannot connect to the Opendaylight Controller"),
- exc_info=True)
- return None
- except KeyError:
- LOG.error(_LE("got invalid hostconfigs"),
- exc_info=True)
- return None
- except Exception:
- LOG.warning(_LW("REST/GET odl hostconfig failed, "),
- exc_info=True)
- return None
- else:
- if LOG.isEnabledFor(logging.DEBUG):
- _hconfig_str = jsonutils.dumps(
- response, sort_keys=True, indent=4, separators=(',', ': '))
- LOG.debug("ODLPORTBINDING hostconfigs:\n%s", _hconfig_str)
-
- return hostconfigs
-
- def _get_and_update_hostconfigs(self, session=None):
- LOG.info(_LI("REST/GET hostconfigs from ODL"))
-
- hostconfigs = self._rest_get_hostconfigs()
-
- if not hostconfigs:
- LOG.warning(_LW("ODL hostconfigs REST/GET failed, "
- "will retry on next poll"))
- return # retry on next poll
-
- self._update_agents_db(hostconfigs=hostconfigs)
-
- def _get_neutron_db_plugin(self):
- if (not self.agents_db) and manager.NeutronManager.has_instance():
- self.agents_db = manager.NeutronManager.get_plugin()
- return self.agents_db
-
- def _update_agents_db(self, hostconfigs):
- LOG.debug("ODLPORTBINDING Updating agents DB with ODL hostconfigs")
-
- agents_db = self._get_neutron_db_plugin()
-
- if not agents_db: # if ML2 is still initializing
- LOG.warning(_LW("ML2 still initializing, Will retry agentdb"
- " update on next poll"))
- return # Retry on next poll
-
- for host_config in hostconfigs:
- try:
- self.agentdb_row['host'] = host_config['host-id']
- self.agentdb_row['agent_type'] = host_config['host-type']
- self.agentdb_row['configurations'] = host_config['config']
-
- agents_db.create_or_update_agent(
- context.get_admin_context(), self.agentdb_row)
- except Exception:
- LOG.exception(_LE("Unable to update agentdb."))
- continue # try next hostcofig
-
- def _substitute_hconfig_tmpl(self, port_context, hconfig):
- # TODO(mzmalick): Explore options for inlines string splicing of
- # port-id to 14 bytes as required by vhostuser types
- subs_ids = {
- # $IDENTIFER string substitution in hostconfigs JSON string
- 'PORT_ID': port_context.current['id'][:14]
- }
-
- # Substitute identifiers and Convert JSON string to dict
- hconfig_conf_json = Template(hconfig['configurations'])
- substituted_str = hconfig_conf_json.safe_substitute(subs_ids)
- hconfig['configurations'] = jsonutils.loads(substituted_str)
-
- return hconfig
-
- def bind_port(self, port_context):
- """bind port using ODL host configuration."""
- # Get all ODL hostconfigs for this host and type
- agentdb = port_context.host_agents(self.L2_TYPE)
-
- if not agentdb:
- LOG.warning(_LW("No valid hostconfigs in agentsdb for host %s"),
- port_context.host)
- return
-
- for raw_hconfig in agentdb:
- # do any $identifier substitution
- hconfig = self._substitute_hconfig_tmpl(port_context, raw_hconfig)
-
- # Found ODL hostconfig for this host in agentdb
- LOG.debug("ODLPORTBINDING bind port with hostconfig: %s", hconfig)
-
- if self._hconfig_bind_port(port_context, hconfig):
- break # Port binding suceeded!
- else: # Port binding failed!
- LOG.warning(_LW("Failed to bind Port %(pid)s for host "
- "%(host)s on network %(network)s."), {
- 'pid': port_context.current['id'],
- 'host': port_context.host,
- 'network': port_context.network.current['id']})
- else: # No hostconfig found for host in agentdb.
- LOG.warning(_LW("No ODL hostconfigs for host %s found in agentdb"),
- port_context.host)
-
- def _hconfig_bind_port(self, port_context, hconfig):
- """bind port after validating odl host configuration."""
- valid_segment = None
-
- for segment in port_context.segments_to_bind:
- if self._is_valid_segment(segment, hconfig['configurations']):
- valid_segment = segment
- break
- else:
- LOG.debug("No valid segments found!")
- return False
-
- confs = hconfig['configurations']['supported_vnic_types']
-
- # nova provides vnic_type in port_context to neutron.
- # neutron provides supported vif_type for binding based on vnic_type
- # in this case ODL hostconfigs has the vif_type to bind for vnic_type
- vnic_type = port_context.current.get(portbindings.VNIC_TYPE)
-
- if vnic_type != portbindings.VNIC_NORMAL:
- LOG.error(_LE("Binding failed: unsupported VNIC %s"), vnic_type)
- return False
-
- for conf in confs:
- if conf["vnic_type"] == vnic_type:
- vif_type = conf.get('vif_type', portbindings.VIF_TYPE_OVS)
- LOG.debug("Binding vnic:'%s' to vif:'%s'", vnic_type, vif_type)
- break
- else:
- vif_type = portbindings.VIF_TYPE_OVS # default: OVS
- LOG.warning(_LW("No supported vif type found for host %s!, "
- "defaulting to OVS"), port_context.host)
-
- vif_details = conf.get('vif_details', {})
-
- if not vif_details: # empty vif_details could be trouble, warn.
- LOG.warning(_LW("hostconfig:vif_details was empty!"))
-
- LOG.debug("Bind port %(port)s on network %(network)s with valid "
- "segment %(segment)s and VIF type %(vif_type)r "
- "VIF details %(vif_details)r.",
- {'port': port_context.current['id'],
- 'network': port_context.network.current['id'],
- 'segment': valid_segment, 'vif_type': vif_type,
- 'vif_details': vif_details})
-
- port_context.set_binding(valid_segment[driver_api.ID], vif_type,
- vif_details,
- status=nl_const.PORT_STATUS_ACTIVE)
- return True
-
- def _is_valid_segment(self, segment, conf):
- """Verify a segment is supported by ODL."""
- network_type = segment[driver_api.NETWORK_TYPE]
- return network_type in conf['allowed_network_types']