def calculate(context, operation, object_type, object_uuid, data): """Calculate resource deps in journaled operations. As a rule of thumb validation takes into consideration only operations in pending or processing state, other states are irrelevant. :param context: enginefacade context :param row: entry in journal entry to be validated """ deps = [] if operation == odl_const.ODL_DELETE: return _get_delete_dependencies(context, object_type, object_uuid) elif operation == odl_const.ODL_UPDATE: deps.extend( db.get_pending_or_processing_ops( context, object_uuid, operation=(odl_const.ODL_CREATE, odl_const.ODL_UPDATE))) elif operation != odl_const.ODL_CREATE: raise ValueError(_("unsupported operation {}").format(operation)) # Validate deps if there are any to validate. dep_generator = _CREATE_OR_UPDATE_DEP_GENERATOR.get(object_type) if dep_generator is not None: object_ids = dep_generator(data) if object_ids is not None: deps.extend(_get_older_operations(context, object_ids)) return deps
def _vif_type_from_conf(conf, userspace_datapath_types): # take vif_type from datapath_type ------------------------------------ if conf.datapath_type: # take it from datapath_type if conf.datapath_type in USERSPACE_DATAPATH_TYPES: if conf.datapath_type not in userspace_datapath_types: LOG.warning( "Using user space data path type '%s' even if no " "support was detected.", conf.datapath_type) return 'vhostuser' else: return 'ovs' # take vif_type from ovs_dpdk ----------------------------------------- if conf.ovs_dpdk is True: if userspace_datapath_types: return 'vhostuser' raise ValueError(_( "--ovs_dpdk option was specified but the 'netdev' datapath_type " "was not enabled. " "To override use option --datapath_type=netdev")) elif conf.ovs_dpdk is False: return 'ovs' # take detected dtype ------------------------------------------------- if userspace_datapath_types: return 'vhostuser' return 'ovs'
def start(self): if self._running: raise RuntimeError( _("Thread has to be stopped before started again") ) super(JournalPeriodicProcessor, self).start() LOG.debug('JournalPeriodicProcessor starting') self._journal.start() self._timer = loopingcall.FixedIntervalLoopingCall(self._call_journal) self._timer.start(self._interval) self._start_maintenance_task() self._create_pidfile() self._running = True
def post(cls, resource_type, resource_dict, urlpath, resource_list): """No ID in URL, elements in resource_list must have ID""" if resource_list is None: raise ValueError(_("resource_list can not be None")) for resource in resource_list: if resource['id'] in resource_dict: LOG.debug("%s %s already exists", resource_type, resource['id']) response = cls._make_response(NOT_ALLOWED) raise requests.exceptions.HTTPError(response=response) resource_dict[resource['id']] = deepcopy(resource) return cls._make_response(NO_CONTENT)
def put(cls, resource_type, resource_dict, urlpath, resource_list): resource_id = cls._get_resource_id(urlpath) if resource_list is None: raise ValueError(_("resource_list can not be None")) if resource_id and len(resource_list) != 1: LOG.debug("Updating %s with multiple resources", urlpath) response = cls._make_response(BAD_REQUEST) raise requests.exceptions.HTTPError(response=response) for resource in resource_list: res_id = resource_id or resource['id'] if res_id in resource_dict: resource_dict[res_id].update(deepcopy(resource)) else: LOG.debug("%s %s does not exist", resource_type, res_id) response = cls._make_response(NOT_FOUND) raise requests.exceptions.HTTPError(response=response) return cls._make_response(NO_CONTENT)
def odl_create_websocket(cls, odl_url, path, datastore, scope, packet_handler, status_cb=None, leaf_node_only=False): """Create a websocket connection with ODL. This method will create a websocket client based on path, datastore and scope params. On data recv from websocket packet_handler callback is called. status_cb callback can be provided if notifications are requried for socket status changes """ if odl_url is None: LOG.error("invalid odl url", exc_info=True) raise ValueError(_("Invalid ODL URL")) odl_rest_client = odl_client.OpenDaylightRestClient.create_client( odl_url) return cls( odl_rest_client, path, datastore, scope, leaf_node_only, packet_handler, cfg.CONF.ml2_odl.timeout, status_cb )
def _vif_details_from_conf(conf, uuid, vif_type): host_addresses = [conf.local_ip or conf.host] if vif_type == 'ovs': # OVS legacy mode return {"uuid": uuid, "host_addresses": host_addresses, "has_datapath_type_netdev": False, "support_vhost_user": False} elif vif_type == 'vhostuser': # enable VHOSTUSER return {"uuid": uuid, "host_addresses": host_addresses, "has_datapath_type_netdev": True, "support_vhost_user": True, "port_prefix": conf.vhostuser_port_prefix, "vhostuser_socket_dir": conf.vhostuser_socket_dir, "vhostuser_ovs_plug": conf.vhostuser_ovs_plug, "vhostuser_mode": conf.vhostuser_mode, "vhostuser_socket": os.path.join( conf.vhostuser_socket_dir, conf.vhostuser_port_prefix + '$PORT_ID')} raise ValueError(_("vif type: '%s' not supported") % vif_type)
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")), cfg.IntOpt('maintenance_interval', default=300, help=_("(V2 driver) Journal maintenance operations interval "
def _subscribe_websocket(self): """ODL Websocket change notification subscription""" # Check ODL URL for details on this process # https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Restconf:Change_event_notification_subscription#rpc_create-data-change-event-subscription # noqa: E501 # pylint: disable=line-too-long # Invoke rpc create-data-change-event-subscription ws_create_dce_subs_url = ("restconf/operations/sal-remote:" "create-data-change-event-subscription") odl_subscription_data = { 'input': { 'path': self.path, 'sal-remote-augment:datastore': self.datastore, 'sal-remote-augment:scope': self.scope, 'sal-remote-augment:notification-output-type': 'JSON' } } try: response = self.odl_rest_client.sendjson('post', ws_create_dce_subs_url, odl_subscription_data) response.raise_for_status() except exceptions.ConnectionError: LOG.error("cannot connect to the opendaylight controller") return None except exceptions.HTTPError as e: # restconf returns 400 on operation when path is not available if e.response.status_code == codes.bad_request: LOG.debug("response code bad_request (400)" "check path for websocket connection") raise ValueError(_("bad_request (http400),check path.")) else: LOG.warning("websocket connection failed", exc_info=True) return None except Exception: LOG.error("websocket subscription failed", exc_info=True) return None # Subscribing to stream. Returns websocket URL to listen to ws_dce_subs_url = """restconf/streams/stream/""" try: stream_name = response.json() stream_name = stream_name['output']['stream-name'] url = ws_dce_subs_url + stream_name if self.leaf_node_only: url += "?odl-leaf-nodes-only=true" response = self.odl_rest_client.get(url) response.raise_for_status() stream_url = response.headers['location'] LOG.debug("websocket stream URL: %s", stream_url) return stream_url except exceptions.ConnectionError: LOG.error("cannot connect to the opendaylight controller") return None except exceptions.HTTPError as e: # restconf returns 404 on operation when there is no entry if e.response.status_code == codes.not_found: LOG.debug("response code not_found (404)" "unable to websocket connection url") raise ValueError(_("bad_request (http400),check path")) else: LOG.warning("websocket connection failed") return None except ValueError: with excutils.save_and_reraise_exception(): LOG.error("websocket subscribe got invalid stream name") except KeyError: LOG.error("websocket subscribe got bad stream data") raise ValueError(_("websocket subscribe bad stream data")) except Exception: LOG.error("websocket subscription failed", exc_info=True) return None
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")),
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")), cfg.IntOpt('maintenance_interval', default=300, help=_("(V2 driver) Journal maintenance operations interval "
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")), cfg.BoolOpt('enable_lightweight_testing', default=False,
from networking_odl._i18n import _ LOG = logging.getLogger(__name__) USERSPACE_DATAPATH_TYPES = ['netdev', 'dpdkvhostuser'] COMMAND_LINE_OPTIONS = [ cfg.ListOpt( 'allowed_network_types', default=['local', 'flat', 'vlan', 'vxlan', 'gre'], help=_(""" Specifies allowed network types given as a Comma-separated list of types. Default: --allowed_network_types=local,vlan,vxlan,gre """)), cfg.DictOpt( 'bridge_mappings', default={}, help=_(""" Comma-separated list of <physical_network>:<bridge> tuples mapping physical network names to the agent's node-specific Open vSwitch bridge names to be used for flat and VLAN networks. The length of bridge names should be no more than 11. Each bridge must exist, and should have a physical network interface configured as a port. All physical networks configured on the server should have mappings to appropriate bridges on each agent.
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")),
def sync_from_callback_precommit(self, context, operation, res_type, res_id, resource_dict, **kwargs): object_type = res_type.singular if resource_dict is not None: resource_dict = resource_dict[object_type] if (operation == odl_const.ODL_CREATE and object_type == odl_const.ODL_SG): self._sync_security_group_create_precommit(context, operation, object_type, res_id, resource_dict) return # NOTE(yamahata): in security group/security gorup rule case, # orm object is passed. not resource dict. So we have to convert it # into resource_dict if not isinstance(resource_dict, dict) and resource_dict is not None: if object_type == odl_const.ODL_SG: resource_dict = self._make_security_group_dict(resource_dict) elif object_type == odl_const.ODL_SG_RULE: resource_dict = self._make_security_group_rule_dict( resource_dict) # NOTE(yamahata): bug work around # callback for update of security grouop doesn't pass complete # info. So we have to build it. Once the bug is fixed, remove # this bug work around. # https://launchpad.net/bugs/1546910 # https://review.openstack.org/#/c/281693/ elif (object_type == odl_const.ODL_SG and operation == odl_const.ODL_UPDATE): # NOTE(yamahata): precommit_update is called before updating # values. so context.session.{new, dirty} doesn't include sg # in question. a dictionary with new values needs to be build. core_plugin = directory.get_plugin() sg = core_plugin._get_security_group(context, res_id) tmp_dict = self._make_security_group_dict(sg) tmp_dict.update(resource_dict) resource_dict = tmp_dict object_uuid = (resource_dict.get('id') if operation == 'create' else res_id) if object_uuid is None: # NOTE(yamahata): bug work around bug/1546910 # TODO(yamahata): once the following patch is merged # remove this bug work around # https://review.openstack.org/#/c/281693/ assert object_type == odl_const.ODL_SG_RULE # NOTE(yamahata): bulk creation case # context.session.new accumulates all newly created orm object. # there is no easy way to pick up the lastly added orm object. rules = [ rule for rule in context.session.new if (isinstance(rule, securitygroup.SecurityGroupRule)) ] if len(rules) == 1: object_uuid = rules[0].id resource_dict['id'] = object_uuid else: LOG.error(_LE("bulk creation of sgrule isn't supported")) raise NotImplementedError( _("unsupporetd bulk creation of security group rule")) journal.record(context, object_type, object_uuid, operation, resource_dict) # NOTE(yamahata): DB auto deletion # Security Group Rule under this Security Group needs to # be deleted. At NeutronDB layer rules are auto deleted with # cascade='all,delete'. if (object_type == odl_const.ODL_SG and operation == odl_const.ODL_DELETE): for rule in kwargs['security_group'].rules: journal.record(context, odl_const.ODL_SG_RULE, rule.id, odl_const.ODL_DELETE, [object_uuid])
def _subscribe_websocket(self): """ODL Websocket change notification subscription""" # Check ODL URL for details on this process # https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Restconf:Change_event_notification_subscription#rpc_create-data-change-event-subscription # noqa: E501 # pylint: disable=line-too-long # Invoke rpc create-data-change-event-subscription ws_create_dce_subs_url = ("restconf/operations/sal-remote:" "create-data-change-event-subscription") odl_subscription_data = {'input': { 'path': self.path, 'sal-remote-augment:datastore': self.datastore, 'sal-remote-augment:scope': self.scope, 'sal-remote-augment:notification-output-type': 'JSON' }} try: response = self.odl_rest_client.sendjson('post', ws_create_dce_subs_url, odl_subscription_data) response.raise_for_status() except exceptions.ConnectionError: LOG.error("cannot connect to the opendaylight controller") return None except exceptions.HTTPError as e: # restconf returns 400 on operation when path is not available if e.response.status_code == codes.bad_request: LOG.debug("response code bad_request (400)" "check path for websocket connection") raise ValueError(_("bad_request (http400),check path.")) else: LOG.warning("websocket connection failed", exc_info=True) return None except Exception: LOG.error("websocket subscription failed", exc_info=True) return None # Subscribing to stream. Returns websocket URL to listen to ws_dce_subs_url = """restconf/streams/stream/""" try: stream_name = response.json() stream_name = stream_name['output']['stream-name'] url = ws_dce_subs_url + stream_name if self.leaf_node_only: url += "?odl-leaf-nodes-only=true" response = self.odl_rest_client.get(url) response.raise_for_status() stream_url = response.headers['location'] LOG.debug("websocket stream URL: %s", stream_url) return stream_url except exceptions.ConnectionError: LOG.error("cannot connect to the opendaylight controller") return None except exceptions.HTTPError as e: # restconf returns 404 on operation when there is no entry if e.response.status_code == codes.not_found: LOG.debug("response code not_found (404)" "unable to websocket connection url") raise ValueError(_("bad_request (http400),check path")) else: LOG.warning("websocket connection failed") return None except ValueError: with excutils.save_and_reraise_exception(): LOG.error("websocket subscribe got invalid stream name") except KeyError: LOG.error("websocket subscribe got bad stream data") raise ValueError(_("websocket subscribe bad stream data")) except Exception: LOG.error("websocket subscription failed", exc_info=True) return None
""" import collections import re import sys import six from oslo_config import cfg from networking_odl._i18n import _ from networking_odl.journal import journal COMMAND_LINE_OPTIONS = [ cfg.StrOpt('file', default=None, help=_("Log file to analyze.")), cfg.IntOpt('slowest', min=1, default=10, help=_("Prints the N slowest entries (10 by default).")), ] # This regex will match any replacement key in the log message and extract # the key name. KEY_MATCHER = re.compile(r'\%\((\S+)\)s') LOG_KEYS = KEY_MATCHER.findall(journal.LOG_ENTRY_TEMPLATE) KEY_TEMP_PATTERN = 'KEYPATTERN' LOG_MATCHER = re.compile( re.sub(KEY_TEMP_PATTERN, r'(\S+)', re.escape( KEY_MATCHER.sub(KEY_TEMP_PATTERN, journal.LOG_ENTRY_TEMPLATE)))) ENTRY_LOG_TEMPLATE = ' * Entry id: %s, processing time: %.3fs; %s %s %s' EntryStats = collections.namedtuple(
from networking_odl._i18n import _ from networking_odl._i18n import _LE from networking_odl._i18n import _LI from networking_odl._i18n import _LW LOG = log.getLogger(__name__) USERSPACE_DATAPATH_TYPES = ['netdev', 'dpdkvhostuser'] COMMAND_LINE_OPTIONS = [ cfg.ListOpt('allowed_network_types', default=['local', 'vlan', 'vxlan', 'gre'], help=_(""" Specifies allowed network types given as a Comma-separated list of types. Default: --allowed_network_types=local,vlan,vxlan,gre """)), cfg.DictOpt('bridge_mappings', default={}, help=_(""" Comma-separated list of <physical_network>:<bridge> tuples mapping physical network names to the agent's node-specific Open vSwitch bridge names to be used for flat and VLAN networks. The length of bridge names should be no more than 11. Each bridge must exist, and should have a physical network interface configured as a port. All physical networks configured on the server should have mappings to appropriate bridges on each agent. Note: If you remove a bridge from this mapping, make sure to disconnect it from the integration bridge as it won't be managed by
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.IntOpt('sync_timeout', default=10, help=_("(V2 driver) Sync thread timeout in seconds.")), cfg.IntOpt('retry_count', default=5, help=_("(V2 driver) Number of times to retry a row " "before failing.")),
# 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 networking_odl._i18n import _ odl_opts = [ cfg.StrOpt('url', help=_("HTTP URL of OpenDaylight REST interface.")), cfg.StrOpt('username', help=_("HTTP username for authentication.")), cfg.StrOpt('password', secret=True, help=_("HTTP password for authentication.")), cfg.IntOpt('timeout', default=10, help=_("HTTP timeout in seconds.")), cfg.IntOpt('session_timeout', default=30, help=_("Tomcat session timeout in minutes.")), cfg.FloatOpt('sync_timeout', default=10, help=_("Sync thread timeout in seconds or fraction.")), cfg.IntOpt('retry_count', default=5, help=_("Number of times to retry a row before failing.")), cfg.IntOpt('maintenance_interval', default=300, help=_("Journal maintenance operations interval in seconds.")), cfg.IntOpt('completed_rows_retention', default=0,
python analyze_journal.py --file /path/to/file.log """ import collections import re import sys import six from oslo_config import cfg from networking_odl._i18n import _ from networking_odl.journal import journal COMMAND_LINE_OPTIONS = [ cfg.StrOpt('file', default=None, help=_("Log file to analyze.")), cfg.IntOpt('slowest', min=1, default=10, help=_("Prints the N slowest entries (10 by default).")), ] # This regex will match any replacement key in the log message and extract # the key name. KEY_MATCHER = re.compile(r'\%\((\S+)\)s') LOG_KEYS = KEY_MATCHER.findall(journal.LOG_ENTRY_TEMPLATE) KEY_TEMP_PATTERN = 'KEYPATTERN' LOG_MATCHER = re.compile( re.sub( KEY_TEMP_PATTERN, r'(\\S+)', re.escape(KEY_MATCHER.sub(KEY_TEMP_PATTERN,