-
Notifications
You must be signed in to change notification settings - Fork 0
/
template_configs.py
116 lines (98 loc) · 4.05 KB
/
template_configs.py
1
2
3
4
5
6
7
8
9
10
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from nornir import InitNornir
from nornir.plugins.functions.text import print_result
from nornir.plugins.tasks.networking import napalm_configure, napalm_get
from nornir.plugins.tasks.text import template_file
from nornsible import InitNornsible, nornsible_task
from termcolor import colored
import os
def format_dir_vars(dir_var):
if isinstance(dir_var, str) != True:
raise ValueError(f"variable passed into 'format_dir_vars' function is not of type string")
"""
make sure environment variables which specify a directory are formatted
correctly for use in script functions
"""
if dir_var[-1] != '/':
dir_var = dir_var + '/'
return dir_var
@nornsible_task
def render_template(task):
"""
Render templates according to role and platform. Replace banner generated by template
with utf-8 encoded banner. Jinja2 doesn't encode in utf-8 and therefore modifies the
carriage return and escape characters that exist in a cisco banner config. Because of this,
when the config is replaced, the banner registers as a diff if not replaced with banner
in utf-8 format
"""
# Render Template per role/device model
role = task.host.get('role')
model = task.host.get('model')
template_dir = f"{IOS_TEMPLATES_DIR}{role}/"
template = f"{model}.j2"
filled_template = task.run(
**task.host,
task=template_file,
name='config',
template=template,
path=template_dir,
)
filled_template = filled_template[0].result
# Convert filled_template to unicode to prep for banner replace
filled_template = filled_template.encode('utf-8')
# Replace ^C in banner with ext character, and '\n' with carriage return
with open('incorrect_banner.txt', 'rb') as f:
incorrect_banner = f.read()
with open('correct_banner.txt', 'rb') as f:
correct_banner = f.read()
filled_template = filled_template.replace(incorrect_banner, correct_banner)
# Write Filled Template to Memory
filename = f'{IOS_FILLED_TEMPLATES_DIR}{task.host.name}.ios'
with open(filename, 'wb') as f:
f.write(filled_template)
@nornsible_task
def replace_config(task):
"""
Replace config on target device with templated configuration. A dry run is
executed first, from which a diff between the current running config and
the target config is generated and output to the user. The user is then
prompted on whether or not they'd like to execute the replace
"""
# Get Config
config_file = f"{IOS_FILLED_TEMPLATES_DIR}{task.host.name}.ios"
# Dry Run Config to get diff and print to terminal
result = task.run(
task=napalm_configure,
dry_run=True,
filename=config_file,
replace=True
)
if result[0].diff != '':
print('\n')
print(f'{task.host.name} Diff: ')
print('-' * 20)
print('\n' + result[0].diff + '\n')
print('\n')
# Query user to see if they want to proceed given diff. If so proceed.
proceed = input('Continue with config replace on {}? (y/n): '.format(task.host.name))
print()
if proceed == 'y':
task.run(task=napalm_configure, dry_run=False, filename=config_file, replace=True)
else:
print('Aborting Config Replace')
print()
else:
print(colored("Nothing Has Changed in the config of ", "green") + colored(f"{task.host.name}", "blue"))
task.run(task=napalm_configure, dry_run=False, filename=config_file, replace=True)
NORNIR_CONFIG_FILE = os.environ['NORNIR_CONFIG_FILE']
IOS_TEMPLATES_DIR = format_dir_vars(os.environ['IOS_TEMPLATES_DIR'])
IOS_FILLED_TEMPLATES_DIR = format_dir_vars(os.environ['IOS_FILLED_TEMPLATES_DIR'])
def main():
# Create Nornir Object, parse with nornsible CLI arguments
nr = InitNornir(config_file=NORNIR_CONFIG_FILE)
nr = InitNornsible(nr)
# Template Configs
nr.run(task=render_template)
# Deploy templated config to switches, print diff, confirm replace
nr.run(task=replace_config)
if __name__ == "__main__":
main()