├── LICENSE ├── README.md ├── cli.py ├── config.json ├── ios-xe_template.j2 ├── static └── style.css ├── templates ├── index.html └── success.html └── web.py /LICENSE: -------------------------------------------------------------------------------- 1 | CISCO SAMPLE CODE LICENSE 2 | Version 1.1 3 | Copyright (c) 2018 Cisco and/or its affiliates 4 | 5 | These terms govern this Cisco Systems, Inc. ("Cisco"), example or demo 6 | source code and its associated documentation (together, the "Sample 7 | Code"). By downloading, copying, modifying, compiling, or redistributing 8 | the Sample Code, you accept and agree to be bound by the following terms 9 | and conditions (the "License"). If you are accepting the License on 10 | behalf of an entity, you represent that you have the authority to do so 11 | (either you or the entity, "you"). Sample Code is not supported by Cisco 12 | TAC and is not tested for quality or performance. This is your only 13 | license to the Sample Code and all rights not expressly granted are 14 | reserved. 15 | 16 | 1. LICENSE GRANT: Subject to the terms and conditions of this License, 17 | Cisco hereby grants to you a perpetual, worldwide, non-exclusive, non- 18 | transferable, non-sublicensable, royalty-free license to copy and 19 | modify the Sample Code in source code form, and compile and 20 | redistribute the Sample Code in binary/object code or other executable 21 | forms, in whole or in part, solely for use with Cisco products and 22 | services. For interpreted languages like Java and Python, the 23 | executable form of the software may include source code and 24 | compilation is not required. 25 | 26 | 2. CONDITIONS: You shall not use the Sample Code independent of, or to 27 | replicate or compete with, a Cisco product or service. Cisco products 28 | and services are licensed under their own separate terms and you shall 29 | not use the Sample Code in any way that violates or is inconsistent 30 | with those terms (for more information, please visit: 31 | www.cisco.com/go/terms). 32 | 33 | 3. OWNERSHIP: Cisco retains sole and exclusive ownership of the Sample 34 | Code, including all intellectual property rights therein, except with 35 | respect to any third-party material that may be used in or by the 36 | Sample Code. Any such third-party material is licensed under its own 37 | separate terms (such as an open source license) and all use must be in 38 | full accordance with the applicable license. This License does not 39 | grant you permission to use any trade names, trademarks, service 40 | marks, or product names of Cisco. If you provide any feedback to Cisco 41 | regarding the Sample Code, you agree that Cisco, its partners, and its 42 | customers shall be free to use and incorporate such feedback into the 43 | Sample Code, and Cisco products and services, for any purpose, and 44 | without restriction, payment, or additional consideration of any kind. 45 | If you initiate or participate in any litigation against Cisco, its 46 | partners, or its customers (including cross-claims and counter-claims) 47 | alleging that the Sample Code and/or its use infringe any patent, 48 | copyright, or other intellectual property right, then all rights 49 | granted to you under this License shall terminate immediately without 50 | notice. 51 | 52 | 4. LIMITATION OF LIABILITY: CISCO SHALL HAVE NO LIABILITY IN CONNECTION 53 | WITH OR RELATING TO THIS LICENSE OR USE OF THE SAMPLE CODE, FOR 54 | DAMAGES OF ANY KIND, INCLUDING BUT NOT LIMITED TO DIRECT, INCIDENTAL, 55 | AND CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OF USE, DATA, INFORMATION, 56 | PROFITS, BUSINESS, OR GOODWILL, HOWEVER CAUSED, EVEN IF ADVISED OF THE 57 | POSSIBILITY OF SUCH DAMAGES. 58 | 59 | 5. DISCLAIMER OF WARRANTY: SAMPLE CODE IS INTENDED FOR EXAMPLE PURPOSES 60 | ONLY AND IS PROVIDED BY CISCO "AS IS" WITH ALL FAULTS AND WITHOUT 61 | WARRANTY OR SUPPORT OF ANY KIND. TO THE MAXIMUM EXTENT PERMITTED BY 62 | LAW, ALL EXPRESS AND IMPLIED CONDITIONS, REPRESENTATIONS, AND 63 | WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OR 64 | CONDITION OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON- 65 | INFRINGEMENT, SATISFACTORY QUALITY, NON-INTERFERENCE, AND ACCURACY, 66 | ARE HEREBY EXCLUDED AND EXPRESSLY DISCLAIMED BY CISCO. CISCO DOES NOT 67 | WARRANT THAT THE SAMPLE CODE IS SUITABLE FOR PRODUCTION OR COMMERCIAL 68 | USE, WILL OPERATE PROPERLY, IS ACCURATE OR COMPLETE, OR IS WITHOUT 69 | ERROR OR DEFECT. 70 | 71 | 6. GENERAL: This License shall be governed by and interpreted in 72 | accordance with the laws of the State of California, excluding its 73 | conflict of laws provisions. You agree to comply with all applicable 74 | United States export laws, rules, and regulations. If any provision of 75 | this License is judged illegal, invalid, or otherwise unenforceable, 76 | that provision shall be severed and the rest of the License shall 77 | remain in full force and effect. No failure by Cisco to enforce any of 78 | its rights related to the Sample Code or to a breach of this License 79 | in a particular situation will act as a waiver of such rights. In the 80 | event of any inconsistencies with any other terms, this License shall 81 | take precedence. 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cisco Configuration Generator 2 | A sample Cisco IOS-XE configuration tool. This tool can produce IOS-XE 3 | configurations by filling out a web form. 4 | 5 | ## Usage 6 | ``` 7 | python web.py 8 | ``` 9 | Once the web server has started open a web browser and proceed to 10 | 127.0.0.1:5000. 11 | 12 | The following web page will be displayed. 13 | 14 | Once all pertinent information has been filled in click submit. 15 | The configuration will be found in the ~/configs directory. 16 | 17 | ## Changing the Configuration Template 18 | The configuration template is a Jinja2 template with the file 19 | name ios-xe_template.j2. This template can be 20 | modified to include additional static configuration or variable 21 | configuration per individual need. User input from index.html is used 22 | in the config function of web.py to assign the user input to variables 23 | in ios-xe_config.j2 template. 24 | 25 | -------------------------------------------------------------------------------- /cli.py: -------------------------------------------------------------------------------- 1 | import jinja2 2 | import os 3 | import json 4 | 5 | 6 | template_file = "ios-xe_template.j2" 7 | output_directory = "configs" 8 | # create the central Jinja2 environment and load template 9 | env = jinja2.Environment( 10 | loader=jinja2.FileSystemLoader(searchpath="."), trim_blocks=True, lstrip_blocks=True 11 | ) 12 | template = env.get_template(template_file) 13 | 14 | # check for configs directory if not present create 15 | if not os.path.exists(output_directory): 16 | os.mkdir(output_directory) 17 | 18 | # create the config templates 19 | with open("config.json", "r") as parameters: 20 | data = json.load(parameters) 21 | for p in data: 22 | result = template.render(p) 23 | f = open(os.path.join(output_directory, p["hostname"] + ".config"), "w") 24 | f.write(result) 25 | f.close() 26 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "hostname": "Router1", 3 | "dns_server": "8.8.8.8", 4 | "domain_name": "cisco.local", 5 | "dhcp_pool_name": "test_pool", 6 | "dhcp_pool_net": "10.10.10.0", 7 | "dhcp_pool_mask": "255.255.255.0", 8 | "dhcp_router": "10.10.10.1", 9 | "dhcp_dns_server": "8.8.8.8", 10 | "dhcp_excluded": "10.10.10.1", 11 | "user": "cisco", 12 | "priv": "15", 13 | "password": "cisco", 14 | "loopback0_address": "10.11.12.13", 15 | "loopback0_mask": "255.255.255.255", 16 | "tunnel0_description": "WAN Tunnel", 17 | "tunnel0_destination": "1.2.3.4", 18 | "g0_description": "WAN Interface", 19 | "g1_description": "LAN Interface", 20 | "g1_address": "4.5.6.7", 21 | "g1_mask": "255.255.255.0" 22 | }, 23 | { 24 | "hostname": "Router2", 25 | "dns_server": "8.8.8.8", 26 | "domain_name": "cisco.local", 27 | "dhcp_pool_name": "test_pool", 28 | "dhcp_pool_net": "10.10.10.0", 29 | "dhcp_pool_mask": "255.255.255.0", 30 | "dhcp_router": "10.10.10.1", 31 | "dhcp_dns_server": "8.8.8.8", 32 | "dhcp_excluded": "10.10.10.1", 33 | "user": "cisco", 34 | "priv": "15", 35 | "password": "cisco", 36 | "loopback0_address": "10.11.12.13", 37 | "loopback0_mask": "255.255.255.255", 38 | "tunnel0_description": "WAN Tunnel", 39 | "tunnel0_destination": "1.2.3.4", 40 | "g0_description": "WAN Interface", 41 | "g1_description": "LAN Interface", 42 | "g1_address": "4.5.6.7", 43 | "g1_mask": "255.255.255.0" 44 | }] -------------------------------------------------------------------------------- /ios-xe_template.j2: -------------------------------------------------------------------------------- 1 | version 16.6 2 | service timestamps debug datetime msec 3 | service timestamps log datetime msec 4 | service password-encryption 5 | platform qfp utilization monitor load 80 6 | no platform punt-keepalive disable-kernel-core 7 | platform hardware throughput level 75000 8 | ! 9 | hostname {{hostname}} 10 | ! 11 | boot-start-marker 12 | boot-end-marker 13 | ! 14 | ! 15 | logging buffered 16384 informational 16 | ! 17 | no aaa new-model 18 | ! 19 | no ip bootp server 20 | ip name-server {{dns_server}} 21 | no ip domain lookup 22 | ip domain name {{domain_name}} 23 | ip dhcp excluded-address {{dhcp_excluded}} 24 | ! 25 | ip dhcp pool {{dhcp_pool_name}} 26 | network {{dhcp_pool_net}} {{dhcp_pool_mask}} 27 | default-router {{dhcp_router}} 28 | dns-server {{dhcp_dns_server}} 29 | ! 30 | ! 31 | ! 32 | ! 33 | ! 34 | ! 35 | ! 36 | ! 37 | ! 38 | ! 39 | subscriber templating 40 | ! 41 | ! 42 | ! 43 | ! 44 | ! 45 | ! 46 | ! 47 | multilink bundle-name authenticated 48 | ! 49 | ! 50 | ! 51 | ! 52 | ! 53 | ! 54 | ! 55 | license accept end user agreement 56 | license boot level securityk9 57 | diagnostic bootup level minimal 58 | spanning-tree extend system-id 59 | ! 60 | ! 61 | ! 62 | username {{user}} privilege {{priv}} secret {{pass}} 63 | ! 64 | redundancy 65 | mode none 66 | ! 67 | ! 68 | ! 69 | vlan internal allocation policy ascending 70 | ! 71 | no cdp run 72 | ! 73 | ! 74 | ! 75 | ! 76 | ! 77 | ! 78 | ! 79 | ! 80 | ! 81 | ! 82 | ! 83 | ! 84 | ! 85 | ! 86 | ! 87 | ! 88 | ! 89 | interface Loopback0 90 | ip address {{loopback0_address}} {{loopback0_mask}} 91 | ip ospf 1 area 0 92 | ! 93 | interface Tunnel0 94 | description {{tunnel0_description}} 95 | ip unnumbered Loopback0 96 | ip ospf 1 area 0 97 | tunnel source GigabitEthernet0/0/0 98 | tunnel mode ipsec ipv4 99 | tunnel destination {{tunnel0_destination}} 100 | tunnel path-mtu-discovery 101 | ! 102 | interface GigabitEthernet0/0/0 103 | description {{g0_description}} 104 | ip address dhcp 105 | no ip redirects 106 | no ip unreachables 107 | no ip proxy-arp 108 | load-interval 30 109 | negotiation auto 110 | ! 111 | interface GigabitEthernet0/0/1 112 | description {{g1_description}} 113 | ip address {{g1_address}} {{g1_mask}} 114 | ip ospf 1 area 0 115 | negotiation auto 116 | ! 117 | interface GigabitEthernet0/1/0 118 | ! 119 | interface GigabitEthernet0/1/1 120 | ! 121 | interface GigabitEthernet0/1/2 122 | ! 123 | interface GigabitEthernet0/1/3 124 | ! 125 | interface GigabitEthernet0/1/4 126 | ! 127 | interface GigabitEthernet0/1/5 128 | ! 129 | interface GigabitEthernet0/1/6 130 | ! 131 | interface GigabitEthernet0/1/7 132 | ! 133 | interface Vlan1 134 | no ip address 135 | ! 136 | ! 137 | router ospf 1 138 | passive-interface GigabitEthernet0/0/0 139 | ! 140 | ip forward-protocol nd 141 | no ip http server 142 | no ip http secure-server 143 | ! 144 | ip route {{tunnel0_destination}} 255.255.255.255 dhcp 145 | ! 146 | ip ssh version 2 147 | ! 148 | ! 149 | ! 150 | ! 151 | ! 152 | control-plane 153 | ! 154 | ! 155 | line con 0 156 | transport input none 157 | stopbits 1 158 | line vty 0 4 159 | login local 160 | transport input ssh 161 | ! 162 | ! 163 | ! 164 | end -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | /* Style inputs with type="text", select elements and textareas */ 2 | input[type=text], select, textarea { 3 | width: 15%; /* Full width */ 4 | padding: 2px; /* Some padding */ 5 | border: 1px solid #ccc; /* Gray border */ 6 | border-radius: 4px; /* Rounded borders */ 7 | box-sizing: border-box; /* Make sure that padding and width stays in place */ 8 | margin-top: 6px; /* Add a top margin */ 9 | margin-bottom: 16px; /* Bottom margin */ 10 | resize: vertical /* Allow the user to vertically resize the textarea (not horizontally) */ 11 | } 12 | 13 | /* Style the submit button with a specific background color etc */ 14 | input[type=submit] { 15 | background-color: #4CAF50; 16 | color: white; 17 | padding: 12px 20px; 18 | border: none; 19 | border-radius: 4px; 20 | cursor: pointer; 21 | } 22 | 23 | /* When moving the mouse over the submit button, add a darker green color */ 24 | input[type=submit]:hover { 25 | background-color: #45a049; 26 | } 27 | 28 | /* Add a background color and some padding around the form */ 29 | .container { 30 | border-radius: 5px; 31 | background-color: #f2f2f2; 32 | padding: 20px; 33 | } 34 | label { 35 | font : 1.2em "Arial", sans-serif; 36 | } -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IOS-XE Configuration Generator 7 | 8 | 9 | 10 |

