def on_message_cb(self, client, obj, msg): """ This method will invoke the specified callback handler by the client app when a notification is received by the app based on the notification type. @param client: the client instance for this callback @param obj: the private user data as set in Client() or userdata_set() @param msg: an instance of Message. This is a class with members topic, payload, qos, retain """ payload = msg.payload topic = msg.topic json_data = None json_data, end = decoder.raw_decode(payload) if json_data is None: LOG.info('Received event has invalid JSON format') LOG.info('Received payload: %s' % payload) if len(payload) != end: LOG.info('Received event has additional invalid JSON format') LOG.info('It has the following additional content: %s' % payload[end:]) callback_called = False for cbs in self.handlers: if cbs != '#': if mqtt.topic_matches_sub(cbs, topic): for cb in self.handlers.get(cbs, []): cb(json_data) callback_called = True if callback_called == False: for cb in self.handlers.get('#', []): LOG.info('Sending data to callback %s' % cb) cb(json_data)
def on_stream_message_cb(self, client, obj, msg): """ This callback function will be used for Thrift streaming messages and won't be encoded in JSON Format but the thrift wire format. The read method corresponding to this data structure needs to be used to decode the data @param client: the client instance for this callback @param obj: the private user data as set in Client() or userdata_set() @param msg: an instance of Message. This is a class with members topic, payload, qos, retain """ payload = msg.payload topic = msg.topic callback_called = False for cbs in self.handlers: if cbs != '#': if mqtt.topic_matches_sub(cbs, topic): for cb in self.handlers.get(cbs, []): cb(payload) callback_called = True if callback_called == False: for cb in self.handlers.get('#', []): LOG.info('Sending data to callback %s' % cb) cb(payload)
def myget(dictitem,key): for keys in dictitem.keys(): if keys.split(':')[-1] == key: value = dictitem.get(keys) return value LOG.info('Key %s not present' % str(key)) return None
def cfgAction(self, instance_id=None, restart_action=True): # Find the specific snabb instance or all depending on instance_id argument # Kill the relevant instances signal_sent = False if instance_id is not None and restart_action is False: cfg_file_name = SNABB_FILENAME + str(instance_id) + '.cfg' conf_file_name = SNABB_FILENAME + str(instance_id) + '.conf' try: os.remove(cfg_file_name) os.remove(conf_file_name) except OSError: pass LOG.info( "Removed the file %s and %s as the instance %d was deleted" % (cfg_file_name, conf_file_name, int(instance_id))) p = subprocess.Popen(['ps', '-axw'], stdout=subprocess.PIPE) out, err = p.communicate() if instance_id is not None: snabb_search_string = SNABB_PROCESS_SEARCH_STRING + \ str(instance_id) else: snabb_search_string = SNABB_PROCESS_SEARCH_STRING for lines in out.splitlines(): if snabb_search_string in lines: pid = int(lines.split(None, 1)[0]) os.kill(pid, signal.SIGTERM) LOG.info("Successfully sent SIGTERM to the snabb instance %s" % str(lines.split(None, 1)[1])) signal_sent = True return signal_sent
def __call__(self): LOG.info("Entered ParseNotification") global dispQ while True: # process the notification message config_dict = dispQ.get() dispQ.task_done() LOG.info("dequeued %s" % str(config_dict)) self.parse_snabb_config(config_dict)
def close_notification_session(self): """ This method closes the JET Notification channel. """ self.notifier.Close() LOG.info('JET notification channel closed by user.') pass
def create_config_update_topic(self): """ This method creates a topic to subscribe config-update events. @return: Returns the config-update topic object """ data = {} data['subscribed'] = 0 data['topic'] = '%s/%s' % (GENPUB_TOPIC_HEADER, CONFIG_UPDATE) self.topics_subscribed.append(data['topic']) LOG.info('Successfully appended the topic %s' % data['topic']) return type('Topic', (), data)
def get_binding_file(self, remote_filename, local_filename): try: localfd = open(local_filename, 'w+') ftp = FTP(self._dev._host) ftp.login(user=self._dev._auth_user, passwd=self._dev._auth_pwd) LOG.info("FTP get the file %s" % remote_filename) ftp.retrbinary('RETR %s' % remote_filename, localfd.write) except Exception as e: LOG.critical( 'Failed to connect to the device: exception: %s' % e.message) return False LOG.info('Successfully copied the file %s' % remote_filename) return True
def __init__(self, device=DEFAULT_USER_NAME, port=DEFAULT_NOTIFICATION_PORT, user=None, password=None, tls=None, keepalive=DEFAULT_MQTT_TIMEOUT, bind_address="", is_stream=False): """ Create a request response session with the JET server. Raises exception in case of invalid arguments or when JET notification server is not accessible. @param device: JET Server IP address. Default is localhost @param port: JET Notification port number. Default is 1883 @param user: Username on the JET server, used for authentication and authorization. @param password: Password to access the JET server, used for authentication and authorization. @param keepalive: Maximum period in seconds between communications with the broker. Default is 60. @param bind_address: Client source address to bind. Can be used to control access at broker side. @return: JET Notification object. """ try: self.notifier = NotifierMqtt() LOG.info('Connecting to JET notification server') self.notifier.mqtt_client.connect(device, port, keepalive, bind_address) self.notifier.mqtt_client.loop_start() self.notifier.handlers = collections.defaultdict(set) if is_stream == True: self.notifier.mqtt_client.on_message = self.notifier.on_stream_message_cb else: self.notifier.mqtt_client.on_message = self.notifier.on_message_cb except struct.error as err: message = err.message err.message = 'Invalid argument value passed in %s at line no. %s\nError: %s' \ % (traceback.extract_stack()[0][0], traceback.extract_stack()[0][1], message) LOG.error('%s' % (err.message)) raise err except Exception, tx: tx.message = 'Could not connect to the JET notification server' LOG.error('%s' % (tx.message)) raise Exception(tx.message)
def write_file(self, filename, templatename, dictitems): PATH = os.path.dirname(os.path.abspath(__file__)) TEMPLATE_ENVIRONMENT = Environment( autoescape=True, loader=FileSystemLoader(os.path.join(PATH, 'template')), trim_blocks=True, lstrip_blocks=False) try: with open(filename, 'w') as f: btext = TEMPLATE_ENVIRONMENT.get_template( templatename).render(context=dictitems) f.write(btext) LOG.info("Successfully written %s" % str(filename)) return True except Exception as e: LOG.critical("Failed to write the file %s, exception: %s" % (str(filename), e.message)) return False
def Subscribe(self, subscriptionType, handler=None, qos=0): """ This method subscribes to a specific topic the client app is interested in. This takes subscription type and the callback function as parameters. When the notification for the subscribed topic is received, user passed callback function will be called. Callback function receives the notification message in json format. @param subscriptionType : Type of notification user wants to subscribe to @param handler: Callback function for each notification """ topic = subscriptionType.topic self.mqtt_client.subscribe(topic, qos) subscriptionType.subscribed = 1 if(handler): self.handlers[topic].add(handler) LOG.info('Successfully subscribed to event:%s' % subscriptionType.topic)
def deleteAction(self): # Delete the cfg files snabb_search_string = SNABB_PROCESS_SEARCH_STRING for f in os.listdir('/tmp'): if snabb_search_string in f: LOG.info('Deleting the file %s' % str(f)) try: os.remove(os.path.join('/tmp/', f)) except OSError: pass signal_sent = False p = subprocess.Popen(['ps', '-axw'], stdout=subprocess.PIPE) out, err = p.communicate() for lines in out.splitlines(): if snabb_search_string in lines: pid = int(lines.split(None, 1)[0]) os.kill(pid, signal.SIGTERM) LOG.info("Successfully sent SIGTERM to the snabb instance %s" % str(lines.split(None, 1)[1])) signal_sent = True return signal_sent
def Unsubscribe(self, subscriptionType=None): """ This method takes the topic as argument and unsubscribes to the given topic. If topic name is not given as argument (no arguments), this method unsubscribes to all the topics which app already subscribed for. @param subscriptionType: Notification type that user wants to unsubscribe from. @return 0 on successful unsubscription and -1 on failure """ if subscriptionType is None: self.mqtt_client.unsubscribe(self.topics_subscribed) self.handlers = collections.defaultdict(set) LOG.info('Successfully unsubscribed from all notifications') return 0 elif not isinstance(subscriptionType, type): message = 'Invalid subscription topic: ' + subscriptionType LOG.info(message) raise Exception(message) else: for item in self.topics_subscribed: if (item == subscriptionType.topic and subscriptionType.subscribed == 1): self.mqtt_client.unsubscribe(subscriptionType.topic) self.mqtt_client.unsubscribe(subscriptionType.topic) self.handlers.pop(str(subscriptionType.topic), None) LOG.info('Successfully unsubscribed %s' % subscriptionType.topic) return 0 # Failed case LOG.error('You have not subscribed to %s. Failed to unsubscribe' % subscriptionType.topic) return -1
def start_snabb_instance(self, instance_id): s = SNABB_INSTANCE_LAUNCH_TEMPLATE config_file_name = SNABB_FILENAME + str(instance_id) + '.cfg' pci_path = SNABB_PCI_PATH + str(instance_id) mac_path = SNABB_MAC_PATH + str(instance_id) # Read the files mac_id = '' pci_id = '' try: with open(pci_path) as f: pci_id = f.read().strip().split('/')[0] except Exception as e: LOG.info('Failed to read the file %s due to exception: %s' % (pci_path, e.message)) return False try: with open(mac_path) as f: mac_id = f.read().strip() except Exception as e: LOG.info('Failed to read the file %s due to exception: %s' % (mac_path, e.message)) return False cmd = s.substitute(cfg=config_file_name, id=instance_id, pci=pci_id, mac=mac_id) # TODO launch the process if required output = 0 try: pid = subprocess.Popen(["sudo", cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT).pid LOG.info('Tried to restart the snabb instance id %s, returned %s' % (str(instance_id), str(pid))) except Exception as e: LOG.info("Failed to start the snabb instance, exception %s" % e.message) return output
def bindAction(self, binding_file): # Compile the binding file signal_sent = False # Find the snabb instances and send sighup to all the instances p = subprocess.Popen(['ps', '-axw'], stdout=subprocess.PIPE) out, err = p.communicate() snabb_search_string = SNABB_PROCESS_SEARCH_STRING for lines in out.splitlines(): if snabb_search_string in lines: pid = int(lines.split(None, 1)[0]) cmd = r"/usr/local/bin/snabb lwaftr control " + str( pid) + " reload" try: output = subprocess.check_output(cmd, shell=True) LOG.info('Sent SIGHUP to instance %d' % pid) except Exception as e: LOG.info("Failed to send SIGHUP to instance %d" % pid) signal_sent = True LOG.info("Successfully sent SIGHUP to the snabb instance") break return signal_sent
def parse_for_binding(self, config_dict): br_addresses = OrderedDict() br_address_idx = -1 softwires = [] addresses = {} remote_binding_table_filename = self.myget(config_dict['binding']['br'],'binding-table-file') # This section will take care of the binding files and binding table entries # Fetch this binding file from the device if remote_binding_table_filename is not None: # New binding table is provided by the user new_binding_file = r'/tmp/snabbvmx.binding.new' # touch the new file open(new_binding_file, 'w+').close() if self.get_binding_file(remote_binding_table_filename, new_binding_file): # Copy the remote file to new_binding_file and create the softwires, psid and br_address tables # Then add to these tables the new entries from the configuration # At the end compare the new binding file with the old one to see if binding entries have changed with open(new_binding_file, 'r') as f: # Walk over the file to create the binding entries regex_br_address = r"softwires_([\w:]+)" regex_br_entries = r"([\w:]+)+\s+(\d+.\d+.\d+.\d+),(\d+),(\d+),(\d+)" for lines in f.readlines(): if re.search(regex_br_address, lines): match = re.search(regex_br_address, lines) br_addresses[match.group(0).split( '_')[1]] = br_address_idx + 1 br_address_idx += 1 elif re.search(regex_br_entries, lines): match = re.search(regex_br_entries, lines) shift = 16 - int(match.group(4)) - \ int(match.group(5)) softwires.append('{ ipv4=%s, psid=%s, b4=%s, aftr=%s }' % (match.group(2),match.group(3), match.group(1),br_address_idx)) if shift > 0: addresses[str(match.group(2))] = "{psid_length=%s, shift=%d}" % (match.group(4), shift) else: addresses[ str(match.group(2))] = "{psid_length=%s}" % match.group(4) else: LOG.info("Ignoring this line: %s" % lines) os.remove(new_binding_file) else: LOG.critical( 'Failed to copy remote binding file onto the local disk') else: LOG.info("No binding table info found in the config") # Now parse the snabb config to see if there is any binding table entry new_instance_list = config_dict['binding']['br']['br-instances']['br-instance'] for instances in new_instance_list: bt = self.myget(instances,'binding-table') if bt is not None: bte = self.myget(bt,'binding-entry') if bte is not None: for items in bte: binding_ipv6_info = self.myget(items,"binding-ipv6info") ipv4 = self.myget(items,"binding-ipv4-addr") b4_address = self.myget(items,"br-ipv6-addr") portset = self.myget(items,'port-set') psid = self.myget(portset,"psid") psid_len = self.myget(portset,"psid-len") offset = self.myget(portset,"psid-offset") shift = 16-psid_len-offset if binding_ipv6_info is not None and ipv4 is not None and b4_address is not None: if shift > 0: addresses[ipv4] = "{psid_length=%s, shift=%d}" % (psid_len, shift) else: addresses[ipv4] = "{psid_length=%s}" %psid_len if b4_address in br_addresses.keys(): aftr = br_addresses[b4_address] else: aftr = len(br_addresses) br_addresses[b4_address] = aftr softwires.append('{ ipv4=%s, psid=%s, b4=%s, aftr=%s }' % ( ipv4,psid,binding_ipv6_info,aftr)) else: LOG.info("Incomplete binding table entry in the configuration %s" %str(items)) else: LOG.info("Empty binding table entry in the configuration") else: LOG.info("No binding table configuration present") # Write it into a file with open(SNABB_BINDING_FILENAME_TMP, 'w+') as nf: nf.write('psid_map {\n') for items in sorted(addresses.iterkeys()): nf.write("\t" + items + " " + addresses[items] + '\n') nf.write("}\nbr_addresses {\n") for items in br_addresses.keys(): nf.write("\t" + items + ",\n") nf.write("}\nsoftwires {\n") for items in softwires: nf.write("\t" + items + "\n") nf.write("}") # Determine if this binding file is different from existing # file if self.old_binding_filename is None: self.old_binding_filename = SNABB_BINDING_FILENAME os.rename(SNABB_BINDING_FILENAME_TMP, self.old_binding_filename) self.binding_changed = True LOG.info("Old binding file not present, so creating a new binding file") elif not filecmp.cmp(self.old_binding_filename, SNABB_BINDING_FILENAME_TMP): os.rename(SNABB_BINDING_FILENAME_TMP, self.old_binding_filename) self.binding_changed = True LOG.info("Binding Table has changed") else: LOG.info("Binding Table has not changed") if (self.binding_changed): cmd = r"/usr/local/bin/snabb lwaftr compile-binding-table " + \ str(self.old_binding_filename) try: output = subprocess.check_output(cmd, shell=True) LOG.info("Compiled the binding file, returned %s" % str(output)) except Exception as e: LOG.critical("Failed to compile the binding file returned %s" % str(e.message)) self.binding_changed = False return
def parse_snabb_config(self, config_dict): if config_dict.get('purge', None) is not None: # Call the confAction to kill all the Snabb applications after # deleting the cfg/conf/binding files self.old_cfg = [] self.old_conf = [] self.old_binding_filename = None self.instances = {} LOG.info("Purging the snabb configuration files and terminating instances") ca = ConfAction() ca.deleteAction() return LOG.info("entered parse_snabb_config") # At first lets clear the present flag in all the instances for keys in self.instances: self.instances[keys] = 0 # Action handler to commit actions for conf/cfg/binding changes action_handler = ConfAction() # First the binding entry changes self.binding_changed = self.parse_for_binding(config_dict) # description is same for all the instances in the YANG schema cfg_dict = {} conf_dict = {} # Parse the config and cfg changes descr = self.myget(config_dict,'description') new_instance_list = config_dict['binding']['br']['br-instances']['br-instance'] for instances in new_instance_list: # TODO try except loop has to be implemented instance_id = self.myget(instances,'id') # Verify that the old config contains this instance, if not then we # need to delete this instance self.instances[instance_id] = 1 cfg_dict['id'] = instance_id cfg_dict['cnf_file_name'] = SNABB_FILENAME + str(instance_id) + '.conf' cfg_dict['ipv4_address'] = self.myget(instances,'ipv4_address') cfg_dict['ipv4_desc'] = descr cfg_dict['ipv4_cache_rate'] = self.myget(instances,'cache_refresh_interval') cfg_dict['ipv4_ingress_filter'] = self.myget(instances, 'ipv4_ingress_filter') cfg_dict['ipv4_egress_filter'] = self.myget(instances, 'ipv4_egress_filter') cfg_dict['fragmentation'] = self.myget(instances, 'fragmentation') cfg_dict['ipv6_address'] = self.myget(instances,'ipv6_address') cfg_dict['ipv6_desc'] = descr cfg_dict['ipv6_cache_rate'] = self.myget(instances,'cache_refresh_interval') cfg_dict['ipv6_ingress_filter'] = self.myget(instances, 'ipv6_ingress_filter') cfg_dict['ipv6_egress_filter'] = self.myget(instances, 'ipv6_egress_filter') cfg_dict['fragmentation'] = self.myget(instances, 'fragmentation') cfg_dict['ingress_drop_interval'] = self.myget(instances,'ingress_drop_interval') cfg_dict['ingress_drop_monitor'] = self.myget(instances,'ingress_drop_monitor') cfg_dict['ingress_drop_threshold'] = self.myget(instances, 'ingress_drop_threshold') cfg_dict['ingress_drop_wait'] = self.myget(instances,'ingress_drop_wait') cfg_dict['ring_buffer_size'] = None # Parse the conf file attributes conf_dict['id'] = instance_id if self.old_binding_filename is not None: conf_dict['binding_table'] = str(self.old_binding_filename) else: conf_dict['binding_table'] = None mac_path = SNABB_MAC_PATH + str(instance_id) # Read the files mac_id = "00:00:00:00:00:00" try: with open(mac_path) as f: mac_id = f.read().strip() except Exception as e: LOG.info('Failed to read the file %s due to exception: %s' % (mac_path, e.message)) conf_dict['v4_vlan_tag'] = self.myget(instances,'v4_vlan_tag') conf_dict['v6_vlan_tag'] = self.myget(instances, 'v6_vlan_tag') if self.myget(instances,'v4_vlan_tag') is not None or self.myget(instances, 'v6_vlan_tag') is not None: conf_dict['vlan_tagging'] = 'true' else: conf_dict['vlan_tagging'] = 'false' conf_dict['policy_icmpv4_incoming'] = self.myget(instances, 'policy_icmpv4_incoming') conf_dict['policy_icmpv4_outgoing'] = self.myget(instances, 'policy_icmpv4_outgoing') conf_dict['policy_icmpv6_incoming'] = self.myget(instances,'policy_icmpv6_incoming') conf_dict['policy_icmpv6_outgoing'] = self.myget(instances, 'policy_icmpv6_outgoing') conf_dict['max_fragments_per_reassembly_packet'] = self.myget(instances, 'max_fragments_per_reassembly_packet') conf_dict['max_ipv4_reassembly_packets'] = self.myget(instances, 'max_ipv4_reassembly_packets') conf_dict['max_ipv6_reassembly_packets'] = self.myget(instances, 'max_ipv6_reassembly_packets') conf_dict['icmpv6_rate_limiter_n_packets'] = self.myget(instances, 'icmpv6_rate_limiter_n_packets') conf_dict['icmpv6_rate_limiter_n_seconds'] = self.myget(instances, 'icmpv6_rate_limiter_n_seconds') conf_dict['ipv4_address'] = self.myget(instances, 'ipv4_address') conf_dict['ipv6_mtu'] = self.myget(instances,"tunnel-path-mru") conf_dict['ipv4_mtu'] = self.myget(instances,"tunnel-payload-mtu") conf_dict['hairpinning'] = self.myget(instances,"hairpinning") #TODO Why are the following values hardcoded conf_dict['ipv6_address'] = '2001:db8::1' conf_dict['inet_mac'] = '02:02:02:02:02:02' conf_dict['next_hop6_mac'] = '02:02:02:02:02:02' # TODO these parameters are not defined conf_dict['aftr_mac_inet_side'] = mac_id conf_dict['aftr_mac_b4_side'] = mac_id # Take action based on whether the cfg or conf files have changed # or not ret_cfg, ret_conf = False, False new_cfg_id_present = False new_conf_id_present = False cnt = 0 cfg_changed = False LOG.debug('New cfg dict = %s' % str(cfg_dict)) if self.old_cfg is None: ret_cfg = self.write_snabb_cfg_file(cfg_dict, instance_id) self.old_cfg.append(cfg_dict) if not ret_cfg: LOG.critical("Failed to write the cfg file") return else: # Add the new cfg to the old_cfg dictionary cnt = 0 for cfg_instance in self.old_cfg: if cfg_instance['id'] == cfg_dict['id']: # Check if the configuration has changed for this new instance if cmp(cfg_instance, cfg_dict) != 0: cfg_changed = True self.old_cfg[cnt] = cfg_dict new_cfg_id_present = True LOG.info("Cfg dictionary has changed") break else: new_cfg_id_present = True cfg_changed = False LOG.info("Cfg dictionary has not changed") break cnt += 1 # New cfg is not in the existing dict, add it if not new_cfg_id_present: self.old_cfg.append(cfg_dict) cfg_changed = True if (cfg_changed): ret_cfg = self.write_snabb_cfg_file(cfg_dict, instance_id) if not ret_cfg: LOG.critical("Failed to write the cfg file") return if self.old_conf is None: ret_conf = self.write_snabb_conf_file(conf_dict, instance_id) self.old_conf.append(conf_dict) if not ret_conf: LOG.critical("Failed to write the conf file") return else: cnt = 0 conf_changed = False new_conf_id_present = False for conf_instance in self.old_conf: if (conf_instance['id'] == conf_dict['id']): if cmp(conf_instance, conf_dict) != 0: conf_changed = True self.old_conf[cnt] = conf_dict new_conf_id_present = True LOG.info("Conf dictionary has changed") break else: new_conf_id_present = True conf_changed = False LOG.info("Conf dictionary has not changed") cnt = + 1 if not new_conf_id_present: self.old_conf.append(conf_dict) conf_changed = True if (conf_changed): ret_conf = self.write_snabb_conf_file( conf_dict, instance_id) if not ret_conf: LOG.critical("Failed to write the conf file") return if ret_conf or ret_cfg: # Assume that the instances list is populated here if not new_cfg_id_present and not new_conf_id_present: # It is a new instance, so start it LOG.info("New id added, starting new instance") ret = action_handler.start_snabb_instance(instance_id) else: LOG.info("The configuration changed, restarting the snabb instance id %s" %instance_id) ret = action_handler.cfgAction(instance_id) if not ret: LOG.critical("Failed to restart the Snabb instance") elif self.binding_changed: # Only the binding table has changed. # Send SIGHUP to the instances LOG.info("Only binding table has changed, sending SIGHUP") ret = action_handler.bindAction(self.old_binding_filename) if not ret: LOG.critical("Failed to reload the binding tables") self.binding_changed = False else: LOG.info("No config change hence did not restart Snabb instance %s id" %instance_id) # Few of the instances might have been deleted, we need to kill those # instances for keys in self.instances: if self.instances[keys] == 0: # Remove the old_cfg item which is for this id cnt = 0 for cfg_instance in self.old_cfg: if cfg_instance['id'] == keys: del self.old_cfg[cnt] break cnt += 1 cnt = 0 for conf_instance in self.old_conf: if conf_instance['id'] == keys: del self.old_conf[cnt] break cnt += 1 # Purge the files needed for this instance LOG.info( "Instance id %d is not present, need to kill it" % int(keys)) ret = action_handler.cfgAction(keys, False) if not ret: LOG.critical( "Failed to kill the Snabb instance %d" % int(keys)) return
def Main(): parser = argparse.ArgumentParser( prog=os.path.basename(__file__), description='Snabb VMX integration JET app') parser.add_argument("--host", help="Host address of the JSD server", type=str, default=DEFAULT_RPC_HOST) parser.add_argument( "--user", help="Username for authentication by JET server (default:%(default)s)", type=str, default=DEFAULT_USER_NAME) parser.add_argument( "--password", help="Password for authentication by JET server (default:%(default)s", type=str, default=DEFAULT_PASSWORD) parser.add_argument( "--rpc_port", nargs='?', help="Port number of the JSD gRPC server. default: %(default)s", type=int, default=DEFAULT_RPC_PORT) parser.add_argument( "--notification_port", nargs='?', help="Port number of the JSD notification server. default: %(default)s", type=int, default=DEFAULT_NOTIFICATION_PORT) parser.add_argument("--config", nargs='?', help="JSON config file", type=str, default=None) args = parser.parse_args() if args.config is not None: try: json_cfg = {} with open(args.config) as json_cfg_file: json_cfg = json.load(json_cfg_file) device = Device(json_cfg['host'], json_cfg['user'], json_cfg['password'], json_cfg['rpc_port'], json_cfg['notification_port']) except Exception as e: LOG.error("exception :%s" % str(e.message)) sys.exit(0) else: try: device = Device(args.host, args.user, args.password, args.rpc_port, args.notification_port) except Exception as e: LOG.error("Exception:%s" % e.message) sys.exit(0) dispatchFunction = ParseNotification(device) dispatchThread = Thread(target=dispatchFunction) dispatchThread.setDaemon(True) dispatchThread.start() try: device.initialize() # log device initialized successfully print "Device initialized for the configuration updates" opw = OpServer() reactor.listenTCP(9191, server.Site(opw)) LOG.info("Starting the reactor") reactor.run() except Exception as e: # log device initialization failed LOG.critical("JET app exiting due to exception: %s" % str(e.message)) sys.exit(0) return
def __call__(self, message): global dispQ LOG.info("Inside Handle commit notifications") LOG.info("Received message: %s" % str(message)) config_dict = message['commit-patch'] print config_dict try: sw_present = False for keys in config_dict: if keys.endswith('softwire-config'): sw_present = True break if sw_present: purge_request = True # Push all the configuration into a new file stub = openconfig_service_pb2.beta_create_OpenconfigRpcApi_stub( self._dev.getChannel()) get_request = openconfig_service_pb2.GetRequestList( operation_id="1001", operation=1, path="/configuration/ietf-softwire:softwire-config") request = openconfig_service_pb2.GetRequest( request_id=1002, encoding=1, get_request=[get_request]) response = stub.Get(request, common.app_globals.RPC_TIMEOUT_SECONDS) for rsp in response.response: print rsp.value if rsp.response_code == openconfig_service_pb2.OK and rsp.value != "": print rsp LOG.info( "Invoked the getRequest for snabb configuration") config_dict = json.loads( rsp.value)["ietf-softwire:softwire-config"] LOG.debug( "Notification message contains the config %s" % (str(config_dict))) purge_request = False dispQ.put(config_dict) if purge_request: LOG.info("Softwire-config deleted in the config") config_dict['purge'] = True dispQ.put(config_dict) else: LOG.info("Softwire-config not present in the config") except Exception as e: LOG.critical("Exception: %s" % e.message) LOG.info('Exiting the JET app') os._exit(1) return