¡@

Home 

OpenStack Study: edge_loadbalancer_driver.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

#

# Copyright 2013 VMware, Inc

#

# 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.

#

# @author: Leon Cui, VMware

from neutron.openstack.common import excutils

from neutron.openstack.common import log as logging

from neutron.plugins.vmware.dbexts import vcns_db

from neutron.plugins.vmware.vshield.common import (

constants as vcns_const)

from neutron.plugins.vmware.vshield.common import (

exceptions as vcns_exc)

from neutron.services.loadbalancer import constants as lb_constants

LOG = logging.getLogger(__name__)

BALANCE_MAP = {

lb_constants.LB_METHOD_ROUND_ROBIN: 'round-robin',

lb_constants.LB_METHOD_LEAST_CONNECTIONS: 'leastconn',

lb_constants.LB_METHOD_SOURCE_IP: 'source'

}

PROTOCOL_MAP = {

lb_constants.PROTOCOL_TCP: 'tcp',

lb_constants.PROTOCOL_HTTP: 'http',

lb_constants.PROTOCOL_HTTPS: 'tcp'

}

SESSION_PERSISTENCE_METHOD_MAP = {

lb_constants.SESSION_PERSISTENCE_SOURCE_IP: 'sourceip',

lb_constants.SESSION_PERSISTENCE_APP_COOKIE: 'cookie',

lb_constants.SESSION_PERSISTENCE_HTTP_COOKIE: 'cookie'}

SESSION_PERSISTENCE_COOKIE_MAP = {

lb_constants.SESSION_PERSISTENCE_APP_COOKIE: 'app',

lb_constants.SESSION_PERSISTENCE_HTTP_COOKIE: 'insert'}

**** CubicPower OpenStack Study ****

class EdgeLbDriver():

"""Implementation of driver APIs for

Edge Loadbalancer feature configuration

"""

**** CubicPower OpenStack Study ****

    def _convert_lb_vip(self, context, edge_id, vip, app_profileid):

        pool_id = vip.get('pool_id')

        poolid_map = vcns_db.get_vcns_edge_pool_binding(

            context.session, pool_id, edge_id)

        pool_vseid = poolid_map['pool_vseid']

        return {

            'name': vip.get(

                'name', '') + vip['id'][-vcns_const.SUFFIX_LENGTH:],

            'description': vip.get('description'),

            'ipAddress': vip.get('address'),

            'protocol': vip.get('protocol'),

            'port': vip.get('protocol_port'),

            'connectionLimit': max(0, vip.get('connection_limit')),

            'defaultPoolId': pool_vseid,

            'applicationProfileId': app_profileid

        }

**** CubicPower OpenStack Study ****

    def _restore_lb_vip(self, context, edge_id, vip_vse):

        pool_binding = vcns_db.get_vcns_edge_pool_binding_by_vseid(

            context.session,

            edge_id,

            vip_vse['defaultPoolId'])

        return {

            'name': vip_vse['name'][:-vcns_const.SUFFIX_LENGTH],

            'address': vip_vse['ipAddress'],

            'protocol': vip_vse['protocol'],

            'protocol_port': vip_vse['port'],

            'pool_id': pool_binding['pool_id']

        }

**** CubicPower OpenStack Study ****

    def _convert_lb_pool(self, context, edge_id, pool, members):

        vsepool = {

            'name': pool.get(

                'name', '') + pool['id'][-vcns_const.SUFFIX_LENGTH:],

            'description': pool.get('description'),

            'algorithm': BALANCE_MAP.get(

                pool.get('lb_method'),

                'round-robin'),

            'transparent': True,

            'member': [],

            'monitorId': []

        }

        for member in members:

            vsepool['member'].append({

                'ipAddress': member['address'],

                'weight': member['weight'],

                'port': member['protocol_port']

            })

        ##TODO(linb) right now, vse only accept at most one monitor per pool

        monitors = pool.get('health_monitors')

        if not monitors:

            return vsepool

        monitorid_map = vcns_db.get_vcns_edge_monitor_binding(

            context.session,

            monitors[0],

            edge_id)

        vsepool['monitorId'].append(monitorid_map['monitor_vseid'])

        return vsepool

