├── .gitattributes ├── .gitignore ├── README.md ├── v1.x ├── build-v1.1.xlsx └── ccg-v1.1.py ├── v2.0 ├── build-v2.0.xlsx └── ccg-v2.0.py ├── v2.1 ├── build-v2.1.xlsx └── ccg-v2.1.py └── v2.2 ├── build-v2.3.xlsx └── ccg-v2.2.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ======================= 2 | Cisco Config Generator 3 | ======================= 4 | This tool will allow the bulk creation of Cisco IOS based configuration using an excel spreadsheet as the front end. 5 | 6 | The intention is to provide engineers with a simple, lightweight utility that allows them to quickly generate configuration without having to manual prepare it in an offline text file. Worksheets are created which allows the user to enter: 7 | 8 | * Configuration templates 9 | * VLANs 10 | * VRFs 11 | * Port-channel interfaces 12 | * Layer 2 settings 13 | * Layer 3 settings 14 | * Static routing 15 | * Prefix-list 16 | 17 | Simply populate whichever worksheet is applicable and then run the script and you're good to go. 18 | 19 | Instructions: 20 | 21 | 1. Download build.xlsx and update to include the relevant configuration 22 | 2. Run the script, i.e. ccg.py build.xlsx 23 | 24 | ========================== 25 | Version Information 26 | ========================== 27 | Version 1.x - original release, does not support configuration templates 28 | Version 2.0 - complete re-write of the code, now supports configuration templates with dynamic variables 29 | Version 2.1 - changes to the build worksheet and minor bug fixes 30 | 31 | -------------------------------------------------------------------------------- /v1.x/build-v1.1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdulkcode/CiscoConfigGenerator/650278f7210937fd9d1f66a834cf4d9806430c90/v1.x/build-v1.1.xlsx -------------------------------------------------------------------------------- /v2.0/build-v2.0.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdulkcode/CiscoConfigGenerator/650278f7210937fd9d1f66a834cf4d9806430c90/v2.0/build-v2.0.xlsx -------------------------------------------------------------------------------- /v2.0/ccg-v2.0.py: -------------------------------------------------------------------------------- 1 | import xlrd 2 | import re 3 | import sys 4 | from netaddr import * 5 | from operator import itemgetter 6 | 7 | __author__ = 'Abdul Karim El-Assaad' 8 | __version__ = '(CCG) Version: 2.0 BETA (19/9/2014)' # Cisco Config Generator version 9 | 10 | 11 | error_db = {} 12 | 13 | raw_db = {} # Stores all the raw data from the build spreadsheet 14 | device_list = [] # Stores the valid device list from raw_db 15 | worksheet_list = [] # Stores the names of all worksheets in the build spreadsheet 16 | column_list = {} 17 | 18 | # Create a unique global dictionary for each worksheet 19 | config_templates = {} # Stores the config templates from raw_db 20 | variable_list = {} # Stores the valid variables from raw_db 21 | profile_list = {} # Stores the profiles from raw_db 22 | vlan_list = {} # Stores the valid vlans from raw_db 23 | vrf_list = {} # Stores the valid vrfs from raw_db 24 | interface_list = {} # Stores the layer2 information from raw_db 25 | static_route_list = {} # Stores the routing information from raw_db 26 | prefix_list = {} # Stores the prefix-list information from raw_db 27 | portchannel_list = {} # Stores the port-channel list information from raw_db 28 | 29 | global filename 30 | 31 | ''' 32 | ============================================================================= 33 | How to add a new worksheet: 34 | * Create a new global dictionary or list (see above) 35 | * Update RemoveEmptyRowsFromDB() function to include the new required columns 36 | * Create a function called GetList 37 | * Create a function called CreateConfiguration 38 | ============================================================================= 39 | ''' 40 | 41 | #----------------------------------------- 42 | # Used to redirect output to a text file 43 | #----------------------------------------- 44 | class Logger(object): 45 | def __init__(self, filename="Default.log"): 46 | self.terminal = sys.stdout 47 | self.log = open(filename, "w") 48 | def write(self, message): 49 | #self.terminal.write(message) # Shows output to screen 50 | self.log.write(message) # Writes output to file 51 | 52 | #----------------------------------------- 53 | # Main class which has all the functions 54 | #----------------------------------------- 55 | class Config(object): 56 | def __init__(self): 57 | self.CreateRawDb() 58 | 59 | # ---------------------------------------------------------------------- 60 | # Read the content of the build spreadsheet into the raw_db dictionary 61 | # To access call: raw_db["worksheet_name"][row_number]["Column name"] 62 | # ---------------------------------------------------------------------- 63 | def CreateRawDb(self): 64 | wb = xlrd.open_workbook(filename) 65 | global raw_db 66 | global worksheet_list 67 | global device_list 68 | global column_list 69 | global error_db 70 | 71 | temp_db = [] 72 | 73 | for i, worksheet in enumerate(wb.sheets()): 74 | if worksheet.name == "Instructions": 75 | continue 76 | header_cells = worksheet.row(0) 77 | num_rows = worksheet.nrows - 1 78 | curr_row = 0 79 | header = [each.value for each in header_cells] 80 | column_list[worksheet.name] = header 81 | # Add a column that doesn't exist in the worksheet 82 | header.append("Row") 83 | #------------------------------------------------------------------------------------- 84 | # Iterate over each row in each worksheet and store the info in the raw_db dictionary 85 | #------------------------------------------------------------------------------------- 86 | while curr_row < num_rows: 87 | curr_row += 1 88 | row = [int(each.value) if isinstance(each.value, float) 89 | else each.value 90 | for each in worksheet.row(curr_row)] 91 | # Add the row number to each record 92 | row.append(curr_row+1) 93 | value_dict = dict(zip(header, row)) 94 | temp_db.append(value_dict) 95 | else: 96 | #print ("raw_db: added '{}'".format(worksheet.name)) 97 | raw_db[worksheet.name] = temp_db 98 | #--------------------------------------------------------------------- 99 | # Grab all the unique device worksheet names in the build spreadsheet 100 | #--------------------------------------------------------------------- 101 | worksheet_list.append(worksheet.name) 102 | error_db[worksheet.name] = [] 103 | 104 | #------------------------------------------------------------------------ 105 | # Re-initalise the temp_db database so it's ready for the next worksheet 106 | #------------------------------------------------------------------------ 107 | temp_db = [] 108 | 109 | #------------------------------------------------------------------------------------- 110 | # Read through raw_db and start storing relevant information in their global database 111 | #------------------------------------------------------------------------------------- 112 | 113 | #----------------------------------------------------------------------- 114 | # Create a database which contains a list devices from every worksheet 115 | #------------------------------------------------------------------------ 116 | def GetDeviceList(self): 117 | global device_list 118 | raw_devices = [] 119 | for worksheet in worksheet_list: 120 | for row,entry in enumerate(raw_db[worksheet]): 121 | if raw_db[worksheet][row].get("Device Name"): 122 | if "!" in raw_db[worksheet][row].get("Device Name"): 123 | continue 124 | value = raw_db[worksheet][row].get("Device Name","none") 125 | value = value.strip() 126 | if value not in raw_devices: 127 | raw_devices.append(value) 128 | device_list = sorted(raw_devices) 129 | 130 | 131 | #----------------------------------------------------------- 132 | # Create a database that contains the VLANs for each device 133 | #----------------------------------------------------------- 134 | def GetVlanList(self): 135 | global vlan_list 136 | for row_no in range(len(raw_db["vlans"])): 137 | device_name = raw_db["vlans"][row_no]["Device Name"] 138 | if vlan_list.get(device_name): 139 | continue 140 | else: 141 | vlan_list[device_name] = {} 142 | for row_no in range(len(raw_db["vlans"])): 143 | device_name = raw_db["vlans"][row_no]["Device Name"] 144 | vlan_no = raw_db["vlans"][row_no]["VLAN No"] 145 | vlan_name = raw_db["vlans"][row_no]["VLAN Name"] 146 | vlan_list[device_name][vlan_no] = vlan_name 147 | 148 | #----------------------------------------------------------- 149 | # Create a database that contains the VRFs for each device 150 | #----------------------------------------------------------- 151 | def GetVrfList(self): 152 | global vrf_list 153 | for row_no in range(len(raw_db["vrf"])): 154 | vrf_columns = {key: [] for key in column_list["vrf"]} 155 | device_name = raw_db["vrf"][row_no]["Device Name"] 156 | vrf = raw_db["vrf"][row_no]["VRF"] 157 | if not vrf_list.get(device_name): 158 | vrf_list[device_name] = {} 159 | if not vrf_list[device_name].get(vrf): 160 | vrf_list[device_name][vrf] = vrf_columns 161 | for column in vrf_columns: 162 | vrf_list[device_name][vrf][column] = raw_db["vrf"][row_no][column] 163 | # If there are multiple route-targets grab them all 164 | current_import = vrf_list[device_name][vrf]["Import RT (separated by commas)"] 165 | current_import = current_import.strip() 166 | current_import = current_import.replace(" ","") 167 | current_export = vrf_list[device_name][vrf]["Export RT (separated by commas)"] 168 | current_export = current_export.strip() 169 | current_export = current_export.replace(" ","") 170 | new_import = current_import.split(",") 171 | new_export = current_export.split(",") 172 | vrf_list[device_name][vrf]["Import RT (separated by commas)"] = new_import 173 | vrf_list[device_name][vrf]["Export RT (separated by commas)"] = new_export 174 | 175 | #------------------------------------------------------------------ 176 | # Create a database that contains the interfaces for each device 177 | #------------------------------------------------------------------ 178 | def GetInterfaceList(self): 179 | global interface_list 180 | for row_no in range(len(raw_db["interfaces"])): 181 | interface_columns = {key: [] for key in column_list["interfaces"]} 182 | device_name = raw_db["interfaces"][row_no]["Device Name"] 183 | port = raw_db["interfaces"][row_no]["Interface"] 184 | if not interface_list.get(device_name): 185 | interface_list[device_name] = {} 186 | if not interface_list[device_name].get(port): 187 | interface_list[device_name][port] = interface_columns 188 | for column in interface_columns: 189 | interface_list[device_name][port][column] = raw_db["interfaces"][row_no][column] 190 | self.AddInterface(device_name,port,True) 191 | 192 | #------------------------------------------------------------------- 193 | # Create a database that contains the static routes for each device 194 | #------------------------------------------------------------------- 195 | def GetStaticRouteList(self): 196 | global static_route_list 197 | for row_no in range(len(raw_db["static routes"])): 198 | static_route_columns = {key: [] for key in column_list["static routes"]} 199 | device_name = raw_db["static routes"][row_no]["Device Name"] 200 | route = raw_db["static routes"][row_no]["Route (x.x.x.x/x)"] 201 | if not static_route_list.get(device_name): 202 | static_route_list[device_name] = {} 203 | if not static_route_list[device_name].get(route): 204 | static_route_list[device_name][route] = static_route_columns 205 | for column in static_route_columns: 206 | static_route_list[device_name][route][column] = raw_db["static routes"][row_no][column] 207 | 208 | new_route = IPNetwork(route) 209 | static_route_list[device_name][route]["Route"] = str(new_route.ip) 210 | static_route_list[device_name][route]["Subnet"] = str(new_route.netmask) 211 | 212 | 213 | def GetPrefixList(self): 214 | global prefix_list 215 | for row_no in range(len(raw_db["prefix-list"])): 216 | device_name = raw_db["prefix-list"][row_no]["Device Name"] 217 | prefix_name = raw_db["prefix-list"][row_no]["Prefix-List Name"] 218 | prefix_seq = raw_db["prefix-list"][row_no]["Prefix-List Sequence No"] 219 | prefix_action = raw_db["prefix-list"][row_no]["Prefix-List Action (permit/deny)"] 220 | prefix_entry = raw_db["prefix-list"][row_no]["Prefix-List Entry"] 221 | if not prefix_list.get(device_name): 222 | prefix_list[device_name] = {} 223 | if not prefix_list[device_name].get(prefix_name): 224 | temp_list = [] 225 | prefix_list[device_name][prefix_name] = temp_list 226 | temp_db = {"sequence":"","action":"","entry":""} 227 | prefix_list[device_name][prefix_name].append(temp_db) 228 | prefix_list[device_name][prefix_name][0]["sequence"] = prefix_seq 229 | prefix_list[device_name][prefix_name][0]["action"] = prefix_action 230 | prefix_list[device_name][prefix_name][0]["entry"] = prefix_entry 231 | elif not self.GetPrefixSeqNo(device_name,prefix_name,prefix_seq): 232 | list_no = len(prefix_list[device_name][prefix_name]) 233 | temp_db = {"sequence":"","action":"","entry":""} 234 | prefix_list[device_name][prefix_name].append(temp_db) 235 | prefix_list[device_name][prefix_name][list_no]["sequence"] = prefix_seq 236 | prefix_list[device_name][prefix_name][list_no]["action"] = prefix_action 237 | prefix_list[device_name][prefix_name][list_no]["entry"] = prefix_entry 238 | 239 | 240 | def GetPortChannelList(self): 241 | global portchannel_list 242 | for row_no in range(len(raw_db["portchannels"])): 243 | portchannel_column = {key: [] for key in column_list["portchannels"]} 244 | device_name = raw_db["portchannels"][row_no]["Device Name"] 245 | interface = raw_db["portchannels"][row_no]["Interface"] 246 | if not portchannel_list.get(device_name): 247 | portchannel_list[device_name] = {} 248 | if not portchannel_list[device_name].get(interface): 249 | portchannel_list[device_name][interface] = portchannel_column 250 | for column in portchannel_column: 251 | portchannel_list[device_name][interface][column] = raw_db["portchannels"][row_no][column] 252 | self.UpdatePortChannels() 253 | 254 | 255 | # Will iterate over the portchannel_list and try to add a new interface for each parent 256 | # or member interfaces. 257 | 258 | def UpdatePortChannels(self): 259 | for device_name in sorted(portchannel_list): 260 | for interface in sorted(portchannel_list[device_name]): 261 | 262 | pc_enabled = portchannel_list[device_name][interface]["Interface Enabled (yes/no)"] 263 | pc_group = portchannel_list[device_name][interface]["Port-Channel Group"] 264 | pc_mode = portchannel_list[device_name][interface]["Port-Channel Mode (active/on/etc)"] 265 | pc_type = portchannel_list[device_name][interface]["Port-Channel Type (layer2 or layer3)"] 266 | pc_profile = portchannel_list[device_name][interface]["Port-Channel Profile"] 267 | pc_members = portchannel_list[device_name][interface]["Port-Channel Members (separated by commas)"] 268 | pc_description = portchannel_list[device_name][interface]["Description"] 269 | 270 | self.AddInterface(device_name,interface) 271 | if pc_enabled: 272 | interface_list[device_name][interface]["Interface Enabled (yes/no)"] = pc_enabled 273 | if pc_description: 274 | interface_list[device_name][interface]["Description"] = pc_description 275 | if pc_profile: 276 | interface_list[device_name][interface]["Profile 1"] = pc_profile 277 | 278 | for member in pc_members.split(","): 279 | member = member.strip() 280 | self.AddInterface(device_name,member) 281 | interface_list[device_name][member]["PC-Group"] = pc_group 282 | interface_list[device_name][member]["PC-Mode"] = pc_mode 283 | interface_list[device_name][member]["PC-Type"] = pc_type 284 | interface_list[device_name][interface]["PC-Members"].append(member) 285 | 286 | def GetVariableList(self): 287 | global variable_list 288 | for row_no in range(len(raw_db["variables"])): 289 | variable_name = raw_db["variables"][row_no]["Variable"] 290 | variable_value = raw_db["variables"][row_no]["Variable Value"] 291 | if "+" in variable_name: 292 | continue 293 | elif variable_name in variable_list: 294 | continue 295 | variable_list[variable_name] = variable_value 296 | 297 | def GetConfigTemplateList(self): 298 | global config_templates 299 | temp_list = [] 300 | for row_no in range(len(raw_db["config-templates"])): 301 | line = raw_db["config-templates"][row_no]["Enter config templates below this line:"] 302 | match = re.search(r'Config Template: \[(.*?)\]', line,re.IGNORECASE) 303 | if not line: 304 | continue 305 | if match: 306 | temp_list = [] 307 | config_templates[match.group(1)] = temp_list 308 | continue 309 | temp_list.append(line) 310 | 311 | # Cycle through each line of the config template to update dynamic variables 312 | for entry in config_templates: 313 | temp_list = [] 314 | for line in config_templates[entry]: 315 | match = re.findall(r'\[(.*?)\]', line) 316 | valid_variable = False 317 | if (match): 318 | for variable_name in match: 319 | lookup_variable = self.GetVariable(variable_name) 320 | if lookup_variable: 321 | valid_variable = True 322 | line = line.replace(variable_name,lookup_variable) 323 | else: 324 | error_db["config-templates"].append("Config-Template: '{}' referenced embedded variable '{}' which does not exist".format(entry,variable_name)) 325 | continue 326 | if (valid_variable): 327 | line = line.replace("[","") 328 | line = line.replace("]","") 329 | temp_list.append(line) 330 | config_templates[entry] = temp_list 331 | 332 | 333 | def GetProfileList(self): 334 | global profile_list 335 | global error_db 336 | for row_no in range(len(raw_db["profiles"])): 337 | device_name = raw_db["profiles"][row_no]["Device Name"] 338 | profile = raw_db["profiles"][row_no]["Profile"] 339 | if not self.GetVariable(profile): 340 | if not self.GetConfigTemplate(profile): 341 | error_db["profiles"].append("Row ({}): Device '{}' referenced variable '{}' which does not exist".format(raw_db["profiles"][row_no]["Row"],device_name,profile)) 342 | continue 343 | if device_name not in profile_list: 344 | temp_list = [] 345 | profile_list[device_name] = temp_list 346 | profile_list[device_name].append(profile) 347 | 348 | 349 | 350 | #------------------------------------------- 351 | # Manual manipulation of one of the lists 352 | #------------------------------------------- 353 | ''' manual_entries will result in manual entries always being triggered. 354 | This will be created when: 355 | a) GetInterfaceList is called (i.e. reading the info from the interfaces tab 356 | b) UpdatePortChannels is called (i.e. only if new interface is detected) 357 | ''' 358 | def AddInterface(self,device_name,interface,manual_entries=False): 359 | global interface_list 360 | 361 | interface_columns = {key: [] for key in column_list["interfaces"]} 362 | if not interface_list.get(device_name): 363 | interface_list[device_name] = {} 364 | if not interface_list[device_name].get(interface): 365 | manual_entries = True 366 | interface_list[device_name][interface] = interface_columns 367 | 368 | # Any manual entries that are not directly from the spreadsheet below 369 | if manual_entries: 370 | error_list = [] 371 | member_list = [] 372 | interface_list[device_name][interface]["Errors"] = error_list 373 | interface_list[device_name][interface]["Interface"] = interface 374 | interface_list[device_name][interface]["PC-Group"] = "" 375 | interface_list[device_name][interface]["PC-Mode"] = "" 376 | interface_list[device_name][interface]["PC-Type"] = "" 377 | interface_list[device_name][interface]["PC-Members"] = member_list 378 | interface_list[device_name][interface]["PC-Parent"] = "" 379 | 380 | # --------------------------------------------------- 381 | # Get specific values from their respective database 382 | # --------------------------------------------------- 383 | def GetVariable(self, variable_name): 384 | if variable_list.get(variable_name): 385 | return variable_list[variable_name] 386 | 387 | def GetVlan(self, device_to_find, vlan_to_find): 388 | if vlan_list[device_to_find].get(vlan_to_find): 389 | return vlan_list[device_to_find][vlan_to_find] 390 | 391 | def GetConfigTemplate(self, template_name): 392 | if config_templates.get(template_name): 393 | return config_templates[template_name] 394 | 395 | def GetPrefixSeqNo(self, device_name,prefix_name,sequence_number): 396 | global prefix_list 397 | if not prefix_list.get(device_name): 398 | return 399 | if not prefix_list[device_name].get(prefix_name): 400 | return 401 | for row, entry in enumerate(prefix_list[device_name][prefix_name]): 402 | if prefix_list[device_name][prefix_name][row]["sequence"] == sequence_number: 403 | return prefix_list[device_name][prefix_name][row] 404 | 405 | def GetIP(self,IP_address,mode="IOS"): 406 | if not IP_address: 407 | return 408 | if "/" not in IP_address: 409 | # Generate error message 410 | return IP_address 411 | if mode == "NXOS": 412 | string = ("{}".format(IP_address)) 413 | return string 414 | elif mode == "IOS": 415 | full_address = IPNetwork(IP_address) 416 | string = ("{} {}".format(full_address.ip,full_address.netmask)) 417 | return string 418 | 419 | def GetInterfaceType(self,interface): 420 | logical_interfaces = ["Po","Tu","Lo","Vl"] 421 | for type in logical_interfaces: 422 | if type in interface: 423 | return "Logical" 424 | return "Physical" 425 | 426 | def GetTrunkVlans(self,device,interface): 427 | if not interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 428 | return 429 | allowed_vlans_raw = interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"] 430 | allowed_vlans_raw = allowed_vlans_raw.replace(" ","") 431 | allowed_vlans_raw = allowed_vlans_raw.strip() 432 | allowed_vlans_raw = allowed_vlans_raw.split(",") 433 | allowed_vlans_new = [] 434 | 435 | for vlan in allowed_vlans_raw: 436 | if "-" not in vlan: 437 | allowed_vlans_new.append(vlan) 438 | elif "-" in vlan: 439 | vlan_range = [] 440 | for entry in vlan.split("-"): 441 | vlan_range.append(entry) 442 | vlan_range_start = int(vlan_range[0]) 443 | vlan_range_end = int(vlan_range[1]) 444 | 445 | while vlan_range_start <= vlan_range_end: 446 | allowed_vlans_new.append(vlan_range_start) 447 | vlan_range_start +=1 448 | return allowed_vlans_new 449 | 450 | # --------------------------------------------- 451 | # Check the interface for specific conditions 452 | # --------------------------------------------- 453 | def is_switch_port(self,device,interface): 454 | if interface_list[device][interface]["Data VLAN"]: 455 | return True 456 | elif interface_list[device][interface]["Voice VLAN"]: 457 | return True 458 | elif interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"]: 459 | return True 460 | elif "layer2" in interface_list[device][interface]["PC-Type"]: 461 | return True 462 | 463 | def is_routed_port(self,device,interface): 464 | if "Logical" in self.GetInterfaceType(interface): 465 | return False 466 | elif interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 467 | return True 468 | elif "layer3" in interface_list[device][interface]["PC-Type"]: 469 | return True 470 | 471 | def is_trunk_port(self,device,interface): 472 | if interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 473 | return True 474 | 475 | def is_data_port(self,device,interface): 476 | if interface_list[device][interface].get("Data VLAN"): 477 | return True 478 | 479 | def is_voice_port(self,device,interface): 480 | if interface_list[device][interface].get("Voice VLAN"): 481 | return True 482 | 483 | def is_interface_enabled(self,device,interface): 484 | if interface_list[device][interface]["Interface Enabled (yes/no)"]: 485 | if "yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 486 | return True 487 | if "Yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 488 | return True 489 | 490 | def is_portchannel_member(self,device,interface): 491 | if interface_list[device][interface]["PC-Group"]: 492 | return True 493 | 494 | def is_portchannel_parent(self,device,interface): 495 | if interface_list[device][interface]["PC-Members"]: 496 | return True 497 | 498 | def is_valid_portchannel(self,device,interface): 499 | if portchannel_list[device].get(interface): 500 | if interface_list[device][interface]: 501 | return True 502 | 503 | def is_valid_variable(self,variable_name): 504 | if variable_list.get(variable_name): 505 | return True 506 | 507 | def is_valid_vlan(self,device,vlan): 508 | if vlan_list.get(device): 509 | if vlan_list[device].get(int(vlan)): 510 | return True 511 | 512 | def is_valid_trunk(self,device,interface): 513 | if not self.is_trunk_port(device,interface): 514 | return False 515 | trunk_vlans = self.GetTrunkVlans(device,interface) 516 | valid_trunk = True 517 | for vlan in trunk_vlans: 518 | if not self.is_valid_vlan(device,vlan): 519 | valid_trunk = False 520 | if valid_trunk: 521 | return True 522 | 523 | def is_valid_vrf(self,device,vrf): 524 | if vrf_list.get(device): 525 | if vrf_list[device].get(vrf): 526 | return True 527 | 528 | def is_valid_ipaddress(self,ip_address_to_check): 529 | ip_address = IPNetwork(ip_address_to_check) 530 | if IPAddress(ip_address.ip) in IPNetwork(ip_address).iter_hosts(): 531 | return True 532 | 533 | def has_profile1_configured(self,device,interface): 534 | if interface_list[device][interface].get("Profile 1"): 535 | return True 536 | 537 | def has_profile2_configured(self,device,interface): 538 | if interface_list[device][interface].get("Profile 2"): 539 | return True 540 | 541 | def has_description_configured(self,device,interface): 542 | if interface_list[device][interface]["Description"]: 543 | return True 544 | 545 | def has_mtu_configured(self,device,interface): 546 | if interface_list[device][interface]["MTU (leave blank for default)"]: 547 | return True 548 | 549 | def has_vrf_configured(self,device,interface): 550 | if interface_list[device][interface]["VRF (leave blank if global)"]: 551 | return True 552 | 553 | def has_ip_configured(self,device,interface): 554 | if interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 555 | return True 556 | 557 | def has_nativevlan_configured(self,device,interface): 558 | if interface_list[device][interface]["Trunk Native VLAN"]: 559 | return True 560 | 561 | def has_speed_configured(self,device,interface): 562 | if interface_list[device][interface]["Speed"]: 563 | return True 564 | 565 | def has_duplex_configured(self,device,interface): 566 | if interface_list[device][interface]["Duplex"]: 567 | return True 568 | 569 | def has_importrt_configured(self,device,vrf): 570 | if vrf_list[device][vrf].get("Import RT (separated by commas)"): 571 | return True 572 | 573 | def has_exportrt_configured(self,device,vrf): 574 | if vrf_list[device][vrf].get("Export RT (separated by commas)"): 575 | return True 576 | 577 | def has_rd_configured(self,device,vrf): 578 | if vrf_list[device][vrf].get("RD"): 579 | return True 580 | 581 | 582 | 583 | # ------------------------------------------------------------------------------------- 584 | # Check each worksheet/row to make sure that the required information is present. 585 | # Otherwise the row will be removed from the database as it will be considered invalid 586 | # ------------------------------------------------------------------------------------- 587 | def RemoveEmptyRowsFromDB(self): 588 | 589 | db_required_columns = {key: [] for key in worksheet_list} 590 | #-------------------------------------------------------------------- 591 | # If the worksheet needs to have a valid column entry, define it below 592 | #-------------------------------------------------------------------- 593 | db_required_columns["variables"] = ["Variable", "Variable Value"] 594 | db_required_columns["profiles"]= ["Device Name","Profile"] 595 | db_required_columns["vrf"] = ["Device Name","VRF","RD"] 596 | db_required_columns["vlans"]= ["Device Name","VLAN No","VLAN Name"] 597 | db_required_columns["interfaces"]= ["Device Name","Interface"] 598 | db_required_columns["static routes"]= ["Device Name","Route (x.x.x.x/x)","Next Hop"] 599 | db_required_columns["portchannels"]= ["Device Name","Interface","Port-Channel Group","Port-Channel Mode (active/on/etc)","Port-Channel Type (layer2 or layer3)","Port-Channel Members (separated by commas)"] 600 | 601 | #-------------------------------------------- 602 | # Search for invalid rows and update database 603 | #-------------------------------------------- 604 | console = sys.__stdout__ 605 | sys.stdout = Logger("ccg-ignored.txt") 606 | for worksheet in worksheet_list: 607 | for entry in db_required_columns[worksheet]: 608 | temp_db = [] 609 | for row_no in range(len(raw_db[worksheet])): 610 | if not raw_db[worksheet][row_no][entry]: 611 | 612 | print ("[{}]-row:{} has empty cell value for column: {} (IGNORED)".format(worksheet,raw_db[worksheet][row_no]["Row"],entry)) 613 | continue 614 | if "$" in str(raw_db[worksheet][row_no][entry]): 615 | continue 616 | temp_db.append(raw_db[worksheet][row_no]) 617 | else: 618 | raw_db[worksheet] = temp_db 619 | sys.stdout = console 620 | 621 | #------------------------------------------------------------- 622 | # Functions to actually show the output of the configuration 623 | #------------------------------------------------------------- 624 | 625 | def CreateGlobalConfig(self,device_name): 626 | if not profile_list.get(device_name): 627 | return 628 | print ("!---------------------------------") 629 | print ("! Global configuration ") 630 | print ("!---------------------------------") 631 | for number, profile in enumerate(profile_list[device_name]): 632 | profile_name = profile_list[device_name][number] 633 | if self.GetConfigTemplate(profile_name): 634 | print ("\n! [{}]:".format(profile_name)) 635 | for line in self.GetConfigTemplate(profile_name): 636 | print ("{}".format(line)) 637 | elif self.GetVariable(profile_name): 638 | print ("\n! [{}]:".format(profile_name)) 639 | print ("{}".format(self.GetVariable(profile_name))) 640 | 641 | def CreateVlanConfig(self,device_name): 642 | if not vlan_list.get(device_name): 643 | return 644 | print ("!---------------------------------") 645 | print ("! VLAN configuration ") 646 | print ("!---------------------------------") 647 | for vlan in sorted(vlan_list[device_name]): 648 | print ("vlan {}".format(vlan)) 649 | print (" name {}".format(vlan_list[device_name].get(vlan))) 650 | 651 | def CreateVrfConfig(self,device_name): 652 | if not vrf_list.get(device_name): 653 | return 654 | print ("!---------------------------------") 655 | print ("! VRF configuration ") 656 | print ("!---------------------------------") 657 | for vrf in sorted(vrf_list[device_name]): 658 | print ("ip vrf {}".format(vrf)) 659 | if self.has_rd_configured(device_name,vrf): 660 | print (" rd {}".format(vrf_list[device_name][vrf]["RD"])) 661 | if self.has_importrt_configured(device_name,vrf): 662 | for route_target in vrf_list[device_name][vrf]["Import RT (separated by commas)"]: 663 | print (" route-target import {}".format(route_target)) 664 | if self.has_exportrt_configured(device_name,vrf): 665 | for route_target in vrf_list[device_name][vrf]["Export RT (separated by commas)"]: 666 | print (" route-target export {}".format(route_target)) 667 | if vrf_list[device_name][vrf]["Profile"]: 668 | if self.is_valid_variable(vrf_list[device_name][vrf]["Profile"]): 669 | print (self.GetVariable(vrf_list[device_name][vrf]["Profile"])) 670 | 671 | 672 | def CreateStaticRouteConfig(self,device_name): 673 | if not static_route_list.get(device_name): 674 | return 675 | print ("!---------------------------------") 676 | print ("! Static routing configuration ") 677 | print ("!---------------------------------") 678 | for route in sorted(static_route_list[device_name]): 679 | route_vrf = static_route_list[device_name][route]["VRF (leave blank if global)"] 680 | route_entry = static_route_list[device_name][route]["Route"] 681 | route_subnet = static_route_list[device_name][route]["Subnet"] 682 | route_nexthop = static_route_list[device_name][route]["Next Hop"] 683 | route_name = static_route_list[device_name][route]["Route Name (no spaces)"] 684 | 685 | if route_entry: 686 | if route_vrf and route_subnet and route_nexthop and route_name: 687 | print ("ip route vrf {} {} {} name {}".format(route_vrf,route_entry,route_subnet,route_name)) 688 | elif route_vrf and route_subnet and route_nexthop: 689 | print ("ip route vrf {} {} {}".format(route_vrf,route_entry,route_subnet)) 690 | elif route_subnet and route_nexthop and route_name: 691 | print ("ip route {} {} {} name {}".format(route_entry,route_subnet,route_nexthop,route_name)) 692 | elif route_subnet and route_nexthop: 693 | print ("ip route {} {} {}".format(route_entry,route_subnet,route_nexthop)) 694 | 695 | def CreatePrefixConfig(self,device_name): 696 | if not prefix_list.get(device_name): 697 | return 698 | print ("!---------------------------------") 699 | print ("! Prefix-list configuration ") 700 | print ("!---------------------------------") 701 | 702 | for prefix_name in sorted(prefix_list[device_name]): 703 | oldlist = prefix_list[device_name][prefix_name] 704 | newlist = sorted(oldlist, key=itemgetter('sequence')) 705 | for entry in newlist: 706 | pl_sequence = entry["sequence"] 707 | pl_action = entry["action"] 708 | pl_entry = entry["entry"] 709 | print ("ip prefix-list {} seq {} {} {}".format(prefix_name,pl_sequence,pl_action,pl_entry)) 710 | else: 711 | print ("!") 712 | 713 | def CreateInterfaceConfig(self,device_name,config_mode): 714 | if not interface_list.get(device_name): 715 | return 716 | first_match = True 717 | for interface in sorted(interface_list[device_name]): 718 | if config_mode == "Physical": 719 | if not self.GetInterfaceType(interface) == "Physical": 720 | continue 721 | elif config_mode == "Logical": 722 | if not self.GetInterfaceType(interface) == "Logical": 723 | continue 724 | if (first_match and "Physical" in config_mode): 725 | print ("!--------------------------------------------") 726 | print ("! Interface configuration (Physical) ") 727 | print ("!--------------------------------------------") 728 | elif (first_match and "Logical" in config_mode): 729 | print ("!--------------------------------------------") 730 | print ("! Interface configuration (Logical) ") 731 | print ("!--------------------------------------------") 732 | first_match = False 733 | 734 | if self.is_portchannel_member(device_name,interface): 735 | pc_type = interface_list[device_name][interface]["PC-Type"] 736 | if "layer2" in pc_type: 737 | print ("!....................................") 738 | print ("! Layer 2 PC: create physical first") 739 | print ("!....................................") 740 | elif "layer3" in pc_type: 741 | print ("!....................................") 742 | print ("! Layer 3 PC: create logical first") 743 | print ("!....................................") 744 | # --------------------------------------------------- 745 | # Start generating interface specific configuration 746 | # --------------------------------------------------- 747 | print ("interface {}".format(interface_list[device_name][interface]["Interface"])) 748 | 749 | if self.is_portchannel_parent(device_name,interface): 750 | pc_members = interface_list[device_name][interface]["PC-Members"] 751 | print (" !- pc members: {}".format(", ".join(pc_members))) 752 | if self.is_switch_port(device_name,interface): 753 | print (" switchport") 754 | if self.is_routed_port(device_name,interface): 755 | print (" no switchport") 756 | if self.has_description_configured(device_name,interface): 757 | print (" description {}".format(interface_list[device_name][interface]["Description"])) 758 | if self.has_mtu_configured(device_name,interface): 759 | print (" mtu {}".format(interface_list[device_name][interface]["MTU (leave blank for default)"])) 760 | if self.has_vrf_configured(device_name,interface): 761 | print (" ip vrf forwarding {}".format(interface_list[device_name][interface]["VRF (leave blank if global)"])) 762 | if self.has_ip_configured(device_name,interface): 763 | print (" ip address {}".format(self.GetIP(interface_list[device_name][interface]["IP Address (x.x.x.x/x)"]))) 764 | if self.is_trunk_port(device_name,interface): 765 | trunk_vlans = interface_list[device_name][interface]["Trunk Allowed VLANs (separated by commas)"] 766 | print (" switchport mode trunk") 767 | print (" switchport trunk allowed vlan {}".format(trunk_vlans)) 768 | if self.has_nativevlan_configured(device_name,interface): 769 | native_vlan = interface_list[device_name][interface]["Trunk Native VLAN"] 770 | print (" switchport trunk native vlan {}".format(native_vlan)) 771 | if self.is_data_port(device_name,interface): 772 | print (" switchport access vlan {}".format(interface_list[device_name][interface]["Data VLAN"])) 773 | if self.is_voice_port(device_name,interface): 774 | print (" switchport voice vlan {}".format(interface_list[device_name][interface]["Voice VLAN"])) 775 | if self.is_portchannel_member(device_name,interface): 776 | pc_group = interface_list[device_name][interface]["PC-Group"] 777 | pc_mode = interface_list[device_name][interface]["PC-Mode"] 778 | print (" channel-group {} mode {}".format(pc_group,pc_mode)) 779 | if self.has_profile1_configured(device_name,interface): 780 | if self.GetVariable(interface_list[device_name][interface]["Profile 1"]): 781 | print (self.GetVariable(interface_list[device_name][interface]["Profile 1"])) 782 | if self.has_profile2_configured(device_name,interface): 783 | if self.GetVariable(interface_list[device_name][interface]["Profile 2"]): 784 | print (self.GetVariable(interface_list[device_name][interface]["Profile 2"])) 785 | if self.has_speed_configured(device_name,interface): 786 | print (" speed {}".format(interface_list[device_name][interface]["Speed"])) 787 | if self.has_duplex_configured(device_name,interface): 788 | print (" duplex {}".format(interface_list[device_name][interface]["Duplex"])) 789 | if self.is_interface_enabled(device_name,interface): 790 | print (" no shutdown") 791 | else: 792 | print (" shutdown") 793 | else: 794 | print ("!") 795 | 796 | 797 | def GenerateConfig(self): 798 | global device_list 799 | console = sys.__stdout__ 800 | for device in device_list: 801 | sys.stdout = Logger(device+".txt") 802 | print ("****************************************") 803 | print ("! Device configuration for {}".format(device)) 804 | print ("****************************************") 805 | self.CreateGlobalConfig(device) 806 | self.CreateVrfConfig(device) 807 | self.CreateVlanConfig(device) 808 | self.CreateInterfaceConfig(device,"Physical") 809 | self.CreateInterfaceConfig(device,"Logical") 810 | self.CreatePrefixConfig(device) 811 | self.CreateStaticRouteConfig(device) 812 | sys.stdout = console 813 | 814 | def CheckInterfacesForErrors(self): 815 | for device in interface_list: 816 | for interface in sorted(interface_list[device]): 817 | if self.is_routed_port(device,interface) and self.is_switch_port(device,interface): 818 | error_db["interfaces"].append("Row ({}): [{}] [{}] both routed and switchport config detected".format(interface_list[device][interface]["Row"],device,interface)) 819 | if self.has_profile1_configured(device,interface): 820 | if not self.GetVariable(interface_list[device][interface]["Profile 1"]): 821 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Profile 1"])) 822 | if self.has_profile2_configured(device,interface): 823 | if not self.GetVariable(interface_list[device][interface]["Profile 2"]): 824 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Profile 2"])) 825 | if self.is_data_port(device,interface): 826 | if not self.is_valid_vlan(device,interface_list[device][interface]["Data VLAN"]): 827 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Data VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 828 | if self.is_voice_port(device,interface): 829 | if not self.is_valid_vlan(device,interface_list[device][interface]["Voice VLAN"]): 830 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Voice VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 831 | if self.has_nativevlan_configured(device,interface): 832 | if not self.is_valid_vlan(device,interface_list[device][interface]["Trunk Native VLAN"]): 833 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Native VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Trunk Native VLAN"])) 834 | if self.has_vrf_configured(device,interface): 835 | if not self.is_valid_vrf(device,interface_list[device][interface]["VRF (leave blank if global)"]): 836 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced vrf '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["VRF (leave blank if global)"])) 837 | if self.has_ip_configured(device,interface): 838 | if not self.is_valid_ipaddress(interface_list[device][interface]["IP Address (x.x.x.x/x)"]): 839 | error_db["interfaces"].append("Row ({}): [{}] [{}] using IPAddr '{}' which is invalid".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["IP Address (x.x.x.x/x)"])) 840 | if self.is_trunk_port(device,interface): 841 | if not self.is_valid_trunk(device,interface): 842 | error_db["interfaces"].append("Row ({}): [{}] [{}] one or more vlans referenced in trunk do not exist".format(interface_list[device][interface]["Row"],device,interface)) 843 | 844 | def GenerateErrorReport(self): 845 | console = sys.__stdout__ 846 | sys.stdout = Logger("ccg-errors.txt") 847 | 848 | if error_db["profiles"]: 849 | print ("===========================") 850 | print ("Worksheet: [profiles]") 851 | print ("===========================") 852 | for entry in error_db["profiles"]: 853 | print (entry) 854 | 855 | if error_db["config-templates"]: 856 | print ("===========================") 857 | print ("Worksheet: [config-templates]") 858 | print ("===========================") 859 | for entry in error_db["config-templates"]: 860 | print (entry) 861 | 862 | if error_db["interfaces"]: 863 | print ("===========================") 864 | print ("Worksheet: [interfaces]") 865 | print ("===========================") 866 | for entry in error_db["interfaces"]: 867 | print (entry) 868 | sys.stdout = console 869 | 870 | def StartCode(): 871 | #-------------------------------------------------------------------------------------------------------- 872 | # Execute the code 873 | #-------------------------------------------------------------------------------------------------------- 874 | db = Config() # Read the build spreadsheet and build the raw database 875 | db.RemoveEmptyRowsFromDB() # Clean up the database and remove rows that don't have required columns 876 | #-------------------------------------------------------------------------------------------------------- 877 | db.GetDeviceList() # Scan through all the worksheets and capture a list of unique devices names 878 | db.GetVlanList() # Scan through the vlan worksheet and capture a list of vlans per device 879 | db.GetVariableList() # Scan through the variable worksheet and capture valid variables 880 | db.GetConfigTemplateList() # Scan through the "config-templates" worksheet and capture templates 881 | db.GetProfileList() # Scan through the "profiles" worksheet and capture which proilfes are used 882 | db.GetVrfList() # Scan through the "vrf" worksheet and capture the VRFs 883 | db.GetInterfaceList() # Scan through the "interfaces" worksheet and capture interfaces 884 | db.GetStaticRouteList() # Scan through the "static routes" worksheet and capture routes 885 | db.GetPrefixList() # Scan through the "prefix-list" worksheet and capture prefix-lists 886 | db.GetPortChannelList() # Scan through the "portchannels" worksheet and capture all the portchannels 887 | #-------------------------------------------------------------------------------------------------------- 888 | db.CheckInterfacesForErrors() 889 | #-------------------------------------------------------------------------------------------------------- 890 | db.GenerateConfig() # Generate the actual configuration 891 | db.GenerateErrorReport() 892 | #-------------------------------------------------------------------------------------------------------- 893 | print ("Complete") 894 | 895 | #filename = "build.xlsx" 896 | #StartCode() 897 | 898 | #--------------- 899 | # Show the menu 900 | #--------------- 901 | def main(argv): 902 | arg_length = len(sys.argv) 903 | if arg_length < 2: 904 | print ("============================================================") 905 | print ("Cisco Config Generator %s"%__version__) 906 | print ("============================================================") 907 | print ("Usage: %s "%sys.argv[0]) 908 | exit() 909 | if sys.argv[1]: 910 | global filename 911 | filename = sys.argv[1] 912 | try: 913 | workbook = xlrd.open_workbook(filename) 914 | StartCode() 915 | except IOError: 916 | print ("Unable to open: %s"% sys.argv[1]) 917 | print ("Program aborted.") 918 | exit() 919 | 920 | if __name__ == '__main__': 921 | main(sys.argv) 922 | 923 | 924 | 925 | 926 | -------------------------------------------------------------------------------- /v2.1/build-v2.1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdulkcode/CiscoConfigGenerator/650278f7210937fd9d1f66a834cf4d9806430c90/v2.1/build-v2.1.xlsx -------------------------------------------------------------------------------- /v2.1/ccg-v2.1.py: -------------------------------------------------------------------------------- 1 | import xlrd 2 | import re 3 | import sys 4 | from netaddr import * 5 | from operator import itemgetter 6 | 7 | __author__ = 'Abdul Karim El-Assaad' 8 | __version__ = '(CCG) Version: 2.1 BETA (25/9/2014)' # Cisco Config Generator version 9 | 10 | error_db = {} 11 | 12 | raw_db = {} # Stores all the raw data from the build spreadsheet 13 | device_list = [] # Stores the valid device list from raw_db 14 | worksheet_list = [] # Stores the names of all worksheets in the build spreadsheet 15 | column_list = {} 16 | 17 | # Create a unique global dictionary for each worksheet 18 | config_templates = {} # Stores the config templates from raw_db 19 | variable_list = {} # Stores the valid variables from raw_db 20 | profile_list = {} # Stores the profiles from raw_db 21 | vlan_list = {} # Stores the valid vlans from raw_db 22 | vrf_list = {} # Stores the valid vrfs from raw_db 23 | interface_list = {} # Stores the layer2 information from raw_db 24 | static_route_list = {} # Stores the routing information from raw_db 25 | prefix_list = {} # Stores the prefix-list information from raw_db 26 | portchannel_list = {} # Stores the port-channel list information from raw_db 27 | 28 | global filename 29 | 30 | ''' 31 | ============================================================================= 32 | How to add a new worksheet: 33 | * Create a new global dictionary or list (see above) 34 | * Update RemoveEmptyRowsFromDB() function to include the new required columns 35 | * Create a function called GetList 36 | * Create a function called CreateConfiguration 37 | ============================================================================= 38 | ''' 39 | 40 | #----------------------------------------- 41 | # Used to redirect output to a text file 42 | #----------------------------------------- 43 | class Logger(object): 44 | def __init__(self, filename="Default.log"): 45 | self.terminal = sys.stdout 46 | self.log = open(filename, "w") 47 | def write(self, message): 48 | #self.terminal.write(message) # Shows output to screen 49 | self.log.write(message) # Writes output to file 50 | 51 | #----------------------------------------- 52 | # Main class which has all the functions 53 | #----------------------------------------- 54 | class Config(object): 55 | def __init__(self): 56 | self.CreateRawDb() 57 | 58 | # ---------------------------------------------------------------------- 59 | # Read the content of the build spreadsheet into the raw_db dictionary 60 | # To access call: raw_db["worksheet_name"][row_number]["Column name"] 61 | # ---------------------------------------------------------------------- 62 | def CreateRawDb(self): 63 | wb = xlrd.open_workbook(filename) 64 | global raw_db 65 | global worksheet_list 66 | global device_list 67 | global column_list 68 | global error_db 69 | 70 | temp_db = [] 71 | 72 | for i, worksheet in enumerate(wb.sheets()): 73 | if worksheet.name == "Instructions": 74 | continue 75 | header_cells = worksheet.row(0) 76 | num_rows = worksheet.nrows - 1 77 | curr_row = 0 78 | header = [each.value for each in header_cells] 79 | column_list[worksheet.name] = header 80 | # Add a column that doesn't exist in the worksheet 81 | header.append("Row") 82 | #------------------------------------------------------------------------------------- 83 | # Iterate over each row in each worksheet and store the info in the raw_db dictionary 84 | #------------------------------------------------------------------------------------- 85 | while curr_row < num_rows: 86 | curr_row += 1 87 | row = [int(each.value) if isinstance(each.value, float) 88 | else each.value 89 | for each in worksheet.row(curr_row)] 90 | # Add the row number to each record 91 | row.append(curr_row+1) 92 | value_dict = dict(zip(header, row)) 93 | temp_db.append(value_dict) 94 | else: 95 | #print ("raw_db: added '{}'".format(worksheet.name)) 96 | raw_db[worksheet.name] = temp_db 97 | #--------------------------------------------------------------------- 98 | # Grab all the unique device worksheet names in the build spreadsheet 99 | #--------------------------------------------------------------------- 100 | worksheet_list.append(worksheet.name) 101 | error_db[worksheet.name] = [] 102 | 103 | #------------------------------------------------------------------------ 104 | # Re-initalise the temp_db database so it's ready for the next worksheet 105 | #------------------------------------------------------------------------ 106 | temp_db = [] 107 | 108 | #------------------------------------------------------------------------------------- 109 | # Read through raw_db and start storing relevant information in their global database 110 | #------------------------------------------------------------------------------------- 111 | 112 | #----------------------------------------------------------------------- 113 | # Create a database which contains a list devices from every worksheet 114 | #------------------------------------------------------------------------ 115 | def GetDeviceList(self): 116 | global device_list 117 | raw_devices = [] 118 | for worksheet in worksheet_list: 119 | for row,entry in enumerate(raw_db[worksheet]): 120 | if raw_db[worksheet][row].get("Device Name"): 121 | if "!" in raw_db[worksheet][row].get("Device Name"): 122 | continue 123 | value = raw_db[worksheet][row].get("Device Name","none") 124 | value = value.strip() 125 | if value not in raw_devices: 126 | raw_devices.append(value) 127 | device_list = sorted(raw_devices) 128 | 129 | 130 | #----------------------------------------------------------- 131 | # Create a database that contains the VLANs for each device 132 | #----------------------------------------------------------- 133 | def GetVlanList(self): 134 | global vlan_list 135 | for row_no in range(len(raw_db["vlans"])): 136 | device_name = raw_db["vlans"][row_no]["Device Name"] 137 | if vlan_list.get(device_name): 138 | continue 139 | else: 140 | vlan_list[device_name] = {} 141 | for row_no in range(len(raw_db["vlans"])): 142 | device_name = raw_db["vlans"][row_no]["Device Name"] 143 | vlan_no = raw_db["vlans"][row_no]["VLAN No"] 144 | vlan_name = raw_db["vlans"][row_no]["VLAN Name"] 145 | vlan_list[device_name][vlan_no] = vlan_name 146 | 147 | #----------------------------------------------------------- 148 | # Create a database that contains the VRFs for each device 149 | #----------------------------------------------------------- 150 | def GetVrfList(self): 151 | global vrf_list 152 | for row_no in range(len(raw_db["vrf"])): 153 | vrf_columns = {key: [] for key in column_list["vrf"]} 154 | device_name = raw_db["vrf"][row_no]["Device Name"] 155 | vrf = raw_db["vrf"][row_no]["VRF"] 156 | if not vrf_list.get(device_name): 157 | vrf_list[device_name] = {} 158 | if not vrf_list[device_name].get(vrf): 159 | vrf_list[device_name][vrf] = vrf_columns 160 | for column in vrf_columns: 161 | vrf_list[device_name][vrf][column] = raw_db["vrf"][row_no][column] 162 | # If there are multiple route-targets grab them all 163 | current_import = vrf_list[device_name][vrf]["Import RT (separated by commas)"] 164 | current_import = current_import.strip() 165 | current_import = current_import.replace(" ","") 166 | current_export = vrf_list[device_name][vrf]["Export RT (separated by commas)"] 167 | current_export = current_export.strip() 168 | current_export = current_export.replace(" ","") 169 | new_import = current_import.split(",") 170 | new_export = current_export.split(",") 171 | vrf_list[device_name][vrf]["Import RT (separated by commas)"] = new_import 172 | vrf_list[device_name][vrf]["Export RT (separated by commas)"] = new_export 173 | 174 | #------------------------------------------------------------------ 175 | # Create a database that contains the interfaces for each device 176 | #------------------------------------------------------------------ 177 | def GetInterfaceList(self): 178 | global interface_list 179 | for row_no in range(len(raw_db["interfaces"])): 180 | interface_columns = {key: [] for key in column_list["interfaces"]} 181 | device_name = raw_db["interfaces"][row_no]["Device Name"] 182 | port = raw_db["interfaces"][row_no]["Interface"] 183 | if not interface_list.get(device_name): 184 | interface_list[device_name] = {} 185 | if not interface_list[device_name].get(port): 186 | interface_list[device_name][port] = interface_columns 187 | for column in interface_columns: 188 | interface_list[device_name][port][column] = raw_db["interfaces"][row_no][column] 189 | self.AddInterface(device_name,port,True) 190 | 191 | #------------------------------------------------------------------- 192 | # Create a database that contains the static routes for each device 193 | #------------------------------------------------------------------- 194 | def GetStaticRouteList(self): 195 | global static_route_list 196 | for row_no in range(len(raw_db["static routes"])): 197 | static_route_columns = {key: [] for key in column_list["static routes"]} 198 | device_name = raw_db["static routes"][row_no]["Device Name"] 199 | route = raw_db["static routes"][row_no]["Route (x.x.x.x/x)"] 200 | if not static_route_list.get(device_name): 201 | static_route_list[device_name] = {} 202 | if not static_route_list[device_name].get(route): 203 | static_route_list[device_name][route] = static_route_columns 204 | for column in static_route_columns: 205 | static_route_list[device_name][route][column] = raw_db["static routes"][row_no][column] 206 | 207 | new_route = IPNetwork(route) 208 | static_route_list[device_name][route]["Route"] = str(new_route.ip) 209 | static_route_list[device_name][route]["Subnet"] = str(new_route.netmask) 210 | 211 | 212 | def GetPrefixList(self): 213 | global prefix_list 214 | for row_no in range(len(raw_db["prefix-list"])): 215 | device_name = raw_db["prefix-list"][row_no]["Device Name"] 216 | prefix_name = raw_db["prefix-list"][row_no]["Prefix-List Name"] 217 | prefix_seq = raw_db["prefix-list"][row_no]["Prefix-List Sequence No"] 218 | prefix_action = raw_db["prefix-list"][row_no]["Prefix-List Action (permit/deny)"] 219 | prefix_entry = raw_db["prefix-list"][row_no]["Prefix-List Entry"] 220 | if not prefix_list.get(device_name): 221 | prefix_list[device_name] = {} 222 | if not prefix_list[device_name].get(prefix_name): 223 | temp_list = [] 224 | prefix_list[device_name][prefix_name] = temp_list 225 | temp_db = {"sequence":"","action":"","entry":""} 226 | prefix_list[device_name][prefix_name].append(temp_db) 227 | prefix_list[device_name][prefix_name][0]["sequence"] = prefix_seq 228 | prefix_list[device_name][prefix_name][0]["action"] = prefix_action 229 | prefix_list[device_name][prefix_name][0]["entry"] = prefix_entry 230 | elif not self.GetPrefixSeqNo(device_name,prefix_name,prefix_seq): 231 | list_no = len(prefix_list[device_name][prefix_name]) 232 | temp_db = {"sequence":"","action":"","entry":""} 233 | prefix_list[device_name][prefix_name].append(temp_db) 234 | prefix_list[device_name][prefix_name][list_no]["sequence"] = prefix_seq 235 | prefix_list[device_name][prefix_name][list_no]["action"] = prefix_action 236 | prefix_list[device_name][prefix_name][list_no]["entry"] = prefix_entry 237 | 238 | 239 | def GetPortChannelList(self): 240 | global portchannel_list 241 | for row_no in range(len(raw_db["portchannels"])): 242 | portchannel_column = {key: [] for key in column_list["portchannels"]} 243 | device_name = raw_db["portchannels"][row_no]["Device Name"] 244 | interface = raw_db["portchannels"][row_no]["Interface"] 245 | if not portchannel_list.get(device_name): 246 | portchannel_list[device_name] = {} 247 | if not portchannel_list[device_name].get(interface): 248 | portchannel_list[device_name][interface] = portchannel_column 249 | for column in portchannel_column: 250 | portchannel_list[device_name][interface][column] = raw_db["portchannels"][row_no][column] 251 | self.UpdatePortChannels() 252 | 253 | 254 | # Will iterate over the portchannel_list and try to add a new interface for each parent 255 | # or member interfaces. 256 | 257 | def UpdatePortChannels(self): 258 | for device_name in sorted(portchannel_list): 259 | for interface in sorted(portchannel_list[device_name]): 260 | 261 | pc_enabled = portchannel_list[device_name][interface]["Interface Enabled (yes/no)"] 262 | pc_group = portchannel_list[device_name][interface]["Port-Channel Group"] 263 | pc_mode = portchannel_list[device_name][interface]["Port-Channel Mode (active/on/etc)"] 264 | pc_type = portchannel_list[device_name][interface]["Port-Channel Type (layer2 or layer3)"] 265 | pc_members = portchannel_list[device_name][interface]["Port-Channel Members (separated by commas)"] 266 | pc_description = portchannel_list[device_name][interface]["Description"] 267 | 268 | self.AddInterface(device_name,interface) 269 | if pc_enabled: 270 | interface_list[device_name][interface]["Interface Enabled (yes/no)"] = pc_enabled 271 | if pc_description: 272 | interface_list[device_name][interface]["Description"] = pc_description 273 | 274 | for member in pc_members.split(","): 275 | member = member.strip() 276 | self.AddInterface(device_name,member) 277 | interface_list[device_name][member]["PC-Group"] = pc_group 278 | interface_list[device_name][member]["PC-Mode"] = pc_mode 279 | interface_list[device_name][member]["PC-Type"] = pc_type 280 | interface_list[device_name][interface]["PC-Members"].append(member) 281 | 282 | def GetVariableList(self): 283 | global variable_list 284 | for row_no in range(len(raw_db["variables"])): 285 | variable_name = raw_db["variables"][row_no]["Variable"] 286 | variable_value = raw_db["variables"][row_no]["Variable Value"] 287 | if "+" in variable_name: 288 | continue 289 | elif variable_name in variable_list: 290 | continue 291 | variable_list[variable_name] = variable_value 292 | 293 | def GetConfigTemplateList(self): 294 | global config_templates 295 | temp_list = [] 296 | for row_no in range(len(raw_db["config-templates"])): 297 | line = raw_db["config-templates"][row_no]["Enter config templates below this line:"] 298 | match = re.search(r'Config Template: \[(.*?)\]', line,re.IGNORECASE) 299 | if not line: 300 | continue 301 | if match: 302 | temp_list = [] 303 | config_templates[match.group(1)] = temp_list 304 | continue 305 | temp_list.append(line) 306 | 307 | # Cycle through each line of the config template to update dynamic variables 308 | for entry in config_templates: 309 | temp_list = [] 310 | for line in config_templates[entry]: 311 | match = re.findall(r'\[(.*?)\]', line) 312 | valid_variable = False 313 | if (match): 314 | for variable_name in match: 315 | lookup_variable = self.GetVariable(variable_name) 316 | if lookup_variable: 317 | valid_variable = True 318 | line = line.replace(variable_name,lookup_variable) 319 | else: 320 | error_db["config-templates"].append("Config-Template: '{}' referenced embedded variable '{}' which does not exist".format(entry,variable_name)) 321 | continue 322 | if (valid_variable): 323 | line = line.replace("[","") 324 | line = line.replace("]","") 325 | temp_list.append(line) 326 | config_templates[entry] = temp_list 327 | 328 | 329 | def GetProfileList(self): 330 | global profile_list 331 | global error_db 332 | for row_no in range(len(raw_db["profiles"])): 333 | device_name = raw_db["profiles"][row_no]["Device Name"] 334 | variable = raw_db["profiles"][row_no]["Template or Variable"] 335 | position = raw_db["profiles"][row_no]["Position (Default: Start)"] 336 | if not position: 337 | position = "Start" 338 | if not self.GetVariable(variable): 339 | if not self.GetConfigTemplate(variable): 340 | error_db["profiles"].append("Row ({}): Device '{}' referenced variable '{}' which does not exist".format(raw_db["profiles"][row_no]["Row"],device_name,variable)) 341 | continue 342 | 343 | # if device_name not in profile_list: 344 | # temp_list = [] 345 | # profile_list[device_name] = temp_list 346 | # profile_list[device_name].append(variable) 347 | 348 | if device_name not in profile_list: 349 | profile_temp = [] 350 | position_temp = [] 351 | profile_list[device_name] = {} 352 | profile_list[device_name]["Profile"] = profile_temp 353 | profile_list[device_name]["Position"] = position_temp 354 | profile_list[device_name]["Profile"].append(variable) 355 | profile_list[device_name]["Position"].append(position) 356 | 357 | 358 | #------------------------------------------- 359 | # Manual manipulation of one of the lists 360 | #------------------------------------------- 361 | ''' manual_entries will result in manual entries always being triggered. 362 | This will be created when: 363 | a) GetInterfaceList is called (i.e. reading the info from the interfaces tab 364 | b) UpdatePortChannels is called (i.e. only if new interface is detected) 365 | ''' 366 | def AddInterface(self,device_name,interface,manual_entries=False): 367 | global interface_list 368 | 369 | interface_columns = {key: [] for key in column_list["interfaces"]} 370 | if not interface_list.get(device_name): 371 | interface_list[device_name] = {} 372 | if not interface_list[device_name].get(interface): 373 | manual_entries = True 374 | interface_list[device_name][interface] = interface_columns 375 | 376 | # Any manual entries that are not directly from the spreadsheet below 377 | if manual_entries: 378 | error_list = [] 379 | member_list = [] 380 | interface_list[device_name][interface]["Errors"] = error_list 381 | interface_list[device_name][interface]["Interface"] = interface 382 | interface_list[device_name][interface]["PC-Group"] = "" 383 | interface_list[device_name][interface]["PC-Mode"] = "" 384 | interface_list[device_name][interface]["PC-Type"] = "" 385 | interface_list[device_name][interface]["PC-Members"] = member_list 386 | interface_list[device_name][interface]["PC-Parent"] = "" 387 | 388 | # --------------------------------------------------- 389 | # Get specific values from their respective database 390 | # --------------------------------------------------- 391 | def GetVariable(self, variable_name): 392 | if variable_list.get(variable_name): 393 | return variable_list[variable_name] 394 | 395 | def GetVlan(self, device_to_find, vlan_to_find): 396 | if vlan_list[device_to_find].get(vlan_to_find): 397 | return vlan_list[device_to_find][vlan_to_find] 398 | 399 | def GetConfigTemplate(self, template_name): 400 | if config_templates.get(template_name): 401 | return config_templates[template_name] 402 | 403 | def GetPrefixSeqNo(self, device_name,prefix_name,sequence_number): 404 | global prefix_list 405 | if not prefix_list.get(device_name): 406 | return 407 | if not prefix_list[device_name].get(prefix_name): 408 | return 409 | for row, entry in enumerate(prefix_list[device_name][prefix_name]): 410 | if prefix_list[device_name][prefix_name][row]["sequence"] == sequence_number: 411 | return prefix_list[device_name][prefix_name][row] 412 | 413 | def GetIP(self,IP_address,mode="IOS"): 414 | if not IP_address: 415 | return 416 | if "/" not in IP_address: 417 | # Generate error message 418 | return IP_address 419 | if mode == "NXOS": 420 | string = ("{}".format(IP_address)) 421 | return string 422 | elif mode == "IOS": 423 | full_address = IPNetwork(IP_address) 424 | string = ("{} {}".format(full_address.ip,full_address.netmask)) 425 | return string 426 | 427 | def GetInterfaceType(self,interface): 428 | logical_interfaces = ["Po","Tu","Lo","Vl"] 429 | for type in logical_interfaces: 430 | if type in interface: 431 | return "Logical" 432 | return "Physical" 433 | 434 | def GetTrunkVlans(self,device,interface): 435 | if not interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 436 | return 437 | allowed_vlans_raw = interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"] 438 | allowed_vlans_raw = allowed_vlans_raw.replace(" ","") 439 | allowed_vlans_raw = allowed_vlans_raw.strip() 440 | allowed_vlans_raw = allowed_vlans_raw.split(",") 441 | allowed_vlans_new = [] 442 | 443 | for vlan in allowed_vlans_raw: 444 | if "-" not in vlan: 445 | allowed_vlans_new.append(vlan) 446 | elif "-" in vlan: 447 | vlan_range = [] 448 | for entry in vlan.split("-"): 449 | vlan_range.append(entry) 450 | vlan_range_start = int(vlan_range[0]) 451 | vlan_range_end = int(vlan_range[1]) 452 | 453 | while vlan_range_start <= vlan_range_end: 454 | allowed_vlans_new.append(vlan_range_start) 455 | vlan_range_start +=1 456 | return allowed_vlans_new 457 | 458 | # --------------------------------------------- 459 | # Check the interface for specific conditions 460 | # --------------------------------------------- 461 | def is_switch_port(self,device,interface): 462 | if interface_list[device][interface]["Data VLAN"]: 463 | return True 464 | elif interface_list[device][interface]["Voice VLAN"]: 465 | return True 466 | elif interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"]: 467 | return True 468 | elif "layer2" in interface_list[device][interface]["PC-Type"]: 469 | return True 470 | 471 | def is_routed_port(self,device,interface): 472 | if "Logical" in self.GetInterfaceType(interface): 473 | return False 474 | elif interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 475 | return True 476 | elif "layer3" in interface_list[device][interface]["PC-Type"]: 477 | return True 478 | 479 | def is_trunk_port(self,device,interface): 480 | if interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 481 | return True 482 | 483 | def is_data_port(self,device,interface): 484 | if interface_list[device][interface].get("Data VLAN"): 485 | return True 486 | 487 | def is_voice_port(self,device,interface): 488 | if interface_list[device][interface].get("Voice VLAN"): 489 | return True 490 | 491 | def is_interface_enabled(self,device,interface): 492 | if interface_list[device][interface]["Interface Enabled (yes/no)"]: 493 | if "yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 494 | return True 495 | if "Yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 496 | return True 497 | 498 | def is_portchannel_member(self,device,interface): 499 | if interface_list[device][interface]["PC-Group"]: 500 | return True 501 | 502 | def is_portchannel_parent(self,device,interface): 503 | if interface_list[device][interface]["PC-Members"]: 504 | return True 505 | 506 | def is_valid_portchannel(self,device,interface): 507 | if portchannel_list[device].get(interface): 508 | if interface_list[device][interface]: 509 | return True 510 | 511 | def is_valid_variable(self,variable_name): 512 | if variable_list.get(variable_name): 513 | return True 514 | 515 | def is_valid_vlan(self,device,vlan): 516 | if vlan_list.get(device): 517 | if vlan_list[device].get(int(vlan)): 518 | return True 519 | 520 | def is_valid_trunk(self,device,interface): 521 | if not self.is_trunk_port(device,interface): 522 | return False 523 | trunk_vlans = self.GetTrunkVlans(device,interface) 524 | valid_trunk = True 525 | for vlan in trunk_vlans: 526 | if not self.is_valid_vlan(device,vlan): 527 | valid_trunk = False 528 | if valid_trunk: 529 | return True 530 | 531 | def is_valid_vrf(self,device,vrf): 532 | if vrf_list.get(device): 533 | if vrf_list[device].get(vrf): 534 | return True 535 | 536 | def is_valid_ipaddress(self,ip_address_to_check): 537 | ip_address = IPNetwork(ip_address_to_check) 538 | if IPAddress(ip_address.ip) in IPNetwork(ip_address).iter_hosts(): 539 | return True 540 | 541 | def has_variable1_configured(self,device,interface): 542 | if interface_list[device][interface].get("Variable 1"): 543 | return True 544 | 545 | def has_variable2_configured(self,device,interface): 546 | if interface_list[device][interface].get("Variable 2"): 547 | return True 548 | 549 | def has_description_configured(self,device,interface): 550 | if interface_list[device][interface]["Description"]: 551 | return True 552 | 553 | def has_mtu_configured(self,device,interface): 554 | if interface_list[device][interface]["MTU"]: 555 | return True 556 | 557 | def has_vrf_configured(self,device,interface): 558 | if interface_list[device][interface]["VRF (leave blank if global)"]: 559 | return True 560 | 561 | def has_ip_configured(self,device,interface): 562 | if interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 563 | return True 564 | 565 | def has_nativevlan_configured(self,device,interface): 566 | if interface_list[device][interface]["Trunk Native VLAN"]: 567 | return True 568 | 569 | def has_speed_configured(self,device,interface): 570 | if interface_list[device][interface]["Speed"]: 571 | return True 572 | 573 | def has_duplex_configured(self,device,interface): 574 | if interface_list[device][interface]["Duplex"]: 575 | return True 576 | 577 | def has_importrt_configured(self,device,vrf): 578 | if vrf_list[device][vrf].get("Import RT (separated by commas)"): 579 | return True 580 | 581 | def has_exportrt_configured(self,device,vrf): 582 | if vrf_list[device][vrf].get("Export RT (separated by commas)"): 583 | return True 584 | 585 | def has_rd_configured(self,device,vrf): 586 | if vrf_list[device][vrf].get("RD"): 587 | return True 588 | 589 | 590 | 591 | # ------------------------------------------------------------------------------------- 592 | # Check each worksheet/row to make sure that the required information is present. 593 | # Otherwise the row will be removed from the database as it will be considered invalid 594 | # ------------------------------------------------------------------------------------- 595 | def RemoveEmptyRowsFromDB(self): 596 | 597 | db_required_columns = {key: [] for key in worksheet_list} 598 | #-------------------------------------------------------------------- 599 | # If the worksheet needs to have a valid column entry, define it below 600 | #-------------------------------------------------------------------- 601 | db_required_columns["variables"] = ["Variable", "Variable Value"] 602 | db_required_columns["profiles"]= ["Device Name","Template or Variable"] 603 | db_required_columns["vrf"] = ["Device Name","VRF","RD"] 604 | db_required_columns["vlans"]= ["Device Name","VLAN No","VLAN Name"] 605 | db_required_columns["interfaces"]= ["Device Name","Interface"] 606 | db_required_columns["static routes"]= ["Device Name","Route (x.x.x.x/x)","Next Hop"] 607 | db_required_columns["portchannels"]= ["Device Name","Interface","Port-Channel Group","Port-Channel Mode (active/on/etc)","Port-Channel Type (layer2 or layer3)","Port-Channel Members (separated by commas)"] 608 | 609 | #-------------------------------------------- 610 | # Search for invalid rows and update database 611 | #-------------------------------------------- 612 | console = sys.__stdout__ 613 | sys.stdout = Logger("ccg-ignored.txt") 614 | for worksheet in worksheet_list: 615 | for entry in db_required_columns[worksheet]: 616 | temp_db = [] 617 | for row_no in range(len(raw_db[worksheet])): 618 | if not raw_db[worksheet][row_no][entry]: 619 | 620 | print ("[{}]-row:{} has empty cell value for column: {} (IGNORED)".format(worksheet,raw_db[worksheet][row_no]["Row"],entry)) 621 | continue 622 | if "$" in str(raw_db[worksheet][row_no][entry]): 623 | continue 624 | temp_db.append(raw_db[worksheet][row_no]) 625 | else: 626 | raw_db[worksheet] = temp_db 627 | sys.stdout = console 628 | 629 | #------------------------------------------------------------- 630 | # Functions to actually show the output of the configuration 631 | #------------------------------------------------------------- 632 | 633 | def CreateGlobalConfig(self,device_name,config_position="Start"): 634 | if not profile_list.get(device_name): 635 | return 636 | 637 | print ("!---------------------------------") 638 | print ("! Global configuration ({}) ".format(config_position)) 639 | print ("!---------------------------------") 640 | for number, profile in enumerate(profile_list[device_name]["Profile"]): 641 | profile_name = profile_list[device_name]["Profile"][number] 642 | profile_position_type = profile_list[device_name]["Position"][number] 643 | if config_position not in profile_position_type: 644 | continue 645 | if self.GetConfigTemplate(profile_name): 646 | print ("\n! [{}]:".format(profile_name)) 647 | for line in self.GetConfigTemplate(profile_name): 648 | print ("{}".format(line)) 649 | elif self.GetVariable(profile_name): 650 | print ("\n! [{}]:".format(profile_name)) 651 | print ("{}".format(self.GetVariable(profile_name))) 652 | 653 | def CreateVlanConfig(self,device_name): 654 | if not vlan_list.get(device_name): 655 | return 656 | print ("!---------------------------------") 657 | print ("! VLAN configuration ") 658 | print ("!---------------------------------") 659 | for vlan in sorted(vlan_list[device_name]): 660 | print ("vlan {}".format(vlan)) 661 | print (" name {}".format(vlan_list[device_name].get(vlan))) 662 | 663 | def CreateVrfConfig(self,device_name): 664 | if not vrf_list.get(device_name): 665 | return 666 | print ("!---------------------------------") 667 | print ("! VRF configuration ") 668 | print ("!---------------------------------") 669 | for vrf in sorted(vrf_list[device_name]): 670 | print ("ip vrf {}".format(vrf)) 671 | if self.has_rd_configured(device_name,vrf): 672 | print (" rd {}".format(vrf_list[device_name][vrf]["RD"])) 673 | if self.has_importrt_configured(device_name,vrf): 674 | for route_target in vrf_list[device_name][vrf]["Import RT (separated by commas)"]: 675 | print (" route-target import {}".format(route_target)) 676 | if self.has_exportrt_configured(device_name,vrf): 677 | for route_target in vrf_list[device_name][vrf]["Export RT (separated by commas)"]: 678 | print (" route-target export {}".format(route_target)) 679 | if vrf_list[device_name][vrf]["Variable"]: 680 | if self.is_valid_variable(vrf_list[device_name][vrf]["Variable"]): 681 | print (self.GetVariable(vrf_list[device_name][vrf]["Variable"])) 682 | 683 | 684 | def CreateStaticRouteConfig(self,device_name): 685 | if not static_route_list.get(device_name): 686 | return 687 | print ("!---------------------------------") 688 | print ("! Static routing configuration ") 689 | print ("!---------------------------------") 690 | for route in sorted(static_route_list[device_name]): 691 | route_vrf = static_route_list[device_name][route]["VRF (leave blank if global)"] 692 | route_entry = static_route_list[device_name][route]["Route"] 693 | route_subnet = static_route_list[device_name][route]["Subnet"] 694 | route_nexthop = static_route_list[device_name][route]["Next Hop"] 695 | route_name = static_route_list[device_name][route]["Route Name (no spaces)"] 696 | 697 | if route_entry: 698 | if route_vrf and route_subnet and route_nexthop and route_name: 699 | print ("ip route vrf {} {} {} name {}".format(route_vrf,route_entry,route_subnet,route_name)) 700 | elif route_vrf and route_subnet and route_nexthop: 701 | print ("ip route vrf {} {} {}".format(route_vrf,route_entry,route_subnet)) 702 | elif route_subnet and route_nexthop and route_name: 703 | print ("ip route {} {} {} name {}".format(route_entry,route_subnet,route_nexthop,route_name)) 704 | elif route_subnet and route_nexthop: 705 | print ("ip route {} {} {}".format(route_entry,route_subnet,route_nexthop)) 706 | 707 | def CreatePrefixConfig(self,device_name): 708 | if not prefix_list.get(device_name): 709 | return 710 | print ("!---------------------------------") 711 | print ("! Prefix-list configuration ") 712 | print ("!---------------------------------") 713 | 714 | for prefix_name in sorted(prefix_list[device_name]): 715 | oldlist = prefix_list[device_name][prefix_name] 716 | newlist = sorted(oldlist, key=itemgetter('sequence')) 717 | for entry in newlist: 718 | pl_sequence = entry["sequence"] 719 | pl_action = entry["action"] 720 | pl_entry = entry["entry"] 721 | print ("ip prefix-list {} seq {} {} {}".format(prefix_name,pl_sequence,pl_action,pl_entry)) 722 | else: 723 | print ("!") 724 | 725 | def CreateInterfaceConfig(self,device_name,config_mode): 726 | if not interface_list.get(device_name): 727 | return 728 | first_match = True 729 | for interface in sorted(interface_list[device_name]): 730 | if config_mode == "Physical": 731 | if not self.GetInterfaceType(interface) == "Physical": 732 | continue 733 | elif config_mode == "Logical": 734 | if not self.GetInterfaceType(interface) == "Logical": 735 | continue 736 | if (first_match and "Physical" in config_mode): 737 | print ("!--------------------------------------------") 738 | print ("! Interface configuration (Physical) ") 739 | print ("!--------------------------------------------") 740 | elif (first_match and "Logical" in config_mode): 741 | print ("!--------------------------------------------") 742 | print ("! Interface configuration (Logical) ") 743 | print ("!--------------------------------------------") 744 | first_match = False 745 | 746 | if self.is_portchannel_member(device_name,interface): 747 | pc_type = interface_list[device_name][interface]["PC-Type"] 748 | if "layer2" in pc_type: 749 | print ("!....................................") 750 | print ("! Layer 2 PC: create physical first") 751 | print ("!....................................") 752 | elif "layer3" in pc_type: 753 | print ("!....................................") 754 | print ("! Layer 3 PC: create logical first") 755 | print ("!....................................") 756 | # --------------------------------------------------- 757 | # Start generating interface specific configuration 758 | # --------------------------------------------------- 759 | print ("interface {}".format(interface_list[device_name][interface]["Interface"])) 760 | 761 | if self.is_portchannel_parent(device_name,interface): 762 | pc_members = interface_list[device_name][interface]["PC-Members"] 763 | print (" !- pc members: {}".format(", ".join(pc_members))) 764 | if self.is_switch_port(device_name,interface): 765 | print (" switchport") 766 | if self.is_routed_port(device_name,interface): 767 | print (" no switchport") 768 | if self.has_description_configured(device_name,interface): 769 | print (" description {}".format(interface_list[device_name][interface]["Description"])) 770 | if self.has_mtu_configured(device_name,interface): 771 | print (" mtu {}".format(interface_list[device_name][interface]["MTU"])) 772 | if self.has_vrf_configured(device_name,interface): 773 | print (" ip vrf forwarding {}".format(interface_list[device_name][interface]["VRF (leave blank if global)"])) 774 | if self.has_ip_configured(device_name,interface): 775 | print (" ip address {}".format(self.GetIP(interface_list[device_name][interface]["IP Address (x.x.x.x/x)"]))) 776 | if self.is_trunk_port(device_name,interface): 777 | trunk_vlans = interface_list[device_name][interface]["Trunk Allowed VLANs (separated by commas)"] 778 | print (" switchport mode trunk") 779 | print (" switchport trunk allowed vlan {}".format(trunk_vlans)) 780 | if self.has_nativevlan_configured(device_name,interface): 781 | native_vlan = interface_list[device_name][interface]["Trunk Native VLAN"] 782 | print (" switchport trunk native vlan {}".format(native_vlan)) 783 | if self.is_data_port(device_name,interface): 784 | print (" switchport access vlan {}".format(interface_list[device_name][interface]["Data VLAN"])) 785 | if self.is_voice_port(device_name,interface): 786 | print (" switchport voice vlan {}".format(interface_list[device_name][interface]["Voice VLAN"])) 787 | if self.is_portchannel_member(device_name,interface): 788 | pc_group = interface_list[device_name][interface]["PC-Group"] 789 | pc_mode = interface_list[device_name][interface]["PC-Mode"] 790 | print (" channel-group {} mode {}".format(pc_group,pc_mode)) 791 | if self.has_variable1_configured(device_name,interface): 792 | if self.is_valid_variable(interface_list[device_name][interface]["Variable 1"]): 793 | print (self.GetVariable(interface_list[device_name][interface]["Variable 1"])) 794 | if self.has_variable2_configured(device_name,interface): 795 | if self.is_valid_variable(interface_list[device_name][interface]["Variable 2"]): 796 | print (self.GetVariable(interface_list[device_name][interface]["Variable 2"])) 797 | if self.has_speed_configured(device_name,interface): 798 | print (" speed {}".format(interface_list[device_name][interface]["Speed"])) 799 | if self.has_duplex_configured(device_name,interface): 800 | print (" duplex {}".format(interface_list[device_name][interface]["Duplex"])) 801 | if self.is_interface_enabled(device_name,interface): 802 | print (" no shutdown") 803 | else: 804 | print (" shutdown") 805 | else: 806 | print ("!") 807 | 808 | 809 | def GenerateConfig(self): 810 | global device_list 811 | console = sys.__stdout__ 812 | print ("Generating configuration....") 813 | for device in device_list: 814 | sys.stdout = Logger(device+".txt") 815 | print ("****************************************") 816 | print ("! Device configuration for {}".format(device)) 817 | print ("****************************************") 818 | self.CreateGlobalConfig(device,"Start") 819 | self.CreateVrfConfig(device) 820 | self.CreateVlanConfig(device) 821 | self.CreateInterfaceConfig(device,"Physical") 822 | self.CreateInterfaceConfig(device,"Logical") 823 | self.CreatePrefixConfig(device) 824 | self.CreateStaticRouteConfig(device) 825 | self.CreateGlobalConfig(device,"End") 826 | sys.stdout = console 827 | print ("- {} configuration generated.".format(device)) 828 | 829 | def CheckInterfacesForErrors(self): 830 | for device in interface_list: 831 | for interface in sorted(interface_list[device]): 832 | if self.is_routed_port(device,interface) and self.is_switch_port(device,interface): 833 | error_db["interfaces"].append("Row ({}): [{}] [{}] both routed and switchport config detected".format(interface_list[device][interface]["Row"],device,interface)) 834 | if self.has_variable1_configured(device,interface): 835 | if not self.GetVariable(interface_list[device][interface]["Variable 1"]): 836 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Variable 1"])) 837 | if self.has_variable2_configured(device,interface): 838 | if not self.GetVariable(interface_list[device][interface]["Variable 2"]): 839 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Variable 2"])) 840 | if self.is_data_port(device,interface): 841 | if not self.is_valid_vlan(device,interface_list[device][interface]["Data VLAN"]): 842 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Data VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 843 | if self.is_voice_port(device,interface): 844 | if not self.is_valid_vlan(device,interface_list[device][interface]["Voice VLAN"]): 845 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Voice VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 846 | if self.has_nativevlan_configured(device,interface): 847 | if not self.is_valid_vlan(device,interface_list[device][interface]["Trunk Native VLAN"]): 848 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Native VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Trunk Native VLAN"])) 849 | if self.has_vrf_configured(device,interface): 850 | if not self.is_valid_vrf(device,interface_list[device][interface]["VRF (leave blank if global)"]): 851 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced vrf '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["VRF (leave blank if global)"])) 852 | if self.has_ip_configured(device,interface): 853 | if not self.is_valid_ipaddress(interface_list[device][interface]["IP Address (x.x.x.x/x)"]): 854 | error_db["interfaces"].append("Row ({}): [{}] [{}] using IPAddr '{}' which is invalid".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["IP Address (x.x.x.x/x)"])) 855 | if self.is_trunk_port(device,interface): 856 | if not self.is_valid_trunk(device,interface): 857 | error_db["interfaces"].append("Row ({}): [{}] [{}] one or more vlans referenced in trunk do not exist".format(interface_list[device][interface]["Row"],device,interface)) 858 | 859 | def GenerateErrorReport(self): 860 | console = sys.__stdout__ 861 | sys.stdout = Logger("ccg-errors.txt") 862 | 863 | if error_db["profiles"]: 864 | print ("===========================") 865 | print ("Worksheet: [profiles]") 866 | print ("===========================") 867 | for entry in error_db["profiles"]: 868 | print (entry) 869 | 870 | if error_db["config-templates"]: 871 | print ("===========================") 872 | print ("Worksheet: [config-templates]") 873 | print ("===========================") 874 | for entry in error_db["config-templates"]: 875 | print (entry) 876 | 877 | if error_db["interfaces"]: 878 | print ("===========================") 879 | print ("Worksheet: [interfaces]") 880 | print ("===========================") 881 | for entry in error_db["interfaces"]: 882 | print (entry) 883 | sys.stdout = console 884 | 885 | def StartCode(): 886 | #-------------------------------------------------------------------------------------------------------- 887 | # Execute the code 888 | #-------------------------------------------------------------------------------------------------------- 889 | db = Config() # Read the build spreadsheet and build the raw database 890 | db.RemoveEmptyRowsFromDB() # Clean up the database and remove rows that don't have required columns 891 | #-------------------------------------------------------------------------------------------------------- 892 | db.GetDeviceList() # Scan through all the worksheets and capture a list of unique devices names 893 | db.GetVlanList() # Scan through the vlan worksheet and capture a list of vlans per device 894 | db.GetVariableList() # Scan through the variable worksheet and capture valid variables 895 | db.GetConfigTemplateList() # Scan through the "config-templates" worksheet and capture templates 896 | db.GetProfileList() # Scan through the "profiles" worksheet and capture which proilfes are used 897 | db.GetVrfList() # Scan through the "vrf" worksheet and capture the VRFs 898 | db.GetInterfaceList() # Scan through the "interfaces" worksheet and capture interfaces 899 | db.GetStaticRouteList() # Scan through the "static routes" worksheet and capture routes 900 | db.GetPrefixList() # Scan through the "prefix-list" worksheet and capture prefix-lists 901 | db.GetPortChannelList() # Scan through the "portchannels" worksheet and capture all the portchannels 902 | #-------------------------------------------------------------------------------------------------------- 903 | db.CheckInterfacesForErrors() 904 | #-------------------------------------------------------------------------------------------------------- 905 | db.GenerateConfig() # Generate the actual configuration 906 | db.GenerateErrorReport() 907 | #-------------------------------------------------------------------------------------------------------- 908 | print ("\nConfiguration has been generated.") 909 | 910 | #filename = "build-v2.0.xlsx" 911 | #StartCode() 912 | 913 | #--------------- 914 | # Show the menu 915 | #--------------- 916 | def main(argv): 917 | arg_length = len(sys.argv) 918 | if arg_length < 2: 919 | print ("============================================================") 920 | print ("Cisco Config Generator %s"%__version__) 921 | print ("============================================================") 922 | print ("Usage: %s "%sys.argv[0]) 923 | exit() 924 | if sys.argv[1]: 925 | global filename 926 | filename = sys.argv[1] 927 | try: 928 | workbook = xlrd.open_workbook(filename) 929 | StartCode() 930 | except IOError: 931 | print ("Unable to open: %s"% sys.argv[1]) 932 | print ("Program aborted.") 933 | exit() 934 | 935 | if __name__ == '__main__': 936 | main(sys.argv) 937 | 938 | 939 | 940 | 941 | # Shows the "global config" even if no entry has been found, fix this -------------------------------------------------------------------------------- /v2.2/build-v2.3.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abdulkcode/CiscoConfigGenerator/650278f7210937fd9d1f66a834cf4d9806430c90/v2.2/build-v2.3.xlsx -------------------------------------------------------------------------------- /v2.2/ccg-v2.2.py: -------------------------------------------------------------------------------- 1 | import xlrd 2 | import re 3 | import sys 4 | from netaddr import * 5 | from operator import itemgetter 6 | 7 | __author__ = 'Abdul Karim El-Assaad' 8 | __version__ = '(CCG) Version: 2.2 (12/11/2014)' # Cisco Config Generator version 9 | 10 | error_db = {} 11 | 12 | raw_db = {} # Stores all the raw data from the build spreadsheet 13 | device_list = [] # Stores the valid device list from raw_db 14 | worksheet_list = [] # Stores the names of all worksheets in the build spreadsheet 15 | column_list = {} 16 | 17 | # Create a unique global dictionary for each worksheet 18 | config_templates = {} # Stores the config templates from raw_db 19 | variable_list = {} # Stores the valid variables from raw_db 20 | profile_list = {} # Stores the profiles from raw_db 21 | vlan_list = {} # Stores the valid vlans from raw_db 22 | vrf_list = {} # Stores the valid vrfs from raw_db 23 | interface_list = {} # Stores the layer2 information from raw_db 24 | static_route_list = {} # Stores the routing information from raw_db 25 | prefix_list = {} # Stores the prefix-list information from raw_db 26 | portchannel_list = {} # Stores the port-channel list information from raw_db 27 | 28 | global filename 29 | 30 | ''' 31 | ============================================================================= 32 | How to add a new worksheet: 33 | * Create a new global dictionary or list (see above) 34 | * Update RemoveEmptyRowsFromDB() function to include the new required columns 35 | * Create a function called GetList 36 | * Create a function called CreateConfiguration 37 | ============================================================================= 38 | ''' 39 | 40 | #----------------------------------------- 41 | # Used to redirect output to a text file 42 | #----------------------------------------- 43 | class Logger(object): 44 | def __init__(self, filename="Default.log"): 45 | self.terminal = sys.stdout 46 | self.log = open(filename, "w") 47 | def write(self, message): 48 | #self.terminal.write(message) # Shows output to screen 49 | self.log.write(message) # Writes output to file 50 | 51 | #----------------------------------------- 52 | # Main class which has all the functions 53 | #----------------------------------------- 54 | class Config(object): 55 | def __init__(self): 56 | self.CreateRawDb() 57 | 58 | # ---------------------------------------------------------------------- 59 | # Read the content of the build spreadsheet into the raw_db dictionary 60 | # To access call: raw_db["worksheet_name"][row_number]["Column name"] 61 | # ---------------------------------------------------------------------- 62 | def CreateRawDb(self): 63 | wb = xlrd.open_workbook(filename) 64 | global raw_db 65 | global worksheet_list 66 | global device_list 67 | global column_list 68 | global error_db 69 | 70 | temp_db = [] 71 | 72 | for i, worksheet in enumerate(wb.sheets()): 73 | if worksheet.name == "Instructions": 74 | continue 75 | header_cells = worksheet.row(0) 76 | num_rows = worksheet.nrows - 1 77 | curr_row = 0 78 | header = [each.value for each in header_cells] 79 | column_list[worksheet.name] = header 80 | # Add a column that doesn't exist in the worksheet 81 | header.append("Row") 82 | #------------------------------------------------------------------------------------- 83 | # Iterate over each row in each worksheet and store the info in the raw_db dictionary 84 | #------------------------------------------------------------------------------------- 85 | while curr_row < num_rows: 86 | curr_row += 1 87 | row = [int(each.value) if isinstance(each.value, float) 88 | else each.value 89 | for each in worksheet.row(curr_row)] 90 | # Add the row number to each record 91 | row.append(curr_row+1) 92 | value_dict = dict(zip(header, row)) 93 | temp_db.append(value_dict) 94 | else: 95 | #print ("raw_db: added '{}'".format(worksheet.name)) 96 | raw_db[worksheet.name] = temp_db 97 | #--------------------------------------------------------------------- 98 | # Grab all the unique device worksheet names in the build spreadsheet 99 | #--------------------------------------------------------------------- 100 | worksheet_list.append(worksheet.name) 101 | error_db[worksheet.name] = [] 102 | 103 | #------------------------------------------------------------------------ 104 | # Re-initalise the temp_db database so it's ready for the next worksheet 105 | #------------------------------------------------------------------------ 106 | temp_db = [] 107 | 108 | #------------------------------------------------------------------------------------- 109 | # Read through raw_db and start storing relevant information in their global database 110 | #------------------------------------------------------------------------------------- 111 | 112 | #----------------------------------------------------------------------- 113 | # Create a database which contains a list devices from every worksheet 114 | #------------------------------------------------------------------------ 115 | def GetDeviceList(self): 116 | global device_list 117 | raw_devices = [] 118 | for worksheet in worksheet_list: 119 | for row,entry in enumerate(raw_db[worksheet]): 120 | if raw_db[worksheet][row].get("Device Name"): 121 | if "!" in raw_db[worksheet][row].get("Device Name"): 122 | continue 123 | value = raw_db[worksheet][row].get("Device Name","none") 124 | value = value.strip() 125 | if value not in raw_devices: 126 | raw_devices.append(value) 127 | device_list = sorted(raw_devices) 128 | 129 | 130 | #----------------------------------------------------------- 131 | # Create a database that contains the VLANs for each device 132 | #----------------------------------------------------------- 133 | def GetVlanList(self): 134 | global vlan_list 135 | for row_no in range(len(raw_db["vlans"])): 136 | device_name = raw_db["vlans"][row_no]["Device Name"] 137 | if vlan_list.get(device_name): 138 | continue 139 | else: 140 | vlan_list[device_name] = {} 141 | for row_no in range(len(raw_db["vlans"])): 142 | device_name = raw_db["vlans"][row_no]["Device Name"] 143 | vlan_no = raw_db["vlans"][row_no]["VLAN No"] 144 | vlan_name = raw_db["vlans"][row_no]["VLAN Name"] 145 | vlan_list[device_name][vlan_no] = vlan_name 146 | 147 | #----------------------------------------------------------- 148 | # Create a database that contains the VRFs for each device 149 | #----------------------------------------------------------- 150 | def GetVrfList(self): 151 | global vrf_list 152 | for row_no in range(len(raw_db["vrf"])): 153 | vrf_columns = {key: [] for key in column_list["vrf"]} 154 | device_name = raw_db["vrf"][row_no]["Device Name"] 155 | vrf = raw_db["vrf"][row_no]["VRF"] 156 | if not vrf_list.get(device_name): 157 | vrf_list[device_name] = {} 158 | if not vrf_list[device_name].get(vrf): 159 | vrf_list[device_name][vrf] = vrf_columns 160 | for column in vrf_columns: 161 | vrf_list[device_name][vrf][column] = raw_db["vrf"][row_no][column] 162 | # If there are multiple route-targets grab them all 163 | current_import = vrf_list[device_name][vrf]["Import RT (separated by commas)"] 164 | current_import = current_import.strip() 165 | current_import = current_import.replace(" ","") 166 | current_export = vrf_list[device_name][vrf]["Export RT (separated by commas)"] 167 | current_export = current_export.strip() 168 | current_export = current_export.replace(" ","") 169 | new_import = current_import.split(",") 170 | new_export = current_export.split(",") 171 | vrf_list[device_name][vrf]["Import RT (separated by commas)"] = new_import 172 | vrf_list[device_name][vrf]["Export RT (separated by commas)"] = new_export 173 | 174 | #------------------------------------------------------------------ 175 | # Create a database that contains the interfaces for each device 176 | #------------------------------------------------------------------ 177 | def GetInterfaceList(self): 178 | global interface_list 179 | for row_no in range(len(raw_db["interfaces"])): 180 | interface_columns = {key: [] for key in column_list["interfaces"]} 181 | device_name = raw_db["interfaces"][row_no]["Device Name"] 182 | port = raw_db["interfaces"][row_no]["Interface"] 183 | if not interface_list.get(device_name): 184 | interface_list[device_name] = {} 185 | if not interface_list[device_name].get(port): 186 | interface_list[device_name][port] = interface_columns 187 | for column in interface_columns: 188 | interface_list[device_name][port][column] = raw_db["interfaces"][row_no][column] 189 | self.AddInterface(device_name,port,True) 190 | 191 | #------------------------------------------------------------------- 192 | # Create a database that contains the static routes for each device 193 | #------------------------------------------------------------------- 194 | def GetStaticRouteList(self): 195 | global static_route_list 196 | for row_no in range(len(raw_db["static routes"])): 197 | static_route_columns = {key: [] for key in column_list["static routes"]} 198 | device_name = raw_db["static routes"][row_no]["Device Name"] 199 | route = raw_db["static routes"][row_no]["Route (x.x.x.x/x)"] 200 | if not static_route_list.get(device_name): 201 | static_route_list[device_name] = {} 202 | if not static_route_list[device_name].get(route): 203 | static_route_list[device_name][route] = static_route_columns 204 | for column in static_route_columns: 205 | static_route_list[device_name][route][column] = raw_db["static routes"][row_no][column] 206 | 207 | new_route = IPNetwork(route) 208 | static_route_list[device_name][route]["Route"] = str(new_route.ip) 209 | static_route_list[device_name][route]["Subnet"] = str(new_route.netmask) 210 | 211 | 212 | def GetPrefixList(self): 213 | global prefix_list 214 | for row_no in range(len(raw_db["prefix-list"])): 215 | device_name = raw_db["prefix-list"][row_no]["Device Name"] 216 | prefix_name = raw_db["prefix-list"][row_no]["Prefix-List Name"] 217 | prefix_seq = raw_db["prefix-list"][row_no]["Prefix-List Sequence No"] 218 | prefix_action = raw_db["prefix-list"][row_no]["Prefix-List Action (permit/deny)"] 219 | prefix_entry = raw_db["prefix-list"][row_no]["Prefix-List Entry"] 220 | if not prefix_list.get(device_name): 221 | prefix_list[device_name] = {} 222 | if not prefix_list[device_name].get(prefix_name): 223 | temp_list = [] 224 | prefix_list[device_name][prefix_name] = temp_list 225 | temp_db = {"sequence":"","action":"","entry":""} 226 | prefix_list[device_name][prefix_name].append(temp_db) 227 | prefix_list[device_name][prefix_name][0]["sequence"] = prefix_seq 228 | prefix_list[device_name][prefix_name][0]["action"] = prefix_action 229 | prefix_list[device_name][prefix_name][0]["entry"] = prefix_entry 230 | elif not self.GetPrefixSeqNo(device_name,prefix_name,prefix_seq): 231 | list_no = len(prefix_list[device_name][prefix_name]) 232 | temp_db = {"sequence":"","action":"","entry":""} 233 | prefix_list[device_name][prefix_name].append(temp_db) 234 | prefix_list[device_name][prefix_name][list_no]["sequence"] = prefix_seq 235 | prefix_list[device_name][prefix_name][list_no]["action"] = prefix_action 236 | prefix_list[device_name][prefix_name][list_no]["entry"] = prefix_entry 237 | 238 | 239 | def GetPortChannelList(self): 240 | global portchannel_list 241 | for row_no in range(len(raw_db["portchannels"])): 242 | portchannel_column = {key: [] for key in column_list["portchannels"]} 243 | device_name = raw_db["portchannels"][row_no]["Device Name"] 244 | interface = raw_db["portchannels"][row_no]["Interface"] 245 | if not portchannel_list.get(device_name): 246 | portchannel_list[device_name] = {} 247 | if not portchannel_list[device_name].get(interface): 248 | portchannel_list[device_name][interface] = portchannel_column 249 | for column in portchannel_column: 250 | portchannel_list[device_name][interface][column] = raw_db["portchannels"][row_no][column] 251 | self.UpdatePortChannels() 252 | 253 | 254 | # Will iterate over the portchannel_list and try to add a new interface for each parent 255 | # or member interfaces. 256 | 257 | def UpdatePortChannels(self): 258 | for device_name in sorted(portchannel_list): 259 | for interface in sorted(portchannel_list[device_name]): 260 | 261 | pc_enabled = portchannel_list[device_name][interface]["Interface Enabled (yes/no)"] 262 | pc_group = portchannel_list[device_name][interface]["Port-Channel Group"] 263 | pc_mode = portchannel_list[device_name][interface]["Port-Channel Mode (active/on/etc)"] 264 | pc_type = portchannel_list[device_name][interface]["Port-Channel Type (layer2 or layer3)"] 265 | pc_members = portchannel_list[device_name][interface]["Port-Channel Members (separated by commas)"] 266 | pc_description = portchannel_list[device_name][interface]["Description"] 267 | 268 | self.AddInterface(device_name,interface) 269 | if pc_enabled: 270 | interface_list[device_name][interface]["Interface Enabled (yes/no)"] = pc_enabled 271 | if pc_description: 272 | interface_list[device_name][interface]["Description"] = pc_description 273 | 274 | for member in pc_members.split(","): 275 | member = member.strip() 276 | self.AddInterface(device_name,member) 277 | interface_list[device_name][member]["PC-Group"] = pc_group 278 | interface_list[device_name][member]["PC-Mode"] = pc_mode 279 | interface_list[device_name][member]["PC-Type"] = pc_type 280 | interface_list[device_name][interface]["PC-Members"].append(member) 281 | 282 | def GetVariableList(self): 283 | global variable_list 284 | for row_no in range(len(raw_db["variables"])): 285 | variable_name = raw_db["variables"][row_no]["Variable"] 286 | variable_value = raw_db["variables"][row_no]["Variable Value"] 287 | if "+" in variable_name: 288 | continue 289 | elif variable_name in variable_list: 290 | continue 291 | variable_list[variable_name] = variable_value 292 | 293 | def GetConfigTemplateList(self): 294 | global config_templates 295 | temp_list = [] 296 | for row_no in range(len(raw_db["config-templates"])): 297 | line = raw_db["config-templates"][row_no]["Enter config templates below this line:"] 298 | match = re.search(r'Config Template: \[(.*?)\]', line,re.IGNORECASE) 299 | if not line: 300 | continue 301 | if match: 302 | temp_list = [] 303 | config_templates[match.group(1)] = temp_list 304 | continue 305 | temp_list.append(line) 306 | 307 | # Cycle through each line of the config template to update dynamic variables 308 | for entry in config_templates: 309 | temp_list = [] 310 | for line in config_templates[entry]: 311 | match = re.findall(r'\[(.*?)\]', line) 312 | valid_variable = False 313 | if (match): 314 | for variable_name in match: 315 | lookup_variable = self.GetVariable(variable_name) 316 | if lookup_variable: 317 | valid_variable = True 318 | line = line.replace(variable_name,lookup_variable) 319 | else: 320 | error_db["config-templates"].append("Config-Template: '{}' referenced embedded variable '{}' which does not exist".format(entry,variable_name)) 321 | continue 322 | if (valid_variable): 323 | line = line.replace("[","") 324 | line = line.replace("]","") 325 | temp_list.append(line) 326 | config_templates[entry] = temp_list 327 | 328 | 329 | def GetProfileList(self): 330 | global profile_list 331 | global error_db 332 | for row_no in range(len(raw_db["profiles"])): 333 | device_name = raw_db["profiles"][row_no]["Device Name"] 334 | variable = raw_db["profiles"][row_no]["Template or Variable"] 335 | position = raw_db["profiles"][row_no]["Position (Default: Start)"] 336 | if not position: 337 | position = "Start" 338 | if not self.GetVariable(variable): 339 | if not self.GetConfigTemplate(variable): 340 | error_db["profiles"].append("Row ({}): Device '{}' referenced variable '{}' which does not exist".format(raw_db["profiles"][row_no]["Row"],device_name,variable)) 341 | continue 342 | 343 | # if device_name not in profile_list: 344 | # temp_list = [] 345 | # profile_list[device_name] = temp_list 346 | # profile_list[device_name].append(variable) 347 | 348 | if device_name not in profile_list: 349 | profile_temp = [] 350 | position_temp = [] 351 | profile_list[device_name] = {} 352 | profile_list[device_name]["Profile"] = profile_temp 353 | profile_list[device_name]["Position"] = position_temp 354 | profile_list[device_name]["Profile"].append(variable) 355 | profile_list[device_name]["Position"].append(position) 356 | 357 | 358 | #------------------------------------------- 359 | # Manual manipulation of one of the lists 360 | #------------------------------------------- 361 | ''' manual_entries will result in manual entries always being triggered. 362 | This will be created when: 363 | a) GetInterfaceList is called (i.e. reading the info from the interfaces tab 364 | b) UpdatePortChannels is called (i.e. only if new interface is detected) 365 | ''' 366 | def AddInterface(self,device_name,interface,manual_entries=False): 367 | global interface_list 368 | 369 | interface_columns = {key: [] for key in column_list["interfaces"]} 370 | if not interface_list.get(device_name): 371 | interface_list[device_name] = {} 372 | if not interface_list[device_name].get(interface): 373 | manual_entries = True 374 | interface_list[device_name][interface] = interface_columns 375 | 376 | # Any manual entries that are not directly from the spreadsheet below 377 | if manual_entries: 378 | error_list = [] 379 | member_list = [] 380 | interface_list[device_name][interface]["Errors"] = error_list 381 | interface_list[device_name][interface]["Interface"] = interface 382 | interface_list[device_name][interface]["PC-Group"] = "" 383 | interface_list[device_name][interface]["PC-Mode"] = "" 384 | interface_list[device_name][interface]["PC-Type"] = "" 385 | interface_list[device_name][interface]["PC-Members"] = member_list 386 | interface_list[device_name][interface]["PC-Parent"] = "" 387 | 388 | # --------------------------------------------------- 389 | # Get specific values from their respective database 390 | # --------------------------------------------------- 391 | def GetVariable(self, variable_name): 392 | if variable_list.get(variable_name): 393 | return variable_list[variable_name] 394 | 395 | def GetVlan(self, device_to_find, vlan_to_find): 396 | if vlan_list[device_to_find].get(vlan_to_find): 397 | return vlan_list[device_to_find][vlan_to_find] 398 | 399 | def GetConfigTemplate(self, template_name): 400 | if config_templates.get(template_name): 401 | return config_templates[template_name] 402 | 403 | def GetPrefixSeqNo(self, device_name,prefix_name,sequence_number): 404 | global prefix_list 405 | if not prefix_list.get(device_name): 406 | return 407 | if not prefix_list[device_name].get(prefix_name): 408 | return 409 | for row, entry in enumerate(prefix_list[device_name][prefix_name]): 410 | if prefix_list[device_name][prefix_name][row]["sequence"] == sequence_number: 411 | return prefix_list[device_name][prefix_name][row] 412 | 413 | def GetIP(self,IP_address,mode="IOS"): 414 | if not IP_address: 415 | return 416 | if "/" not in IP_address: 417 | # Generate error message 418 | return IP_address 419 | if mode == "NXOS": 420 | string = ("{}".format(IP_address)) 421 | return string 422 | elif mode == "IOS": 423 | full_address = IPNetwork(IP_address) 424 | string = ("{} {}".format(full_address.ip,full_address.netmask)) 425 | return string 426 | 427 | def GetInterfaceType(self,interface): 428 | logical_interfaces = ["Po","Tu","Lo","Vl"] 429 | for type in logical_interfaces: 430 | if type in interface: 431 | return "Logical" 432 | return "Physical" 433 | 434 | def GetTrunkVlans(self,device,interface): 435 | if not interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 436 | return 437 | allowed_vlans_raw = interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"] 438 | allowed_vlans_raw = allowed_vlans_raw.replace(" ","") 439 | allowed_vlans_raw = allowed_vlans_raw.strip() 440 | allowed_vlans_raw = allowed_vlans_raw.split(",") 441 | allowed_vlans_new = [] 442 | 443 | for vlan in allowed_vlans_raw: 444 | if "-" not in vlan: 445 | allowed_vlans_new.append(vlan) 446 | elif "-" in vlan: 447 | vlan_range = [] 448 | for entry in vlan.split("-"): 449 | vlan_range.append(entry) 450 | vlan_range_start = int(vlan_range[0]) 451 | vlan_range_end = int(vlan_range[1]) 452 | 453 | while vlan_range_start <= vlan_range_end: 454 | allowed_vlans_new.append(vlan_range_start) 455 | vlan_range_start +=1 456 | return allowed_vlans_new 457 | 458 | # --------------------------------------------- 459 | # Check the interface for specific conditions 460 | # --------------------------------------------- 461 | def is_switch_port(self,device,interface): 462 | if interface_list[device][interface]["Data VLAN"]: 463 | return True 464 | elif interface_list[device][interface]["Voice VLAN"]: 465 | return True 466 | elif interface_list[device][interface]["Trunk Allowed VLANs (separated by commas)"]: 467 | return True 468 | elif "layer2" in interface_list[device][interface]["PC-Type"]: 469 | return True 470 | 471 | def is_routed_port(self,device,interface): 472 | if "Logical" in self.GetInterfaceType(interface): 473 | return False 474 | elif interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 475 | return True 476 | elif "layer3" in interface_list[device][interface]["PC-Type"]: 477 | return True 478 | 479 | def is_trunk_port(self,device,interface): 480 | if interface_list[device][interface].get("Trunk Allowed VLANs (separated by commas)"): 481 | return True 482 | 483 | def is_data_port(self,device,interface): 484 | if interface_list[device][interface].get("Data VLAN"): 485 | return True 486 | 487 | def is_voice_port(self,device,interface): 488 | if interface_list[device][interface].get("Voice VLAN"): 489 | return True 490 | 491 | def is_interface_enabled(self,device,interface): 492 | if interface_list[device][interface]["Interface Enabled (yes/no)"]: 493 | if "yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 494 | return True 495 | if "Yes" in interface_list[device][interface]["Interface Enabled (yes/no)"]: 496 | return True 497 | 498 | def is_portchannel_member(self,device,interface): 499 | if interface_list[device][interface]["PC-Group"]: 500 | return True 501 | 502 | def is_portchannel_parent(self,device,interface): 503 | if interface_list[device][interface]["PC-Members"]: 504 | return True 505 | 506 | def is_valid_portchannel(self,device,interface): 507 | if portchannel_list[device].get(interface): 508 | if interface_list[device][interface]: 509 | return True 510 | 511 | def is_valid_variable(self,variable_name): 512 | if variable_list.get(variable_name): 513 | return True 514 | 515 | def is_valid_vlan(self,device,vlan): 516 | if vlan_list.get(device): 517 | if vlan_list[device].get(int(vlan)): 518 | return True 519 | 520 | def is_valid_trunk(self,device,interface): 521 | if not self.is_trunk_port(device,interface): 522 | return False 523 | trunk_vlans = self.GetTrunkVlans(device,interface) 524 | valid_trunk = True 525 | for vlan in trunk_vlans: 526 | if not self.is_valid_vlan(device,vlan): 527 | valid_trunk = False 528 | if valid_trunk: 529 | return True 530 | 531 | def is_valid_vrf(self,device,vrf): 532 | if vrf_list.get(device): 533 | if vrf_list[device].get(vrf): 534 | return True 535 | 536 | def is_valid_ipaddress(self,ip_address_to_check): 537 | ip_address = IPNetwork(ip_address_to_check) 538 | if IPAddress(ip_address.ip) in IPNetwork(ip_address).iter_hosts(): 539 | return True 540 | 541 | def has_variable1_configured(self,device,interface): 542 | if interface_list[device][interface].get("Variable 1"): 543 | return True 544 | 545 | def has_variable2_configured(self,device,interface): 546 | if interface_list[device][interface].get("Variable 2"): 547 | return True 548 | 549 | def has_description_configured(self,device,interface): 550 | if interface_list[device][interface]["Description"]: 551 | return True 552 | 553 | def has_mtu_configured(self,device,interface): 554 | if interface_list[device][interface]["MTU"]: 555 | return True 556 | 557 | def has_vrf_configured(self,device,interface): 558 | if interface_list[device][interface]["VRF (leave blank if global)"]: 559 | return True 560 | 561 | def has_ip_configured(self,device,interface): 562 | if interface_list[device][interface]["IP Address (x.x.x.x/x)"]: 563 | return True 564 | 565 | def has_nativevlan_configured(self,device,interface): 566 | if interface_list[device][interface]["Trunk Native VLAN"]: 567 | return True 568 | 569 | def has_speed_configured(self,device,interface): 570 | if interface_list[device][interface]["Speed"]: 571 | return True 572 | 573 | def has_duplex_configured(self,device,interface): 574 | if interface_list[device][interface]["Duplex"]: 575 | return True 576 | 577 | def has_importrt_configured(self,device,vrf): 578 | if vrf_list[device][vrf].get("Import RT (separated by commas)"): 579 | return True 580 | 581 | def has_exportrt_configured(self,device,vrf): 582 | if vrf_list[device][vrf].get("Export RT (separated by commas)"): 583 | return True 584 | 585 | def has_rd_configured(self,device,vrf): 586 | if vrf_list[device][vrf].get("RD"): 587 | return True 588 | 589 | 590 | 591 | # ------------------------------------------------------------------------------------- 592 | # Check each worksheet/row to make sure that the required information is present. 593 | # Otherwise the row will be removed from the database as it will be considered invalid 594 | # ------------------------------------------------------------------------------------- 595 | def RemoveEmptyRowsFromDB(self): 596 | 597 | db_required_columns = {key: [] for key in worksheet_list} 598 | #-------------------------------------------------------------------- 599 | # If the worksheet needs to have a valid column entry, define it below 600 | #-------------------------------------------------------------------- 601 | db_required_columns["variables"] = ["Variable", "Variable Value"] 602 | db_required_columns["profiles"]= ["Device Name","Template or Variable"] 603 | db_required_columns["vrf"] = ["Device Name","VRF","RD"] 604 | db_required_columns["vlans"]= ["Device Name","VLAN No","VLAN Name"] 605 | db_required_columns["interfaces"]= ["Device Name","Interface"] 606 | db_required_columns["static routes"]= ["Device Name","Route (x.x.x.x/x)","Next Hop"] 607 | db_required_columns["portchannels"]= ["Device Name","Interface","Port-Channel Group","Port-Channel Mode (active/on/etc)","Port-Channel Type (layer2 or layer3)","Port-Channel Members (separated by commas)"] 608 | 609 | #-------------------------------------------- 610 | # Search for invalid rows and update database 611 | #-------------------------------------------- 612 | console = sys.__stdout__ 613 | sys.stdout = Logger("ccg-ignored.txt") 614 | for worksheet in worksheet_list: 615 | for entry in db_required_columns[worksheet]: 616 | temp_db = [] 617 | for row_no in range(len(raw_db[worksheet])): 618 | if not raw_db[worksheet][row_no][entry]: 619 | 620 | print ("[{}]-row:{} has empty cell value for column: {} (IGNORED)".format(worksheet,raw_db[worksheet][row_no]["Row"],entry)) 621 | continue 622 | if "$" in str(raw_db[worksheet][row_no][entry]): 623 | continue 624 | temp_db.append(raw_db[worksheet][row_no]) 625 | else: 626 | raw_db[worksheet] = temp_db 627 | sys.stdout = console 628 | 629 | #------------------------------------------------------------- 630 | # Functions to actually show the output of the configuration 631 | #------------------------------------------------------------- 632 | 633 | def CreateGlobalConfig(self,device_name,config_position="Start"): 634 | if not profile_list.get(device_name): 635 | return 636 | 637 | print ("!---------------------------------") 638 | print ("! Global configuration ({}) ".format(config_position)) 639 | print ("!---------------------------------") 640 | for number, profile in enumerate(profile_list[device_name]["Profile"]): 641 | profile_name = profile_list[device_name]["Profile"][number] 642 | profile_position_type = profile_list[device_name]["Position"][number] 643 | if config_position not in profile_position_type: 644 | continue 645 | if self.GetConfigTemplate(profile_name): 646 | print ("\n! [{}]:".format(profile_name)) 647 | for line in self.GetConfigTemplate(profile_name): 648 | print ("{}".format(line)) 649 | elif self.GetVariable(profile_name): 650 | print ("\n! [{}]:".format(profile_name)) 651 | print ("{}".format(self.GetVariable(profile_name))) 652 | 653 | def CreateVlanConfig(self,device_name): 654 | if not vlan_list.get(device_name): 655 | return 656 | print ("!---------------------------------") 657 | print ("! VLAN configuration ") 658 | print ("!---------------------------------") 659 | for vlan in sorted(vlan_list[device_name]): 660 | print ("vlan {}".format(vlan)) 661 | print (" name {}".format(vlan_list[device_name].get(vlan))) 662 | 663 | def CreateVrfConfig(self,device_name): 664 | if not vrf_list.get(device_name): 665 | return 666 | print ("!---------------------------------") 667 | print ("! VRF configuration ") 668 | print ("!---------------------------------") 669 | for vrf in sorted(vrf_list[device_name]): 670 | print ("ip vrf {}".format(vrf)) 671 | if self.has_rd_configured(device_name,vrf): 672 | print (" rd {}".format(vrf_list[device_name][vrf]["RD"])) 673 | if self.has_importrt_configured(device_name,vrf): 674 | for route_target in vrf_list[device_name][vrf]["Import RT (separated by commas)"]: 675 | print (" route-target import {}".format(route_target)) 676 | if self.has_exportrt_configured(device_name,vrf): 677 | for route_target in vrf_list[device_name][vrf]["Export RT (separated by commas)"]: 678 | print (" route-target export {}".format(route_target)) 679 | if vrf_list[device_name][vrf]["Variable"]: 680 | if self.is_valid_variable(vrf_list[device_name][vrf]["Variable"]): 681 | print (self.GetVariable(vrf_list[device_name][vrf]["Variable"])) 682 | 683 | 684 | def CreateStaticRouteConfig(self,device_name): 685 | if not static_route_list.get(device_name): 686 | return 687 | print ("!---------------------------------") 688 | print ("! Static routing configuration ") 689 | print ("!---------------------------------") 690 | for route in sorted(static_route_list[device_name]): 691 | route_vrf = static_route_list[device_name][route]["VRF (leave blank if global)"] 692 | route_entry = static_route_list[device_name][route]["Route"] 693 | route_subnet = static_route_list[device_name][route]["Subnet"] 694 | route_nexthop = static_route_list[device_name][route]["Next Hop"] 695 | route_name = static_route_list[device_name][route]["Route Name (no spaces)"] 696 | 697 | if route_entry: 698 | if route_vrf and route_subnet and route_nexthop and route_name: 699 | print ("ip route vrf {} {} {} name {}".format(route_vrf,route_entry,route_subnet,route_name)) 700 | elif route_vrf and route_subnet and route_nexthop: 701 | print ("ip route vrf {} {} {}".format(route_vrf,route_entry,route_subnet)) 702 | elif route_subnet and route_nexthop and route_name: 703 | print ("ip route {} {} {} name {}".format(route_entry,route_subnet,route_nexthop,route_name)) 704 | elif route_subnet and route_nexthop: 705 | print ("ip route {} {} {}".format(route_entry,route_subnet,route_nexthop)) 706 | 707 | def CreatePrefixConfig(self,device_name): 708 | if not prefix_list.get(device_name): 709 | return 710 | print ("!---------------------------------") 711 | print ("! Prefix-list configuration ") 712 | print ("!---------------------------------") 713 | 714 | for prefix_name in sorted(prefix_list[device_name]): 715 | oldlist = prefix_list[device_name][prefix_name] 716 | newlist = sorted(oldlist, key=itemgetter('sequence')) 717 | for entry in newlist: 718 | pl_sequence = entry["sequence"] 719 | pl_action = entry["action"] 720 | pl_entry = entry["entry"] 721 | print ("ip prefix-list {} seq {} {} {}".format(prefix_name,pl_sequence,pl_action,pl_entry)) 722 | else: 723 | print ("!") 724 | 725 | def CreateInterfaceConfig(self,device_name,config_mode): 726 | if not interface_list.get(device_name): 727 | return 728 | first_match = True 729 | for interface in sorted(interface_list[device_name]): 730 | if config_mode == "Physical": 731 | if not self.GetInterfaceType(interface) == "Physical": 732 | continue 733 | elif config_mode == "Logical": 734 | if not self.GetInterfaceType(interface) == "Logical": 735 | continue 736 | if (first_match and "Physical" in config_mode): 737 | print ("!--------------------------------------------") 738 | print ("! Interface configuration (Physical) ") 739 | print ("!--------------------------------------------") 740 | elif (first_match and "Logical" in config_mode): 741 | print ("!--------------------------------------------") 742 | print ("! Interface configuration (Logical) ") 743 | print ("!--------------------------------------------") 744 | first_match = False 745 | 746 | if self.is_portchannel_member(device_name,interface): 747 | pc_type = interface_list[device_name][interface]["PC-Type"] 748 | if "layer2" in pc_type: 749 | print ("!....................................") 750 | print ("! Layer 2 PC: create physical first") 751 | print ("!....................................") 752 | elif "layer3" in pc_type: 753 | print ("!....................................") 754 | print ("! Layer 3 PC: create logical first") 755 | print ("!....................................") 756 | # --------------------------------------------------- 757 | # Start generating interface specific configuration 758 | # --------------------------------------------------- 759 | print ("interface {}".format(interface_list[device_name][interface]["Interface"])) 760 | 761 | if self.is_portchannel_parent(device_name,interface): 762 | pc_members = interface_list[device_name][interface]["PC-Members"] 763 | print (" !- pc members: {}".format(", ".join(pc_members))) 764 | if self.is_switch_port(device_name,interface): 765 | print (" switchport") 766 | if self.is_routed_port(device_name,interface): 767 | print (" no switchport") 768 | if self.has_description_configured(device_name,interface): 769 | print (" description {}".format(interface_list[device_name][interface]["Description"])) 770 | if self.has_mtu_configured(device_name,interface): 771 | print (" mtu {}".format(interface_list[device_name][interface]["MTU"])) 772 | if self.has_vrf_configured(device_name,interface): 773 | print (" ip vrf forwarding {}".format(interface_list[device_name][interface]["VRF (leave blank if global)"])) 774 | if self.has_ip_configured(device_name,interface): 775 | print (" ip address {}".format(self.GetIP(interface_list[device_name][interface]["IP Address (x.x.x.x/x)"]))) 776 | if self.is_trunk_port(device_name,interface): 777 | trunk_vlans = interface_list[device_name][interface]["Trunk Allowed VLANs (separated by commas)"] 778 | print (" switchport mode trunk") 779 | print (" switchport trunk allowed vlan {}".format(trunk_vlans)) 780 | if self.has_nativevlan_configured(device_name,interface): 781 | native_vlan = interface_list[device_name][interface]["Trunk Native VLAN"] 782 | print (" switchport trunk native vlan {}".format(native_vlan)) 783 | if self.is_data_port(device_name,interface): 784 | print (" switchport access vlan {}".format(interface_list[device_name][interface]["Data VLAN"])) 785 | if self.is_voice_port(device_name,interface): 786 | print (" switchport voice vlan {}".format(interface_list[device_name][interface]["Voice VLAN"])) 787 | if self.is_portchannel_member(device_name,interface): 788 | pc_group = interface_list[device_name][interface]["PC-Group"] 789 | pc_mode = interface_list[device_name][interface]["PC-Mode"] 790 | print (" channel-group {} mode {}".format(pc_group,pc_mode)) 791 | if self.has_variable1_configured(device_name,interface): 792 | if self.is_valid_variable(interface_list[device_name][interface]["Variable 1"]): 793 | print (self.GetVariable(interface_list[device_name][interface]["Variable 1"])) 794 | if self.has_variable2_configured(device_name,interface): 795 | if self.is_valid_variable(interface_list[device_name][interface]["Variable 2"]): 796 | print (self.GetVariable(interface_list[device_name][interface]["Variable 2"])) 797 | if self.has_speed_configured(device_name,interface): 798 | print (" speed {}".format(interface_list[device_name][interface]["Speed"])) 799 | if self.has_duplex_configured(device_name,interface): 800 | print (" duplex {}".format(interface_list[device_name][interface]["Duplex"])) 801 | if self.is_interface_enabled(device_name,interface): 802 | print (" no shutdown") 803 | else: 804 | print (" shutdown") 805 | else: 806 | print ("!") 807 | 808 | 809 | def GenerateConfig(self): 810 | global device_list 811 | console = sys.__stdout__ 812 | print ("Generating configuration....") 813 | for device in device_list: 814 | sys.stdout = Logger(device+".txt") 815 | print ("****************************************") 816 | print ("! Device configuration for {}".format(device)) 817 | print ("****************************************") 818 | self.CreateGlobalConfig(device,"Start") 819 | self.CreateVrfConfig(device) 820 | self.CreateVlanConfig(device) 821 | self.CreateInterfaceConfig(device,"Physical") 822 | self.CreateInterfaceConfig(device,"Logical") 823 | self.CreatePrefixConfig(device) 824 | self.CreateStaticRouteConfig(device) 825 | self.CreateGlobalConfig(device,"End") 826 | sys.stdout = console 827 | print ("- {} configuration generated.".format(device)) 828 | 829 | def CheckInterfacesForErrors(self): 830 | for device in interface_list: 831 | for interface in sorted(interface_list[device]): 832 | if self.is_routed_port(device,interface) and self.is_switch_port(device,interface): 833 | error_db["interfaces"].append("Row ({}): [{}] [{}] both routed and switchport config detected".format(interface_list[device][interface]["Row"],device,interface)) 834 | if self.has_variable1_configured(device,interface): 835 | if not self.GetVariable(interface_list[device][interface]["Variable 1"]): 836 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Variable 1"])) 837 | if self.has_variable2_configured(device,interface): 838 | if not self.GetVariable(interface_list[device][interface]["Variable 2"]): 839 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced variable '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Variable 2"])) 840 | if self.is_data_port(device,interface): 841 | if not self.is_valid_vlan(device,interface_list[device][interface]["Data VLAN"]): 842 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Data VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 843 | if self.is_voice_port(device,interface): 844 | if not self.is_valid_vlan(device,interface_list[device][interface]["Voice VLAN"]): 845 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Voice VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Data VLAN"])) 846 | if self.has_nativevlan_configured(device,interface): 847 | if not self.is_valid_vlan(device,interface_list[device][interface]["Trunk Native VLAN"]): 848 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced Native VLAN '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["Trunk Native VLAN"])) 849 | if self.has_vrf_configured(device,interface): 850 | if not self.is_valid_vrf(device,interface_list[device][interface]["VRF (leave blank if global)"]): 851 | error_db["interfaces"].append("Row ({}): [{}] [{}] referenced vrf '{}' which does not exist".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["VRF (leave blank if global)"])) 852 | if self.has_ip_configured(device,interface): 853 | if not self.is_valid_ipaddress(interface_list[device][interface]["IP Address (x.x.x.x/x)"]): 854 | error_db["interfaces"].append("Row ({}): [{}] [{}] using IPAddr '{}' which is invalid".format(interface_list[device][interface]["Row"],device,interface,interface_list[device][interface]["IP Address (x.x.x.x/x)"])) 855 | if self.is_trunk_port(device,interface): 856 | if not self.is_valid_trunk(device,interface): 857 | error_db["interfaces"].append("Row ({}): [{}] [{}] one or more vlans referenced in trunk do not exist".format(interface_list[device][interface]["Row"],device,interface)) 858 | 859 | def GenerateErrorReport(self): 860 | console = sys.__stdout__ 861 | sys.stdout = Logger("ccg-errors.txt") 862 | 863 | if error_db["profiles"]: 864 | print ("===========================") 865 | print ("Worksheet: [profiles]") 866 | print ("===========================") 867 | for entry in error_db["profiles"]: 868 | print (entry) 869 | 870 | if error_db["config-templates"]: 871 | print ("===========================") 872 | print ("Worksheet: [config-templates]") 873 | print ("===========================") 874 | for entry in error_db["config-templates"]: 875 | print (entry) 876 | 877 | if error_db["interfaces"]: 878 | print ("===========================") 879 | print ("Worksheet: [interfaces]") 880 | print ("===========================") 881 | for entry in error_db["interfaces"]: 882 | print (entry) 883 | sys.stdout = console 884 | 885 | def StartCode(): 886 | #-------------------------------------------------------------------------------------------------------- 887 | # Execute the code 888 | #-------------------------------------------------------------------------------------------------------- 889 | db = Config() # Read the build spreadsheet and build the raw database 890 | db.RemoveEmptyRowsFromDB() # Clean up the database and remove rows that don't have required columns 891 | #-------------------------------------------------------------------------------------------------------- 892 | db.GetDeviceList() # Scan through all the worksheets and capture a list of unique devices names 893 | db.GetVlanList() # Scan through the vlan worksheet and capture a list of vlans per device 894 | db.GetVariableList() # Scan through the variable worksheet and capture valid variables 895 | db.GetConfigTemplateList() # Scan through the "config-templates" worksheet and capture templates 896 | db.GetProfileList() # Scan through the "profiles" worksheet and capture which proilfes are used 897 | db.GetVrfList() # Scan through the "vrf" worksheet and capture the VRFs 898 | db.GetInterfaceList() # Scan through the "interfaces" worksheet and capture interfaces 899 | db.GetStaticRouteList() # Scan through the "static routes" worksheet and capture routes 900 | db.GetPrefixList() # Scan through the "prefix-list" worksheet and capture prefix-lists 901 | db.GetPortChannelList() # Scan through the "portchannels" worksheet and capture all the portchannels 902 | #-------------------------------------------------------------------------------------------------------- 903 | db.CheckInterfacesForErrors() 904 | #-------------------------------------------------------------------------------------------------------- 905 | db.GenerateConfig() # Generate the actual configuration 906 | db.GenerateErrorReport() 907 | #-------------------------------------------------------------------------------------------------------- 908 | print ("\nConfiguration has been generated.") 909 | 910 | #filename = "build-v2.0.xlsx" 911 | #StartCode() 912 | 913 | #--------------- 914 | # Show the menu 915 | #--------------- 916 | def main(argv): 917 | arg_length = len(sys.argv) 918 | if arg_length < 2: 919 | print ("============================================================") 920 | print ("Cisco Config Generator %s"%__version__) 921 | print ("============================================================") 922 | print ("Usage: %s "%sys.argv[0]) 923 | exit() 924 | if sys.argv[1]: 925 | global filename 926 | filename = sys.argv[1] 927 | try: 928 | workbook = xlrd.open_workbook(filename) 929 | StartCode() 930 | except IOError: 931 | print ("Unable to open: %s"% sys.argv[1]) 932 | print ("Program aborted.") 933 | exit() 934 | 935 | if __name__ == '__main__': 936 | main(sys.argv) 937 | 938 | 939 | 940 | 941 | # Shows the "global config" even if no entry has been found, fix this 942 | --------------------------------------------------------------------------------