def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                client_type='Service Monitor')

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)

        # rotating log file for catchall errors
        self._err_file = '/var/log/contrail/svc-monitor.err'
        self._tmp_file = '/var/log/contrail/svc-monitor.tmp'
        try:
            with open(self._err_file, 'a'):
                pass
            with open(self._tmp_file, 'a'):
                pass
        except IOError:
            self._err_file = './svc-monitor.err'
            self._tmp_file = './svc-monitor.tmp'
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        handler = logging.handlers.RotatingFileHandler(
            self._err_file, maxBytes=64*1024, backupCount=2)
        self._svc_err_logger.addHandler(handler)
示例#2
0
    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(
                self._args.disc_server_ip, self._args.disc_server_port,
                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(self._err_file,
                                                               maxBytes=64 *
                                                               1024,
                                                               backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log("Failed to open trace file %s" % self._err_file)
示例#3
0
    def __init__(self, sm_logger=None, args=None):
        self._args = args
        self._args.analytics_api_ssl_params = analytics_api_ssl_params(args)
        # initialize logger
        if sm_logger is not None:
            self.logger = sm_logger
        else:
            # Initialize logger
            self.logger = ServiceMonitorLogger(args)

        # init object_db
        self._object_db = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._object_db)

        # init rabbit connection
        rabbitmq_cfg = get_rabbitmq_cfg(args)
        if 'host_ip' in self._args:
            host_ip = self._args.host_ip
        else:
            host_ip = socket.gethostbyname(socket.getfqdn())
        self.rabbit = VncAmqpHandle(self.logger._sandesh, self.logger,
                                    DBBaseSM, REACTION_MAP, 'svc_monitor',
                                    rabbitmq_cfg, host_ip,
                                    self._args.trace_file)
        self.rabbit.establish()
    def __init__(self, args=None):
        self._args = args
        # initialize logger
        self.logger = ServiceMonitorLogger(args)

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(self._err_file,
                                                               maxBytes=64 *
                                                               1024,
                                                               backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.warning("Failed to open trace file %s" %
                                self._err_file)

        # init object_db
        self._object_db = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._object_db)

        # init rabbit connection
        self.rabbit = VncAmqpHandle(self.logger,
                                    DBBaseSM,
                                    REACTION_MAP,
                                    'svc_monitor',
                                    args=self._args)
        self.rabbit.establish()
    def __init__(self, args=None):
        self._args = args

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(
                self._args.disc_server_ip, self._args.disc_server_port,
                ModuleNames[Module.SVC_MONITOR])
        # initialize logger
        self.logger = ServiceMonitorLogger(self._disc, args)

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(self._err_file,
                                                               maxBytes=64 *
                                                               1024,
                                                               backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.warning("Failed to open trace file %s" %
                                self._err_file)

        # init cassandra
        self._cassandra = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._cassandra)

        # init rabbit connection
        self.rabbit = RabbitConnection(self.logger, args)
        self.rabbit._connect_rabbit()
示例#6
0
    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(
                    self._err_file, maxBytes=64*1024, backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log("Failed to open trace file %s" % self._err_file)
    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                client_type='Service Monitor')

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = '/var/log/contrail/svc-monitor.err'
        self._tmp_file = '/var/log/contrail/svc-monitor.tmp'
        try:
            with open(self._err_file, 'a'):
                pass
            with open(self._tmp_file, 'a'):
                pass
        except IOError:
            self._err_file = './svc-monitor.err'
            self._tmp_file = './svc-monitor.tmp'
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        handler = logging.handlers.RotatingFileHandler(
            self._err_file, maxBytes=64*1024, backupCount=2)
        self._svc_err_logger.addHandler(handler)
    def __init__(self, sm_logger=None, args=None):
        self._args = args

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            dss_kwargs = {}
            if self._args.disc_server_ssl:
                if self._args.disc_server_cert:
                    dss_kwargs.update({'cert': self._args.disc_server_cert})
                if self._args.disc_server_key:
                    dss_kwargs.update({'key': self._args.disc_server_key})
                if self._args.disc_server_cacert:
                    dss_kwargs.update(
                        {'cacert': self._args.disc_server_cacert})
            self._disc = client.DiscoveryClient(
                self._args.disc_server_ip, self._args.disc_server_port,
                ModuleNames[Module.SVC_MONITOR], **dss_kwargs)
        # initialize logger
        if sm_logger is not None:
            self.logger = sm_logger
        else:
            # Initialize logger
            self.logger = ServiceMonitorLogger(self._disc, args)

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(self._err_file,
                                                               maxBytes=64 *
                                                               1024,
                                                               backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.warning("Failed to open trace file %s" %
                                self._err_file)

        # init cassandra
        self._cassandra = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._cassandra)

        # init rabbit connection
        self.rabbit = VncAmqpHandle(self.logger,
                                    DBBaseSM,
                                    REACTION_MAP,
                                    'svc_monitor',
                                    args=self._args)
        self.rabbit.establish()
    def __init__(self, sm_logger=None, args=None):
        self._args = args
        # initialize logger
        if sm_logger is not None:
            self.logger = sm_logger
        else:
            # Initialize logger
            self.logger = ServiceMonitorLogger(args)

        # init object_db
        self._object_db = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._object_db)

        # init rabbit connection
        rabbitmq_cfg = get_rabbitmq_cfg(args)
        self.rabbit = VncAmqpHandle(self.logger._sandesh, self.logger,
                                    DBBaseSM, REACTION_MAP, 'svc_monitor',
                                    rabbitmq_cfg, self._args.trace_file)
        self.rabbit.establish()
    def _connect_rabbit(self):
        rabbit_server = self._args.rabbit_server
        rabbit_port = self._args.rabbit_port
        rabbit_user = self._args.rabbit_user
        rabbit_password = self._args.rabbit_password
        rabbit_vhost = self._args.rabbit_vhost
        rabbit_ha_mode = self._args.rabbit_ha_mode

        self._db_resync_done = gevent.event.Event()

        q_name = 'svc_mon.%s' % (socket.gethostname())
        self._vnc_kombu = VncKombuClient(rabbit_server, rabbit_port,
                                         rabbit_user, rabbit_password,
                                         rabbit_vhost, rabbit_ha_mode,
                                         q_name, self._vnc_subscribe_callback,
                                         self.logger.log)

        self._cassandra = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._cassandra)
示例#11
0
    def _connect_rabbit(self):
        rabbit_server = self._args.rabbit_server
        rabbit_port = self._args.rabbit_port
        rabbit_user = self._args.rabbit_user
        rabbit_password = self._args.rabbit_password
        rabbit_vhost = self._args.rabbit_vhost
        rabbit_ha_mode = self._args.rabbit_ha_mode

        self._db_resync_done = gevent.event.Event()

        q_name = 'svc_mon.%s' % (socket.gethostname())
        self._vnc_kombu = VncKombuClient(rabbit_server, rabbit_port,
                                         rabbit_user, rabbit_password,
                                         rabbit_vhost, rabbit_ha_mode, q_name,
                                         self._vnc_subscribe_callback,
                                         self.logger.log)

        self._cassandra = ServiceMonitorDB(self._args, self.logger)
        DBBaseSM.init(self, self.logger, self._cassandra)