**** CubicPower OpenStack Study ****

    def _restore_lb_pool(self, context, edge_id, pool_vse):

        #TODO(linb): Get more usefule info

        return {

            'name': pool_vse['name'][:-vcns_const.SUFFIX_LENGTH],

        }

**** CubicPower OpenStack Study ****

    def _convert_lb_monitor(self, context, monitor):

        return {

            'type': PROTOCOL_MAP.get(

                monitor.get('type'), 'http'),

            'interval': monitor.get('delay'),

            'timeout': monitor.get('timeout'),

            'maxRetries': monitor.get('max_retries'),

            'name': monitor.get('id')

        }

**** CubicPower OpenStack Study ****

    def _restore_lb_monitor(self, context, edge_id, monitor_vse):

        return {

            'delay': monitor_vse['interval'],

            'timeout': monitor_vse['timeout'],

            'max_retries': monitor_vse['maxRetries'],

            'id': monitor_vse['name']

        }

**** CubicPower OpenStack Study ****

    def _convert_app_profile(self, name, sess_persist, protocol):

        vcns_app_profile = {

            'insertXForwardedFor': False,

            'name': name,

            'serverSslEnabled': False,

            'sslPassthrough': False,

            'template': protocol,

        }

        # Since SSL Termination is not supported right now, so just use

        # sslPassthrough mehtod if the protocol is HTTPS.

        if protocol == lb_constants.PROTOCOL_HTTPS:

            vcns_app_profile['sslPassthrough'] = True

        if sess_persist.get('type'):

            # If protocol is not HTTP, only sourceip is supported

            if (protocol != lb_constants.PROTOCOL_HTTP and

                sess_persist['type'] != (

                    lb_constants.SESSION_PERSISTENCE_SOURCE_IP)):

                msg = (_("Invalid %(protocol)s persistence method: %(type)s") %

                       {'protocol': protocol,

                        'type': sess_persist['type']})

                raise vcns_exc.VcnsBadRequest(resource='sess_persist', msg=msg)

            persistence = {

                'method': SESSION_PERSISTENCE_METHOD_MAP.get(

                    sess_persist['type'])}

            if sess_persist['type'] in SESSION_PERSISTENCE_COOKIE_MAP:

                if sess_persist.get('cookie_name'):

                    persistence['cookieName'] = sess_persist['cookie_name']

                else:

                    persistence['cookieName'] = 'default_cookie_name'

                persistence['cookieMode'] = SESSION_PERSISTENCE_COOKIE_MAP.get(

                    sess_persist['type'])

            vcns_app_profile['persistence'] = persistence

        return vcns_app_profile

**** CubicPower OpenStack Study ****

    def create_vip(self, context, edge_id, vip):

        app_profile = self._convert_app_profile(

            vip['name'], (vip.get('session_persistence') or {}),

            vip.get('protocol'))

        try:

            header, response = self.vcns.create_app_profile(

                edge_id, app_profile)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to create app profile on edge: %s"),

                              edge_id)

        objuri = header['location']

        app_profileid = objuri[objuri.rfind("/") + 1:]

        vip_new = self._convert_lb_vip(context, edge_id, vip, app_profileid)

        try:

            header, response = self.vcns.create_vip(

                edge_id, vip_new)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to create vip on vshield edge: %s"),

                              edge_id)

                self.vcns.delete_app_profile(edge_id, app_profileid)

        objuri = header['location']

        vip_vseid = objuri[objuri.rfind("/") + 1:]

        # Add the vip mapping

        map_info = {

            "vip_id": vip['id'],

            "vip_vseid": vip_vseid,

            "edge_id": edge_id,

            "app_profileid": app_profileid

        }

        vcns_db.add_vcns_edge_vip_binding(context.session, map_info)

