¡@

Home 

OpenStack Study: mechanism_ncs.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright (c) 2013 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 re

from oslo.config import cfg

import requests

from neutron.openstack.common import jsonutils

from neutron.openstack.common import log

from neutron.plugins.ml2 import driver_api as api

LOG = log.getLogger(__name__)

ncs_opts = [

cfg.StrOpt('url',

help=_("HTTP URL of Tail-f NCS 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.CONF.register_opts(ncs_opts, "ml2_ncs")

**** CubicPower OpenStack Study ****

class NCSMechanismDriver(api.MechanismDriver):

"""Mechanism Driver for Tail-f Network Control System (NCS).

This driver makes portions of the Neutron database available for

service provisioning in NCS. For example, NCS can use this

information to provision physical switches and routers in response

to OpenStack configuration changes.

The database is replicated from Neutron to NCS using HTTP and JSON.

The driver has two states: out-of-sync (initially) and in-sync.

In the out-of-sync state each driver event triggers an attempt

to synchronize the complete database. On success the driver

transitions to the in-sync state.

In the in-sync state each driver event triggers synchronization

of one network or port. On success the driver stays in-sync and

on failure it transitions to the out-of-sync state.

"""

out_of_sync = True

**** CubicPower OpenStack Study ****

    def initialize(self):

        self.url = cfg.CONF.ml2_ncs.url

        self.timeout = cfg.CONF.ml2_ncs.timeout

        self.username = cfg.CONF.ml2_ncs.username

        self.password = cfg.CONF.ml2_ncs.password

    # Postcommit hooks are used to trigger synchronization.

**** CubicPower OpenStack Study ****

    def create_network_postcommit(self, context):

        self.synchronize('create', 'network', context)

**** CubicPower OpenStack Study ****

    def update_network_postcommit(self, context):

        self.synchronize('update', 'network', context)

**** CubicPower OpenStack Study ****

    def delete_network_postcommit(self, context):

        self.synchronize('delete', 'network', context)

**** CubicPower OpenStack Study ****

    def create_subnet_postcommit(self, context):

        self.synchronize('create', 'subnet', context)

**** CubicPower OpenStack Study ****

    def update_subnet_postcommit(self, context):

        self.synchronize('update', 'subnet', context)

**** CubicPower OpenStack Study ****

    def delete_subnet_postcommit(self, context):

        self.synchronize('delete', 'subnet', context)

**** CubicPower OpenStack Study ****

    def create_port_postcommit(self, context):

        self.synchronize('create', 'port', context)

**** CubicPower OpenStack Study ****

    def update_port_postcommit(self, context):

        self.synchronize('update', 'port', context)

**** CubicPower OpenStack Study ****

    def delete_port_postcommit(self, context):

        self.synchronize('delete', 'port', context)

**** CubicPower OpenStack Study ****

    def synchronize(self, operation, object_type, context):

        """Synchronize NCS with Neutron following a configuration change."""

        if self.out_of_sync:

            self.sync_full(context)

        else:

            self.sync_object(operation, object_type, context)

**** CubicPower OpenStack Study ****

    def sync_full(self, context):

        """Resync the entire database to NCS.

        Transition to the in-sync state on success.

        """

        dbcontext = context._plugin_context

        networks = context._plugin.get_networks(dbcontext)

        subnets = context._plugin.get_subnets(dbcontext)

        ports = context._plugin.get_ports(dbcontext)

        for port in ports:

            self.add_security_groups(context, dbcontext, port)

        json = {'openstack': {'network': networks,

                              'subnet': subnets,

                              'port': ports}}

        self.sendjson('put', '', json)

        self.out_of_sync = False

**** CubicPower OpenStack Study ****

    def sync_object(self, operation, object_type, context):

        """Synchronize the single modified record to NCS.

        Transition to the out-of-sync state on failure.

        """

        self.out_of_sync = True

        dbcontext = context._plugin_context

        id = context.current['id']

        urlpath = object_type + '/' + id

        if operation == 'delete':

            self.sendjson('delete', urlpath, None)

        else:

            assert operation == 'create' or operation == 'update'

            if object_type == 'network':

                network = context._plugin.get_network(dbcontext, id)

                self.sendjson('put', urlpath, {'network': network})

            elif object_type == 'subnet':

                subnet = context._plugin.get_subnet(dbcontext, id)

                self.sendjson('put', urlpath, {'subnet': subnet})

            else:

                assert object_type == 'port'

                port = context._plugin.get_port(dbcontext, id)

                self.add_security_groups(context, dbcontext, port)

                self.sendjson('put', urlpath, {'port': port})

        self.out_of_sync = False

**** CubicPower OpenStack Study ****

    def add_security_groups(self, context, dbcontext, port):

        """Populate the 'security_groups' field with entire records."""

        groups = [context._plugin.get_security_group(dbcontext, sg)

                  for sg in port['security_groups']]

        port['security_groups'] = groups

**** CubicPower OpenStack Study ****

    def sendjson(self, method, urlpath, obj):

        obj = self.escape_keys(obj)

        headers = {'Content-Type': 'application/vnd.yang.data+json'}

        if obj is None:

            data = None

        else:

            data = jsonutils.dumps(obj, indent=2)

        auth = None

        if self.username and self.password:

            auth = (self.username, self.password)

        if self.url:

            url = '/'.join([self.url, urlpath])

            r = requests.request(method, url=url,

                                 headers=headers, data=data,

                                 auth=auth, timeout=self.timeout)

            r.raise_for_status()

**** CubicPower OpenStack Study ****

    def escape_keys(self, obj):

        """Escape JSON keys to be NCS compatible.

        NCS does not allow period (.) or colon (:) characters.

        """

        if isinstance(obj, dict):

            obj = dict((self.escape(k), self.escape_keys(v))

                       for k, v in obj.iteritems())

        if isinstance(obj, list):

            obj = [self.escape_keys(x) for x in obj]

        return obj

**** CubicPower OpenStack Study ****

    def escape(self, string):

        return re.sub('[:._]', '-', string)