示例#12
0
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """
    _REACTION_MAP = {
        "loadbalancer_pool": {
            'self': [],
            'virtual_ip': [],
            'loadbalancer_member': [],
            'loadbalancer_healthmonitor': [],
        },
        "loadbalancer_member": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "virtual_ip": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "loadbalancer_healthmonitor": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "service_instance": {
            'self': [],
        },
        "service_template": {
            'self': [],
        }
    }

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(
                    self._err_file, maxBytes=64*1024, backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log("Failed to open trace file %s" % self._err_file)

        # Connect to Rabbit and Initialize cassandra connection
        # TODO activate this code
        # self._connect_rabbit()

    def _connect_rabbit(self):
        rabbit_server = self._args.rabbit_server
        rabbit_port = self._args.rabbit_port
        rabbit_user = self._args.rabbit_user
        rabbit_password = self._args.rabbit_password
        rabbit_vhost = self._args.rabbit_vhost

        self._db_resync_done = gevent.event.Event()

        q_name = 'svc_mon.%s' % (socket.gethostname())
        self._vnc_kombu = VncKombuClient(rabbit_server, rabbit_port,
                                         rabbit_user, rabbit_password,
                                         rabbit_vhost, q_name,
                                         self._vnc_subscribe_callback,
                                         self.config_log)

        cass_server_list = self._args.cassandra_server_list
        reset_config = self._args.reset_config
        self._cassandra = VncCassandraClient(cass_server_list, reset_config,
                                             self._args.cluster_id, None,
                                             self.config_log)
        DBBase.init(self, self.logger, self._cassandra)
    # end _connect_rabbit

    def config_log(self, msg, level):
        self.logger.log(msg)

    def _vnc_subscribe_callback(self, oper_info):
        import pdb;pdb.set_trace()
        self._db_resync_done.wait()
        try:
            msg = "Notification Message: %s" % (pformat(oper_info))
            self.config_log(msg, level=SandeshLevel.SYS_DEBUG)
            obj_type = oper_info['type'].replace('-', '_')
            obj_class = DBBase._OBJ_TYPE_MAP.get(obj_type)
            if obj_class is None:
                return

            if oper_info['oper'] == 'CREATE' or oper_info['oper'] == 'UPDATE':
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP, self._REACTION_MAP)
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is not None:
                    dependency_tracker.evaluate(obj_type, obj)
                else:
                    obj = obj_class.locate(obj_id)
                obj.update()
                dependency_tracker.evaluate(obj_type, obj)
            elif oper_info['oper'] == 'DELETE':
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is None:
                    return
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP, self._REACTION_MAP)
                dependency_tracker.evaluate(obj_type, obj)
                obj_class.delete(obj_id)
            else:
                # unknown operation
                self.config_log('Unknown operation %s' % oper_info['oper'],
                                level=SandeshLevel.SYS_ERR)
                return

            if obj is None:
                self.config_log('Error while accessing %s uuid %s' % (
                                obj_type, obj_id))
                return


        except Exception:
            string_buf = cStringIO.StringIO()
            cgitb.Hook(file=string_buf, format="text").handle(sys.exc_info())
            self.config_log(string_buf.getvalue(), level=SandeshLevel.SYS_ERR)

        for lb_pool_id in dependency_tracker.resources.get('loadbalancer_pool', []):
            lb_pool = LoadbalancerPoolSM.get(lb_pool_id)
            if lb_pool is not None:
                lb_pool.add()
    # end _vnc_subscribe_callback


    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        # create default analyzer template
        self._create_default_template('analyzer-template', 'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template', 'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template', 'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template', 'loadbalancer',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        self._create_default_template('docker-template', 'firewall',
                                      svc_mode='transparent',
                                      image_name="ubuntu",
                                      hypervisor_type='vrouter-instance',
                                      vrouter_instance_type='docker',
                                      instance_data={
                                          "command": "/bin/bash"
                                      })

        self._nova_client = importutils.import_object(
            'svc_monitor.nova_client.ServiceMonitorNovaClient',
            self._args, self.logger)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver,
            self._vnc_lib, self._nova_client,
            self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.virtual_machine_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a vrouter instance manager
        self.vrouter_manager = importutils.import_object(
            'svc_monitor.vrouter_instance_manager.VRouterInstanceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a loadbalancer agent
        # TODO : activate the code 
        # self.loadbalancer_agent = LoadbalancerAgent(self._vnc_lib, self._args)

        # Read the cassandra and populate the entry in ServiceMonitor DB
        # TODO : activate the code 
        # self.sync_sm()

        # resync db
        self.db_resync()

    def db_resync(self):
        si_list = self.db.service_instance_list()
        for si_fq_str, si in si_list or []:
            for idx in range(0, int(si.get('max-instances', '0'))):
                prefix = self.db.get_vm_db_prefix(idx)
                vm_key = prefix + 'uuid'
                if vm_key not in si.keys():
                    continue

                try:
                    vm_obj = self._vnc_lib.virtual_machine_read(id=si[vm_key])
                except NoIdError:
                    continue

                vmi_back_refs = vm_obj.get_virtual_machine_interface_back_refs()
                for vmi_back_ref in vmi_back_refs or []:
                    try:
                        vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                            id=vmi_back_ref['uuid'])
                    except NoIdError:
                        continue
                    vmi_props = vmi_obj.get_virtual_machine_interface_properties()
                    if not vmi_props:
                        continue
                    if_type = vmi_props.get_service_interface_type()
                    if not if_type:
                        continue
                    key = prefix + 'if-' + if_type
                    self.db.service_instance_insert(si_fq_str,
                                                    {key:vmi_obj.uuid})

    def sync_sm(self):
        vn_set = set()
        vmi_set = set()
        iip_set = set()
        ok, lb_pool_list = self._cassandra._cassandra_loadbalancer_pool_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_list:
                lb_pool = LoadbalancerPoolSM.locate(uuid)
                if lb_pool.virtual_machine_interface:
                    vmi_set.add(lb_pool.virtual_machine_interface)

        ok, lb_pool_member_list = self._cassandra._cassandra_loadbalancer_member_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_member_list:
                lb_pool_member = LoadbalancerMemberSM.locate(uuid)

        ok, lb_vip_list = self._cassandra._cassandra_virtual_ip_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_vip_list:
                virtual_ip = VirtualIpSM.locate(uuid)
                if virtual_ip.virtual_machine_interface:
                    vmi_set.add(virtual_ip.virtual_machine_interface)

        ok, lb_hm_list = self._cassandra._cassandra_loadbalancer_healthmonitor_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_hm_list:
                lb_hm = HealthMonitorSM.locate(uuid)

        ok, si_list = self._cassandra._cassandra_service_instance_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in si_list:
                si = ServiceInstanceSM.locate(uuid)

        ok, st_list = self._cassandra._cassandra_service_template_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in si_list:
                si = ServiceInstanceSM.locate(uuid)

        for vmi_id in vmi_set:
            vmi = VirtualMachineInterfaceSM.locate(vmi_id)
            if (vmi.instance_ip):
                iip_set.add(vmi.instance_ip)

        for iip_id in iip_set:
            iip = InstanceIpSM.locate(iip_id)

        for lb_pool in LoadbalancerPoolSM.values():
            lb_pool.add()

        self._db_resync_done.set()
    # end sync_sm

    # create service template
    def _create_default_template(self, st_name, svc_type, svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None, flavor=None, scaling=False,
                                 vrouter_instance_type=None,
                                 instance_data=None):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log("Creating %s %s hypervisor %s" %
                         (domain_name, st_name, hypervisor_type))

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name=st_fq_name)
            st_uuid = st_obj.uuid
            self.logger.log("%s exists uuid %s" % (st_name, str(st_uuid)))
            return
        except NoIdError:
            domain = self._vnc_lib.domain_read(fq_name=domain_fq_name)
            st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
            st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['right', True], ['left', True]]
        else:
            if_list = [
                ['management', False], ['left', False], ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        if vrouter_instance_type is not None:
            svc_properties.set_vrouter_instance_type(vrouter_instance_type)

        if instance_data is not None:
            svc_properties.set_instance_data(
                json.dumps(instance_data, separators=(',', ':')))

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log("%s created with uuid %s" % (st_name, str(st_uuid)))
    #_create_default_analyzer_template

    def cleanup(self):
        pass
    # end cleanup

    def _get_proj_name_from_si_fq_str(self, si_fq_str):
        return si_fq_str.split(':')[1]
    # enf _get_si_fq_str_to_proj_name

    def _get_virtualization_type(self, st_props):
        return st_props.get_service_virtualization_type() or 'virtual-machine'
    # end _get_virtualization_type

    def _check_store_si_info(self, st_obj, si_obj):
        config_complete = True
        st_props = st_obj.get_service_template_properties()
        st_if_list = st_props.get_interface_type()
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        # for lb relax the check because vip and pool could be in same net
        if (st_props.get_service_type() != svc_info.get_lb_service_type()) \
                and si_if_list and (len(si_if_list) != len(st_if_list)):
            self.logger.log("Error: IF mismatch template %s instance %s" %
                             (len(st_if_list), len(si_if_list)))
            return

        # read existing si_entry
        si_entry = self.db.service_instance_get(si_obj.get_fq_name_str())
        if not si_entry:
            si_entry = {}
        si_entry['instance_type'] = self._get_virtualization_type(st_props)
        si_entry['uuid'] = si_obj.uuid

        # walk the interface list
        for idx in range(0, len(st_if_list)):
            st_if = st_if_list[idx]
            itf_type = st_if.service_interface_type

            si_if = None
            if si_if_list and st_props.get_ordered_interfaces():
                try:
                    si_if = si_if_list[idx]
                except IndexError:
                    continue
                si_vn_str = si_if.get_virtual_network()
            else:
                funcname = "get_" + itf_type + "_virtual_network"
                func = getattr(si_props, funcname)
                si_vn_str = func()

            if not si_vn_str:
                continue

            si_entry[itf_type + '-vn'] = si_vn_str
            try:
                vn_obj = self._vnc_lib.virtual_network_read(
                    fq_name_str=si_vn_str)
                if vn_obj.uuid != si_entry.get(si_vn_str, None):
                    si_entry[si_vn_str] = vn_obj.uuid
            except NoIdError:
                self.logger.log("Warn: VN %s add is pending" % si_vn_str)
                si_entry[si_vn_str] = 'pending'
                config_complete = False

        if config_complete:
            self.logger.log("SI %s info is complete" %
                             si_obj.get_fq_name_str())
            si_entry['state'] = 'config_complete'
        else:
            self.logger.log("Warn: SI %s info is not complete" %
                             si_obj.get_fq_name_str())
            si_entry['state'] = 'pending_config'

        #insert entry
        self.db.service_instance_insert(si_obj.get_fq_name_str(), si_entry)
        return config_complete
    #end _check_store_si_info

    def _restart_svc(self, si_fq_str):
        si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        st_list = si_obj.get_service_template_refs()
        if st_list is not None:
            fq_name = st_list[0]['to']
            st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)
            self._create_svc_instance(st_obj, si_obj)
    # end _restart_svc

    def _create_svc_instance(self, st_obj, si_obj):
        #check if all config received before launch
        if not self._check_store_si_info(st_obj, si_obj):
            return

        st_props = st_obj.get_service_template_properties()
        if st_props is None:
            self.logger.log("Cannot find service template associated to "
                             "service instance %s" % si_obj.get_fq_name_str())
        virt_type = self._get_virtualization_type(st_props)

        if virt_type == 'virtual-machine':
            self.vm_manager.create_service(st_obj, si_obj)
        elif virt_type == 'network-namespace':
            self.netns_manager.create_service(st_obj, si_obj)
        elif virt_type == 'vrouter-instance':
            self.vrouter_manager.create_service(st_obj, si_obj)
        else:
            self.logger.log("Unkown virtualization type: %s" % virt_type)

    def _delete_svc_instance(self, vm_uuid, proj_name,
                             si_fq_str=None, virt_type=None):
        self.logger.log("Deleting VM %s %s" % (proj_name, vm_uuid))

        try:
            if virt_type == svc_info.get_vm_instance_type():
                self.vm_manager.delete_iip(vm_uuid)
                self.vm_manager.delete_service(si_fq_str, vm_uuid, proj_name)
            elif virt_type == svc_info.get_netns_instance_type():
                self.netns_manager.delete_service(si_fq_str, vm_uuid)
            elif virt_type == 'vrouter-instance':
                self.vrouter_manager.delete_service(si_fq_str, vm_uuid)
        except KeyError:
            return True

        # generate UVE
        self.logger.uve_svc_instance(si_fq_str, status='DELETE',
                                     vms=[{'uuid': vm_uuid}])
        return False

    def _delete_shared_vn(self, vn_uuid, proj_name):
        try:
            vn_obj = self._vnc_lib.virtual_network_read(id=vn_uuid)
        except NoIdError:
            self.logger.log("Deleted VN %s %s" % (proj_name, vn_uuid))
            return True

        iip_back_refs = vn_obj.get_instance_ip_back_refs()
        for iip_back_ref in iip_back_refs or []:
            try:
                self._vnc_lib.instance_ip_delete(id=iip_back_ref['uuid'])
            except (NoIdError, RefsExistError):
                continue

        try:
            self.logger.log("Deleting VN %s %s" % (proj_name, vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except RefsExistError:
            pass
        except NoIdError:
            self.logger.log("Deleted VN %s %s" % (proj_name, vn_uuid))
            return True
        return False

    def _cleanup_si(self, si_fq_str):
        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return
        cleaned_up = True
        state = {}
        state['state'] = 'deleting'
        self.db.service_instance_insert(si_fq_str, state)
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)

        for idx in range(0, int(si_info.get('max-instances', '0'))):
            prefix = self.db.get_vm_db_prefix(idx)
            vm_key = prefix + 'uuid'
            if vm_key in si_info.keys():
                if not self._delete_svc_instance(
                        si_info[vm_key], proj_name, si_fq_str=si_fq_str,
                        virt_type=si_info['instance_type']):
                    cleaned_up = False

        if cleaned_up:
            vn_name = 'snat-si-left_%s' % si_fq_str.split(':')[-1]
            if vn_name in si_info.keys():
                if not self._delete_shared_vn(si_info[vn_name], proj_name):
                    cleaned_up = False

        if cleaned_up:
            for vn_name in svc_info.get_shared_vn_list():
                if vn_name in si_info.keys():
                    self._delete_shared_vn(si_info[vn_name], proj_name)
            self.db.service_instance_remove(si_fq_str)

    def _check_si_status(self, si_fq_name_str, si_info):
        try:
            si_obj = self._vnc_lib.service_instance_read(id=si_info['uuid'])
        except NoIdError:
            # cleanup service instance
            return 'DELETE'

        # check status only if service is active
        if si_info['state'] != 'active':
            return ''

        if si_info['instance_type'] == 'virtual-machine':
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_name_str)
            status = self.vm_manager.check_service(si_obj, proj_name)
        elif si_info['instance_type'] == 'network-namespace':
            status = self.netns_manager.check_service(si_obj)
        elif si_info['instance_type'] == 'vrouter-instance':
            status = self.vrouter_manager.check_service(si_obj)

        return status 

    def _delmsg_virtual_machine_service_instance(self, idents):
        vm_fq_str = idents['virtual-machine']
        si_fq_str = idents['service-instance']
        self.db.remove_vm_info(si_fq_str, vm_fq_str)

    def _delmsg_virtual_machine_interface_virtual_network(self, idents):
        vmi_fq_str = idents['virtual-machine-interface']
        vn_fq_str = idents['virtual-network']
        vn_fq_name = vn_fq_str.split(':')
        for vn_name in svc_info.get_shared_vn_list():
            if vn_name != vn_fq_name[2]:
                continue
            try:
                vn_id = self._vnc_lib.fq_name_to_id(
                    'virtual-network', vn_fq_name)
            except NoIdError:
                continue
            self._delete_shared_vn(vn_id, vn_fq_name[1])

    def _delmsg_service_instance_service_template(self, idents):
        self._cleanup_si(idents['service-instance'])

    def _delmsg_virtual_machine_interface_route_table(self, idents):
        rt_fq_str = idents['interface-route-table']

        try:
            rt_obj = self._vnc_lib.interface_route_table_read(
                fq_name_str=rt_fq_str)
        except NoIdError:
            return

        try:
            vmi_list = rt_obj.get_virtual_machine_interface_back_refs()
            if vmi_list is None:
                self._vnc_lib.interface_route_table_delete(id=rt_obj.uuid)
        except NoIdError:
            return

    def _addmsg_service_instance_service_template(self, idents):
        st_fq_str = idents['service-template']
        si_fq_str = idents['service-instance']

        try:
            st_obj = self._vnc_lib.service_template_read(
                fq_name_str=st_fq_str)
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            self.logger.log("No template or service instance with ids: %s, %s"
                            % (st_fq_str, si_fq_str))
            return

        #launch VMs
        self._create_svc_instance(st_obj, si_obj)
    # end _addmsg_service_instance_service_template

    def _addmsg_service_instance_properties(self, idents):
        si_fq_str = idents['service-instance']

        try:
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            return

        #update static routes
        self.vm_manager.update_static_routes(si_obj)

    def _addmsg_project_virtual_network(self, idents):
        vn_fq_str = idents['virtual-network']

        si_list = self.db.service_instance_list()
        if not si_list:
            return

        for si_fq_str, si_info in si_list:
            if vn_fq_str not in si_info.keys():
                continue

            try:
                si_obj = self._vnc_lib.service_instance_read(
                    fq_name_str=si_fq_str)
                if si_obj.get_virtual_machine_back_refs():
                    continue

                st_refs = si_obj.get_service_template_refs()
                fq_name = st_refs[0]['to']
                st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)

                #launch VMs
                self._create_svc_instance(st_obj, si_obj)
            except Exception:
                continue

    def _addmsg_floating_ip_virtual_machine_interface(self, idents):
        fip_fq_str = idents['floating-ip']
        vmi_fq_str = idents['virtual-machine-interface']

        try:
            fip_obj = self._vnc_lib.floating_ip_read(
                fq_name_str=fip_fq_str)
            vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                fq_name_str=vmi_fq_str)
        except NoIdError:
            return

        # handle only if VIP back ref exists
        vip_back_refs = vmi_obj.get_virtual_ip_back_refs()
        if vip_back_refs is None:
            return

        # associate fip to all VMIs
        iip_back_refs = vmi_obj.get_instance_ip_back_refs()
        try:
            iip_obj = self._vnc_lib.instance_ip_read(
                id=iip_back_refs[0]['uuid'])
        except NoIdError:
            return

        fip_updated = False
        vmi_refs_iip = iip_obj.get_virtual_machine_interface_refs()
        vmi_refs_fip = fip_obj.get_virtual_machine_interface_refs()
        for vmi_ref_iip in vmi_refs_iip:
            if vmi_ref_iip in vmi_refs_fip:
                continue
            try:
                vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                    id=vmi_ref_iip['uuid'])
            except NoIdError:
                continue
            fip_obj.add_virtual_machine_interface(vmi_obj)
            fip_updated = True

        if fip_updated:
            self._vnc_lib.floating_ip_update(fip_obj)


    def process_poll_result(self, poll_result_str):
        result_list = parse_poll_result(poll_result_str)

        # process ifmap message
        for (result_type, idents, metas) in result_list:
            if 'ERROR' in idents.values():
                continue
            for meta in metas:
                meta_name = re.sub('{.*}', '', meta.tag)
                if result_type == 'deleteResult':
                    funcname = "_delmsg_" + meta_name.replace('-', '_')
                elif result_type in ['searchResult', 'updateResult']:
                    funcname = "_addmsg_" + meta_name.replace('-', '_')
                # end if result_type
                try:
                    func = getattr(self, funcname)
                except AttributeError:
                    pass
                else:
                    self.logger.log("%s with %s/%s"
                                     % (funcname, meta_name, idents))
                    func(idents)
示例#13
0
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                client_type='Service Monitor')

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = '/var/log/contrail/svc-monitor.err'
        self._tmp_file = '/var/log/contrail/svc-monitor.tmp'
        try:
            with open(self._err_file, 'a'):
                pass
            with open(self._tmp_file, 'a'):
                pass
        except IOError:
            self._err_file = './svc-monitor.err'
            self._tmp_file = './svc-monitor.tmp'
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        handler = logging.handlers.RotatingFileHandler(
            self._err_file, maxBytes=64*1024, backupCount=2)
        self._svc_err_logger.addHandler(handler)


    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        # create default analyzer template
        self._create_default_template('analyzer-template', 'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template', 'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template', 'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template', 'loadbalancer',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver,
            self._vnc_lib,
            self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.instance_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._args)


    # create service template
    def _create_default_template(self, st_name, svc_type, svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None, flavor=None, scaling=False):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log("Creating %s %s hypervisor %s" %
                         (domain_name, st_name, hypervisor_type))

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name=st_fq_name)
            st_uuid = st_obj.uuid
            self.logger.log("%s exists uuid %s" % (st_name, str(st_uuid)))
            return
        except NoIdError:
            domain = self._vnc_lib.domain_read(fq_name=domain_fq_name)
            st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
            st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['right', True], ['left', True]]
        else:
            if_list = [
                ['management', False], ['left', False], ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log("%s created with uuid %s" % (st_name, str(st_uuid)))
    #_create_default_analyzer_template

    def cleanup(self):
        pass
    # end cleanup

    def _get_proj_name_from_si_fq_str(self, si_fq_str):
        return si_fq_str.split(':')[1]
    # enf _get_si_fq_str_to_proj_name

    def _get_virtualization_type(self, st_props):
        return st_props.get_service_virtualization_type() or 'virtual-machine'
    # end _get_virtualization_type

    def _check_store_si_info(self, st_obj, si_obj):
        config_complete = True
        st_props = st_obj.get_service_template_properties()
        st_if_list = st_props.get_interface_type()
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        # for lb relax the check because vip and pool could be in same net
        if (st_props.get_service_type() != svc_info.get_lb_service_type()) \
                and si_if_list and (len(si_if_list) != len(st_if_list)):
            self.logger.log("Error: IF mismatch template %s instance %s" %
                             (len(st_if_list), len(si_if_list)))
            return

        # read existing si_entry
        si_entry = self.db.service_instance_get(si_obj.get_fq_name_str())
        if not si_entry:
            si_entry = {}
        si_entry['instance_type'] = self._get_virtualization_type(st_props)
        si_entry['uuid'] = si_obj.uuid

        # walk the interface list
        for idx in range(0, len(st_if_list)):
            st_if = st_if_list[idx]
            itf_type = st_if.service_interface_type

            si_if = None
            if si_if_list and st_props.get_ordered_interfaces():
                try:
                    si_if = si_if_list[idx]
                except IndexError:
                    continue
                si_vn_str = si_if.get_virtual_network()
            else:
                funcname = "get_" + itf_type + "_virtual_network"
                func = getattr(si_props, funcname)
                si_vn_str = func()

            if not si_vn_str:
                continue

            si_entry[itf_type + '-vn'] = si_vn_str
            try:
                vn_obj = self._vnc_lib.virtual_network_read(
                    fq_name_str=si_vn_str)
                if vn_obj.uuid != si_entry.get(si_vn_str, None):
                    si_entry[si_vn_str] = vn_obj.uuid
            except NoIdError:
                self.logger.log("Warn: VN %s add is pending" % si_vn_str)
                si_entry[si_vn_str] = 'pending'
                config_complete = False

        if config_complete:
            self.logger.log("SI %s info is complete" %
                             si_obj.get_fq_name_str())
            si_entry['state'] = 'active'
        else:
            self.logger.log("Warn: SI %s info is not complete" %
                             si_obj.get_fq_name_str())
            si_entry['state'] = 'pending'

        #insert entry
        self.db.service_instance_insert(si_obj.get_fq_name_str(), si_entry)
        return config_complete
    #end _check_store_si_info

    def _restart_svc(self, si_fq_str):
        si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        st_list = si_obj.get_service_template_refs()
        if st_list is not None:
            fq_name = st_list[0]['to']
            st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)
            self._create_svc_instance(st_obj, si_obj)
    # end _restart_svc

    def _create_svc_instance(self, st_obj, si_obj):
        #check if all config received before launch
        if not self._check_store_si_info(st_obj, si_obj):
            return

        st_props = st_obj.get_service_template_properties()
        if st_props is None:
            self.logger.log("Cannot find service template associated to "
                             "service instance %s" % si_obj.get_fq_name_str())
        virt_type = self._get_virtualization_type(st_props)
        if virt_type == 'virtual-machine':
            self.vm_manager.create_service(st_obj, si_obj)
        elif virt_type == 'network-namespace':
            self.netns_manager.create_service(st_obj, si_obj)

    def _delete_svc_instance(self, vm_uuid, proj_name,
                             si_fq_str=None, virt_type=None):
        self.logger.log("Deleting VM %s %s" % (proj_name, vm_uuid))

        try:
            if virt_type == svc_info.get_vm_instance_type():
                self.vm_manager.delete_service(vm_uuid, proj_name)
            elif virt_type == svc_info.get_netns_instance_type():
                self.netns_manager.delete_service(vm_uuid)
        except KeyError:
            return True

        # generate UVE
        self.logger.uve_svc_instance(si_fq_str, status='DELETE',
                                     vms=[{'uuid': vm_uuid}])
        return False

    def _delete_shared_vn(self, vn_uuid, proj_name):
        try:
            self.logger.log("Deleting VN %s %s" % (proj_name, vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except RefsExistError:
            self._svc_err_logger.error("Delete failed refs exist VN %s %s" %
                                       (proj_name, vn_uuid))
        except NoIdError:
            return True
        return False

    def _cleanup_si(self, si_fq_str):
        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return
        cleaned_up = True
        state = {}
        state['state'] = 'deleting'
        self.db.service_instance_insert(si_fq_str, state)
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)

        for idx in range(0, int(si_info.get('max-instances', '0'))):
            prefix = self.db.get_vm_db_prefix(idx)
            vm_key = prefix + 'uuid'
            if vm_key in si_info.keys():
                if not self._delete_svc_instance(
                        si_info[vm_key], proj_name, si_fq_str=si_fq_str,
                        virt_type=si_info['instance_type']):
                    cleaned_up = False

        if cleaned_up:
            vn_name = 'snat-si-left_%s' % si_fq_str.split(':')[-1]
            if vn_name in si_info.keys():
                if not self._delete_shared_vn(si_info[vn_name], proj_name):
                    cleaned_up = False

        # delete shared vn and delete si info
        if cleaned_up:
            for vn_name in svc_info.get_shared_vn_list():
                if vn_name in si_info.keys():
                    self._delete_shared_vn(si_info[vn_name], proj_name)
            self.db.service_instance_remove(si_fq_str)

    def _check_si_status(self, si_fq_name_str, si_info):
        try:
            si_obj = self._vnc_lib.service_instance_read(id=si_info['uuid'])
        except NoIdError:
            # cleanup service instance
            return 'DELETE'

        if si_info['instance_type'] == 'virtual-machine':
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_name_str)
            status = self.vm_manager.check_service(si_obj, proj_name)
        elif si_info['instance_type'] == 'network-namespace':
            status = self.netns_manager.check_service(si_obj)

        return status 

    def _delmsg_service_instance_service_template(self, idents):
        self._cleanup_si(idents['service-instance'])

    def _delmsg_virtual_machine_interface_route_table(self, idents):
        rt_fq_str = idents['interface-route-table']

        try:
            rt_obj = self._vnc_lib.interface_route_table_read(
                fq_name_str=rt_fq_str)
        except NoIdError:
            return

        vmi_list = rt_obj.get_virtual_machine_interface_back_refs()
        if vmi_list is None:
            self._vnc_lib.interface_route_table_delete(id=rt_obj.uuid)

    def _addmsg_service_instance_service_template(self, idents):
        st_fq_str = idents['service-template']
        si_fq_str = idents['service-instance']

        try:
            st_obj = self._vnc_lib.service_template_read(
                fq_name_str=st_fq_str)
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            return

        #launch VMs
        self._create_svc_instance(st_obj, si_obj)
    # end _addmsg_service_instance_service_template

    def _addmsg_service_instance_properties(self, idents):
        si_fq_str = idents['service-instance']

        try:
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            return

        #update static routes
        self.vm_manager.update_static_routes(si_obj)

    def _addmsg_project_virtual_network(self, idents):
        vn_fq_str = idents['virtual-network']

        si_list = self.db.service_instance_list()
        if not si_list:
            return

        for si_fq_str, si_info in si_list:
            if vn_fq_str not in si_info.keys():
                continue

            try:
                si_obj = self._vnc_lib.service_instance_read(
                    fq_name_str=si_fq_str)
                if si_obj.get_virtual_machine_back_refs():
                    continue

                st_refs = si_obj.get_service_template_refs()
                fq_name = st_refs[0]['to']
                st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)

                #launch VMs
                self._create_svc_instance(st_obj, si_obj)
            except Exception:
                continue

    def _addmsg_floating_ip_virtual_machine_interface(self, idents):
        fip_fq_str = idents['floating-ip']
        vmi_fq_str = idents['virtual-machine-interface']

        try:
            fip_obj = self._vnc_lib.floating_ip_read(
                fq_name_str=fip_fq_str)
            vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                fq_name_str=vmi_fq_str)
        except NoIdError:
            return

        # handle only if VIP back ref exists
        vip_back_refs = vmi_obj.get_virtual_ip_back_refs()
        if vip_back_refs is None:
            return

        # associate fip to all VMIs
        iip_back_refs = vmi_obj.get_instance_ip_back_refs()
        try:
            iip_obj = self._vnc_lib.instance_ip_read(
                id=iip_back_refs[0]['uuid'])
        except NoIdError:
            return

        fip_updated = False
        vmi_refs_iip = iip_obj.get_virtual_machine_interface_refs()
        vmi_refs_fip = fip_obj.get_virtual_machine_interface_refs()
        for vmi_ref_iip in vmi_refs_iip:
            if vmi_ref_iip in vmi_refs_fip:
                continue
            try:
                vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                    id=vmi_ref_iip['uuid'])
            except NoIdError:
                continue
            fip_obj.add_virtual_machine_interface(vmi_obj)
            fip_updated = True

        if fip_updated:
            self._vnc_lib.floating_ip_update(fip_obj)


    def process_poll_result(self, poll_result_str):
        result_list = parse_poll_result(poll_result_str)

        # process ifmap message
        for (result_type, idents, metas) in result_list:
            if 'ERROR' in idents.values():
                continue
            for meta in metas:
                meta_name = re.sub('{.*}', '', meta.tag)
                if result_type == 'deleteResult':
                    funcname = "_delmsg_" + meta_name.replace('-', '_')
                elif result_type in ['searchResult', 'updateResult']:
                    funcname = "_addmsg_" + meta_name.replace('-', '_')
                # end if result_type
                try:
                    func = getattr(self, funcname)
                except AttributeError:
                    pass
                else:
                    self.logger.log("%s with %s/%s"
                                     % (funcname, meta_name, idents))
                    func(idents)
示例#14
0
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """
    _REACTION_MAP = {
        "loadbalancer_pool": {
            'self': [],
            'virtual_ip': [],
            'loadbalancer_member': [],
            'loadbalancer_healthmonitor': [],
        },
        "loadbalancer_member": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "virtual_ip": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "loadbalancer_healthmonitor": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "service_instance": {
            'self': ['virtual_machine'],
            'virtual_machine': []
        },
        "instance_ip": {
            'self': [],
        },
        "service_template": {
            'self': [],
        },
        "physical_router": {
            'self': [],
        },
        "physical_interface": {
            'self': [],
        },
        "logical_interface": {
            'self': [],
        },
        "virtual_network": {
            'self': [],
        },
        "virtual_machine": {
            'self': ['virtual_machine_interface'],
            'service_instance': [],
            'virtual_machine_interface': [],
        },
        "virtual_machine_interface": {
            'self': ['interface_route_table', 'virtual_machine'],
            'interface_route_table': [],
            'virtual_machine': [],
        },
        "interface_route_table": {
            'self': [],
            'virtual_machine_interface': [],
        },
        "project": {
            'self': [],
        },
    }

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(
                    self._err_file, maxBytes=64*1024, backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log_warning("Failed to open trace file %s" %
                self._err_file)

        # Connect to Rabbit and Initialize cassandra connection
        self._connect_rabbit()

    def _connect_rabbit(self):
        rabbit_server = self._args.rabbit_server
        rabbit_port = self._args.rabbit_port
        rabbit_user = self._args.rabbit_user
        rabbit_password = self._args.rabbit_password
        rabbit_vhost = self._args.rabbit_vhost
        rabbit_ha_mode = self._args.rabbit_ha_mode

        self._db_resync_done = gevent.event.Event()

        q_name = 'svc_mon.%s' % (socket.gethostname())
        self._vnc_kombu = VncKombuClient(rabbit_server, rabbit_port,
                                         rabbit_user, rabbit_password,
                                         rabbit_vhost, rabbit_ha_mode,
                                         q_name, self._vnc_subscribe_callback,
                                         self.config_log)

        cass_server_list = self._args.cassandra_server_list
        reset_config = self._args.reset_config
        self._cassandra = VncCassandraClient(cass_server_list, reset_config,
                                             self._args.cluster_id, None,
                                             self.config_log)
        DBBase.init(self, self.logger, self._cassandra)
    # end _connect_rabbit

    def config_log(self, msg, level):
        self.logger.log(msg)

    def _vnc_subscribe_callback(self, oper_info):
        self._db_resync_done.wait()
        try:
            msg = "Notification Message: %s" % (pformat(oper_info))
            self.config_log(msg, level=SandeshLevel.SYS_DEBUG)
            obj_type = oper_info['type'].replace('-', '_')
            obj_class = DBBase._OBJ_TYPE_MAP.get(obj_type)
            if obj_class is None:
                return

            if oper_info['oper'] == 'CREATE' or oper_info['oper'] == 'UPDATE':
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP,
                    self._REACTION_MAP)
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is not None:
                    dependency_tracker.evaluate(obj_type, obj)
                else:
                    obj = obj_class.locate(obj_id)
                obj.update()
                dependency_tracker.evaluate(obj_type, obj)
            elif oper_info['oper'] == 'DELETE':
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is None:
                    return
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP,
                    self._REACTION_MAP)
                dependency_tracker.evaluate(obj_type, obj)
                obj_class.delete(obj_id)
            else:
                # unknown operation
                self.config_log('Unknown operation %s' % oper_info['oper'],
                                level=SandeshLevel.SYS_ERR)
                return

            if obj is None:
                self.config_log('Error while accessing %s uuid %s' % (
                                obj_type, obj_id))
                return


        except Exception:
            string_buf = cStringIO.StringIO()
            cgitb.Hook(file=string_buf, format="text").handle(sys.exc_info())
            self.config_log(string_buf.getvalue(), level=SandeshLevel.SYS_ERR)

        for sas_id in dependency_tracker.resources.get('service_appliance_set', []):
            sas_obj = ServiceApplianceSetSM.get(sas_id)
            if sas_obj is not None:
                sas_obj.add()

        for lb_pool_id in dependency_tracker.resources.get('loadbalancer_pool', []):
            lb_pool = LoadbalancerPoolSM.get(lb_pool_id)
            if lb_pool is not None:
                lb_pool.add()
    # end _vnc_subscribe_callback

        for si_id in dependency_tracker.resources.get('service_instance', []):
            si = ServiceInstanceSM.get(si_id)
            if si:
                self._create_service_instance(si)
            else:
                for vm_id in dependency_tracker.resources.get(
                        'virtual_machine', []):
                    vm = VirtualMachineSM.get(vm_id)
                    self._delete_service_instance(vm)

        for vn_id in dependency_tracker.resources.get('virtual_network', []):
            vn = VirtualNetworkSM.get(vn_id)
            if vn:
                for si_id in ServiceInstanceSM:
                    si = ServiceInstanceSM.get(si_id)
                    if (':').join(vn.fq_name) in si.params.values():
                        self._create_service_instance(si)

        for vmi_id in dependency_tracker.resources.get('virtual_machine_interface', []):
            vmi = VirtualMachineInterfaceSM.get(vmi_id)
            if vmi:
                for vm_id in dependency_tracker.resources.get(
                        'virtual_machine', []):
                    vm = VirtualMachineSM.get(vm_id)
                    if vm:
                        self.check_link_si_to_vm(vm, vmi)
            else:
                for irt_id in dependency_tracker.resources.get(
                        'interface_route_table', []):
                    self._delete_interface_route_table(irt_id)

    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        self._nova_client = importutils.import_object(
            'svc_monitor.nova_client.ServiceMonitorNovaClient',
            self._args, self.logger)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver,
            self._vnc_lib, self._nova_client,
            self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.virtual_machine_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a vrouter instance manager
        self.vrouter_manager = importutils.import_object(
            'svc_monitor.vrouter_instance_manager.VRouterInstanceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a loadbalancer agent
        self.loadbalancer_agent = LoadbalancerAgent(self, self._vnc_lib, self._args)

        # Read the cassandra and populate the entry in ServiceMonitor DB
        self.sync_sm()

        # create default analyzer template
        self._create_default_template('analyzer-template', 'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template', 'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template', 'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template', 'loadbalancer',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        self._create_default_template('docker-template', 'firewall',
                                      svc_mode='transparent',
                                      image_name="ubuntu",
                                      hypervisor_type='vrouter-instance',
                                      vrouter_instance_type='docker',
                                      instance_data={
                                          "command": "/bin/bash"
                                      })

        # check services
        self.launch_services()

    def launch_services(self):
        for si in ServiceInstanceSM.values():
            self._create_service_instance(si)

    def sync_sm(self):
        vn_set = set()
        vmi_set = set()
        iip_set = set()
        ok, lb_pool_list = self._cassandra._cassandra_loadbalancer_pool_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_list:
                lb_pool = LoadbalancerPoolSM.locate(uuid)
                if lb_pool.virtual_machine_interface:
                    vmi_set.add(lb_pool.virtual_machine_interface)

        ok, lb_pool_member_list = self._cassandra._cassandra_loadbalancer_member_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_member_list:
                lb_pool_member = LoadbalancerMemberSM.locate(uuid)

        ok, lb_vip_list = self._cassandra._cassandra_virtual_ip_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_vip_list:
                virtual_ip = VirtualIpSM.locate(uuid)
                if virtual_ip.virtual_machine_interface:
                    vmi_set.add(virtual_ip.virtual_machine_interface)

        ok, lb_hm_list = self._cassandra._cassandra_loadbalancer_healthmonitor_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_hm_list:
                lb_hm = HealthMonitorSM.locate(uuid)

        ok, si_list = self._cassandra._cassandra_service_instance_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in si_list:
                si = ServiceInstanceSM.locate(uuid)

        ok, st_list = self._cassandra._cassandra_service_template_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in st_list:
                st = ServiceTemplateSM.locate(uuid)

        ok, vn_list = self._cassandra._cassandra_virtual_network_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vn_list:
                vn = VirtualNetworkSM.locate(uuid)
                vmi_set |= vn.virtual_machine_interfaces

        ok, ifd_list = self._cassandra._cassandra_physical_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in ifd_list:
                ifd = PhysicalInterfaceSM.locate(uuid)


        ok, ifl_list = self._cassandra._cassandra_logical_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in ifl_list:
                ifl = LogicalInterfaceSM.locate(uuid)
                if ifl.virtual_machine_interface:
                    vmi_set.add(ifl.virtual_machine_interface)

        ok, pr_list = self._cassandra._cassandra_physical_router_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in pr_list:
                pr = PhysicalRouterSM.locate(uuid)

        ok, vr_list = self._cassandra._cassandra_virtual_router_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vr_list:
                vr = VirtualRouterSM.locate(uuid)

        ok, vmi_list = self._cassandra._cassandra_virtual_machine_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vmi_list:
                vmi = VirtualMachineInterfaceSM.locate(uuid)
                if vmi.instance_ip:
                    iip_set.add(vmi.instance_ip)

        ok, irt_list = self._cassandra._cassandra_interface_route_table_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in irt_list:
                irt = InterfaceRouteTableSM.locate(uuid)

        ok, project_list = self._cassandra._cassandra_project_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in project_list:
                prj = ProjectSM.locate(uuid)

        ok, sas_list = self._cassandra._cassandra_service_appliance_set_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in sas_list:
                sas = ServiceApplianceSetSM.locate(uuid)

        ok, sa_list = self._cassandra._cassandra_service_appliance_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in sa_list:
                sa = ServiceApplianceSM.locate(uuid)

        ok, domain_list = self._cassandra._cassandra_domain_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in domain_list:
                DomainSM.locate(uuid)

        ok, iip_list = self._cassandra._cassandra_instance_ip_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in iip_list:
                InstanceIpSM.locate(uuid)

        ok, vm_list = self._cassandra._cassandra_virtual_machine_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vm_list:
                vm = VirtualMachineSM.locate(uuid)
                if vm.service_instance:
                    continue
                for vmi_id in vm.virtual_machine_interfaces:
                    vmi = VirtualMachineInterfaceSM.get(vmi_id)
                    if not vmi:
                        continue
                    self.check_link_si_to_vm(vm, vmi)

        # Load the loadbalancer driver
        self.loadbalancer_agent.load_drivers()

        for lb_pool in LoadbalancerPoolSM.values():
            lb_pool.add()


        self._db_resync_done.set()
    # end sync_sm

    # create service template
    def _create_default_template(self, st_name, svc_type, svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None, flavor=None, scaling=False,
                                 vrouter_instance_type=None,
                                 instance_data=None):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log_info("Creating %s %s hypervisor %s" %
            (domain_name, st_name, hypervisor_type))

        domain_obj = None
        for domain in DomainSM.values():
            if domain.fq_name == domain_fq_name:
                domain_obj = Domain()
                domain_obj.uuid = domain.uuid
                domain_obj.fq_name = domain_fq_name
                break
        if not domain_obj:
            self.logger.log_error("%s domain not found" % (domain_name))
            return

        for st in ServiceTemplateSM.values():
            if st.fq_name == st_fq_name:
                self.logger.log_info("%s exists uuid %s" %
                    (st.name, str(st.uuid)))
                return

        st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
        st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['right', True], ['left', True]]
        else:
            if_list = [
                ['management', False], ['left', False], ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        if vrouter_instance_type is not None:
            svc_properties.set_vrouter_instance_type(vrouter_instance_type)

        if instance_data is not None:
            svc_properties.set_instance_data(
                json.dumps(instance_data, separators=(',', ':')))

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log_info("%s created with uuid %s" %
            (st_name, str(st_uuid)))
    #_create_default_analyzer_template

    def check_link_si_to_vm(self, vm, vmi):
        if vm.service_instance:
            return
        if not vmi.if_type:
            return

        si_fq_name = vmi.name.split('__')[0:3]
        index = int(vmi.name.split('__')[3]) - 1
        for si in ServiceInstanceSM.values():
            if si.fq_name != si_fq_name:
                continue
            st = ServiceTemplateSM.get(si.service_template)
            self.vm_manager.link_si_to_vm(si, st, index, vm.uuid)
            return

    def _create_service_instance(self, si):
        if si.state == 'active':
            return
        st = ServiceTemplateSM.get(si.service_template)
        if st.virtualization_type == 'virtual-machine':
            self.vm_manager.create_service(st, si)
        elif st.virtualization_type == 'network-namespace':
            self.netns_manager.create_service(st, si)
        elif st.virtualization_type == 'vrouter-instance':
            self.vrouter_manager.create_service(st, si)
        else:
            self.logger.log_error("Unknown virt type: %s" %
                st.virtualization_type)

    def _delete_service_instance(self, vm):
        self.logger.log_info("Deleting VM %s %s" %
            ((':').join(vm.proj_fq_name), vm.uuid))

        if vm.virtualization_type == svc_info.get_vm_instance_type():
            self.vm_manager.delete_service(vm)
        elif vm.virtualization_type == svc_info.get_netns_instance_type():
            self.netns_manager.delete_service(vm)
        elif vm.virtualization_type == 'vrouter-instance':
            self.vrouter_manager.delete_service(vm)

        # generate UVE
        si_fq_name = vm.display_name.split('__')[:-2]
        si_fq_str = (':').join(si_fq_name)
        self.logger.uve_svc_instance(si_fq_str, status='DELETE',
                                     vms=[{'uuid': vm.uuid}])
        return True

    def _relaunch_service_instance(self, si):
        if si.state == 'active':
            si.state = 'relaunch'
            self._create_service_instance(si)

    def _check_service_running(self, si):
        if si.state != 'active':
            return
        st = ServiceTemplateSM.get(si.service_template)
        if st.virtualization_type == 'virtual-machine':
            status = self.vm_manager.check_service(si)
        elif st.virtualization_type == 'network-namespace':
            status = self.netns_manager.check_service(si)
        elif st.virtualization_type == 'vrouter-instance':
            status = self.vrouter_manager.check_service(si)

        return status

    def _delete_interface_route_table(self, irt_uuid):
        try:
            self._vnc_lib.interface_route_table_delete(id=irt_uuid)
        except (NoIdError, RefsExistError):
            return

    def _delete_shared_vn(self, vn_uuid):
        try:
            self.logger.log_info("Deleting vn %s" % (vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except (NoIdError, RefsExistError):
            pass
示例#15
0
class SvcMonitor(object):
    """
    data + methods used/referred to by ssrc and arc greenlets
    """
    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(
                self._args.disc_server_ip, self._args.disc_server_port,
                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(self._err_file,
                                                               maxBytes=64 *
                                                               1024,
                                                               backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log("Failed to open trace file %s" % self._err_file)

    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        # create default analyzer template
        self._create_default_template('analyzer-template',
                                      'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template',
                                      'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template',
                                      'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template',
                                      'loadbalancer',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        self._create_default_template('docker-template',
                                      'firewall',
                                      svc_mode='transparent',
                                      image_name="ubuntu",
                                      hypervisor_type='vrouter-instance',
                                      vrouter_instance_type='docker',
                                      instance_data={"command": "/bin/bash"})

        self._nova_client = importutils.import_object(
            'svc_monitor.nova_client.ServiceMonitorNovaClient', self._args)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver, self._vnc_lib,
            self._nova_client, self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.virtual_machine_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger, self.vrouter_scheduler,
            self._nova_client, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger, self.vrouter_scheduler,
            self._nova_client, self._args)

        # load a vrouter instance manager
        self.vrouter_manager = importutils.import_object(
            'svc_monitor.vrouter_instance_manager.VRouterInstanceManager',
            self._vnc_lib, self.db, self.logger, self.vrouter_scheduler,
            self._nova_client, self._args)

    # create service template
    def _create_default_template(self,
                                 st_name,
                                 svc_type,
                                 svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None,
                                 flavor=None,
                                 scaling=False,
                                 vrouter_instance_type=None,
                                 instance_data=None):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log("Creating %s %s hypervisor %s" %
                        (domain_name, st_name, hypervisor_type))

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name=st_fq_name)
            st_uuid = st_obj.uuid
            self.logger.log("%s exists uuid %s" % (st_name, str(st_uuid)))
            return
        except NoIdError:
            domain = self._vnc_lib.domain_read(fq_name=domain_fq_name)
            st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
            st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['right', True], ['left', True]]
        else:
            if_list = [['management', False], ['left', False],
                       ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        if vrouter_instance_type is not None:
            svc_properties.set_vrouter_instance_type(vrouter_instance_type)

        if instance_data is not None:
            svc_properties.set_instance_data(
                json.dumps(instance_data, separators=(',', ':')))

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log("%s created with uuid %s" % (st_name, str(st_uuid)))

    #_create_default_analyzer_template

    def cleanup(self):
        pass

    # end cleanup

    def _get_proj_name_from_si_fq_str(self, si_fq_str):
        return si_fq_str.split(':')[1]

    # enf _get_si_fq_str_to_proj_name

    def _get_virtualization_type(self, st_props):
        return st_props.get_service_virtualization_type() or 'virtual-machine'

    # end _get_virtualization_type

    def _check_store_si_info(self, st_obj, si_obj):
        config_complete = True
        st_props = st_obj.get_service_template_properties()
        st_if_list = st_props.get_interface_type()
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        # for lb relax the check because vip and pool could be in same net
        if (st_props.get_service_type() != svc_info.get_lb_service_type()) \
                and si_if_list and (len(si_if_list) != len(st_if_list)):
            self.logger.log("Error: IF mismatch template %s instance %s" %
                            (len(st_if_list), len(si_if_list)))
            return

        # read existing si_entry
        si_entry = self.db.service_instance_get(si_obj.get_fq_name_str())
        if not si_entry:
            si_entry = {}
        si_entry['instance_type'] = self._get_virtualization_type(st_props)
        si_entry['uuid'] = si_obj.uuid

        # walk the interface list
        for idx in range(0, len(st_if_list)):
            st_if = st_if_list[idx]
            itf_type = st_if.service_interface_type

            si_if = None
            if si_if_list and st_props.get_ordered_interfaces():
                try:
                    si_if = si_if_list[idx]
                except IndexError:
                    continue
                si_vn_str = si_if.get_virtual_network()
            else:
                funcname = "get_" + itf_type + "_virtual_network"
                func = getattr(si_props, funcname)
                si_vn_str = func()

            if not si_vn_str:
                continue

            si_entry[itf_type + '-vn'] = si_vn_str
            try:
                vn_obj = self._vnc_lib.virtual_network_read(
                    fq_name_str=si_vn_str)
                if vn_obj.uuid != si_entry.get(si_vn_str, None):
                    si_entry[si_vn_str] = vn_obj.uuid
            except NoIdError:
                self.logger.log("Warn: VN %s add is pending" % si_vn_str)
                si_entry[si_vn_str] = 'pending'
                config_complete = False

        if config_complete:
            self.logger.log("SI %s info is complete" %
                            si_obj.get_fq_name_str())
            si_entry['state'] = 'config_complete'
        else:
            self.logger.log("Warn: SI %s info is not complete" %
                            si_obj.get_fq_name_str())
            si_entry['state'] = 'pending_config'

        #insert entry
        self.db.service_instance_insert(si_obj.get_fq_name_str(), si_entry)
        return config_complete

    #end _check_store_si_info

    def _restart_svc(self, si_fq_str):
        si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        st_list = si_obj.get_service_template_refs()
        if st_list is not None:
            fq_name = st_list[0]['to']
            st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)
            self._create_svc_instance(st_obj, si_obj)

    # end _restart_svc

    def _create_svc_instance(self, st_obj, si_obj):
        #check if all config received before launch
        if not self._check_store_si_info(st_obj, si_obj):
            return

        st_props = st_obj.get_service_template_properties()
        if st_props is None:
            self.logger.log("Cannot find service template associated to "
                            "service instance %s" % si_obj.get_fq_name_str())
        virt_type = self._get_virtualization_type(st_props)

        if virt_type == 'virtual-machine':
            self.vm_manager.create_service(st_obj, si_obj)
        elif virt_type == 'network-namespace':
            self.netns_manager.create_service(st_obj, si_obj)
        elif virt_type == 'vrouter-instance':
            self.vrouter_manager.create_service(st_obj, si_obj)
        else:
            self.logger.log("Unkown virtualization type: %s" % virt_type)

    def _delete_svc_instance(self,
                             vm_uuid,
                             proj_name,
                             si_fq_str=None,
                             virt_type=None):
        self.logger.log("Deleting VM %s %s" % (proj_name, vm_uuid))

        try:
            if virt_type == svc_info.get_vm_instance_type():
                self.vm_manager.delete_service(si_fq_str, vm_uuid, proj_name)
            elif virt_type == svc_info.get_netns_instance_type():
                self.netns_manager.delete_service(si_fq_str, vm_uuid)
            elif virt_type == 'vrouter-instance':
                self.vrouter_manager.delete_service(si_fq_str, vm_uuid)
        except KeyError:
            return True

        # generate UVE
        self.logger.uve_svc_instance(si_fq_str,
                                     status='DELETE',
                                     vms=[{
                                         'uuid': vm_uuid
                                     }])
        return False

    def _delete_shared_vn(self, vn_uuid, proj_name):
        try:
            self.logger.log("Deleting VN %s %s" % (proj_name, vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except RefsExistError:
            pass
        except NoIdError:
            self.logger.log("Deleted VN %s %s" % (proj_name, vn_uuid))
            return True
        return False

    def _cleanup_si(self, si_fq_str):
        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return
        cleaned_up = True
        state = {}
        state['state'] = 'deleting'
        self.db.service_instance_insert(si_fq_str, state)
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)

        for idx in range(0, int(si_info.get('max-instances', '0'))):
            prefix = self.db.get_vm_db_prefix(idx)
            vm_key = prefix + 'uuid'
            if vm_key in si_info.keys():
                if not self._delete_svc_instance(
                        si_info[vm_key],
                        proj_name,
                        si_fq_str=si_fq_str,
                        virt_type=si_info['instance_type']):
                    cleaned_up = False

        if cleaned_up:
            vn_name = 'snat-si-left_%s' % si_fq_str.split(':')[-1]
            if vn_name in si_info.keys():
                if not self._delete_shared_vn(si_info[vn_name], proj_name):
                    cleaned_up = False

        if cleaned_up:
            for vn_name in svc_info.get_shared_vn_list():
                if vn_name in si_info.keys():
                    self._delete_shared_vn(si_info[vn_name], proj_name)
            self.db.service_instance_remove(si_fq_str)

    def _check_si_status(self, si_fq_name_str, si_info):
        try:
            si_obj = self._vnc_lib.service_instance_read(id=si_info['uuid'])
        except NoIdError:
            # cleanup service instance
            return 'DELETE'

        # check status only if service is active
        if si_info['state'] != 'active':
            return ''

        if si_info['instance_type'] == 'virtual-machine':
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_name_str)
            status = self.vm_manager.check_service(si_obj, proj_name)
        elif si_info['instance_type'] == 'network-namespace':
            status = self.netns_manager.check_service(si_obj)
        elif si_info['instance_type'] == 'vrouter-instance':
            status = self.vrouter_manager.check_service(si_obj)

        return status

    def _delmsg_virtual_machine_service_instance(self, idents):
        vm_fq_str = idents['virtual-machine']
        si_fq_str = idents['service-instance']
        self.db.remove_vm_info(si_fq_str, vm_fq_str)

    def _delmsg_virtual_machine_interface_virtual_network(self, idents):
        vmi_fq_str = idents['virtual-machine-interface']
        vn_fq_str = idents['virtual-network']
        vn_fq_name = vn_fq_str.split(':')
        for vn_name in svc_info.get_shared_vn_list():
            if vn_name != vn_fq_name[2]:
                continue
            try:
                vn_id = self._vnc_lib.fq_name_to_id('virtual-network',
                                                    vn_fq_name)
            except NoIdError:
                continue
            self._delete_shared_vn(vn_id, vn_fq_name[1])

    def _delmsg_service_instance_service_template(self, idents):
        self._cleanup_si(idents['service-instance'])

    def _delmsg_virtual_machine_interface_route_table(self, idents):
        rt_fq_str = idents['interface-route-table']

        try:
            rt_obj = self._vnc_lib.interface_route_table_read(
                fq_name_str=rt_fq_str)
        except NoIdError:
            return

        try:
            vmi_list = rt_obj.get_virtual_machine_interface_back_refs()
            if vmi_list is None:
                self._vnc_lib.interface_route_table_delete(id=rt_obj.uuid)
        except NoIdError:
            return

    def _addmsg_service_instance_service_template(self, idents):
        st_fq_str = idents['service-template']
        si_fq_str = idents['service-instance']

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name_str=st_fq_str)
            si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        except NoIdError:
            self.logger.log(
                "No template or service instance with ids: %s, %s" %
                (st_fq_str, si_fq_str))
            return

        #launch VMs
        self._create_svc_instance(st_obj, si_obj)

    # end _addmsg_service_instance_service_template

    def _addmsg_service_instance_properties(self, idents):
        si_fq_str = idents['service-instance']

        try:
            si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        except NoIdError:
            return

        #update static routes
        self.vm_manager.update_static_routes(si_obj)

    def _addmsg_project_virtual_network(self, idents):
        vn_fq_str = idents['virtual-network']

        si_list = self.db.service_instance_list()
        if not si_list:
            return

        for si_fq_str, si_info in si_list:
            if vn_fq_str not in si_info.keys():
                continue

            try:
                si_obj = self._vnc_lib.service_instance_read(
                    fq_name_str=si_fq_str)
                if si_obj.get_virtual_machine_back_refs():
                    continue

                st_refs = si_obj.get_service_template_refs()
                fq_name = st_refs[0]['to']
                st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)

                #launch VMs
                self._create_svc_instance(st_obj, si_obj)
            except Exception:
                continue

    def _addmsg_floating_ip_virtual_machine_interface(self, idents):
        fip_fq_str = idents['floating-ip']
        vmi_fq_str = idents['virtual-machine-interface']

        try:
            fip_obj = self._vnc_lib.floating_ip_read(fq_name_str=fip_fq_str)
            vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                fq_name_str=vmi_fq_str)
        except NoIdError:
            return

        # handle only if VIP back ref exists
        vip_back_refs = vmi_obj.get_virtual_ip_back_refs()
        if vip_back_refs is None:
            return

        # associate fip to all VMIs
        iip_back_refs = vmi_obj.get_instance_ip_back_refs()
        try:
            iip_obj = self._vnc_lib.instance_ip_read(
                id=iip_back_refs[0]['uuid'])
        except NoIdError:
            return

        fip_updated = False
        vmi_refs_iip = iip_obj.get_virtual_machine_interface_refs()
        vmi_refs_fip = fip_obj.get_virtual_machine_interface_refs()
        for vmi_ref_iip in vmi_refs_iip:
            if vmi_ref_iip in vmi_refs_fip:
                continue
            try:
                vmi_obj = self._vnc_lib.virtual_machine_interface_read(
                    id=vmi_ref_iip['uuid'])
            except NoIdError:
                continue
            fip_obj.add_virtual_machine_interface(vmi_obj)
            fip_updated = True

        if fip_updated:
            self._vnc_lib.floating_ip_update(fip_obj)

    def process_poll_result(self, poll_result_str):
        result_list = parse_poll_result(poll_result_str)

        # process ifmap message
        for (result_type, idents, metas) in result_list:
            if 'ERROR' in idents.values():
                continue
            for meta in metas:
                meta_name = re.sub('{.*}', '', meta.tag)
                if result_type == 'deleteResult':
                    funcname = "_delmsg_" + meta_name.replace('-', '_')
                elif result_type in ['searchResult', 'updateResult']:
                    funcname = "_addmsg_" + meta_name.replace('-', '_')
                # end if result_type
                try:
                    func = getattr(self, funcname)
                except AttributeError:
                    pass
                else:
                    self.logger.log("%s with %s/%s" %
                                    (funcname, meta_name, idents))
                    func(idents)
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """
    _REACTION_MAP = {
        "loadbalancer_pool": {
            'self': [],
            'virtual_ip': [],
            'loadbalancer_member': [],
            'loadbalancer_healthmonitor': [],
        },
        "loadbalancer_member": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "virtual_ip": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "loadbalancer_healthmonitor": {
            'self': ['loadbalancer_pool'],
            'loadbalancer_pool': []
        },
        "service_instance": {
            'self': ['virtual_machine'],
            'virtual_machine': []
        },
        "instance_ip": {
            'self': [],
        },
        "service_template": {
            'self': [],
        },
        "physical_router": {
            'self': [],
        },
        "physical_interface": {
            'self': [],
        },
        "logical_interface": {
            'self': [],
        },
        "virtual_network": {
            'self': [],
        },
        "virtual_machine": {
            'self': ['virtual_machine_interface'],
            'service_instance': [],
            'virtual_machine_interface': [],
        },
        "virtual_machine_interface": {
            'self': ['interface_route_table', 'virtual_machine'],
            'interface_route_table': [],
            'virtual_machine': [],
        },
        "interface_route_table": {
            'self': [],
            'virtual_machine_interface': [],
        },
        "project": {
            'self': [],
        },
    }

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                ModuleNames[Module.SVC_MONITOR])

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)
        self.db.init_database()

        # rotating log file for catchall errors
        self._err_file = self._args.trace_file
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        try:
            with open(self._err_file, 'a'):
                handler = logging.handlers.RotatingFileHandler(
                    self._err_file, maxBytes=64*1024, backupCount=2)
                self._svc_err_logger.addHandler(handler)
        except IOError:
            self.logger.log_warning("Failed to open trace file %s" %
                self._err_file)

        # Connect to Rabbit and Initialize cassandra connection
        self._connect_rabbit()

    def _connect_rabbit(self):
        rabbit_server = self._args.rabbit_server
        rabbit_port = self._args.rabbit_port
        rabbit_user = self._args.rabbit_user
        rabbit_password = self._args.rabbit_password
        rabbit_vhost = self._args.rabbit_vhost
        rabbit_ha_mode = self._args.rabbit_ha_mode

        self._db_resync_done = gevent.event.Event()

        q_name = 'svc_mon.%s' % (socket.gethostname())
        self._vnc_kombu = VncKombuClient(rabbit_server, rabbit_port,
                                         rabbit_user, rabbit_password,
                                         rabbit_vhost, rabbit_ha_mode,
                                         q_name, self._vnc_subscribe_callback,
                                         self.config_log)

        cass_server_list = self._args.cassandra_server_list
        reset_config = self._args.reset_config
        self._cassandra = VncCassandraClient(cass_server_list, reset_config,
                                             self._args.cluster_id, None,
                                             self.config_log)
        DBBase.init(self, self.logger, self._cassandra)
    # end _connect_rabbit

    def config_log(self, msg, level):
        self.logger.log(msg)

    def _vnc_subscribe_callback(self, oper_info):
        self._db_resync_done.wait()
        try:
            msg = "Notification Message: %s" % (pformat(oper_info))
            self.config_log(msg, level=SandeshLevel.SYS_DEBUG)
            obj_type = oper_info['type'].replace('-', '_')
            obj_class = DBBase._OBJ_TYPE_MAP.get(obj_type)
            if obj_class is None:
                return

            if oper_info['oper'] == 'CREATE' or oper_info['oper'] == 'UPDATE':
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP,
                    self._REACTION_MAP)
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is not None:
                    dependency_tracker.evaluate(obj_type, obj)
                else:
                    obj = obj_class.locate(obj_id)
                obj.update()
                dependency_tracker.evaluate(obj_type, obj)
            elif oper_info['oper'] == 'DELETE':
                obj_id = oper_info['uuid']
                obj = obj_class.get(obj_id)
                if obj is None:
                    return
                dependency_tracker = DependencyTracker(DBBase._OBJ_TYPE_MAP,
                    self._REACTION_MAP)
                dependency_tracker.evaluate(obj_type, obj)
                obj_class.delete(obj_id)
            else:
                # unknown operation
                self.config_log('Unknown operation %s' % oper_info['oper'],
                                level=SandeshLevel.SYS_ERR)
                return

            if obj is None:
                self.config_log('Error while accessing %s uuid %s' % (
                                obj_type, obj_id))
                return


        except Exception:
            string_buf = cStringIO.StringIO()
            cgitb.Hook(file=string_buf, format="text").handle(sys.exc_info())
            self.config_log(string_buf.getvalue(), level=SandeshLevel.SYS_ERR)

        for sas_id in dependency_tracker.resources.get('service_appliance_set', []):
            sas_obj = ServiceApplianceSetSM.get(sas_id)
            if sas_obj is not None:
                sas_obj.add()

        for lb_pool_id in dependency_tracker.resources.get('loadbalancer_pool', []):
            lb_pool = LoadbalancerPoolSM.get(lb_pool_id)
            if lb_pool is not None:
                lb_pool.add()
    # end _vnc_subscribe_callback

        for si_id in dependency_tracker.resources.get('service_instance', []):
            si = ServiceInstanceSM.get(si_id)
            if si:
                self._create_service_instance(si)
            else:
                for vm_id in dependency_tracker.resources.get(
                        'virtual_machine', []):
                    vm = VirtualMachineSM.get(vm_id)
                    self._delete_service_instance(vm)

        for vn_id in dependency_tracker.resources.get('virtual_network', []):
            vn = VirtualNetworkSM.get(vn_id)
            if vn:
                for si_id in ServiceInstanceSM:
                    si = ServiceInstanceSM.get(si_id)
                    if (':').join(vn.fq_name) in si.params.values():
                        self._create_service_instance(si)

        for vmi_id in dependency_tracker.resources.get('virtual_machine_interface', []):
            vmi = VirtualMachineInterfaceSM.get(vmi_id)
            if vmi:
                for vm_id in dependency_tracker.resources.get(
                        'virtual_machine', []):
                    vm = VirtualMachineSM.get(vm_id)
                    if vm:
                        self.check_link_si_to_vm(vm, vmi)
            else:
                for irt_id in dependency_tracker.resources.get(
                        'interface_route_table', []):
                    self._delete_interface_route_table(irt_id)

    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        self._nova_client = importutils.import_object(
            'svc_monitor.nova_client.ServiceMonitorNovaClient',
            self._args, self.logger)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver,
            self._vnc_lib, self._nova_client,
            self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.virtual_machine_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a vrouter instance manager
        self.vrouter_manager = importutils.import_object(
            'svc_monitor.vrouter_instance_manager.VRouterInstanceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._nova_client, self._args)

        # load a loadbalancer agent
        self.loadbalancer_agent = LoadbalancerAgent(self, self._vnc_lib, self._args)

        # Read the cassandra and populate the entry in ServiceMonitor DB
        self.sync_sm()

        # create default analyzer template
        self._create_default_template('analyzer-template', 'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template', 'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template', 'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template', 'loadbalancer',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        self._create_default_template('docker-template', 'firewall',
                                      svc_mode='transparent',
                                      image_name="ubuntu",
                                      hypervisor_type='vrouter-instance',
                                      vrouter_instance_type='docker',
                                      instance_data={
                                          "command": "/bin/bash"
                                      })

        # upgrade handling
        self.upgrade()

        # check services
        self.launch_services()

    def upgrade(self):
        for si in ServiceInstanceSM.values():
            st = ServiceTemplateSM.get(si.service_template)
            if not st:
                continue
            for vm_id in si.virtual_machines:
                vm = VirtualMachineSM.get(vm_id)
                if vm.virtualization_type:
                    continue
                nova_vm = self._nova_client.oper('servers', 'get',
                    si.proj_name, id=vm_id)
                if not nova_vm:
                    continue

                si_obj = ServiceInstance()
                si_obj.name = si.name
                si_obj.fq_name = si.fq_name
                instance_name = self.vm_manager._get_instance_name(
                    si_obj, vm.index)
                if vm.name == instance_name:
                    continue
                nova_vm.update(name=instance_name)
                vm_obj = VirtualMachine()
                vm_obj.uuid = vm_id
                vm_obj.fq_name = [vm_id]
                vm_obj.set_display_name(instance_name + '__' +
                    st.virtualization_type)
                try:
                    self._vnc_lib.virtual_machine_update(vm_obj)
                except Exception:
                    pass

    def launch_services(self):
        for si in ServiceInstanceSM.values():
            self._create_service_instance(si)

    def sync_sm(self):
        vn_set = set()
        vmi_set = set()
        iip_set = set()
        ok, lb_pool_list = self._cassandra._cassandra_loadbalancer_pool_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_list:
                lb_pool = LoadbalancerPoolSM.locate(uuid)
                if lb_pool.virtual_machine_interface:
                    vmi_set.add(lb_pool.virtual_machine_interface)

        ok, lb_pool_member_list = self._cassandra._cassandra_loadbalancer_member_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_pool_member_list:
                lb_pool_member = LoadbalancerMemberSM.locate(uuid)

        ok, lb_vip_list = self._cassandra._cassandra_virtual_ip_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_vip_list:
                virtual_ip = VirtualIpSM.locate(uuid)
                if virtual_ip.virtual_machine_interface:
                    vmi_set.add(virtual_ip.virtual_machine_interface)

        ok, lb_hm_list = self._cassandra._cassandra_loadbalancer_healthmonitor_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in lb_hm_list:
                lb_hm = HealthMonitorSM.locate(uuid)

        ok, si_list = self._cassandra._cassandra_service_instance_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in si_list:
                si = ServiceInstanceSM.locate(uuid)

        ok, st_list = self._cassandra._cassandra_service_template_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in st_list:
                st = ServiceTemplateSM.locate(uuid)

        ok, vn_list = self._cassandra._cassandra_virtual_network_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vn_list:
                vn = VirtualNetworkSM.locate(uuid)
                vmi_set |= vn.virtual_machine_interfaces

        ok, ifd_list = self._cassandra._cassandra_physical_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in ifd_list:
                ifd = PhysicalInterfaceSM.locate(uuid)


        ok, ifl_list = self._cassandra._cassandra_logical_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in ifl_list:
                ifl = LogicalInterfaceSM.locate(uuid)
                if ifl.virtual_machine_interface:
                    vmi_set.add(ifl.virtual_machine_interface)

        ok, pr_list = self._cassandra._cassandra_physical_router_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in pr_list:
                pr = PhysicalRouterSM.locate(uuid)

        ok, vr_list = self._cassandra._cassandra_virtual_router_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vr_list:
                vr = VirtualRouterSM.locate(uuid)

        ok, vmi_list = self._cassandra._cassandra_virtual_machine_interface_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vmi_list:
                vmi = VirtualMachineInterfaceSM.locate(uuid)
                if vmi.instance_ip:
                    iip_set.add(vmi.instance_ip)

        ok, irt_list = self._cassandra._cassandra_interface_route_table_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in irt_list:
                irt = InterfaceRouteTableSM.locate(uuid)

        ok, project_list = self._cassandra._cassandra_project_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in project_list:
                prj = ProjectSM.locate(uuid)

        ok, sas_list = self._cassandra._cassandra_service_appliance_set_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in sas_list:
                sas = ServiceApplianceSetSM.locate(uuid)

        ok, sa_list = self._cassandra._cassandra_service_appliance_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in sa_list:
                sa = ServiceApplianceSM.locate(uuid)

        ok, domain_list = self._cassandra._cassandra_domain_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in domain_list:
                DomainSM.locate(uuid)

        ok, iip_list = self._cassandra._cassandra_instance_ip_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in iip_list:
                InstanceIpSM.locate(uuid)

        ok, sg_list = self._cassandra._cassandra_security_group_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in sg_list:
                SecurityGroupSM.locate(uuid)

        ok, vm_list = self._cassandra._cassandra_virtual_machine_list()
        if not ok:
            pass
        else:
            for fq_name, uuid in vm_list:
                vm = VirtualMachineSM.locate(uuid)
                if vm.service_instance:
                    continue
                for vmi_id in vm.virtual_machine_interfaces:
                    vmi = VirtualMachineInterfaceSM.get(vmi_id)
                    if not vmi:
                        continue
                    self.check_link_si_to_vm(vm, vmi)

        # Load the loadbalancer driver
        self.loadbalancer_agent.load_drivers()

        for lb_pool in LoadbalancerPoolSM.values():
            lb_pool.add()


        self._db_resync_done.set()
    # end sync_sm

    # create service template
    def _create_default_template(self, st_name, svc_type, svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None, flavor=None, scaling=False,
                                 vrouter_instance_type=None,
                                 instance_data=None):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log_info("Creating %s %s hypervisor %s" %
            (domain_name, st_name, hypervisor_type))

        domain_obj = None
        for domain in DomainSM.values():
            if domain.fq_name == domain_fq_name:
                domain_obj = Domain()
                domain_obj.uuid = domain.uuid
                domain_obj.fq_name = domain_fq_name
                break
        if not domain_obj:
            self.logger.log_error("%s domain not found" % (domain_name))
            return

        for st in ServiceTemplateSM.values():
            if st.fq_name == st_fq_name:
                self.logger.log_info("%s exists uuid %s" %
                    (st.name, str(st.uuid)))
                return

        st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
        st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['right', True], ['left', True]]
        else:
            if_list = [
                ['management', False], ['left', False], ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        if vrouter_instance_type is not None:
            svc_properties.set_vrouter_instance_type(vrouter_instance_type)

        if instance_data is not None:
            svc_properties.set_instance_data(
                json.dumps(instance_data, separators=(',', ':')))

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log_info("%s created with uuid %s" %
            (st_name, str(st_uuid)))
    #_create_default_analyzer_template

    def check_link_si_to_vm(self, vm, vmi):
        if vm.service_instance:
            return
        if not vmi.if_type:
            return

        si_fq_name = vmi.name.split('__')[0:3]
        index = int(vmi.name.split('__')[3]) - 1
        for si in ServiceInstanceSM.values():
            if si.fq_name != si_fq_name:
                continue
            st = ServiceTemplateSM.get(si.service_template)
            self.vm_manager.link_si_to_vm(si, st, index, vm.uuid)
            return

    def _create_service_instance(self, si):
        if si.state == 'active':
            return
        st = ServiceTemplateSM.get(si.service_template)
        if st.virtualization_type == 'virtual-machine':
            self.vm_manager.create_service(st, si)
        elif st.virtualization_type == 'network-namespace':
            self.netns_manager.create_service(st, si)
        elif st.virtualization_type == 'vrouter-instance':
            self.vrouter_manager.create_service(st, si)
        else:
            self.logger.log_error("Unknown virt type: %s" %
                st.virtualization_type)

    def _delete_service_instance(self, vm):
        self.logger.log_info("Deleting VM %s %s" %
            ((':').join(vm.proj_fq_name), vm.uuid))

        if vm.virtualization_type == svc_info.get_vm_instance_type():
            self.vm_manager.delete_service(vm)
        elif vm.virtualization_type == svc_info.get_netns_instance_type():
            self.netns_manager.delete_service(vm)
        elif vm.virtualization_type == 'vrouter-instance':
            self.vrouter_manager.delete_service(vm)

        # generate UVE
        si_fq_name = vm.display_name.split('__')[:-2]
        si_fq_str = (':').join(si_fq_name)
        self.logger.uve_svc_instance(si_fq_str, status='DELETE',
                                     vms=[{'uuid': vm.uuid}])
        return True

    def _relaunch_service_instance(self, si):
        if si.state == 'active':
            si.state = 'relaunch'
            self._create_service_instance(si)

    def _check_service_running(self, si):
        if si.state != 'active':
            return
        st = ServiceTemplateSM.get(si.service_template)
        if st.virtualization_type == 'virtual-machine':
            status = self.vm_manager.check_service(si)
        elif st.virtualization_type == 'network-namespace':
            status = self.netns_manager.check_service(si)
        elif st.virtualization_type == 'vrouter-instance':
            status = self.vrouter_manager.check_service(si)

        return status

    def _delete_interface_route_table(self, irt_uuid):
        try:
            self._vnc_lib.interface_route_table_delete(id=irt_uuid)
        except (NoIdError, RefsExistError):
            return

    def _delete_shared_vn(self, vn_uuid):
        try:
            self.logger.log_info("Deleting vn %s" % (vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except (NoIdError, RefsExistError):
            pass
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(
                self._args.disc_server_ip, self._args.disc_server_port, client_type="Service Monitor"
            )

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)

        # rotating log file for catchall errors
        self._err_file = "/var/log/contrail/svc-monitor.err"
        self._tmp_file = "/var/log/contrail/svc-monitor.tmp"
        try:
            with open(self._err_file, "a"):
                pass
            with open(self._tmp_file, "a"):
                pass
        except IOError:
            self._err_file = "./svc-monitor.err"
            self._tmp_file = "./svc-monitor.tmp"
        self._svc_err_logger = logging.getLogger("SvcErrLogger")
        self._svc_err_logger.setLevel(logging.ERROR)
        handler = logging.handlers.RotatingFileHandler(self._err_file, maxBytes=64 * 1024, backupCount=2)
        self._svc_err_logger.addHandler(handler)

    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        # create default analyzer template
        self._create_default_template("analyzer-template", "analyzer", flavor="m1.medium", image_name="analyzer")
        # create default NAT template
        self._create_default_template(
            "nat-template", "firewall", svc_mode="in-network-nat", image_name="analyzer", flavor="m1.medium"
        )
        # create default netns SNAT template
        self._create_default_template(
            "netns-snat-template",
            "source-nat",
            svc_mode="in-network-nat",
            hypervisor_type="network-namespace",
            scaling=True,
        )
        # create default loadbalancer template
        self._create_default_template(
            "haproxy-loadbalancer-template",
            "loadbalancer",
            svc_mode="in-network-nat",
            hypervisor_type="network-namespace",
            scaling=True,
        )

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver, self._vnc_lib, self._args
        )

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            "svc_monitor.instance_manager.VirtualMachineManager",
            self._vnc_lib,
            self.db,
            self.logger,
            self.vrouter_scheduler,
            self._args,
        )

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            "svc_monitor.instance_manager.NetworkNamespaceManager",
            self._vnc_lib,
            self.db,
            self.logger,
            self.vrouter_scheduler,
            self._args,
        )

    # create service template
    def _create_default_template(
        self,
        st_name,
        svc_type,
        svc_mode=None,
        hypervisor_type="virtual-machine",
        image_name=None,
        flavor=None,
        scaling=False,
    ):
        domain_name = "default-domain"
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log("Creating %s %s hypervisor %s" % (domain_name, st_name, hypervisor_type))

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name=st_fq_name)
            st_uuid = st_obj.uuid
            self.logger.log("%s exists uuid %s" % (st_name, str(st_uuid)))
            return
        except NoIdError:
            domain = self._vnc_lib.domain_read(fq_name=domain_fq_name)
            st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
            st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == "analyzer":
            if_list = [["left", False]]
        elif hypervisor_type == "network-namespace":
            if_list = [["right", True], ["left", True]]
        else:
            if_list = [["management", False], ["left", False], ["right", False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log("%s created with uuid %s" % (st_name, str(st_uuid)))

    # _create_default_analyzer_template

    def cleanup(self):
        # TODO cleanup sandesh context
        pass

    # end cleanup

    def _get_proj_name_from_si_fq_str(self, si_fq_str):
        return si_fq_str.split(":")[1]

    # enf _get_si_fq_str_to_proj_name

    def _get_virtualization_type(self, st_props):
        return st_props.get_service_virtualization_type() or "virtual-machine"

    # end _get_virtualization_type

    def _check_store_si_info(self, st_obj, si_obj):
        config_complete = True
        st_props = st_obj.get_service_template_properties()
        st_if_list = st_props.get_interface_type()
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        # for lb relax the check because vip and pool could be in same net
        if (
            (st_props.get_service_type() != svc_info.get_lb_service_type())
            and si_if_list
            and (len(si_if_list) != len(st_if_list))
        ):
            self.logger.log("Error: IF mismatch template %s instance %s" % (len(st_if_list), len(si_if_list)))
            return

        # read existing si_entry
        si_entry = self.db.service_instance_get(si_obj.get_fq_name_str())
        if not si_entry:
            si_entry = {}
        si_entry["instance_type"] = self._get_virtualization_type(st_props)
        si_entry["uuid"] = si_obj.uuid

        # walk the interface list
        for idx in range(0, len(st_if_list)):
            st_if = st_if_list[idx]
            itf_type = st_if.service_interface_type

            si_if = None
            if si_if_list and st_props.get_ordered_interfaces():
                try:
                    si_if = si_if_list[idx]
                except IndexError:
                    continue
                si_vn_str = si_if.get_virtual_network()
            else:
                funcname = "get_" + itf_type + "_virtual_network"
                func = getattr(si_props, funcname)
                si_vn_str = func()

            if not si_vn_str:
                continue

            si_entry[itf_type + "-vn"] = si_vn_str
            try:
                vn_obj = self._vnc_lib.virtual_network_read(fq_name_str=si_vn_str)
                if vn_obj.uuid != si_entry.get(si_vn_str, None):
                    si_entry[si_vn_str] = vn_obj.uuid
            except NoIdError:
                self.logger.log("Warn: VN %s add is pending" % si_vn_str)
                si_entry[si_vn_str] = "pending"
                config_complete = False

        if config_complete:
            self.logger.log("SI %s info is complete" % si_obj.get_fq_name_str())
        else:
            self.logger.log("Warn: SI %s info is not complete" % si_obj.get_fq_name_str())

        # insert entry
        self.db.service_instance_insert(si_obj.get_fq_name_str(), si_entry)
        return config_complete

    # end _check_store_si_info

    def _restart_svc(self, si_fq_str):
        si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        st_list = si_obj.get_service_template_refs()
        if st_list is not None:
            fq_name = st_list[0]["to"]
            st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)
            self._create_svc_instance(st_obj, si_obj)

    # end _restart_svc

    def _delete_shared_vn(self, vn_uuid, proj_name):
        try:
            self.logger.log("Deleting VN %s %s" % (proj_name, vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except RefsExistError:
            self._svc_err_logger.error("Delete failed refs exist VN %s %s" % (proj_name, vn_uuid))
        except NoIdError:
            # remove from cleanup list
            self.db.cleanup_table_remove(vn_uuid)

    # end _delete_shared_vn

    def _create_svc_instance(self, st_obj, si_obj):
        # check if all config received before launch
        if not self._check_store_si_info(st_obj, si_obj):
            return

        st_props = st_obj.get_service_template_properties()
        if st_props is None:
            self.logger.log(
                "Cannot find service template associated to " "service instance %s" % si_obj.get_fq_name_str()
            )
        virt_type = self._get_virtualization_type(st_props)
        if virt_type == "virtual-machine":
            self.vm_manager.create_service(st_obj, si_obj)
        elif virt_type == "network-namespace":
            self.netns_manager.create_service(st_obj, si_obj)

    def _delete_svc_instance(self, vm_uuid, proj_name, si_fq_str=None, virt_type=None):
        self.logger.log("Deleting VM %s %s" % (proj_name, vm_uuid))

        try:
            if virt_type == svc_info.get_vm_instance_type():
                self.vm_manager.delete_service(vm_uuid, proj_name)
            elif virt_type == svc_info.get_netns_instance_type():
                self.netns_manager.delete_service(vm_uuid)
        except KeyError:
            self.db.cleanup_table_remove(vm_uuid)
            return

        # remove from launch table and queue into cleanup list
        self.db.virtual_machine_remove(vm_uuid)
        self.db.cleanup_table_insert(vm_uuid, {"proj_name": proj_name, "type": virt_type})
        self.logger.uve_svc_instance(si_fq_str, status="DELETE", vm_uuid=vm_uuid)

    def _check_si_status(self, si_fq_name_str, si_info):
        try:
            si_obj = self._vnc_lib.service_instance_read(id=si_info["uuid"])
        except NoIdError:
            self.db.service_instance_remove(si_fq_name_str)
            return "ACTIVE"

        if si_info["instance_type"] == "virtual-machine":
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_name_str)
            status = self.vm_manager.check_service(si_obj, proj_name)
        elif si_info["instance_type"] == "network-namespace":
            status = self.netns_manager.check_service(si_obj)

        return status

    def _check_vm_si_link(self, vm_uuid, si_info):
        try:
            vm_obj = self._vnc_lib.virtual_machine_read(id=vm_uuid)
        except NoIdError:
            return

        si_fq_str = si_info["si_fq_str"]
        si_refs = vm_obj.get_service_instance_refs()
        if (si_refs is None) or (si_refs[0]["to"][0] == "ERROR"):
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
            self._delete_svc_instance(vm_uuid, proj_name, si_fq_str, si_info["instance_type"])

    def _delmsg_project_service_instance(self, idents):
        proj_fq_str = idents["project"]
        si_fq_str = idents["service-instance"]

        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return

        virt_type = si_info["instance_type"]
        if virt_type == "virtual-machine":
            self.vm_manager.clean_resources(proj_fq_str, si_fq_str)
        elif virt_type == "network-namespace":
            self.netns_manager.clean_resources(proj_fq_str, si_fq_str)

        # delete si info
        self.db.service_instance_remove(si_fq_str)

    # end _delmsg_project_service_instance

    def _delmsg_service_instance_service_template(self, idents):
        si_fq_str = idents["service-instance"]
        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return

        vm_list = self.db.virtual_machine_list()
        for vm_uuid, si in vm_list:
            if si_fq_str != si["si_fq_str"]:
                continue

            proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
            self._delete_svc_instance(vm_uuid, proj_name, si_fq_str=si_fq_str, virt_type=si["instance_type"])

            # insert shared instance IP uuids into cleanup list if present
            for itf_str in svc_info.get_if_str_list():
                iip_uuid_str = itf_str + "-iip-uuid"
                if not iip_uuid_str in si_info:
                    continue
                self.db.cleanup_table_insert(si_info[iip_uuid_str], {"proj_name": proj_name, "type": "iip"})

        # delete si info
        self.db.service_instance_remove(si_fq_str)

    # end _delmsg_service_instance_service_template

    def _delmsg_virtual_machine_service_instance(self, idents):
        vm_uuid = idents["virtual-machine"]
        si_fq_str = idents["service-instance"]
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
        vm_info = self.db.virtual_machine_get(vm_uuid)
        if vm_info:
            self._delete_svc_instance(
                vm_uuid, proj_name, si_fq_str=vm_info["si_fq_str"], virt_type=vm_info["instance_type"]
            )
        return

    # end _delmsg_service_instance_virtual_machine

    def _delmsg_virtual_machine_interface_route_table(self, idents):
        rt_fq_str = idents["interface-route-table"]

        rt_obj = self._vnc_lib.interface_route_table_read(fq_name_str=rt_fq_str)
        vmi_list = rt_obj.get_virtual_machine_interface_back_refs()
        if vmi_list is None:
            self._vnc_lib.interface_route_table_delete(id=rt_obj.uuid)

    # end _delmsg_virtual_machine_interface_route_table

    def _addmsg_virtual_machine_interface_virtual_machine(self, idents):
        vm_fq_str = idents["virtual-machine"]

        try:
            vm_obj = self._vnc_lib.virtual_machine_read(fq_name_str=vm_fq_str)
        except NoIdError:
            return

        # check if this is a service vm
        si_list = vm_obj.get_service_instance_refs()
        if si_list:
            return

        vm_info = self.db.virtual_machine_get(vm_obj.uuid)
        if not vm_info:
            return
        si_fq_str = vm_info["si_fq_str"]

        try:
            si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        except NoIdError:
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
            self._delete_svc_instance(vm_obj.uuid, proj_name, si_fq_str=si_fq_str, virt_type=vm_info["instance_type"])
            return

        # create service instance to service vm link
        vm_obj.add_service_instance(si_obj)
        self._vnc_lib.virtual_machine_update(vm_obj)
        self.logger.log("Info: VM %s updated SI %s" % (vm_obj.get_fq_name_str(), si_fq_str))

    # end _addmsg_virtual_machine_interface_virtual_machine

    def _addmsg_service_instance_service_template(self, idents):
        st_fq_str = idents["service-template"]
        si_fq_str = idents["service-instance"]

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name_str=st_fq_str)
            si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        except NoIdError:
            return

        # launch VMs
        self._create_svc_instance(st_obj, si_obj)

    # end _addmsg_service_instance_service_template

    def _addmsg_service_instance_properties(self, idents):
        si_fq_str = idents["service-instance"]

        try:
            si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        except NoIdError:
            return

        # update static routes
        self._update_static_routes(si_obj)

    # end _addmsg_service_instance_service_template

    def _addmsg_project_virtual_network(self, idents):
        vn_fq_str = idents["virtual-network"]

        si_list = self.db.service_instance_list()
        if not si_list:
            return

        for si_fq_str, si_info in si_list:
            if vn_fq_str not in si_info.keys():
                continue

            try:
                si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
                if si_obj.get_virtual_machine_back_refs():
                    continue

                st_refs = si_obj.get_service_template_refs()
                fq_name = st_refs[0]["to"]
                st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)

                # launch VMs
                self._create_svc_instance(st_obj, si_obj)
            except Exception:
                continue

    # end _addmsg_project_virtual_network

    def _addmsg_floating_ip_virtual_machine_interface(self, idents):
        fip_fq_str = idents["floating-ip"]
        vmi_fq_str = idents["virtual-machine-interface"]

        try:
            fip_obj = self._vnc_lib.floating_ip_read(fq_name_str=fip_fq_str)
            vmi_obj = self._vnc_lib.virtual_machine_interface_read(fq_name_str=vmi_fq_str)
        except NoIdError:
            return

        # handle only if VIP back ref exists
        vip_back_refs = vmi_obj.get_virtual_ip_back_refs()
        if vip_back_refs is None:
            return

        # associate fip to all VMIs
        iip_back_refs = vmi_obj.get_instance_ip_back_refs()
        try:
            iip_obj = self._vnc_lib.instance_ip_read(id=iip_back_refs[0]["uuid"])
        except NoIdError:
            return

        fip_updated = False
        vmi_refs_iip = iip_obj.get_virtual_machine_interface_refs()
        vmi_refs_fip = fip_obj.get_virtual_machine_interface_refs()
        for vmi_ref_iip in vmi_refs_iip:
            if vmi_ref_iip in vmi_refs_fip:
                continue
            try:
                vmi_obj = self._vnc_lib.virtual_machine_interface_read(id=vmi_ref_iip["uuid"])
            except NoIdError:
                continue
            fip_obj.add_virtual_machine_interface(vmi_obj)
            fip_updated = True

        if fip_updated:
            self._vnc_lib.floating_ip_update(fip_obj)

    def process_poll_result(self, poll_result_str):
        result_list = parse_poll_result(poll_result_str)

        # process ifmap message
        for (result_type, idents, metas) in result_list:
            if "ERROR" in idents.values():
                continue
            for meta in metas:
                meta_name = re.sub("{.*}", "", meta.tag)
                if result_type == "deleteResult":
                    funcname = "_delmsg_" + meta_name.replace("-", "_")
                elif result_type in ["searchResult", "updateResult"]:
                    funcname = "_addmsg_" + meta_name.replace("-", "_")
                # end if result_type
                try:
                    func = getattr(self, funcname)
                except AttributeError:
                    pass
                else:
                    self.logger.log("%s with %s/%s" % (funcname, meta_name, idents))
                    func(idents)
            # end for meta
        # end for result_type

    # end process_poll_result

    def _update_static_routes(self, si_obj):
        # get service instance interface list
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        if not si_if_list:
            return

        for idx in range(0, len(si_if_list)):
            si_if = si_if_list[idx]
            static_routes = si_if.get_static_routes()
            if not static_routes:
                static_routes = {"route": []}

            # update static routes
            try:
                domain_name, proj_name = si_obj.get_parent_fq_name()
                rt_name = si_obj.uuid + " " + str(idx)
                rt_fq_name = [domain_name, proj_name, rt_name]
                rt_obj = self._vnc_lib.interface_route_table_read(fq_name=rt_fq_name)
                rt_obj.set_interface_route_table_routes(static_routes)
                self._vnc_lib.interface_route_table_update(rt_obj)
            except NoIdError:
                pass
class SvcMonitor(object):

    """
    data + methods used/referred to by ssrc and arc greenlets
    """

    def __init__(self, args=None):
        self._args = args

        # create database and logger
        self.db = ServiceMonitorDB(args)

        # initialize discovery client
        self._disc = None
        if self._args.disc_server_ip and self._args.disc_server_port:
            self._disc = client.DiscoveryClient(self._args.disc_server_ip,
                                                self._args.disc_server_port,
                                                client_type='Service Monitor')

        # initialize logger
        self.logger = ServiceMonitorLogger(self.db, self._disc, args)
        self.db.add_logger(self.logger)

        # rotating log file for catchall errors
        self._err_file = '/var/log/contrail/svc-monitor.err'
        self._tmp_file = '/var/log/contrail/svc-monitor.tmp'
        try:
            with open(self._err_file, 'a'):
                pass
            with open(self._tmp_file, 'a'):
                pass
        except IOError:
            self._err_file = './svc-monitor.err'
            self._tmp_file = './svc-monitor.tmp'
        self._svc_err_logger = logging.getLogger('SvcErrLogger')
        self._svc_err_logger.setLevel(logging.ERROR)
        handler = logging.handlers.RotatingFileHandler(
            self._err_file, maxBytes=64*1024, backupCount=2)
        self._svc_err_logger.addHandler(handler)


    def post_init(self, vnc_lib, args=None):
        # api server
        self._vnc_lib = vnc_lib

        # create default analyzer template
        self._create_default_template('analyzer-template', 'analyzer',
                                      flavor='m1.medium',
                                      image_name='analyzer')
        # create default NAT template
        self._create_default_template('nat-template', 'firewall',
                                      svc_mode='in-network-nat',
                                      image_name='analyzer',
                                      flavor='m1.medium')
        # create default netns SNAT template
        self._create_default_template('netns-snat-template', 'source-nat',
                                      svc_mode='in-network-nat',
                                      hypervisor_type='network-namespace',
                                      scaling=True)
        # create default loadbalancer template
        self._create_default_template('haproxy-loadbalancer-template', 'loadbalancer',
                                      image_name='in-network',
                                      hypervisor_type='network-namespace',
                                      scaling=True)

        # load vrouter scheduler
        self.vrouter_scheduler = importutils.import_object(
            self._args.si_netns_scheduler_driver,
            self._vnc_lib,
            self._args)

        # load virtual machine instance manager
        self.vm_manager = importutils.import_object(
            'svc_monitor.instance_manager.VirtualMachineManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._args)

        # load network namespace instance manager
        self.netns_manager = importutils.import_object(
            'svc_monitor.instance_manager.NetworkNamespaceManager',
            self._vnc_lib, self.db, self.logger,
            self.vrouter_scheduler, self._args)


    # create service template
    def _create_default_template(self, st_name, svc_type, svc_mode=None,
                                 hypervisor_type='virtual-machine',
                                 image_name=None, flavor=None, scaling=False):
        domain_name = 'default-domain'
        domain_fq_name = [domain_name]
        st_fq_name = [domain_name, st_name]
        self.logger.log("Creating %s %s hypervisor %s" %
                         (domain_name, st_name, hypervisor_type))

        try:
            st_obj = self._vnc_lib.service_template_read(fq_name=st_fq_name)
            st_uuid = st_obj.uuid
            self.logger.log("%s exists uuid %s" % (st_name, str(st_uuid)))
            return
        except NoIdError:
            domain = self._vnc_lib.domain_read(fq_name=domain_fq_name)
            st_obj = ServiceTemplate(name=st_name, domain_obj=domain)
            st_uuid = self._vnc_lib.service_template_create(st_obj)

        svc_properties = ServiceTemplateType()
        svc_properties.set_service_type(svc_type)
        svc_properties.set_service_mode(svc_mode)
        svc_properties.set_service_virtualization_type(hypervisor_type)
        svc_properties.set_image_name(image_name)
        svc_properties.set_flavor(flavor)
        svc_properties.set_ordered_interfaces(True)
        svc_properties.set_service_scaling(scaling)

        # set interface list
        if svc_type == 'analyzer':
            if_list = [['left', False]]
        elif hypervisor_type == 'network-namespace':
            if_list = [['left', False], ['right', False]]
        else:
            if_list = [
                ['management', False], ['left', False], ['right', False]]

        for itf in if_list:
            if_type = ServiceTemplateInterfaceType(shared_ip=itf[1])
            if_type.set_service_interface_type(itf[0])
            svc_properties.add_interface_type(if_type)

        try:
            st_obj.set_service_template_properties(svc_properties)
            self._vnc_lib.service_template_update(st_obj)
        except Exception as e:
            print e

        self.logger.log("%s created with uuid %s" % (st_name, str(st_uuid)))
    #_create_default_analyzer_template

    def cleanup(self):
        # TODO cleanup sandesh context
        pass
    # end cleanup

    def _get_proj_name_from_si_fq_str(self, si_fq_str):
        return si_fq_str.split(':')[1]
    # enf _get_si_fq_str_to_proj_name

    def _get_virtualization_type(self, st_props):
        return st_props.get_service_virtualization_type() or 'virtual-machine'
    # end _get_virtualization_type

    def _check_svc_vm_exists(self, si_obj):
        vm_back_refs = si_obj.get_virtual_machine_back_refs()
        if not vm_back_refs:
            return False
        si_props = si_obj.get_service_instance_properties()
        if si_props.get_scale_out():
            max_instances = si_props.get_scale_out().get_max_instances()
        else:
            max_instances = 1
        if max_instances == len(vm_back_refs):
            return True
        return False
    #end _check_svc_vm_exists

    def _check_store_si_info(self, st_obj, si_obj):
        config_complete = True
        st_props = st_obj.get_service_template_properties()
        st_if_list = st_props.get_interface_type()
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        if si_if_list and (len(si_if_list) != len(st_if_list)):
            self.logger.log("Error: IF mismatch template %s instance %s" %
                             (len(st_if_list), len(si_if_list)))
            return

        # read existing si_entry
        si_entry = self.db.service_instance_get(si_obj.get_fq_name_str())
        if not si_entry:
            si_entry = {}
        si_entry['instance_type'] = self._get_virtualization_type(st_props)

        # walk the interface list
        for idx in range(0, len(st_if_list)):
            st_if = st_if_list[idx]
            itf_type = st_if.service_interface_type

            si_if = None
            if si_if_list and st_props.get_ordered_interfaces():
                si_if = si_if_list[idx]
                si_vn_str = si_if.get_virtual_network()
            else:
                funcname = "get_" + itf_type + "_virtual_network"
                func = getattr(si_props, funcname)
                si_vn_str = func()

            if not si_vn_str:
                continue

            si_entry[itf_type + '-vn'] = si_vn_str
            try:
                vn_obj = self._vnc_lib.virtual_network_read(
                    fq_name_str=si_vn_str)
                if vn_obj.uuid != si_entry.get(si_vn_str, None):
                    si_entry[si_vn_str] = vn_obj.uuid
            except NoIdError:
                self.logger.log("Warn: VN %s add is pending" % si_vn_str)
                si_entry[si_vn_str] = 'pending'
                config_complete = False

        if config_complete:
            self.logger.log("SI %s info is complete" %
                             si_obj.get_fq_name_str())
        else:
            self.logger.log("Warn: SI %s info is not complete" %
                             si_obj.get_fq_name_str())

        #insert entry
        self.db.service_instance_insert(si_obj.get_fq_name_str(), si_entry)
        return config_complete
    #end _check_store_si_info

    def _restart_svc(self, vm_uuid, si_fq_str):
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
        self._delete_svc_instance(vm_uuid, proj_name, si_fq_str=si_fq_str)

        # Wait the clean phase was completely done before recreate the SI
        gevent.sleep(_CHECK_CLEANUP_INTERVAL + 1)

        si_obj = self._vnc_lib.service_instance_read(fq_name_str=si_fq_str)
        st_list = si_obj.get_service_template_refs()
        if st_list is not None:
            fq_name = st_list[0]['to']
            st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)
            self._create_svc_instance(st_obj, si_obj)
    # end _restart_svc

    def _delete_shared_vn(self, vn_uuid, proj_name):
        try:
            self.logger.log("Deleting VN %s %s" % (proj_name, vn_uuid))
            self._vnc_lib.virtual_network_delete(id=vn_uuid)
        except RefsExistError:
            self._svc_err_logger.error("Delete failed refs exist VN %s %s" %
                                       (proj_name, vn_uuid))
        except NoIdError:
            # remove from cleanup list
            self.db.cleanup_table_remove(vn_uuid)
    # end _delete_shared_vn

    def _create_svc_instance(self, st_obj, si_obj):
        #check if all config received before launch
        if not self._check_store_si_info(st_obj, si_obj):
            return

        #check if VMs already exist
        if self._check_svc_vm_exists(si_obj):
            return

        st_props = st_obj.get_service_template_properties()
        if st_props is None:
            self.logger.log("Cannot find service template associated to "
                             "service instance %s" % si_obj.get_fq_name_str())
        virt_type = self._get_virtualization_type(st_props)
        if virt_type == 'virtual-machine':
            self.vm_manager.create_service(st_obj, si_obj)
        elif virt_type == 'network-namespace':
            self.netns_manager.create_service(st_obj, si_obj)

    def _delete_svc_instance(self, vm_uuid, proj_name, si_fq_str=None):
        vm_entry = self.db.virtual_machine_get(vm_uuid)
        if not vm_entry: 
            self.db.cleanup_table_remove(vm_uuid)
            return

        self.logger.log("Deleting VM %s %s" % (proj_name, vm_uuid))
        virt_type = vm_entry['instance_type']
        if virt_type == 'virtual-machine':
            self.vm_manager.delete_service(vm_uuid, proj_name)
        elif virt_type == 'network-namespace':
            self.netns_manager.delete_service(vm_uuid)

        # remove from launch table and queue into cleanup list
        self.db.virtual_machine_remove(vm_uuid)
        self.db.cleanup_table_insert(
            vm_uuid, {'proj_name': proj_name, 'type': 'vm'})
        self.logger.uve_svc_instance(si_fq_str, status='DELETE', vm_uuid=vm_uuid)

    def _delmsg_project_service_instance(self, idents):
        proj_fq_str = idents['project']
        si_fq_str = idents['service-instance']

        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return

        virt_type = si_info['instance_type']
        if virt_type == 'virtual-machine':
            self.vm_manager.clean_resources(proj_fq_str, si_fq_str)
        elif virt_type == 'network-namespace':
            self.netns_manager.clean_resources(proj_fq_str, si_fq_str)

        #delete si info
        self.db.service_instance_remove(si_fq_str)
    # end _delmsg_project_service_instance

    def _delmsg_service_instance_service_template(self, idents):
        si_fq_str = idents['service-instance']
        si_info = self.db.service_instance_get(si_fq_str)
        if not si_info:
            return

        vm_list = self.db.virtual_machine_list()
        for vm_uuid, si in vm_list:
            if si_fq_str != si['si_fq_str']:
                continue

            proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
            self._delete_svc_instance(vm_uuid, proj_name, si_fq_str=si_fq_str)

            #insert shared instance IP uuids into cleanup list if present
            for itf_str in svc_info.get_if_str_list():
                iip_uuid_str = itf_str + '-iip-uuid'
                if not iip_uuid_str in si_info:
                    continue
                self.db.cleanup_table_insert(
                    si_info[iip_uuid_str], {'proj_name': proj_name,
                                            'type': 'iip'})
    #end _delmsg_service_instance_service_template

    def _delmsg_virtual_machine_service_instance(self, idents):
        vm_uuid = idents['virtual-machine']
        si_fq_str = idents['service-instance']
        proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
        vm_list = self.db.virtual_machine_list()
        for vm_uuid, si in vm_list:
            if si_fq_str != si['si_fq_str']:
                continue

            self._delete_svc_instance(vm_uuid, proj_name, si_fq_str=si_fq_str)
    # end _delmsg_service_instance_virtual_machine

    def _delmsg_virtual_machine_interface_route_table(self, idents):
        rt_fq_str = idents['interface-route-table']

        rt_obj = self._vnc_lib.interface_route_table_read(
            fq_name_str=rt_fq_str)
        vmi_list = rt_obj.get_virtual_machine_interface_back_refs()
        if vmi_list is None:
            self._vnc_lib.interface_route_table_delete(id=rt_obj.uuid)
    # end _delmsg_virtual_machine_interface_route_table

    def _addmsg_virtual_machine_interface_virtual_machine(self, idents):
        vm_fq_str = idents['virtual-machine']

        try:
            vm_obj = self._vnc_lib.virtual_machine_read(
                fq_name_str=vm_fq_str)
        except NoIdError:
            return

        # check if this is a service vm
        si_list = vm_obj.get_service_instance_refs()
        if not si_list:
            return

        vm_info = self.db.virtual_machine_get(vm_obj.uuid)
        if not vm_info:
            return
        si_fq_str = vm_info['si_fq_str']

        try:
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            proj_name = self._get_proj_name_from_si_fq_str(si_fq_str)
            self._delete_svc_instance(vm_obj.uuid, proj_name,
                                      si_fq_str=si_fq_str)
            return

        # create service instance to service vm link
        vm_obj.add_service_instance(si_obj)
        self._vnc_lib.virtual_machine_update(vm_obj)
        self.logger.log("Info: VM %s updated SI %s" %
                         (vm_obj.get_fq_name_str(), si_fq_str))
    # end _addmsg_virtual_machine_interface_virtual_machine

    def _addmsg_service_instance_service_template(self, idents):
        st_fq_str = idents['service-template']
        si_fq_str = idents['service-instance']

        try:
            st_obj = self._vnc_lib.service_template_read(
                fq_name_str=st_fq_str)
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            return

        #launch VMs
        self._create_svc_instance(st_obj, si_obj)
    # end _addmsg_service_instance_service_template

    def _addmsg_service_instance_properties(self, idents):
        si_fq_str = idents['service-instance']

        try:
            si_obj = self._vnc_lib.service_instance_read(
                fq_name_str=si_fq_str)
        except NoIdError:
            return

        #update static routes
        self._update_static_routes(si_obj)
    # end _addmsg_service_instance_service_template

    def _addmsg_project_virtual_network(self, idents):
        vn_fq_str = idents['virtual-network']

        si_list = self.db.service_instance_list()
        if not si_list:
            return

        for si_fq_str, si_info in si_list:
            if vn_fq_str not in si_info.keys():
                continue

            try:
                si_obj = self._vnc_lib.service_instance_read(
                    fq_name_str=si_fq_str)
                if si_obj.get_virtual_machine_back_refs():
                    continue

                st_refs = si_obj.get_service_template_refs()
                fq_name = st_refs[0]['to']
                st_obj = self._vnc_lib.service_template_read(fq_name=fq_name)

                #launch VMs
                self._create_svc_instance(st_obj, si_obj)
            except Exception:
                continue
    #end _addmsg_project_virtual_network

    def process_poll_result(self, poll_result_str):
        result_list = parse_poll_result(poll_result_str)

        # process ifmap message
        for (result_type, idents, metas) in result_list:
            if 'ERROR' in idents.values():
                continue
            for meta in metas:
                meta_name = re.sub('{.*}', '', meta.tag)
                if result_type == 'deleteResult':
                    funcname = "_delmsg_" + meta_name.replace('-', '_')
                elif result_type in ['searchResult', 'updateResult']:
                    funcname = "_addmsg_" + meta_name.replace('-', '_')
                # end if result_type
                try:
                    func = getattr(self, funcname)
                except AttributeError:
                    pass
                else:
                    self.logger.log("%s with %s/%s"
                                     % (funcname, meta_name, idents))
                    func(idents)
            # end for meta
        # end for result_type
    # end process_poll_result

    def _update_static_routes(self, si_obj):
        # get service instance interface list
        si_props = si_obj.get_service_instance_properties()
        si_if_list = si_props.get_interface_list()
        if not si_if_list:
            return

        for idx in range(0, len(si_if_list)):
            si_if = si_if_list[idx]
            static_routes = si_if.get_static_routes()
            if not static_routes:
                static_routes = {'route':[]}

            # update static routes
            try:
                domain_name, proj_name = si_obj.get_parent_fq_name()
                rt_name = si_obj.uuid + ' ' + str(idx)
                rt_fq_name = [domain_name, proj_name, rt_name]
                rt_obj = self._vnc_lib.interface_route_table_read(
                    fq_name=rt_fq_name)
                rt_obj.set_interface_route_table_routes(static_routes)
                self._vnc_lib.interface_route_table_update(rt_obj)
            except NoIdError:
                pass