**** CubicPower OpenStack Study ****

    def _get_vip_binding(self, session, id):

        vip_binding = vcns_db.get_vcns_edge_vip_binding(session, id)

        if not vip_binding:

            msg = (_("vip_binding not found with id: %(id)s "

                     "edge_id: %(edge_id)s") % {

                   'id': id,

                   'edge_id': vip_binding[vcns_const.EDGE_ID]})

            LOG.error(msg)

            raise vcns_exc.VcnsNotFound(

                resource='router_service_binding', msg=msg)

        return vip_binding

**** CubicPower OpenStack Study ****

    def get_vip(self, context, id):

        vip_binding = vcns_db.get_vcns_edge_vip_binding(context.session, id)

        edge_id = vip_binding[vcns_const.EDGE_ID]

        vip_vseid = vip_binding['vip_vseid']

        try:

            response = self.vcns.get_vip(edge_id, vip_vseid)[1]

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to get vip on edge"))

        return self._restore_lb_vip(context, edge_id, response)

**** CubicPower OpenStack Study ****

    def update_vip(self, context, vip, session_persistence_update=True):

        vip_binding = self._get_vip_binding(context.session, vip['id'])

        edge_id = vip_binding[vcns_const.EDGE_ID]

        vip_vseid = vip_binding.get('vip_vseid')

        if session_persistence_update:

            app_profileid = vip_binding.get('app_profileid')

            app_profile = self._convert_app_profile(

                vip['name'], vip.get('session_persistence', {}),

                vip.get('protocol'))

            try:

                self.vcns.update_app_profile(

                    edge_id, app_profileid, app_profile)

            except vcns_exc.VcnsApiException:

                with excutils.save_and_reraise_exception():

                    LOG.exception(_("Failed to update app profile on "

                                    "edge: %s") % edge_id)

        vip_new = self._convert_lb_vip(context, edge_id, vip, app_profileid)

        try:

            self.vcns.update_vip(edge_id, vip_vseid, vip_new)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to update vip on edge: %s") % edge_id)

**** CubicPower OpenStack Study ****

    def delete_vip(self, context, id):

        vip_binding = self._get_vip_binding(context.session, id)

        edge_id = vip_binding[vcns_const.EDGE_ID]

        vip_vseid = vip_binding['vip_vseid']

        app_profileid = vip_binding['app_profileid']

        try:

            self.vcns.delete_vip(edge_id, vip_vseid)

        except vcns_exc.ResourceNotFound:

            LOG.exception(_("vip not found on edge: %s") % edge_id)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to delete vip on edge: %s") % edge_id)

        try:

            self.vcns.delete_app_profile(edge_id, app_profileid)

        except vcns_exc.ResourceNotFound:

            LOG.exception(_("app profile not found on edge: %s") % edge_id)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to delete app profile on edge: %s") %

                              edge_id)

        vcns_db.delete_vcns_edge_vip_binding(context.session, id)

**** CubicPower OpenStack Study ****

    def create_pool(self, context, edge_id, pool, members):

        pool_new = self._convert_lb_pool(context, edge_id, pool, members)

        try:

            header = self.vcns.create_pool(edge_id, pool_new)[0]

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to create pool"))

        objuri = header['location']

        pool_vseid = objuri[objuri.rfind("/") + 1:]

        # update the pool mapping table

        map_info = {

            "pool_id": pool['id'],

            "pool_vseid": pool_vseid,

            "edge_id": edge_id

        }

        vcns_db.add_vcns_edge_pool_binding(context.session, map_info)

**** CubicPower OpenStack Study ****

    def get_pool(self, context, id, edge_id):

        pool_binding = vcns_db.get_vcns_edge_pool_binding(

            context.session, id, edge_id)

        if not pool_binding:

            msg = (_("pool_binding not found with id: %(id)s "

                     "edge_id: %(edge_id)s") % {'id': id, 'edge_id': edge_id})

            LOG.error(msg)

            raise vcns_exc.VcnsNotFound(

                resource='router_service_binding', msg=msg)

        pool_vseid = pool_binding['pool_vseid']

        try:

            response = self.vcns.get_pool(edge_id, pool_vseid)[1]

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to get pool on edge"))

        return self._restore_lb_pool(context, edge_id, response)

