class SchemaTransformer(object): _REACTION_MAP = { 'routing_instance': { 'self': ['virtual_network'], }, 'virtual_machine_interface': { 'self': [ 'virtual_machine', 'port_tuple', 'virtual_network', 'bgp_as_a_service' ], 'virtual_network': ['virtual_machine', 'port_tuple', 'bgp_as_a_service'], 'logical_router': ['virtual_network'], 'instance_ip': [ 'virtual_machine', 'port_tuple', 'bgp_as_a_service', 'virtual_network' ], 'floating_ip': ['virtual_machine', 'port_tuple'], 'virtual_machine': ['virtual_network'], 'port_tuple': ['virtual_network'], 'bgp_as_a_service': [], }, 'virtual_network': { 'self': ['network_policy', 'route_table'], 'routing_instance': ['network_policy'], 'network_policy': [], 'virtual_machine_interface': [], 'route_table': [], }, 'virtual_machine': { 'self': ['service_instance'], 'virtual_machine_interface': ['service_instance'], 'service_instance': ['virtual_machine_interface'] }, 'port_tuple': { 'self': ['service_instance'], 'virtual_machine_interface': ['service_instance'], 'service_instance': ['virtual_machine_interface'] }, 'service_instance': { 'self': ['network_policy', 'virtual_machine', 'port_tuple'], 'route_table': ['network_policy', 'virtual_machine', 'port_tuple'], 'routing_policy': ['network_policy'], 'route_aggregate': ['network_policy'], 'virtual_machine': ['network_policy'], 'port_tuple': ['network_policy'], 'network_policy': ['virtual_machine', 'port_tuple'] }, 'network_policy': { 'self': ['virtual_network', 'network_policy', 'service_instance'], 'service_instance': ['virtual_network'], 'network_policy': ['virtual_network'], 'virtual_network': ['virtual_network', 'network_policy', 'service_instance'] }, 'security_group': { 'self': ['security_group'], 'security_group': [], }, 'route_table': { 'self': ['virtual_network', 'service_instance'], 'virtual_network': ['service_instance'], }, 'logical_router': { 'self': [], 'virtual_machine_interface': [], }, 'floating_ip': { 'self': ['virtual_machine_interface'], }, 'instance_ip': { 'self': ['virtual_machine_interface'], }, 'bgp_as_a_service': { 'self': ['bgp_router'], 'virtual_machine_interface': ['bgp_router'] }, 'bgp_router': { 'self': [], 'bgp_as_a_service': [], }, 'global_system_config': { 'self': [], }, 'routing_policy': { 'self': ['service_instance'], }, 'route_aggregate': { 'self': ['service_instance'], } } def __init__(self, args=None): self._args = args self._fabric_rt_inst_obj = None # 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.SCHEMA_TRANSFORMER]) self._sandesh = Sandesh() # Reset the sandesh send rate limit value if args.sandesh_send_rate_limit is not None: SandeshSystem.set_sandesh_send_rate_limit( args.sandesh_send_rate_limit) sandesh.VnList.handle_request = self.sandesh_vn_handle_request sandesh.RoutintInstanceList.handle_request = \ self.sandesh_ri_handle_request sandesh.ServiceChainList.handle_request = \ self.sandesh_sc_handle_request sandesh.StObjectReq.handle_request = \ self.sandesh_st_object_handle_request module = Module.SCHEMA_TRANSFORMER module_name = ModuleNames[module] node_type = Module2NodeType[module] node_type_name = NodeTypeNames[node_type] instance_id = INSTANCE_ID_DEFAULT hostname = socket.gethostname() self._sandesh.init_generator( module_name, hostname, node_type_name, instance_id, self._args.collectors, 'to_bgp_context', int(args.http_server_port), ['cfgm_common', 'schema_transformer.sandesh'], self._disc, logger_class=args.logger_class, logger_config_file=args.logging_conf) self._sandesh.set_logging_params(enable_local_log=args.log_local, category=args.log_category, level=args.log_level, file=args.log_file, enable_syslog=args.use_syslog, syslog_facility=args.syslog_facility) ConnectionState.init( self._sandesh, hostname, module_name, instance_id, staticmethod(ConnectionState.get_process_state_cb), NodeStatusUVE, NodeStatus) self._sandesh.trace_buffer_create(name="MessageBusNotifyTraceBuf", size=1000) rabbit_servers = 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 = 'schema_transformer.%s' % (socket.gethostname()) self._vnc_kombu = VncKombuClient(rabbit_servers, rabbit_port, rabbit_user, rabbit_password, rabbit_vhost, rabbit_ha_mode, q_name, self._vnc_subscribe_callback, self.config_log) self._cassandra = SchemaTransformerDB(self, _zookeeper_client) DBBaseST.init(self, self._sandesh.logger(), self._cassandra) DBBaseST._sandesh = self._sandesh DBBaseST._vnc_lib = _vnc_lib ServiceChain.init() self.reinit() # create cpu_info object to send periodic updates sysinfo_req = False cpu_info = vnc_cpu_info.CpuInfo(module_name, instance_id, sysinfo_req, self._sandesh, 60) self._cpu_info = cpu_info self._db_resync_done.set() # end __init__ def config_log(self, msg, level): self._sandesh.logger().log(SandeshLogger.get_py_logger_level(level), msg) def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() dependency_tracker = None try: msg = "Notification Message: %s" % (pformat(oper_info)) self.config_log(msg, level=SandeshLevel.SYS_DEBUG) obj_type = oper_info['type'].replace('-', '_') obj_class = DBBaseST.get_obj_type_map().get(obj_type) if obj_class is None: return oper = oper_info['oper'] obj_id = oper_info['uuid'] notify_trace = MessageBusNotifyTrace( request_id=oper_info.get('request_id'), operation=oper, uuid=obj_id) if oper == 'CREATE': obj_dict = oper_info['obj_dict'] obj_fq_name = ':'.join(obj_dict['fq_name']) obj = obj_class.locate(obj_fq_name) if obj is None: self.config_log('%s id %s fq_name %s not found' % (obj_type, obj_id, obj_fq_name), level=SandeshLevel.SYS_INFO) return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) elif oper == 'UPDATE': obj = obj_class.get_by_uuid(obj_id) old_dt = None if obj is not None: old_dt = DependencyTracker(DBBaseST.get_obj_type_map(), self._REACTION_MAP) old_dt.evaluate(obj_type, obj) else: self.config_log('%s id %s not found' % (obj_type, obj_id), level=SandeshLevel.SYS_INFO) return try: obj.update() except NoIdError: self.config_log('%s id %s update caused NoIdError' % (obj_type, obj_id), level=SandeshLevel.SYS_INFO) return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in dependency_tracker.resources: dependency_tracker.resources[resource] = ids else: dependency_tracker.resources[resource] = list( set(dependency_tracker.resources[resource]) | set(ids)) elif oper == 'DELETE': obj = obj_class.get_by_uuid(obj_id) if obj is None: return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) obj_class.delete(obj.name) else: # unknown operation self.config_log('Unknown operation %s' % oper, level=SandeshLevel.SYS_ERR) return if obj is None: self.config_log('Error while accessing %s uuid %s' % (obj_type, obj_id)) return notify_trace.fq_name = obj.name if not dependency_tracker: return notify_trace.dependency_tracker_resources = [] for res_type, res_id_list in dependency_tracker.resources.items(): if not res_id_list: continue dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) notify_trace.dependency_tracker_resources.append(dtr) cls = DBBaseST.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() for vn_id in dependency_tracker.resources.get( 'virtual_network', []): vn = VirtualNetworkST.get(vn_id) if vn is not None: vn.uve_send() # end for vn_id except Exception as e: string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") notify_trace.error = string_buf.getvalue() try: with open(self._args.trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: self.config_log(string_buf.getvalue(), level=SandeshLevel.SYS_ERR) finally: try: notify_trace.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self._sandesh) except Exception: pass # end _vnc_subscribe_callback # Clean up stale objects def reinit(self): GlobalSystemConfigST.reinit() BgpRouterST.reinit() LogicalRouterST.reinit() vn_list = list(VirtualNetworkST.list_vnc_obj()) vn_id_list = [vn.uuid for vn in vn_list] ri_dict = {} service_ri_dict = {} for ri in DBBaseST.list_vnc_obj('routing_instance'): delete = False if ri.parent_uuid not in vn_id_list: delete = True else: # if the RI was for a service chain and service chain no # longer exists, delete the RI sc_id = RoutingInstanceST._get_service_id_from_ri( ri.get_fq_name_str()) if sc_id: if sc_id not in ServiceChain: delete = True else: service_ri_dict[ri.get_fq_name_str()] = ri else: ri_dict[ri.get_fq_name_str()] = ri if delete: try: ri_obj = RoutingInstanceST(ri.get_fq_name_str(), ri) ri_obj.delete_obj() except NoIdError: pass except Exception as e: self._sandesh._logger.error( "Error while deleting routing instance %s: %s", ri.get_fq_name_str(), str(e)) # end for ri sg_list = list(SecurityGroupST.list_vnc_obj()) sg_id_list = [sg.uuid for sg in sg_list] sg_acl_dict = {} vn_acl_dict = {} for acl in DBBaseST.list_vnc_obj('access_control_list'): delete = False if acl.parent_type == 'virtual-network': if acl.parent_uuid in vn_id_list: vn_acl_dict[acl.uuid] = acl else: delete = True elif acl.parent_type == 'security-group': if acl.parent_uuid in sg_id_list: sg_acl_dict[acl.uuid] = acl else: delete = True else: delete = True if delete: try: _vnc_lib.access_control_list_delete(id=acl.uuid) except NoIdError: pass except Exception as e: self._sandesh._logger.error( "Error while deleting acl %s: %s", acl.uuid, str(e)) # end for acl gevent.sleep(0.001) for sg in sg_list: SecurityGroupST.locate(sg.get_fq_name_str(), sg, sg_acl_dict) # update sg rules after all SG objects are initialized to avoid # rewriting of ACLs multiple times for sg in SecurityGroupST.values(): sg.update_policy_entries() gevent.sleep(0.001) RouteTargetST.reinit() for vn in vn_list: VirtualNetworkST.locate(vn.get_fq_name_str(), vn, vn_acl_dict) for ri_name, ri_obj in ri_dict.items(): RoutingInstanceST.locate(ri_name, ri_obj) # Initialize service instance RI's after Primary RI's for si_ri_name, si_ri_obj in service_ri_dict.items(): RoutingInstanceST.locate(si_ri_name, si_ri_obj) NetworkPolicyST.reinit() gevent.sleep(0.001) VirtualMachineInterfaceST.reinit() gevent.sleep(0.001) InstanceIpST.reinit() gevent.sleep(0.001) FloatingIpST.reinit() gevent.sleep(0.001) for si in ServiceInstanceST.list_vnc_obj(): si_st = ServiceInstanceST.locate(si.get_fq_name_str(), si) if si_st is None: continue for ref in si.get_virtual_machine_back_refs() or []: vm_name = ':'.join(ref['to']) vm = VirtualMachineST.locate(vm_name) si_st.virtual_machines.add(vm_name) props = si.get_service_instance_properties() if not props.auto_policy: continue si_st.add_properties(props) gevent.sleep(0.001) RoutingPolicyST.reinit() gevent.sleep(0.001) RouteAggregateST.reinit() gevent.sleep(0.001) PortTupleST.reinit() BgpAsAServiceST.reinit() RouteTableST.reinit() # evaluate virtual network objects first because other objects, # e.g. vmi, depend on it. for vn_obj in VirtualNetworkST.values(): vn_obj.evaluate() for cls in DBBaseST.get_obj_type_map().values(): if cls is VirtualNetworkST: continue for obj in cls.values(): obj.evaluate() self.process_stale_objects() # end reinit def cleanup(self): # TODO cleanup sandesh context pass # end cleanup def process_stale_objects(self): for sc in ServiceChain.values(): if sc.created_stale: sc.destroy() if sc.present_stale: sc.delete() # end process_stale_objects def sandesh_ri_build(self, vn_name, ri_name): vn = VirtualNetworkST.get(vn_name) sandesh_ri_list = [] for riname in vn.routing_instances: ri = RoutingInstanceST.get(riname) sandesh_ri = sandesh.RoutingInstance(name=ri.obj.get_fq_name_str()) sandesh_ri.service_chain = ri.service_chain sandesh_ri.connections = list(ri.connections) sandesh_ri_list.append(sandesh_ri) return sandesh_ri_list # end sandesh_ri_build def sandesh_ri_handle_request(self, req): # Return the list of VNs ri_resp = sandesh.RoutingInstanceListResp(routing_instances=[]) if req.vn_name is None: for vn in VirtualNetworkST: sandesh_ri = self.sandesh_ri_build(vn, req.ri_name) ri_resp.routing_instances.extend(sandesh_ri) elif req.vn_name in VirtualNetworkST: self.sandesh_ri_build(req.vn_name, req.ri_name) ri_resp.routing_instances.extend(sandesh_ri) ri_resp.response(req.context()) # end sandesh_ri_handle_request def sandesh_vn_build(self, vn_name): vn = VirtualNetworkST.get(vn_name) sandesh_vn = sandesh.VirtualNetwork(name=vn_name) sandesh_vn.policies = vn.network_policys.keys() sandesh_vn.connections = list(vn.connections) sandesh_vn.routing_instances = vn.routing_instances if vn.acl: sandesh_vn.acl = vn.acl.get_fq_name_str() if vn.dynamic_acl: sandesh_vn.dynamic_acl = vn.dynamic_acl.get_fq_name_str() return sandesh_vn # end sandesh_vn_build def sandesh_vn_handle_request(self, req): # Return the list of VNs vn_resp = sandesh.VnListResp(vn_names=[]) if req.vn_name is None: for vn in VirtualNetworkST: sandesh_vn = self.sandesh_vn_build(vn) vn_resp.vn_names.append(sandesh_vn) elif req.vn_name in VirtualNetworkST: sandesh_vn = self.sandesh_vn_build(req.vn_name) vn_resp.vn_names.append(sandesh_vn) vn_resp.response(req.context()) # end sandesh_vn_handle_request def sandesh_sc_handle_request(self, req): sc_resp = sandesh.ServiceChainListResp(service_chains=[]) if req.sc_name is None: for sc in ServiceChain.values(): sandesh_sc = sc.build_introspect() sc_resp.service_chains.append(sandesh_sc) elif req.sc_name in ServiceChain: sandesh_sc = ServiceChain[req.sc_name].build_introspect() sc_resp.service_chains.append(sandesh_sc) sc_resp.response(req.context()) # end sandesh_sc_handle_request def sandesh_st_object_handle_request(self, req): st_resp = sandesh.StObjectListResp(objects=[]) obj_type_map = DBBaseST.get_obj_type_map() if req.object_type is not None: if req.object_type not in obj_type_map: return st_resp obj_cls_list = [obj_type_map[req.object_type]] else: obj_cls_list = obj_type_map.values() for obj_cls in obj_cls_list: id_or_name = req.object_id_or_fq_name if id_or_name: obj = obj_cls.get(id_or_name) or obj_cls.get_by_uuid( id_or_name) if obj is None: continue st_resp.objects.append(obj.handle_st_object_req()) else: for obj in obj_cls.values(): st_resp.objects.append(obj.handle_st_object_req()) st_resp.response(req.context()) # end sandesh_st_object_handle_request def reset(self): for cls in DBBaseST.get_obj_type_map().values(): cls.reset() self._vnc_kombu.shutdown()
class SchemaTransformer(object): _REACTION_MAP = { 'routing_instance': { 'self': ['virtual_network'], }, 'virtual_machine_interface': { 'self': ['virtual_machine', 'port_tuple', 'virtual_network', 'bgp_as_a_service'], 'virtual_network': ['virtual_machine', 'port_tuple', 'bgp_as_a_service'], 'logical_router': ['virtual_network'], 'instance_ip': ['virtual_machine', 'port_tuple', 'bgp_as_a_service'], 'floating_ip': ['virtual_machine', 'port_tuple'], 'virtual_machine': [], 'port_tuple': [], 'bgp_as_a_service': [], }, 'virtual_network': { 'self': ['network_policy'], 'routing_instance': ['network_policy'], 'network_policy': [], 'virtual_machine_interface': [], 'route_table': [], }, 'virtual_machine': { 'self': ['service_instance'], 'virtual_machine_interface': ['service_instance'], 'service_instance': ['virtual_machine_interface'] }, 'port_tuple': { 'self': ['service_instance'], 'virtual_machine_interface': ['service_instance'], 'service_instance': ['virtual_machine_interface'] }, 'service_instance': { 'self': ['network_policy', 'virtual_machine', 'port_tuple'], 'routing_policy': ['network_policy'], 'route_aggregate': ['network_policy'], 'virtual_machine': ['network_policy'], 'port_tuple': ['network_policy'], 'network_policy': ['virtual_machine', 'port_tuple'] }, 'network_policy': { 'self': ['virtual_network', 'network_policy', 'service_instance'], 'service_instance': ['virtual_network'], 'network_policy': ['virtual_network'], 'virtual_network': ['virtual_network', 'network_policy', 'service_instance'] }, 'security_group': { 'self': ['security_group'], 'security_group': [], }, 'route_table': { 'self': ['virtual_network'], }, 'logical_router': { 'self': [], 'virtual_machine_interface': [], }, 'floating_ip': { 'self': ['virtual_machine_interface'], }, 'instance_ip': { 'self': ['virtual_machine_interface'], }, 'bgp_as_a_service': { 'self': ['bgp_router'], 'virtual_machine_interface': ['bgp_router'] }, 'bgp_router': { 'self': [], 'bgp_as_a_service': [], }, 'global_system_config': { 'self': [], }, 'routing_policy': { 'self': ['service_instance'], }, 'route_aggregate': { 'self': ['service_instance'], } } def __init__(self, args=None): self._args = args self._fabric_rt_inst_obj = None # 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.SCHEMA_TRANSFORMER]) self._sandesh = Sandesh() # Reset the sandesh send rate limit value if args.sandesh_send_rate_limit is not None: SandeshSystem.set_sandesh_send_rate_limit( args.sandesh_send_rate_limit) sandesh.VnList.handle_request = self.sandesh_vn_handle_request sandesh.RoutintInstanceList.handle_request = \ self.sandesh_ri_handle_request sandesh.ServiceChainList.handle_request = \ self.sandesh_sc_handle_request sandesh.StObjectReq.handle_request = \ self.sandesh_st_object_handle_request module = Module.SCHEMA_TRANSFORMER module_name = ModuleNames[module] node_type = Module2NodeType[module] node_type_name = NodeTypeNames[node_type] instance_id = INSTANCE_ID_DEFAULT hostname = socket.gethostname() self._sandesh.init_generator( module_name, hostname, node_type_name, instance_id, self._args.collectors, 'to_bgp_context', int(args.http_server_port), ['cfgm_common', 'schema_transformer.sandesh'], self._disc, logger_class=args.logger_class, logger_config_file=args.logging_conf) self._sandesh.set_logging_params(enable_local_log=args.log_local, category=args.log_category, level=args.log_level, file=args.log_file, enable_syslog=args.use_syslog, syslog_facility=args.syslog_facility) ConnectionState.init(self._sandesh, hostname, module_name, instance_id, staticmethod(ConnectionState.get_process_state_cb), NodeStatusUVE, NodeStatus) self._sandesh.trace_buffer_create(name="MessageBusNotifyTraceBuf", size=1000) rabbit_servers = 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 = 'schema_transformer.%s' % (socket.gethostname()) self._vnc_kombu = VncKombuClient(rabbit_servers, rabbit_port, rabbit_user, rabbit_password, rabbit_vhost, rabbit_ha_mode, q_name, self._vnc_subscribe_callback, self.config_log) self._cassandra = SchemaTransformerDB(self, _zookeeper_client) DBBaseST.init(self, self._sandesh.logger(), self._cassandra) DBBaseST._sandesh = self._sandesh DBBaseST._vnc_lib = _vnc_lib ServiceChain.init() self.reinit() # create cpu_info object to send periodic updates sysinfo_req = False cpu_info = vnc_cpu_info.CpuInfo( module_name, instance_id, sysinfo_req, self._sandesh, 60) self._cpu_info = cpu_info self._db_resync_done.set() # end __init__ def config_log(self, msg, level): self._sandesh.logger().log(SandeshLogger.get_py_logger_level(level), msg) def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() dependency_tracker = None try: msg = "Notification Message: %s" % (pformat(oper_info)) self.config_log(msg, level=SandeshLevel.SYS_DEBUG) obj_type = oper_info['type'].replace('-', '_') obj_class = DBBaseST.get_obj_type_map().get(obj_type) if obj_class is None: return oper = oper_info['oper'] obj_id = oper_info['uuid'] notify_trace = MessageBusNotifyTrace( request_id=oper_info.get('request_id'), operation=oper, uuid=obj_id) if oper == 'CREATE': obj_dict = oper_info['obj_dict'] obj_fq_name = ':'.join(obj_dict['fq_name']) obj = obj_class.locate(obj_fq_name) if obj is None: self.config_log('%s id %s fq_name %s not found' % ( obj_type, obj_id, obj_fq_name), level=SandeshLevel.SYS_INFO) return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) elif oper == 'UPDATE': obj = obj_class.get_by_uuid(obj_id) old_dt = None if obj is not None: old_dt = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) old_dt.evaluate(obj_type, obj) else: self.config_log('%s id %s not found' % (obj_type, obj_id), level=SandeshLevel.SYS_INFO) return try: obj.update() except NoIdError: self.config_log('%s id %s update caused NoIdError' % (obj_type, obj_id), level=SandeshLevel.SYS_INFO) return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in dependency_tracker.resources: dependency_tracker.resources[resource] = ids else: dependency_tracker.resources[resource] = list( set(dependency_tracker.resources[resource]) | set(ids)) elif oper == 'DELETE': obj = obj_class.get_by_uuid(obj_id) if obj is None: return dependency_tracker = DependencyTracker( DBBaseST.get_obj_type_map(), self._REACTION_MAP) dependency_tracker.evaluate(obj_type, obj) obj_class.delete(obj.name) else: # unknown operation self.config_log('Unknown operation %s' % oper, level=SandeshLevel.SYS_ERR) return if obj is None: self.config_log('Error while accessing %s uuid %s' % ( obj_type, obj_id)) return notify_trace.fq_name = obj.name if not dependency_tracker: return notify_trace.dependency_tracker_resources = [] for res_type, res_id_list in dependency_tracker.resources.items(): if not res_id_list: continue dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) notify_trace.dependency_tracker_resources.append(dtr) cls = DBBaseST.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() for vn_id in dependency_tracker.resources.get('virtual_network', []): vn = VirtualNetworkST.get(vn_id) if vn is not None: vn.uve_send() # end for vn_id except Exception as e: string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") notify_trace.error = string_buf.getvalue() try: with open(self._args.trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: self.config_log(string_buf.getvalue(), level=SandeshLevel.SYS_ERR) finally: try: notify_trace.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self._sandesh) except Exception: pass # end _vnc_subscribe_callback # Clean up stale objects def reinit(self): GlobalSystemConfigST.reinit() BgpRouterST.reinit() LogicalRouterST.reinit() vn_list = list(VirtualNetworkST.list_vnc_obj()) vn_id_list = [vn.uuid for vn in vn_list] ri_dict = {} service_ri_dict = {} for ri in DBBaseST.list_vnc_obj('routing_instance'): delete = False if ri.parent_uuid not in vn_id_list: delete = True else: # if the RI was for a service chain and service chain no # longer exists, delete the RI sc_id = RoutingInstanceST._get_service_id_from_ri( ri.get_fq_name_str()) if sc_id: if sc_id not in ServiceChain: delete = True else: service_ri_dict[ri.get_fq_name_str()] = ri else: ri_dict[ri.get_fq_name_str()] = ri if delete: try: ri_obj = RoutingInstanceST(ri.get_fq_name_str(), ri) ri_obj.delete_obj() except NoIdError: pass except Exception as e: self._sandesh._logger.error( "Error while deleting routing instance %s: %s", ri.get_fq_name_str(), str(e)) # end for ri sg_list = list(SecurityGroupST.list_vnc_obj()) sg_id_list = [sg.uuid for sg in sg_list] sg_acl_dict = {} vn_acl_dict = {} for acl in DBBaseST.list_vnc_obj('access_control_list'): delete = False if acl.parent_type == 'virtual-network': if acl.parent_uuid in vn_id_list: vn_acl_dict[acl.uuid] = acl else: delete = True elif acl.parent_type == 'security-group': if acl.parent_uuid in sg_id_list: sg_acl_dict[acl.uuid] = acl else: delete = True else: delete = True if delete: try: _vnc_lib.access_control_list_delete(id=acl.uuid) except NoIdError: pass except Exception as e: self._sandesh._logger.error( "Error while deleting acl %s: %s", acl.uuid, str(e)) # end for acl gevent.sleep(0.001) for sg in sg_list: SecurityGroupST.locate(sg.get_fq_name_str(), sg, sg_acl_dict) # update sg rules after all SG objects are initialized to avoid # rewriting of ACLs multiple times for sg in SecurityGroupST.values(): sg.update_policy_entries() gevent.sleep(0.001) RouteTargetST.reinit() for vn in vn_list: VirtualNetworkST.locate(vn.get_fq_name_str(), vn, vn_acl_dict) for ri_name, ri_obj in ri_dict.items(): RoutingInstanceST.locate(ri_name, ri_obj) # Initialize service instance RI's after Primary RI's for si_ri_name, si_ri_obj in service_ri_dict.items(): RoutingInstanceST.locate(si_ri_name, si_ri_obj) NetworkPolicyST.reinit() gevent.sleep(0.001) VirtualMachineInterfaceST.reinit() gevent.sleep(0.001) InstanceIpST.reinit() gevent.sleep(0.001) FloatingIpST.reinit() gevent.sleep(0.001) for si in ServiceInstanceST.list_vnc_obj(): si_st = ServiceInstanceST.locate(si.get_fq_name_str(), si) if si_st is None: continue for ref in si.get_virtual_machine_back_refs() or []: vm_name = ':'.join(ref['to']) vm = VirtualMachineST.locate(vm_name) si_st.virtual_machines.add(vm_name) props = si.get_service_instance_properties() if not props.auto_policy: continue si_st.add_properties(props) gevent.sleep(0.001) RoutingPolicyST.reinit() gevent.sleep(0.001) RouteAggregateST.reinit() gevent.sleep(0.001) PortTupleST.reinit() BgpAsAServiceST.reinit() RouteTableST.reinit() # evaluate virtual network objects first because other objects, # e.g. vmi, depend on it. for vn_obj in VirtualNetworkST.values(): vn_obj.evaluate() for cls in DBBaseST.get_obj_type_map().values(): if cls is VirtualNetworkST: continue for obj in cls.values(): obj.evaluate() self.process_stale_objects() # end reinit def cleanup(self): # TODO cleanup sandesh context pass # end cleanup def process_stale_objects(self): for sc in ServiceChain.values(): if sc.created_stale: sc.destroy() if sc.present_stale: sc.delete() # end process_stale_objects def sandesh_ri_build(self, vn_name, ri_name): vn = VirtualNetworkST.get(vn_name) sandesh_ri_list = [] for riname in vn.routing_instances: ri = RoutingInstanceST.get(riname) sandesh_ri = sandesh.RoutingInstance(name=ri.obj.get_fq_name_str()) sandesh_ri.service_chain = ri.service_chain sandesh_ri.connections = list(ri.connections) sandesh_ri_list.append(sandesh_ri) return sandesh_ri_list # end sandesh_ri_build def sandesh_ri_handle_request(self, req): # Return the list of VNs ri_resp = sandesh.RoutingInstanceListResp(routing_instances=[]) if req.vn_name is None: for vn in VirtualNetworkST: sandesh_ri = self.sandesh_ri_build(vn, req.ri_name) ri_resp.routing_instances.extend(sandesh_ri) elif req.vn_name in VirtualNetworkST: self.sandesh_ri_build(req.vn_name, req.ri_name) ri_resp.routing_instances.extend(sandesh_ri) ri_resp.response(req.context()) # end sandesh_ri_handle_request def sandesh_vn_build(self, vn_name): vn = VirtualNetworkST.get(vn_name) sandesh_vn = sandesh.VirtualNetwork(name=vn_name) sandesh_vn.policies = vn.network_policys.keys() sandesh_vn.connections = list(vn.connections) sandesh_vn.routing_instances = vn.routing_instances if vn.acl: sandesh_vn.acl = vn.acl.get_fq_name_str() if vn.dynamic_acl: sandesh_vn.dynamic_acl = vn.dynamic_acl.get_fq_name_str() return sandesh_vn # end sandesh_vn_build def sandesh_vn_handle_request(self, req): # Return the list of VNs vn_resp = sandesh.VnListResp(vn_names=[]) if req.vn_name is None: for vn in VirtualNetworkST: sandesh_vn = self.sandesh_vn_build(vn) vn_resp.vn_names.append(sandesh_vn) elif req.vn_name in VirtualNetworkST: sandesh_vn = self.sandesh_vn_build(req.vn_name) vn_resp.vn_names.append(sandesh_vn) vn_resp.response(req.context()) # end sandesh_vn_handle_request def sandesh_sc_handle_request(self, req): sc_resp = sandesh.ServiceChainListResp(service_chains=[]) if req.sc_name is None: for sc in ServiceChain.values(): sandesh_sc = sc.build_introspect() sc_resp.service_chains.append(sandesh_sc) elif req.sc_name in ServiceChain: sandesh_sc = ServiceChain[req.sc_name].build_introspect() sc_resp.service_chains.append(sandesh_sc) sc_resp.response(req.context()) # end sandesh_sc_handle_request def sandesh_st_object_handle_request(self, req): st_resp = sandesh.StObjectListResp(objects=[]) obj_type_map = DBBaseST.get_obj_type_map() if req.object_type is not None: if req.object_type not in obj_type_map: return st_resp obj_cls_list = [obj_type_map[req.object_type]] else: obj_cls_list = obj_type_map.values() for obj_cls in obj_cls_list: id_or_name = req.object_id_or_fq_name if id_or_name: obj = obj_cls.get(id_or_name) or obj_cls.get_by_uuid(id_or_name) if obj is None: continue st_resp.objects.append(obj.handle_st_object_req()) else: for obj in obj_cls.values(): st_resp.objects.append(obj.handle_st_object_req()) st_resp.response(req.context()) # end sandesh_st_object_handle_request def reset(self): for cls in DBBaseST.get_obj_type_map().values(): cls.reset() self._vnc_kombu.shutdown()
class VncAmqpHandle(object): def __init__(self, logger, db_cls, reaction_map, q_name_prefix, args=None): self.logger = logger self.db_cls = db_cls self.reaction_map = reaction_map self.q_name_prefix = q_name_prefix self._db_resync_done = gevent.event.Event() self._args = args def establish(self): q_name = '.'.join([self.q_name_prefix, socket.gethostname()]) self._vnc_kombu = VncKombuClient( self._args.rabbit_server, self._args.rabbit_port, self._args.rabbit_user, self._args.rabbit_password, self._args.rabbit_vhost, self._args.rabbit_ha_mode, q_name, self._vnc_subscribe_callback, self.logger.log, rabbit_use_ssl=self._args.rabbit_use_ssl, kombu_ssl_version=self._args.kombu_ssl_version, kombu_ssl_keyfile=self._args.kombu_ssl_keyfile, kombu_ssl_certfile=self._args.kombu_ssl_certfile, kombu_ssl_ca_certs=self._args.kombu_ssl_ca_certs) def msgbus_store_err_msg(self, msg): self.msg_tracer.error = msg def msgbus_trace_msg(self): self.msg_tracer.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self.logger._sandesh) def log_exception(self): string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") self.logger.error(string_buf.getvalue()) self.msgbus_store_err_msg(string_buf.getvalue()) try: with open(self._args.trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: pass def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() try: self.oper_info = oper_info self.vnc_subscribe_actions() except ConnectionError: try: # retry write during api-server ConnectionError self.vnc_subscribe_actions() except ConnectionError: # log the exception, and exit during api-server # ConnectionError on retry to let standby to become active. self.log_exception() self.logger.error("Api-server connection lost. Exiting") self.close() raise SystemExit except Exception: self.log_exception() except Exception: self.log_exception() finally: try: self.msgbus_trace_msg() except Exception: pass del self.oper_info del self.obj_type del self.obj_class del self.obj del self.dependency_tracker def create_msgbus_trace(self, request_id, oper, uuid): self.msg_tracer = MessageBusNotifyTrace(request_id=request_id, operation=oper, uuid=uuid) def vnc_subscribe_actions(self): msg = "Notification Message: %s" % (pformat(self.oper_info)) self.logger.debug(msg) self.obj = None self.dependency_tracker = None self.obj_type = self.oper_info['type'].replace('-', '_') self.obj_class = self.db_cls.get_obj_type_map().get(self.obj_type) if self.obj_class is None: return oper = self.oper_info['oper'] obj_id = self.oper_info['uuid'] self.create_msgbus_trace(self.oper_info.get('request_id'), oper, obj_id) if oper == 'CREATE': self.handle_create() elif oper == 'UPDATE': self.handle_update() elif oper == 'DELETE': self.handle_delete() else: self.handle_unknown() return if self.obj is None: self.logger.warning( "Object %s uuid %s was not found for operation %s" % (self.obj_type, obj_id, oper)) return self.evaluate_dependency() def _get_key_from_oper_info(self): if self.db_cls._indexed_by_name: return ':'.join(self.oper_info['fq_name']) return self.oper_info['uuid'] def handle_create(self): obj_key = self._get_key_from_oper_info() obj_id = self.oper_info['uuid'] obj_fq_name = self.oper_info['fq_name'] self.db_cls._object_db.cache_uuid_to_fq_name_add( obj_id, obj_fq_name, self.obj_type) self.obj = self.obj_class.locate(obj_key) if self.obj is None: self.logger.info('%s id %s fq_name %s not found' % (self.obj_type, obj_id, obj_fq_name)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) def handle_update(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) old_dt = None if self.obj is not None: old_dt = DependencyTracker(self.db_cls.get_obj_type_map(), self.reaction_map) old_dt.evaluate(self.obj_type, self.obj) else: self.logger.info('%s id %s not found' % (self.obj_type, obj_id)) return try: ret = self.obj.update() if ret is not None and not ret: # If update returns None, the function may not support a # return value, hence treat it as if something might have # changed. If a value is returned, use its truth value. # If it True, then some change was detected. # If no change, then terminate dependency tracker return except NoIdError: obj_id = self.oper_info['uuid'] self.logger.warning('%s uuid %s update caused NoIdError' % (self.obj_type, obj_id)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in self.dependency_tracker.resources: self.dependency_tracker.resources[resource] = ids else: self.dependency_tracker.resources[resource] = list( set(self.dependency_tracker.resources[resource]) | set(ids)) def handle_delete(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) self.db_cls._object_db.cache_uuid_to_fq_name_del(obj_id) if self.obj is None: return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) obj_key = self._get_key_from_oper_info() self.obj_class.delete(obj_key) def handle_unknown(self): # unknown operation self.logger.error('Unknown operation %s' % self.oper_info['oper']) def init_msgbus_fq_name(self): self.msg_tracer.fq_name = self.obj.name def init_msgbus_dtr(self): self.msg_tracer.dependency_tracker_resources = [] def add_msgbus_dtr(self, res_type, res_id_list): dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) self.msg_tracer.dependency_tracker_resources.append(dtr) def evaluate_dependency(self): if not self.dependency_tracker: return self.init_msgbus_fq_name() self.init_msgbus_dtr() for res_type, res_id_list in self.dependency_tracker.resources.items(): if not res_id_list: continue self.add_msgbus_dtr(res_type, res_id_list) cls = self.db_cls.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() def close(self): self._vnc_kombu.shutdown()
class VncAmqpHandle(object): def __init__(self, logger, db_cls, reaction_map, q_name_prefix, args=None): self.logger = logger self.db_cls = db_cls self.reaction_map = reaction_map self.q_name_prefix = q_name_prefix self._db_resync_done = gevent.event.Event() self._args = args def establish(self): q_name = '.'.join([self.q_name_prefix, socket.gethostname()]) self._vnc_kombu = VncKombuClient( self._args.rabbit_server, self._args.rabbit_port, self._args.rabbit_user, self._args.rabbit_password, self._args.rabbit_vhost, self._args.rabbit_ha_mode, q_name, self._vnc_subscribe_callback, self.logger.log, rabbit_use_ssl=self._args.rabbit_use_ssl, kombu_ssl_version=self._args.kombu_ssl_version, kombu_ssl_keyfile=self._args.kombu_ssl_keyfile, kombu_ssl_certfile=self._args.kombu_ssl_certfile, kombu_ssl_ca_certs=self._args.kombu_ssl_ca_certs) def msgbus_store_err_msg(self, msg): self.msg_tracer.error = msg def msgbus_trace_msg(self): self.msg_tracer.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self.logger._sandesh) def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() try: self.oper_info = oper_info self.vnc_subscribe_actions() except Exception: string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") self.logger.error(string_buf.getvalue()) self.msgbus_store_err_msg(string_buf.getvalue()) try: with open(self._args.trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: pass finally: try: self.msgbus_trace_msg() except Exception: pass del self.oper_info del self.obj_type del self.obj_class del self.obj del self.dependency_tracker def create_msgbus_trace(self, request_id, oper, uuid): self.msg_tracer = MessageBusNotifyTrace(request_id=request_id, operation=oper, uuid=uuid) def vnc_subscribe_actions(self): msg = "Notification Message: %s" % (pformat(self.oper_info)) self.logger.debug(msg) self.obj = None self.dependency_tracker = None self.obj_type = self.oper_info['type'].replace('-', '_') self.obj_class = self.db_cls.get_obj_type_map().get(self.obj_type) if self.obj_class is None: return oper = self.oper_info['oper'] obj_id = self.oper_info['uuid'] self.create_msgbus_trace(self.oper_info.get('request_id'), oper, obj_id) if oper == 'CREATE': self.handle_create() elif oper == 'UPDATE': self.handle_update() elif oper == 'DELETE': self.handle_delete() else: self.handle_unknown() return if self.obj is None: self.logger.error('Error while accessing %s uuid %s' % (self.obj_type, obj_id)) return self.evaluate_dependency() def handle_create(self): obj_dict = self.oper_info['obj_dict'] obj_key = self.db_cls.get_key_from_dict(obj_dict) obj_id = self.oper_info['uuid'] obj_fq_name = obj_dict['fq_name'] self.db_cls._object_db.cache_uuid_to_fq_name_add( obj_id, obj_fq_name, self.obj_type) self.obj = self.obj_class.locate(obj_key) if self.obj is None: self.logger.info('%s id %s fq_name %s not found' % (self.obj_type, obj_id, obj_fq_name)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) def handle_update(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) old_dt = None if self.obj is not None: old_dt = DependencyTracker(self.db_cls.get_obj_type_map(), self.reaction_map) old_dt.evaluate(self.obj_type, self.obj) else: self.logger.info('%s id %s not found' % (self.obj_type, obj_id)) return try: self.obj.update() except NoIdError: obj_id = self.oper_info['uuid'] self.logger.warning('%s uuid %s update caused NoIdError' % (self.obj_type, obj_id)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in self.dependency_tracker.resources: self.dependency_tracker.resources[resource] = ids else: self.dependency_tracker.resources[resource] = list( set(self.dependency_tracker.resources[resource]) | set(ids)) def handle_delete(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) self.db_cls._object_db.cache_uuid_to_fq_name_del(obj_id) if self.obj is None: return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) obj_key = self.db_cls.get_key_from_dict(self.oper_info['obj_dict']) self.obj_class.delete(obj_key) def handle_unknown(self): # unknown operation self.logger.error('Unknown operation %s' % self.oper_info['oper']) def init_msgbus_fq_name(self): self.msg_tracer.fq_name = self.obj.name def init_msgbus_dtr(self): self.msg_tracer.dependency_tracker_resources = [] def add_msgbus_dtr(self, res_type, res_id_list): dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) self.msg_tracer.dependency_tracker_resources.append(dtr) def evaluate_dependency(self): if not self.dependency_tracker: return self.init_msgbus_fq_name() self.init_msgbus_dtr() for res_type, res_id_list in self.dependency_tracker.resources.items(): if not res_id_list: continue self.add_msgbus_dtr(res_type, res_id_list) cls = self.db_cls.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() def close(self): self._vnc_kombu.shutdown()
class VncAmqpHandle(object): def __init__(self, logger, db_cls, reaction_map, q_name_prefix, args=None): self.logger = logger self.db_cls = db_cls self.reaction_map = reaction_map self.q_name_prefix = q_name_prefix self._db_resync_done = gevent.event.Event() self._args = args def establish(self): q_name = '.'.join([self.q_name_prefix, socket.gethostname()]) self._vnc_kombu = VncKombuClient( self._args.rabbit_server, self._args.rabbit_port, self._args.rabbit_user, self._args.rabbit_password, self._args.rabbit_vhost, self._args.rabbit_ha_mode, q_name, self._vnc_subscribe_callback, self.logger.log, rabbit_use_ssl=self._args.rabbit_use_ssl, kombu_ssl_version=self._args.kombu_ssl_version, kombu_ssl_keyfile=self._args.kombu_ssl_keyfile, kombu_ssl_certfile=self._args.kombu_ssl_certfile, kombu_ssl_ca_certs=self._args.kombu_ssl_ca_certs) def msgbus_store_err_msg(self, msg): self.msg_tracer.error = msg def msgbus_trace_msg(self): self.msg_tracer.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self.logger._sandesh) def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() try: self.oper_info = oper_info self.vnc_subscribe_actions() except Exception: string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") self.logger.error(string_buf.getvalue()) self.msgbus_store_err_msg(string_buf.getvalue()) try: with open(self._args.trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: pass finally: try: self.msgbus_trace_msg() except Exception: pass del self.oper_info del self.obj_type del self.obj_class del self.obj del self.dependency_tracker def create_msgbus_trace(self, request_id, oper, uuid): self.msg_tracer = MessageBusNotifyTrace(request_id=request_id, operation=oper, uuid=uuid) def vnc_subscribe_actions(self): msg = "Notification Message: %s" % (pformat(self.oper_info)) self.logger.debug(msg) self.obj = None self.dependency_tracker = None self.obj_type = self.oper_info['type'].replace('-', '_') self.obj_class = self.db_cls.get_obj_type_map().get(self.obj_type) if self.obj_class is None: return oper = self.oper_info['oper'] obj_id = self.oper_info['uuid'] self.create_msgbus_trace(self.oper_info.get('request_id'), oper, obj_id) if oper == 'CREATE': self.handle_create() elif oper == 'UPDATE': self.handle_update() elif oper == 'DELETE': self.handle_delete() else: self.handle_unknown() return if self.obj is None: self.logger.error('Error while accessing %s uuid %s' % ( self.obj_type, obj_id)) return self.evaluate_dependency() def handle_create(self): obj_dict = self.oper_info['obj_dict'] obj_key = self.db_cls.get_key_from_dict(obj_dict) obj_id = self.oper_info['uuid'] obj_fq_name = obj_dict['fq_name'] self.db_cls._object_db.cache_uuid_to_fq_name_add( obj_id, obj_fq_name, self.obj_type) self.obj = self.obj_class.locate(obj_key) if self.obj is None: self.logger.info('%s id %s fq_name %s not found' % ( self.obj_type, obj_id, obj_fq_name)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) def handle_update(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) old_dt = None if self.obj is not None: old_dt = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) old_dt.evaluate(self.obj_type, self.obj) else: self.logger.info('%s id %s not found' % (self.obj_type, obj_id)) return try: self.obj.update() except NoIdError: obj_id = self.oper_info['uuid'] self.logger.warning('%s uuid %s update caused NoIdError' % (self.obj_type, obj_id)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in self.dependency_tracker.resources: self.dependency_tracker.resources[resource] = ids else: self.dependency_tracker.resources[resource] = list( set(self.dependency_tracker.resources[resource]) | set(ids)) def handle_delete(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) self.db_cls._object_db.cache_uuid_to_fq_name_del(obj_id) if self.obj is None: return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) obj_key = self.db_cls.get_key_from_dict(self.oper_info['obj_dict']) self.obj_class.delete(obj_key) def handle_unknown(self): # unknown operation self.logger.error('Unknown operation %s' % self.oper_info['oper']) def init_msgbus_fq_name(self): self.msg_tracer.fq_name = self.obj.name def init_msgbus_dtr(self): self.msg_tracer.dependency_tracker_resources = [] def add_msgbus_dtr(self, res_type, res_id_list): dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) self.msg_tracer.dependency_tracker_resources.append(dtr) def evaluate_dependency(self): if not self.dependency_tracker: return self.init_msgbus_fq_name() self.init_msgbus_dtr() for res_type, res_id_list in self.dependency_tracker.resources.items(): if not res_id_list: continue self.add_msgbus_dtr(res_type, res_id_list) cls = self.db_cls.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() def close(self): self._vnc_kombu.shutdown()
class VncAmqpHandle(object): def __init__(self, sandesh, logger, db_cls, reaction_map, q_name_prefix, rabbitmq_cfg, host_ip, trace_file=None, timer_obj=None, register_handler=True): self.sandesh = sandesh self.logger = logger self.db_cls = db_cls self.reaction_map = reaction_map self.q_name_prefix = q_name_prefix self._db_resync_done = gevent.event.Event() self._rabbitmq_cfg = rabbitmq_cfg self._trace_file = trace_file self.timer = timer_obj self.host_ip = host_ip self.register_handler = register_handler self._vnc_kombu = None def establish(self): q_name = '.'.join([self.q_name_prefix, socket.getfqdn(self.host_ip)]) self._vnc_kombu = VncKombuClient( self._rabbitmq_cfg['servers'], self._rabbitmq_cfg['port'], self._rabbitmq_cfg['user'], self._rabbitmq_cfg['password'], self._rabbitmq_cfg['vhost'], self._rabbitmq_cfg['ha_mode'], q_name, self._vnc_subscribe_callback, self.logger.log, rabbit_use_ssl=self._rabbitmq_cfg['use_ssl'], kombu_ssl_version=self._rabbitmq_cfg['ssl_version'], kombu_ssl_keyfile=self._rabbitmq_cfg['ssl_keyfile'], kombu_ssl_certfile=self._rabbitmq_cfg['ssl_certfile'], kombu_ssl_ca_certs=self._rabbitmq_cfg['ssl_ca_certs'], register_handler=self.register_handler) def msgbus_store_err_msg(self, msg): self.msg_tracer.error = msg def msgbus_trace_msg(self): self.msg_tracer.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self.sandesh) def log_exception(self): string_buf = StringIO() cgitb_hook(file=string_buf, format="text") self.logger.error(string_buf.getvalue()) self.msgbus_store_err_msg(string_buf.getvalue()) if not self._trace_file: return try: with open(self._trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: pass def log_ignored_errors(self, obj_class): if not self._trace_file: return try: with open(self._trace_file, 'a') as err_file: for err_msg, tb in obj_class._ignored_errors.items(): err_file.write("\nIGNORING: %s\n%s" % (err_msg, tb)) except IOError: pass finally: obj_class.clear_ignored_errors() def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() try: self.oper_info = oper_info self.vnc_subscribe_actions() except ConnectionError: try: # retry write during api-server ConnectionError self.vnc_subscribe_actions() except ConnectionError: # log the exception, and exit during api-server # ConnectionError on retry to let standby to become active. self.log_exception() self.logger.error("Api-server connection lost. Exiting") self.close() raise SystemExit except Exception: self.log_exception() except Exception: self.log_exception() finally: try: self.msgbus_trace_msg() except Exception: pass del self.oper_info del self.obj_type del self.obj_class del self.obj del self.dependency_tracker def create_msgbus_trace(self, request_id, oper, uuid): self.msg_tracer = MessageBusNotifyTrace(request_id=request_id, operation=oper, uuid=uuid) def vnc_subscribe_actions(self): msg = "Notification Message: %s" % (pformat(self.oper_info)) self.logger.debug(msg) self.obj = None self.dependency_tracker = None self.obj_type = self.oper_info['type'].replace('-', '_') self.obj_class = self.db_cls.get_obj_type_map().get(self.obj_type) if self.obj_class is None: return oper = self.oper_info['oper'] obj_id = self.oper_info['uuid'] self.create_msgbus_trace(self.oper_info.get('request_id'), oper, obj_id) if oper == 'CREATE': self.handle_create() elif oper == 'UPDATE': self.handle_update() elif oper == 'DELETE': self.handle_delete() elif oper == 'UPDATE-IMPLICIT': # Ignore this operation return else: self.handle_unknown() return if self.obj is None: self.logger.warning( "Object %s uuid %s was not found for operation %s" % (self.obj_type, obj_id, oper)) return self.evaluate_dependency() def _get_key_from_oper_info(self): if self.db_cls._indexed_by_name: return ':'.join(self.oper_info['fq_name']) return self.oper_info['uuid'] def _set_meta(self): self.db_cls.set_meta({ 'request_id': self.oper_info.get('request-id'), 'oper': self.oper_info.get('oper') }) def handle_create(self): obj_key = self._get_key_from_oper_info() obj_id = self.oper_info['uuid'] obj_fq_name = self.oper_info['fq_name'] self.db_cls._object_db.cache_uuid_to_fq_name_add( obj_id, obj_fq_name, self.obj_type) self._set_meta() try: self.obj = self.obj_class.locate(obj_key) finally: self.log_ignored_errors(self.obj_class) if self.obj is None: self.logger.info('%s id %s fq_name %s not found' % (self.obj_type, obj_id, obj_fq_name)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) def handle_update(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) old_dt = None if self.obj is not None: old_dt = DependencyTracker(self.db_cls.get_obj_type_map(), self.reaction_map) old_dt.evaluate(self.obj_type, self.obj) else: self.logger.info('%s id %s not found' % (self.obj_type, obj_id)) return try: self._set_meta() ret = self.obj.update() if ret is not None and not ret: # If update returns None, the function may not support a # return value, hence treat it as if something might have # changed. If a value is returned, use its truth value. # If it True, then some change was detected. # If no change, then terminate dependency tracker return except NoIdError: obj_id = self.oper_info['uuid'] self.logger.warning('%s uuid %s update caused NoIdError' % (self.obj_type, obj_id)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) if old_dt: for resource, ids in list(old_dt.resources.items()): if resource not in self.dependency_tracker.resources: self.dependency_tracker.resources[resource] = ids else: self.dependency_tracker.resources[resource] = list( set(self.dependency_tracker.resources[resource]) | set(ids)) def handle_delete(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) self.db_cls._object_db.cache_uuid_to_fq_name_del(obj_id) if self.obj is None: return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) obj_key = self._get_key_from_oper_info() self._set_meta() self.obj_class.delete(obj_key) def handle_unknown(self): # unknown operation self.logger.error('Unknown operation %s' % self.oper_info['oper']) def init_msgbus_fq_name(self): self.msg_tracer.fq_name = self.obj.name def init_msgbus_dtr(self): self.msg_tracer.dependency_tracker_resources = [] def add_msgbus_dtr(self, res_type, res_id_list): dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) self.msg_tracer.dependency_tracker_resources.append(dtr) def evaluate_dependency(self): if not self.dependency_tracker: return self.init_msgbus_fq_name() self.init_msgbus_dtr() evaluate_kwargs = {} if self.timer and self.timer.yield_in_evaluate: evaluate_kwargs['timer'] = self.timer for res_type, res_id_list in list( self.dependency_tracker.resources.items()): if not res_id_list: continue self.add_msgbus_dtr(res_type, res_id_list) cls = self.db_cls.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: try: if evaluate_kwargs: res_obj.evaluate(**evaluate_kwargs) else: res_obj.evaluate() finally: self.log_ignored_errors(res_obj) if self.timer: self.timer.timed_yield() def close(self): if self._vnc_kombu is not None: # VncKombuClient is instancied when calling 'establish()', # if for some reasons (mostly related to cleanup after # exception handling) we call `close()` we should consider # a no-op. self._vnc_kombu.shutdown()
class VncAmqpHandle(object): def __init__(self, sandesh, logger, db_cls, reaction_map, q_name_prefix, rabbitmq_cfg, trace_file=None): self.sandesh = sandesh self.logger = logger self.db_cls = db_cls self.reaction_map = reaction_map self.q_name_prefix = q_name_prefix self._db_resync_done = gevent.event.Event() self._rabbitmq_cfg = rabbitmq_cfg self._trace_file = trace_file def establish(self): q_name = '.'.join([self.q_name_prefix, socket.gethostname()]) self._vnc_kombu = VncKombuClient( self._rabbitmq_cfg['servers'], self._rabbitmq_cfg['port'], self._rabbitmq_cfg['user'], self._rabbitmq_cfg['password'], self._rabbitmq_cfg['vhost'], self._rabbitmq_cfg['ha_mode'], q_name, self._vnc_subscribe_callback, self.logger.log, rabbit_use_ssl=self._rabbitmq_cfg['use_ssl'], kombu_ssl_version=self._rabbitmq_cfg['ssl_version'], kombu_ssl_keyfile=self._rabbitmq_cfg['ssl_keyfile'], kombu_ssl_certfile=self._rabbitmq_cfg['ssl_certfile'], kombu_ssl_ca_certs=self._rabbitmq_cfg['ssl_ca_certs']) def msgbus_store_err_msg(self, msg): self.msg_tracer.error = msg def msgbus_trace_msg(self): self.msg_tracer.trace_msg(name='MessageBusNotifyTraceBuf', sandesh=self.sandesh) def log_exception(self): string_buf = cStringIO.StringIO() cgitb_hook(file=string_buf, format="text") self.logger.error(string_buf.getvalue()) self.msgbus_store_err_msg(string_buf.getvalue()) if not self._trace_file: return try: with open(self._trace_file, 'a') as err_file: err_file.write(string_buf.getvalue()) except IOError: pass def _vnc_subscribe_callback(self, oper_info): self._db_resync_done.wait() try: self.oper_info = oper_info self.vnc_subscribe_actions() except ConnectionError: try: # retry write during api-server ConnectionError self.vnc_subscribe_actions() except ConnectionError: # log the exception, and exit during api-server # ConnectionError on retry to let standby to become active. self.log_exception() self.logger.error("Api-server connection lost. Exiting") self.close() raise SystemExit except Exception: self.log_exception() except Exception: self.log_exception() finally: try: self.msgbus_trace_msg() except Exception: pass del self.oper_info del self.obj_type del self.obj_class del self.obj del self.dependency_tracker def create_msgbus_trace(self, request_id, oper, uuid): self.msg_tracer = MessageBusNotifyTrace(request_id=request_id, operation=oper, uuid=uuid) def vnc_subscribe_actions(self): msg = "Notification Message: %s" % (pformat(self.oper_info)) self.logger.debug(msg) self.obj = None self.dependency_tracker = None self.obj_type = self.oper_info['type'].replace('-', '_') self.obj_class = self.db_cls.get_obj_type_map().get(self.obj_type) if self.obj_class is None: return oper = self.oper_info['oper'] obj_id = self.oper_info['uuid'] self.create_msgbus_trace(self.oper_info.get('request_id'), oper, obj_id) if oper == 'CREATE': self.handle_create() elif oper == 'UPDATE': self.handle_update() elif oper == 'DELETE': self.handle_delete() elif oper == 'UPDATE-IMPLICIT': # Ignore this operation return else: self.handle_unknown() return if self.obj is None: self.logger.warning( "Object %s uuid %s was not found for operation %s" % (self. obj_type, obj_id, oper)) return self.evaluate_dependency() def _get_key_from_oper_info(self): if self.db_cls._indexed_by_name: return ':'.join(self.oper_info['fq_name']) return self.oper_info['uuid'] def handle_create(self): obj_key = self._get_key_from_oper_info() obj_id = self.oper_info['uuid'] obj_fq_name = self.oper_info['fq_name'] self.db_cls._object_db.cache_uuid_to_fq_name_add( obj_id, obj_fq_name, self.obj_type) self.obj = self.obj_class.locate(obj_key) if self.obj is None: self.logger.info('%s id %s fq_name %s not found' % ( self.obj_type, obj_id, obj_fq_name)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) def handle_update(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) old_dt = None if self.obj is not None: old_dt = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) old_dt.evaluate(self.obj_type, self.obj) else: self.logger.info('%s id %s not found' % (self.obj_type, obj_id)) return try: ret = self.obj.update() if ret is not None and not ret: # If update returns None, the function may not support a # return value, hence treat it as if something might have # changed. If a value is returned, use its truth value. # If it True, then some change was detected. # If no change, then terminate dependency tracker return except NoIdError: obj_id = self.oper_info['uuid'] self.logger.warning('%s uuid %s update caused NoIdError' % (self.obj_type, obj_id)) return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) if old_dt: for resource, ids in old_dt.resources.items(): if resource not in self.dependency_tracker.resources: self.dependency_tracker.resources[resource] = ids else: self.dependency_tracker.resources[resource] = list( set(self.dependency_tracker.resources[resource]) | set(ids)) def handle_delete(self): obj_id = self.oper_info['uuid'] self.obj = self.obj_class.get_by_uuid(obj_id) self.db_cls._object_db.cache_uuid_to_fq_name_del(obj_id) if self.obj is None: return self.dependency_tracker = DependencyTracker( self.db_cls.get_obj_type_map(), self.reaction_map) self.dependency_tracker.evaluate(self.obj_type, self.obj) obj_key = self._get_key_from_oper_info() self.obj_class.delete(obj_key) def handle_unknown(self): # unknown operation self.logger.error('Unknown operation %s' % self.oper_info['oper']) def init_msgbus_fq_name(self): self.msg_tracer.fq_name = self.obj.name def init_msgbus_dtr(self): self.msg_tracer.dependency_tracker_resources = [] def add_msgbus_dtr(self, res_type, res_id_list): dtr = DependencyTrackerResource(obj_type=res_type, obj_keys=res_id_list) self.msg_tracer.dependency_tracker_resources.append(dtr) def evaluate_dependency(self): if not self.dependency_tracker: return self.init_msgbus_fq_name() self.init_msgbus_dtr() for res_type, res_id_list in self.dependency_tracker.resources.items(): if not res_id_list: continue self.add_msgbus_dtr(res_type, res_id_list) cls = self.db_cls.get_obj_type_map().get(res_type) if cls is None: continue for res_id in res_id_list: res_obj = cls.get(res_id) if res_obj is not None: res_obj.evaluate() def close(self): self._vnc_kombu.shutdown()