IOS-XE Configuration Generator

11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 | 60 |
61 |
62 | 63 | 64 |
65 |
66 | 67 | 68 |
69 |
70 | 71 | 72 |
73 |
74 | 75 | 76 |
77 |
78 | 79 | 80 |
81 |
82 | 83 | 84 |
85 |
86 | 87 | 88 |
89 |
90 | 91 | 92 |
93 |
94 | 95 |
96 |
97 | 98 | 99 | -------------------------------------------------------------------------------- /templates/success.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IOS-XE Configuration Generator 6 | 7 | 8 | 9 |

IOS-XE Configuration Generator

10 |

Configuration Generated Successfully

11 |

Please find your configuration in the configs directory

12 | 13 | -------------------------------------------------------------------------------- /web.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2019 Cisco and/or its affiliates. 3 | This software is licensed to you under the terms of the Cisco Sample 4 | Code License, Version 1.1 (the "License"). You may obtain a copy of the 5 | License at 6 | https://developer.cisco.com/docs/licenses 7 | All use of the material herein must be in accordance with the terms of 8 | the License. All rights not expressly granted by the License are 9 | reserved. Unless required by applicable law or agreed to separately in 10 | writing, software distributed under the License is distributed on an "AS 11 | IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 12 | or implied. 13 | 14 | Filename: config.py 15 | Version: Python 3.7.2 16 | Authors: Aaron Warner (aawarner@cisco.com) 17 | Description: Simple IOS-XE configuration Generator. Run program and browse to 127.0.0.1:5000 18 | """ 19 | 20 | import jinja2 21 | import os 22 | from flask import Flask, render_template, request, redirect, url_for, flash, send_file 23 | app = Flask(__name__) 24 | 25 | @app.route("/") 26 | def webroot(): 27 | return render_template("index.html") 28 | 29 | @app.route("/success", methods = ["GET"]) 30 | def success(): 31 | return render_template("success.html") 32 | 33 | @app.route("/config", methods = ["POST"]) 34 | def config(): 35 | hostname = request.form["hostname"] 36 | dns_server = request.form["dns_server"] 37 | domain_name = request.form["domain_name"] 38 | dhcp_pool_name = request.form["dhcp_pool_name"] 39 | dhcp_pool_net = request.form["dhcp_pool_net"] 40 | dhcp_pool_mask = request.form["dhcp_pool_mask"] 41 | dhcp_router = request.form["dhcp_router"] 42 | dhcp_dns_server = request.form["dhcp_dns_server"] 43 | dhcp_excluded = request.form["dhcp_excluded"] 44 | user = request.form["user"] 45 | priv = request.form["priv"] 46 | password = request.form["password"] 47 | loopback0_address = request.form["loopback0_address"] 48 | loopback0_mask = request.form["loopback0_mask"] 49 | tunnel0_description = request.form["tunnel0_description"] 50 | tunnel0_destination = request.form["tunnel0_destination"] 51 | g0_description = request.form["g0_description"] 52 | g1_description = request.form["g1_description"] 53 | g1_address = request.form["g1_address"] 54 | g1_mask = request.form["g1_mask"] 55 | 56 | data = [{ 57 | "hostname": hostname, 58 | "dns_server": dns_server, 59 | "domain_name": domain_name, 60 | "dhcp_pool_name": dhcp_pool_name, 61 | "dhcp_pool_net": dhcp_pool_net, 62 | "dhcp_pool_mask": dhcp_pool_mask, 63 | "dhcp_router": dhcp_router, 64 | "dhcp_dns_server": dhcp_dns_server, 65 | "dhcp_excluded": dhcp_excluded, 66 | "user": user, 67 | "priv": priv, 68 | "password": password, 69 | "loopback0_address": loopback0_address, 70 | "loopback0_mask": loopback0_mask, 71 | "tunnel0_description": tunnel0_description, 72 | "tunnel0_destination": tunnel0_destination, 73 | "g0_description": g0_description, 74 | "g1_description": g1_description, 75 | "g1_address": g1_address, 76 | "g1_mask": g1_mask 77 | }] 78 | 79 | template_file = "ios-xe_template.j2" 80 | output_directory = "configs" 81 | # create the central Jinja2 environment and load template 82 | env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath="."), 83 | trim_blocks=True, 84 | lstrip_blocks=True) 85 | template = env.get_template(template_file) 86 | 87 | # check for configs directory if not present create 88 | if not os.path.exists(output_directory): 89 | os.mkdir(output_directory) 90 | 91 | # create the config templates 92 | for p in data: 93 | result = template.render(p) 94 | f = open(os.path.join(output_directory, p['hostname'] + ".config"), "w") 95 | f.write(result) 96 | f.close() 97 | return redirect(url_for("success")) 98 | 99 | if __name__ == '__main__': 100 | app.run() --------------------------------------------------------------------------------