def transfer(host, username, local, remote = None, key_filename = None, password = None): log.debug("Transferring lab to %s" % host) log.info("Transferring Netkit lab") if not remote: remote = local # same filename import paramiko ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy()) try: if key_filename: log.debug("Connecting to %s with %s and key %s" % (host, username, key_filename)) ssh.connect(host, username = username, key_filename = key_filename) elif password: log.info("Connecting to %s with %s" % (host, username)) ssh.connect(host, username = username, password=password) else: log.error("No password, no key assigned for deployment") exit(1) except paramiko.SSHException: log.error("Could not get access to host") exit(1) log.debug("Opening SSH for SFTP") ftp = ssh.open_sftp() log.debug("Putting file %s to %s" % (local, remote)) ftp.put(local, remote) log.debug("Put file %s to %s" % (local, remote)) ftp.close()
def applyConfig(data, ank_data, cfg): if data.has_key('link_list'): configurePortChannel(data, ank_data) configureVirtualPortChannel(data, ank_data) ank_data = AddConfigInfo(ank_data, cfg) if ank_data is None: log.error("VPC id block is not correct") raise ValueError('Range not proper') ''' By default ASN was set to 1. If BGP profile is applicable on the node then ASN may be different. We will be filling ASN info from BGP profile. ''' ank_data = AddAsnInfo(ank_data, cfg)
def main(topo_file, cfg_file): import json dst_folder = None try: json_data=open(topo_file).read() except: log.error("json_converter.py...file open failed for topo_file") return dst_folder try: data = json.loads(json_data) except ValueError, e: #Error in JSON format. Check JSON file log.error("json_converter.py...Error in JSON format. Loading of topology json failed") return dst_folder
def main(topo_data, cfg_data, fab, syntax, fab_id, pool_dict): import json dst_folder = None config_passed = False data = topo_data if cfg_data is not None: cfg_data = {"device_profile": cfg_data} #Above is done so that we don't need to make change to other functions config_passed = True #Create JSOn from POAP json ank_data = createAnkJsonData(data, cfg_data) if ank_data['nodes'] is None: log.debug("json_converter.py...Error received in createAnkJsonData.") return None try: #Add config info onto nodes. if config_passed == True: applyConfig(data, ank_data, cfg_data, fab, fab_id, pool_dict) log.debug("json_converter.py...applyConfig completed") else: log.debug("json_converter.py...no seperate config info supplied") except: log.error("json_converter.py...applyConfig failed") return dst_folder options = test() #options = create_args() options.debug = True options.syntax = syntax #Since input is coming from poap we can assume that it will #be a dictionary. Otherwise it will be a file. #options.file = 'temp.json' options.file = 'dictionary' options.dictionary = ank_data try: dst_folder = console_script.main(options) log.debug("json_converter.py...call to ank completed.") log.debug(str(dst_folder)) return dst_folder except: log.error("json_converter.py...call to ank failed.") return dst_folder
def run_ank(topo_detail={}, prof_detail={}, fab='', syntax='nx_os', fab_id='', pool_dict=None): try: #dst_folder is the place where ank places it's output config files #print REPO_PATH #print fab if REPO_PATH is None or topo_detail is None or prof_detail is None: log.error( "start_ank.py...one or more parameters to run_ank is empty") return None dst_folder = json_converter.main(topo_detail, prof_detail, fab, syntax, fab_id, pool_dict) #print dst_folder line_ank = "!!!!!!!!!!!!!!!!!!!!!!!!!!!ANK CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" line_poap = "!!!!!!!!!!!!!!!!!!!!!!!!!!!POAP CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" if dst_folder is not None: import os import re #fn_ank is the name of the file generated by ank #fn_poap is the name of the file generated by poap for file_ank in os.listdir(dst_folder): #removing ".conf" at the end and adding ".cfg" at end file_final = file_ank[:len(file_ank) - 4] + 'cfg' file_ank = dst_folder + '/' + file_ank file_final = REPO_PATH + '/' + file_final with open(file_ank, "r") as f_ank: buff_ank = f_ank.read() with open(file_final, "w+") as fpc: fpc.write(buff_ank) dst_folder = dst_folder[:dst_folder.rfind('/')] command = "rm -rf " + dst_folder try: os.system(command) except: log.error( "start_ank.py...removal of ank generated folder failed") return 1 else: log.error("start_ank.py...ank returned destination folder as None") return None except: log.error( "start_ank.py...exception recieved in call to json_converter") return None
def run_ank(topo_file, cfg_file, fab='', loc=''): try: #dst_folder is the place where ank places it's output config files #print loc #print fab if fab is None or loc is None or topo_file is None or cfg_file is None: log.error("start_ank.py...one or more parameters to run_ank is empty") return None dst_folder = json_converter.main(topo_file, cfg_file) #print dst_folder line_ank = "!!!!!!!!!!!!!!!!!!!!!!!!!!!ANK CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" line_poap = "!!!!!!!!!!!!!!!!!!!!!!!!!!!POAP CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" if dst_folder is not None: import os import re #fn_ank is the name of the file generated by ank #fn_poap is the name of the file generated by poap for fn_ank in os.listdir(dst_folder): ''' while generating output files ank replaces '-' in output file name with '_'. Therefore we are taking out both to make it easier for string matching. ''' fn_ank_temp = re.sub('[-_]', '', fn_ank[:len(fn_ank)-5])#ignore .conf at the end #print fn_ank_temp #for fn_poap in os.listdir('/home/dev/ignite/repo'): for fn_poap in os.listdir(loc): #print fn_poap #print fn_poap[:len(fab)] #print fab if fn_poap[:len(fab)] == fab: pod_re = "([_])(.+)" id = (re.search(pod_re,fn_poap[len(fab):])).group(2)#this will give the device name id = re.sub('[-_]','',id[:len(id)-4])#ignore .cfg at end #print id if id == fn_ank_temp: file = loc + fn_poap #print file with open(file, "r") as fpc: buff_poap = fpc.read() file_ank = dst_folder + '/' + fn_ank with open(file_ank,"r") as f_ank: buff_ank = f_ank.read() with open(file, "w+") as fpc: fpc.write(line_ank) fpc.write(buff_ank) fpc.write(line_poap) fpc.write(buff_poap) return 1 else: log.error("start_ank.py...ank returned destination folder as None") return None except: log.error("start_ank.py...exception recieved in call to json_converter") return None
def run_ank(topo_detail ={}, prof_detail ={}, fab = '', syntax ='nx_os', fab_id ='',pool_dict =None): try: #dst_folder is the place where ank places it's output config files #print REPO_PATH #print fab if REPO_PATH is None or topo_detail is None or prof_detail is None: log.error("start_ank.py...one or more parameters to run_ank is empty") return None dst_folder = json_converter.main(topo_detail, prof_detail, fab, syntax, fab_id, pool_dict) #print dst_folder line_ank = "!!!!!!!!!!!!!!!!!!!!!!!!!!!ANK CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" line_poap = "!!!!!!!!!!!!!!!!!!!!!!!!!!!POAP CONFIG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" if dst_folder is not None: import os import re #fn_ank is the name of the file generated by ank #fn_poap is the name of the file generated by poap for file_ank in os.listdir(dst_folder): #removing ".conf" at the end and adding ".cfg" at end file_final = file_ank[:len(file_ank)-4] + 'cfg' file_ank = dst_folder + '/' + file_ank file_final = REPO_PATH + '/' + file_final with open(file_ank,"r") as f_ank: buff_ank = f_ank.read() with open(file_final, "w+") as fpc: fpc.write(buff_ank) dst_folder = dst_folder[:dst_folder.rfind('/')] command = "rm -rf " + dst_folder try: os.system(command) except: log.error("start_ank.py...removal of ank generated folder failed") return 1 else: log.error("start_ank.py...ank returned destination folder as None") return None except: log.error("start_ank.py...exception recieved in call to json_converter") return None
def build(self, group_attr='asn'): """Builds tree from unallocated_nodes, groupby is the attribute to build subtrees from""" subgraphs = [] # if network final octet is .0 eg 10.0.0.0 or 192.168.0.0, then add extra "dummy" node, so don't have a loopback of 10.0.0.0 # Change strategy: if just hosts (ie loopbacks), then allocate as a large # collision domain if not len(self.unallocated_nodes): # no nodes to allocate - eg could be no collision domains return unallocated_nodes = self.unallocated_nodes key_func = lambda x: x.get(group_attr) if all(isinstance(item, autonetkit.anm.NmPort) and item.is_loopback for item in unallocated_nodes): # interface, map key function to be the interface's node key_func = lambda x: x.node.get(group_attr) unallocated_nodes = sorted(unallocated_nodes, key=key_func) groupings = itertools.groupby(unallocated_nodes, key=key_func) prefixes_by_attr = {} for (attr_value, items) in groupings: # make subtree for each attr items = sorted(list(items)) subgraph = nx.DiGraph() if all(isinstance(item, autonetkit.anm.NmPort) for item in items): # interface if all(item.is_loopback for item in items): parent_id = self.next_node_id # group all loopbacks into single subnet prefixlen = 32 - subnet_size(len(items)) subgraph.add_node(parent_id, prefixlen=prefixlen, loopback_group=True) for item in sorted(items): # subgraph.add_edge(node, child_a) item_id = self.next_node_id subgraph.add_node(item_id, prefixlen=32, host=item) subgraph.add_edge(parent_id, item_id) root_node = parent_id subgraphs.append(subgraph) subgraph.graph['root'] = root_node subgraph.node[root_node]['group_attr'] = attr_value subgraph.node[root_node]['prefixlen'] = 24 # finished for loopbacks, continue only for collision # domains continue if all(item.is_l3device() for item in items): # Note: only l3 devices are added for loopbacks: cds allocate # to edges not devices (for now) - will be fixed when move to # proper interface model parent_id = self.next_node_id # group all loopbacks into single subnet prefixlen = 32 - subnet_size(len(items)) subgraph.add_node(parent_id, prefixlen=prefixlen, loopback_group=True) for item in sorted(items): # subgraph.add_edge(node, child_a) item_id = self.next_node_id subgraph.add_node(item_id, prefixlen=32, host=item) subgraph.add_edge(parent_id, item_id) root_node = parent_id subgraphs.append(subgraph) subgraph.graph['root'] = root_node subgraph.node[root_node]['group_attr'] = attr_value # finished for loopbacks, continue only for collision domains continue for item in sorted(items): if item.broadcast_domain: subgraph.add_node(self.next_node_id, prefixlen=32 - subnet_size(item.degree()), host=item) if item.is_l3device(): subgraph.add_node(self.next_node_id, prefixlen=32, host=item) # now group by levels level_counts = defaultdict(int) nodes_by_level = defaultdict(list) for node in subgraph.nodes(): prefixlen = subgraph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) log.debug('Building IP subtree for %s %s' % (group_attr, attr_value)) for (level, nodes) in nodes_by_level.items(): level_counts[level] = len(nodes) self.add_parent_nodes(subgraph, level_counts) # test if min_level node is bound, if so then add a parent, so root for AS # isn't a cd min_level = min(level_counts) min_level_nodes = [n for n in subgraph if subgraph.node[n]['prefixlen'] == min_level] # test if bound if len(min_level_nodes) == 2: subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 2}) subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 2}) subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 1}) if len(min_level_nodes) == 1: subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 1}) # rebuild with parent nodes nodes_by_level = defaultdict(list) for node in sorted(subgraph.nodes()): prefixlen = subgraph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) root_node = self.build_tree(subgraph, level_counts, nodes_by_level) subgraphs.append(subgraph) subgraph.graph['root'] = root_node # FOrce to be a /16 block # TODO: document this subgraph.node[root_node]['prefixlen'] = 16 subgraph.node[root_node]['group_attr'] = attr_value prefixes_by_attr[attr_value] = subgraph.node[ root_node]['prefixlen'] global_graph = nx.DiGraph() subgraphs = sorted(subgraphs, key=lambda x: subgraph.node[subgraph.graph['root' ]]['group_attr']) root_nodes = [subgraph.graph['root'] for subgraph in subgraphs] root_nodes = [] for subgraph in subgraphs: root_node = subgraph.graph['root'] root_nodes.append(root_node) global_graph.add_node(root_node, subgraph.node[root_node]) nodes_by_level = defaultdict(list) for node in root_nodes: prefixlen = global_graph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) level_counts = defaultdict(int) for (level, nodes) in nodes_by_level.items(): level_counts[level] = len(nodes) self.add_parent_nodes(global_graph, level_counts) # rebuild nodes by level # TODO: make this a function nodes_by_level = defaultdict(list) for node in global_graph: prefixlen = global_graph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) global_root = self.build_tree(global_graph, level_counts, nodes_by_level) global_root = TreeNode(global_graph, global_root) for subgraph in subgraphs: global_graph = nx.compose(global_graph, subgraph) # now allocate the IPs global_prefix_len = global_root.prefixlen # TODO: try/catch if the block is too small for prefix try: global_ip_block = \ self.root_ip_block.subnet(global_prefix_len).next() except StopIteration: #message = ("Unable to allocate IPv4 subnets. ") formatted_prefixes = ", ".join( "AS%s: /%s" % (k, v) for k, v in sorted(prefixes_by_attr.items())) message = ("Cannot create requested number of /%s subnets from root block %s. Please specify a larger root IP block. (Requested subnet allocations are: %s)" % (global_prefix_len, self.root_ip_block, formatted_prefixes)) log.error(message) # TODO: throw ANK specific exception here raise AutoNetkitException(message) self.graph = global_graph # add children of collision domains cd_nodes = [n for n in self if n.is_broadcast_domain()] for cd in sorted(cd_nodes): for edge in sorted(cd.host.edges()): # TODO: sort these child_id = self.next_node_id cd_id = cd.node global_graph.add_node(child_id, prefixlen=32, host=edge.dst_int) # cd -> neigh (cd is parent) global_graph.add_edge(cd_id, child_id) # TODO: make allocate seperate step def allocate(node): # children = graph.successors(node) children = sorted(node.children()) prefixlen = node.prefixlen + 1 # workaround for clobbering attr subgraph root node with /16 if was # a /28 subnet = node.subnet.subnet(prefixlen) # handle case where children subnet # special case of single AS -> root is loopback_group if node.is_loopback_group() or node.is_broadcast_domain(): # TODO: generalise this rather than repeated code with below # node.subnet = subnet.next() # Note: don't break into smaller # subnets if single-AS # ensures start at .1 rather than .0 iterhosts = node.subnet.iter_hosts() sub_children = node.children() for sub_child in sorted(sub_children): # TODO: tidy up this allocation to always record the subnet if sub_child.is_interface() \ and sub_child.host.is_loopback: if sub_child.host.is_loopback_zero: # loopback zero, just store the ip address sub_child.ip_address = iterhosts.next() else: # secondary loopback sub_child.ip_address = iterhosts.next() sub_child.subnet = node.subnet elif sub_child.is_interface() \ and sub_child.host.is_physical: # physical interface sub_child.ip_address = iterhosts.next() sub_child.subnet = node.subnet else: sub_child.subnet = iterhosts.next() return for child in sorted(children): # traverse the tree if child.is_broadcast_domain(): subnet = subnet.next() child.subnet = subnet # ensures start at .1 rather than .0 iterhosts = child.subnet.iter_hosts() sub_children = child.children() for sub_child in sorted(sub_children): if sub_child.is_interface(): interface = sub_child.host if interface.is_physical: # physical interface sub_child.ip_address = iterhosts.next() sub_child.subnet = subnet elif interface.is_loopback \ and not interface.is_loopback_zero: # secondary loopback interface sub_child.ip_address = iterhosts.next() sub_child.subnet = subnet else: sub_child.subnet = iterhosts.next() #log.debug('Allocate sub_child to %s %s'% (sub_child, sub_child.subnet)) elif child.is_host(): child.subnet = subnet.next() elif child.is_loopback_group(): child.subnet = subnet.next() # ensures start at .1 rather than .0 iterhosts = child.subnet.iter_hosts() sub_children = child.children() for sub_child in sorted(sub_children): if sub_child.is_interface() \ and not sub_child.host.is_loopback_zero: # secondary loopback sub_child.ip_address = iterhosts.next() sub_child.subnet = child.subnet else: sub_child.subnet = iterhosts.next() else: child.subnet = subnet.next() allocate(child) # continue down the tree global_root.subnet = global_ip_block # TODO: fix this workaround where referring to the wrong graph global_root_id = global_root.node global_root = TreeNode(global_graph, global_root_id) allocate(global_root) # check for parentless nodes self.graph = global_graph self.root_node = global_root
def main(options): settings = config.settings if options.vis_uuid: config.settings['Http Post']['uuid'] = options.vis_uuid try: # test if can import, if not present will fail and not add to template # path import autonetkit_cisco except ImportError: pass else: import autonetkit_cisco.version version_banner = autonetkit_cisco.version.banner() log.info("%s" % version_banner) log.info("AutoNetkit %s" % ANK_VERSION) if options.target == "cisco": # output target is Cisco log.info("Setting output target as Cisco") settings['Graphml']['Node Defaults']['platform'] = "VIRL" settings['Graphml']['Node Defaults']['host'] = "internal" settings['Graphml']['Node Defaults']['syntax'] = "ios_xr" settings['Compiler']['Cisco']['to memory'] = 1 settings['General']['deploy'] = 1 settings['Deploy Hosts']['internal'] = {'VIRL': {'deploy': 1}} if options.debug or settings['General']['debug']: # TODO: fix this import logging logger = logging.getLogger("ANK") logger.setLevel(logging.DEBUG) if options.quiet or settings['General']['quiet']: import logging logger = logging.getLogger("ANK") logger.setLevel(logging.WARNING) build_options = { 'compile': options.compile or settings['General']['compile'], 'render': options.render or settings['General']['render'], 'validate': options.validate or settings['General']['validate'], 'build': options.build or settings['General']['build'], 'deploy': options.deploy or settings['General']['deploy'], 'measure': options.measure or settings['General']['measure'], 'monitor': options.monitor or settings['General']['monitor'], 'diff': options.diff or settings['General']['diff'], 'archive': options.archive or settings['General']['archive'], } if options.webserver: log.info("Webserver not yet supported, please run as seperate module") if options.file: with open(options.file, "r") as fh: input_string = fh.read() timestamp = os.stat(options.file).st_mtime elif options.stdin: input_string = sys.stdin now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") elif options.grid: input_string = "" now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") else: log.info("No input file specified. Exiting") return try: manage_network(input_string, timestamp, build_options=build_options, grid=options.grid) except Exception, err: log.error( "Error generating network configurations: %s. More information may be available in the debug log." % err) log.debug("Error generating network configurations", exc_info=True) if settings['General']['stack_trace']: print traceback.print_exc() sys.exit("Unable to build configurations.")
except: log.error("json_converter.py...file open failed for topo_file") return dst_folder try: data = json.loads(json_data) except ValueError, e: #Error in JSON format. Check JSON file log.error("json_converter.py...Error in JSON format. Loading of topology json failed") return dst_folder #Create JSOn from POAP json ank_data = createAnkJsonData(data) if ank_data['nodes'] is None: log.error("json_converter.py...No nodes found in topology json.") return None try: #Add config info onto nodes. applyConfig(data, ank_data, cfg_file) except: log.error("json_converter.py...applyConfig failed") return dst_folder options = test() #options = create_args() options.debug = True #write ank_data to a file #we will write ank data in the same directory where topo_file resides. #so first we will extract the directory from that path
def build(self, group_attr='asn'): """Builds tree from unallocated_nodes, groupby is the attribute to build subtrees from""" subgraphs = [] # if network final octet is .0 eg 10.0.0.0 or 192.168.0.0, then add extra "dummy" node, so don't have a loopback of 10.0.0.0 # Change strategy: if just hosts (ie loopbacks), then allocate as a large collision domain if not len(self.unallocated_nodes): # no nodes to allocate - eg could be no collision domains return unallocated_nodes = self.unallocated_nodes key_func = lambda x: x.get(group_attr) if all(isinstance(item, autonetkit.anm.overlay_interface) and item.is_loopback for item in unallocated_nodes): key_func = lambda x: x.node.get(group_attr) # interface, map key function to be the interface's node unallocated_nodes = sorted(unallocated_nodes, key=key_func) groupings = itertools.groupby(unallocated_nodes, key=key_func) prefixes_by_attr = {} for (attr_value, items) in groupings: # make subtree for each attr items = sorted(list(items)) subgraph = nx.DiGraph() if all(isinstance(item, autonetkit.anm.overlay_interface) for item in items): # interface if all(item.is_loopback for item in items): parent_id = self.next_node_id prefixlen = 32 - subnet_size(len(items)) # group all loopbacks into single subnet subgraph.add_node(parent_id, prefixlen=prefixlen, loopback_group=True) for item in items: # subgraph.add_edge(node, child_a) item_id = self.next_node_id subgraph.add_node(item_id, prefixlen=32, host=item) subgraph.add_edge(parent_id, item_id) root_node = parent_id subgraphs.append(subgraph) subgraph.graph['root'] = root_node subgraph.node[root_node]['group_attr'] = attr_value continue # finished for loopbacks, continue only for collision domains if all(item.is_l3device() for item in items): # Note: only l3 devices are added for loopbacks: cds allocate to edges not devices (for now) - will be fixed when move to proper interface model parent_id = self.next_node_id prefixlen = 32 - subnet_size(len(items)) # group all loopbacks into single subnet subgraph.add_node(parent_id, prefixlen=prefixlen, loopback_group=True) for item in items: # subgraph.add_edge(node, child_a) item_id = self.next_node_id subgraph.add_node(item_id, prefixlen=32, host=item) subgraph.add_edge(parent_id, item_id) root_node = parent_id subgraphs.append(subgraph) subgraph.graph['root'] = root_node subgraph.node[root_node]['group_attr'] = attr_value continue # finished for loopbacks, continue only for collision domains for item in items: if item.broadcast_domain: subgraph.add_node(self.next_node_id, prefixlen=32 - subnet_size(item.degree()), host=item) if item.is_l3device(): subgraph.add_node(self.next_node_id, prefixlen=32, host=item) # now group by levels level_counts = defaultdict(int) nodes_by_level = defaultdict(list) for node in subgraph.nodes(): prefixlen = subgraph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) log.debug('Building IP subtree for %s %s' % (group_attr, attr_value)) for (level, nodes) in nodes_by_level.items(): level_counts[level] = len(nodes) self.add_parent_nodes(subgraph, level_counts) # test if min_level node is bound, if so then add a parent, so root for AS isn't a cd min_level = min(level_counts) min_level_nodes = [n for n in subgraph if subgraph.node[n]['prefixlen'] == min_level] # test if bound if len(min_level_nodes) == 2: subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 2}) subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 2}) subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 1}) if len(min_level_nodes) == 1: subgraph.add_node(self.next_node_id, {'prefixlen': min_level - 1}) # rebuild with parent nodes nodes_by_level = defaultdict(list) for node in subgraph.nodes(): prefixlen = subgraph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) root_node = self.build_tree(subgraph, level_counts, nodes_by_level) subgraphs.append(subgraph) subgraph.graph['root'] = root_node # FOrce to be a /16 block # TODO: document this subgraph.node[root_node]['prefixlen'] = 16 subgraph.node[root_node]['group_attr'] = attr_value prefixes_by_attr[attr_value] = subgraph.node[root_node]['prefixlen'] global_graph = nx.DiGraph() subgraphs = sorted(subgraphs, key=lambda x: \ subgraph.node[subgraph.graph['root' ]]['group_attr']) root_nodes = [subgraph.graph['root'] for subgraph in subgraphs] root_nodes = [] for subgraph in subgraphs: root_node = subgraph.graph['root'] root_nodes.append(root_node) global_graph.add_node(root_node, subgraph.node[root_node]) nodes_by_level = defaultdict(list) for node in root_nodes: prefixlen = global_graph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) level_counts = defaultdict(int) for (level, nodes) in nodes_by_level.items(): level_counts[level] = len(nodes) self.add_parent_nodes(global_graph, level_counts) # rebuild nodes by level # TODO: make this a function nodes_by_level = defaultdict(list) for node in global_graph: prefixlen = global_graph.node[node]['prefixlen'] nodes_by_level[prefixlen].append(node) global_root = self.build_tree(global_graph, level_counts, nodes_by_level) global_root = TreeNode(global_graph, global_root) for subgraph in subgraphs: global_graph = nx.compose(global_graph, subgraph) # now allocate the IPs global_prefix_len = global_root.prefixlen # TODO: try/catch if the block is too small for prefix try: global_ip_block = \ self.root_ip_block.subnet(global_prefix_len).next() except StopIteration: #message = ("Unable to allocate IPv4 subnets. ") formatted_prefixes = ", ".join("AS%s: /%s" % (k,v) for k,v in sorted(prefixes_by_attr.items())) message = ("Cannot create requested number of /%s subnets from root block %s. Please specify a larger root IP block. (Requested subnet allocations are: %s)" % (global_prefix_len, self.root_ip_block, formatted_prefixes)) log.error(message) raise AutoNetkitException(message) # TODO: throw ANK specific exception here self.graph = global_graph # add children of collision domains cd_nodes = [n for n in self if n.is_broadcast_domain()] for cd in cd_nodes: for edge in sorted(cd.host.edges()): # TODO: sort these child_id = self.next_node_id cd_id = cd.node global_graph.add_node(child_id, prefixlen=32, host=edge.dst_int) global_graph.add_edge(cd_id, child_id) # cd -> neigh (cd is parent) # TODO: make allocate seperate step def allocate(node): # children = graph.successors(node) children = sorted(node.children()) prefixlen = node.prefixlen + 1 # workaround for clobbering attr subgraph root node with /16 if was a /28 subnet = node.subnet.subnet(prefixlen) # handle case where children subnet if node.is_loopback_group() or node.is_broadcast_domain(): # special case of single AS -> root is loopback_group # TODO: generalise this rather than repeated code with below # node.subnet = subnet.next() # Note: don't break into smaller subnets if single-AS iterhosts = node.subnet.iter_hosts() # ensures start at .1 rather than .0 sub_children = node.children() for sub_child in sub_children: # TODO: tidy up this allocation to always record the subnet if sub_child.is_interface() \ and sub_child.host.is_loopback: if sub_child.host.is_loopback_zero: # loopback zero, just store the ip address sub_child.ip_address = iterhosts.next() else: # secondary loopback sub_child.ip_address = iterhosts.next() sub_child.subnet = node.subnet elif sub_child.is_interface() \ and sub_child.host.is_physical: # physical interface sub_child.ip_address = iterhosts.next() sub_child.subnet = node.subnet else: sub_child.subnet = iterhosts.next() return for child in children: # traverse the tree if child.is_broadcast_domain(): subnet = subnet.next() child.subnet = subnet iterhosts = child.subnet.iter_hosts() # ensures start at .1 rather than .0 sub_children = child.children() for sub_child in sub_children: if sub_child.is_interface(): interface = sub_child.host if interface.is_physical: # physical interface sub_child.ip_address = iterhosts.next() sub_child.subnet = subnet elif interface.is_loopback \ and not interface.is_loopback_zero: # secondary loopback interface sub_child.ip_address = iterhosts.next() sub_child.subnet = subnet else: sub_child.subnet = iterhosts.next() #log.debug('Allocate sub_child to %s %s'% (sub_child, sub_child.subnet)) elif child.is_host(): child.subnet = subnet.next() elif child.is_loopback_group(): child.subnet = subnet.next() iterhosts = child.subnet.iter_hosts() # ensures start at .1 rather than .0 sub_children = child.children() for sub_child in sub_children: if sub_child.is_interface() \ and not sub_child.host.is_loopback_zero: # secondary loopback sub_child.ip_address = iterhosts.next() sub_child.subnet = child.subnet else: sub_child.subnet = iterhosts.next() else: child.subnet = subnet.next() allocate(child) # continue down the tree global_root.subnet = global_ip_block # TODO: fix this workaround where referring to the wrong graph global_root_id = global_root.node global_root = TreeNode(global_graph, global_root_id) allocate(global_root) # check for parentless nodes self.graph = global_graph self.root_node = global_root
def main(options): import json settings = config.settings dst_folder = None if options.vis_uuid: config.settings['Http Post']['uuid'] = options.vis_uuid try: # test if can import, if not present will fail and not add to template # path import autonetkit_cisco except ImportError: pass else: import autonetkit_cisco.version version_banner = autonetkit_cisco.version.banner() log.info("%s" % version_banner) log.info("AutoNetkit %s" % ANK_VERSION) if options.target == "cisco": # output target is Cisco log.info("Setting output target as Cisco") settings['Graphml']['Node Defaults']['platform'] = "cisco" settings['Graphml']['Node Defaults']['host'] = "internal" settings['Graphml']['Node Defaults']['syntax'] = options.syntax settings['JSON']['Node Defaults']['syntax'] = options.syntax settings['Compiler']['Cisco']['to memory'] = 1 settings['General']['deploy'] = 1 settings['Deploy Hosts']['internal'] = {'cisco': {'deploy': 1}} if options.debug or settings['General']['debug']: # TODO: fix this import logging logger = logging.getLogger("ANK") logger.setLevel(logging.DEBUG) if options.quiet or settings['General']['quiet']: import logging logger = logging.getLogger("ANK") logger.setLevel(logging.WARNING) build_options = { 'compile': options.compile or settings['General']['compile'], 'render': options.render or settings['General']['render'], 'validate': options.validate or settings['General']['validate'], 'build': options.build or settings['General']['build'], 'deploy': options.deploy or settings['General']['deploy'], 'measure': options.measure or settings['General']['measure'], 'monitor': options.monitor or settings['General']['monitor'], 'diff': options.diff or settings['General']['diff'], 'archive': options.archive or settings['General']['archive'], # use and for visualise as no_vis negates 'visualise': options.visualise and settings['General']['visualise'], 'syntax': options.syntax, } if options.webserver: log.info("Webserver not yet supported, please run as seperate module") if options.file: if options.file == 'dictionary': input_string = json.dumps(options.dictionary) else: with open(options.file, "r") as fh: input_string = fh.read() filename = os.path.join(BASE_DIR, "autonetkit/ank.log") timestamp = os.stat(filename).st_mtime elif options.stdin: input_string = sys.stdin now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") elif options.grid: input_string = "" now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") else: log.info("No input file specified. Exiting") return None try: dst_folder = workflow.manage_network(input_string, timestamp, grid=options.grid, **build_options) log.debug("Generated network configurations: %s" % dst_folder) except Exception, err: log.error("Error generating network configurations: %s" % err) log.debug("Error generating network configurations", exc_info=True) if settings['General']['stack_trace']: print traceback.print_exc()
def main(options): settings = config.settings if options.vis_uuid: config.settings['Http Post']['uuid'] = options.vis_uuid try: # test if can import, if not present will fail and not add to template # path import autonetkit_cisco except ImportError: pass else: import autonetkit_cisco.version version_banner = autonetkit_cisco.version.banner() log.info("%s" % version_banner) log.info("AutoNetkit %s" % ANK_VERSION) if options.target == "cisco": # output target is Cisco log.info("Setting output target as Cisco") settings['Graphml']['Node Defaults']['platform'] = "VIRL" settings['Graphml']['Node Defaults']['host'] = "internal" settings['Graphml']['Node Defaults']['syntax'] = "ios_xr" settings['Compiler']['Cisco']['to memory'] = 1 settings['General']['deploy'] = 1 settings['Deploy Hosts']['internal'] = {'VIRL': {'deploy': 1}} if options.debug or settings['General']['debug']: # TODO: fix this import logging logger = logging.getLogger("ANK") logger.setLevel(logging.DEBUG) if options.quiet or settings['General']['quiet']: import logging logger = logging.getLogger("ANK") logger.setLevel(logging.WARNING) build_options = { 'compile': options.compile or settings['General']['compile'], 'render': options.render or settings['General']['render'], 'validate': options.validate or settings['General']['validate'], 'build': options.build or settings['General']['build'], 'deploy': options.deploy or settings['General']['deploy'], 'measure': options.measure or settings['General']['measure'], 'monitor': options.monitor or settings['General']['monitor'], 'diff': options.diff or settings['General']['diff'], 'archive': options.archive or settings['General']['archive'], } if options.webserver: log.info("Webserver not yet supported, please run as seperate module") if options.file: with open(options.file, "r") as fh: input_string = fh.read() timestamp = os.stat(options.file).st_mtime elif options.stdin: import sys input_string = sys.stdin now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") elif options.grid: input_string = "" now = datetime.now() timestamp = now.strftime("%Y%m%d_%H%M%S_%f") else: log.info("No input file specified. Exiting") raise SystemExit try: manage_network(input_string, timestamp, build_options=build_options, grid=options.grid) except Exception, err: log.error( "Error generating network configurations: %s. More information may be available in the debug log." % err) log.debug("Error generating network configurations", exc_info=True) if settings['General']['stack_trace']: print traceback.print_exc() import sys sys.exit("Unable to build configurations.")
conn.execute('cd') # back to home directory tar file copied to conn.execute('rm -Rf rendered') conn.execute('tar -xzf %s' % tar_file) conn.execute('cd %s' % cd_dir) conn.execute('vlist') conn.execute("lclean") log.info("Starting lab") start_command = 'lstart -p20 -o--con0=none' try: conn.execute(start_command) except InvalidCommandException, error: if "already running" in str(error): time.sleep(1) conn.execute(start_command) first_match(conn, r'^The lab has been started') conn.send("exit") if key_filename: key = PrivateKey.from_file(key_filename) log.debug("Connecting to %s with username %s and key %s" % (host, username, key_filename)) accounts = [Account(username, key = key)] elif password: log.debug("Connecting to %s with username %s" % (host, username)) accounts = [Account(username, password)] else: log.error("No password nor keyfile provided") exit(1) hosts = ['ssh://%s' % host] start(accounts, hosts, start_lab, verbose = verbosity)