**** CubicPower OpenStack Study ****

    def update_pool(self, context, edge_id, pool, members):

        pool_binding = vcns_db.get_vcns_edge_pool_binding(

            context.session, pool['id'], edge_id)

        pool_vseid = pool_binding['pool_vseid']

        pool_new = self._convert_lb_pool(context, edge_id, pool, members)

        try:

            self.vcns.update_pool(edge_id, pool_vseid, pool_new)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to update pool"))

**** CubicPower OpenStack Study ****

    def delete_pool(self, context, id, edge_id):

        pool_binding = vcns_db.get_vcns_edge_pool_binding(

            context.session, id, edge_id)

        pool_vseid = pool_binding['pool_vseid']

        try:

            self.vcns.delete_pool(edge_id, pool_vseid)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to delete pool"))

        vcns_db.delete_vcns_edge_pool_binding(

            context.session, id, edge_id)

**** CubicPower OpenStack Study ****

    def create_health_monitor(self, context, edge_id, health_monitor):

        monitor_new = self._convert_lb_monitor(context, health_monitor)

        try:

            header = self.vcns.create_health_monitor(edge_id, monitor_new)[0]

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to create monitor on edge: %s"),

                              edge_id)

        objuri = header['location']

        monitor_vseid = objuri[objuri.rfind("/") + 1:]

        # update the health_monitor mapping table

        map_info = {

            "monitor_id": health_monitor['id'],

            "monitor_vseid": monitor_vseid,

            "edge_id": edge_id

        }

        vcns_db.add_vcns_edge_monitor_binding(context.session, map_info)

**** CubicPower OpenStack Study ****

    def get_health_monitor(self, context, id, edge_id):

        monitor_binding = vcns_db.get_vcns_edge_monitor_binding(

            context.session, id, edge_id)

        if not monitor_binding:

            msg = (_("monitor_binding not found with id: %(id)s "

                     "edge_id: %(edge_id)s") % {'id': id, 'edge_id': edge_id})

            LOG.error(msg)

            raise vcns_exc.VcnsNotFound(

                resource='router_service_binding', msg=msg)

        monitor_vseid = monitor_binding['monitor_vseid']

        try:

            response = self.vcns.get_health_monitor(edge_id, monitor_vseid)[1]

        except vcns_exc.VcnsApiException as e:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to get monitor on edge: %s"),

                              e.response)

        return self._restore_lb_monitor(context, edge_id, response)

**** CubicPower OpenStack Study ****

    def update_health_monitor(self, context, edge_id,

                              old_health_monitor, health_monitor):

        monitor_binding = vcns_db.get_vcns_edge_monitor_binding(

            context.session,

            old_health_monitor['id'], edge_id)

        monitor_vseid = monitor_binding['monitor_vseid']

        monitor_new = self._convert_lb_monitor(

            context, health_monitor)

        try:

            self.vcns.update_health_monitor(

                edge_id, monitor_vseid, monitor_new)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to update monitor on edge: %s"),

                              edge_id)

**** CubicPower OpenStack Study ****

    def delete_health_monitor(self, context, id, edge_id):

        monitor_binding = vcns_db.get_vcns_edge_monitor_binding(

            context.session, id, edge_id)

        monitor_vseid = monitor_binding['monitor_vseid']

        try:

            self.vcns.delete_health_monitor(edge_id, monitor_vseid)

        except vcns_exc.VcnsApiException:

            with excutils.save_and_reraise_exception():

                LOG.exception(_("Failed to delete monitor"))

        vcns_db.delete_vcns_edge_monitor_binding(

            context.session, id, edge_id)