-
Notifications
You must be signed in to change notification settings - Fork 4
/
ixvztp
executable file
·223 lines (175 loc) · 10.9 KB
/
ixvztp
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/env python
###############################################################################
#
# Zero-Touch Automation utility for Ixia Vision Network Packet Brokers
#
# File: ixvztp
# Author: Alex Bortok (https://github.com/bortok)
#
# Description: Main launcher script for IxVision-ZTA utility
#
# COPYRIGHT 2018 - 2019 Keysight Technologies.
#
# This code is provided under the MIT license.
# You can find the complete terms in LICENSE.txt
#
###############################################################################
import sys
import argparse
import threading
import json
from ixvision_ztp_sysinfo import *
from ixvision_ztp_port_discovery import *
from ixvision_ztp_lldp_tag import *
from ixvision_ztp_port_mode import *
from ixvision_ztp_port_group import *
from ixvision_ztp_filter import *
# DEFINE GLOBAL VARs HERE
debug_on = False
# Possible actions and usage arguments help sting
ztp_actions_choices = {'sysinfo': 'Display system information', \
'portup': 'Performs link status discovery for all currently disabled ports. Successfully connected ports would be configured in Network (ingress) mode.', \
'lldptag': 'Search for LLDP neighbor port descriptions that match one or more supplied tags. Tag the ports, connected to the matched neighbors, with corresponding keywords.', \
'portmode': 'Set port mode to the specified value for ports that match one or more supplied tags.', \
'pgform' : 'Form a group of ports that have keywords matching supplied tags. Both Network and Tool Port Groups are supported.', \
'dfform' : 'Form a dynamic filter with specified input, output and filtering mode.',\
'dfupdate': 'Update a dynamic filter with new criteria'}
ztp_actions_helper = {'sysinfo': 'system information inquiry',\
'portup': 'port status discovery', \
'lldptag': 'lldp-based port tagging', \
'portmode': 'port mode update', \
'pgform' : 'port group formation', \
'dfform' : 'dynamic filter formation',\
'dfupdate': 'dynamic filter update'}
# DEFINE GLOBAL FUNCTIONS HERE
def load_json_from_file(filename):
data = None
parse_failed = False
try:
with open(filename) as f:
try:
data = json.load(f)
except:
parse_failed = True
except:
if not parse_failed:
print("Error: can't read from %s" % filename)
sys.exit(2)
return data
# ****************************************************************************************** #
# Main thread
# CLI arguments parser
parser = argparse.ArgumentParser(prog='ixvztp', description='Zero-Touch Provisioning script for Ixia Vision Network Packet Brokers.')
parser.add_argument('-u', '--username', required=True)
parser.add_argument('-p', '--password', required=True)
parser.add_argument('-d', '--hostname', required=True)
parser.add_argument('-r', '--port', default='8000')
subparsers = parser.add_subparsers(dest='subparser_name')
sysinfo_parser = subparsers.add_parser('sysinfo', description=ztp_actions_choices['sysinfo'])
portup_parser = subparsers.add_parser('portup', description=ztp_actions_choices['portup'])
portup_parser.add_argument('-k', '--keyword', help='Limit discovery to only ports with specified keyword')
lldptag_parser = subparsers.add_parser('lldptag', description=ztp_actions_choices['lldptag'])
lldptag_parser.add_argument('-t', '--tag', required=True, help='Comma-separated list of tags to search for in LLDP neighbor port descriptions')
portmode_parser = subparsers.add_parser('portmode', description=ztp_actions_choices['portmode'])
portmode_parser.add_argument('-t', '--tag', required=True, help='Comma-separated list of tags to search for in NPB port keywords')
portmode_parser.add_argument('-m', '--mode', required=True, help='Port mode: net for network ports, tool for tool ports', choices=port_modes_supported.keys())
pgform_parser = subparsers.add_parser('pgform', description=ztp_actions_choices['pgform'])
pgform_parser.add_argument('-t', '--tag', required=True, help='Comma-separated list of tags to search for in NPB port keywords')
pgform_parser.add_argument('-n', '--name', required=True, help='Port Group name. Can be either an existing PG or a new one')
pgform_parser.add_argument('-m', '--mode', required=True, help='Port Group mode: net for combining network ports, lb for load-balancing across tool ports', choices=pg_modes_supported.keys())
dfform_parser = subparsers.add_parser('dfform', description=ztp_actions_choices['dfform'])
dfform_parser.add_argument('-n', '--name', required=True, help='Dynamic Filter name. Can be either an existing filter or a new one')
dfform_parser.add_argument('-i', '--input', required=True, help='Input port group name to connect to the filter')
dfform_parser.add_argument('-o', '--output', required=True, help='Output port group name to connect to the filter')
dfform_parser.add_argument('-T', '--tag_mode', required=False, help='Execute in tag mode: interpret -i and -o values as tags, instead of port group names', action="store_true")
dfform_parser.add_argument('-m', '--mode', required=True, help='Filtering mode: all - pass any traffic, none - block any traffic, pbc - pass by criteria, dbc - deny by criteria, pbcu - pass traffic unmatched by any other filter, dbcm - pass traffic denied by other filters', choices=df_modes_supported.keys())
dfform_parser.add_argument('-c', '--criteria', help='A JSON file with criteria to use for pbc/dbc filtering modes.')
dfudpate_parser = subparsers.add_parser('dfupdate', description=ztp_actions_choices['dfupdate'])
dfudpate_parser.add_argument('-n', '--name', required=True, help='Name of the Dynamic Filter to update')
dfudpate_parser.add_argument('-f', '--field', required=True, help='Criteria field to update')
dfudpate_parser.add_argument('-a', '--append', required=False, help='Criteria field values to append')
dfudpate_parser.add_argument('-x', '--remove', required=False, help='Criteria field values to remove')
# Common parameters
args = parser.parse_args()
if debug_on:
print ('DEBUG: argumens %s' % args)
username = args.username
password = args.password
host = args.hostname
port = args.port
if args.subparser_name in ztp_actions_choices:
print ('Starting %s for %s' % (ztp_actions_helper[args.subparser_name], host))
if args.subparser_name == 'sysinfo':
nto_get_sysinfo(host, port, username, password)
elif args.subparser_name == 'portup':
# Task-specific parameters
keyword = args.keyword # USING KEYWORD ARG HERE TO DEFINE ZTP SCOPE
discover_ports(host, port, username, password, keyword)
elif args.subparser_name == 'lldptag':
# Task-specific parameters
tags = args.tag.split(",") # A list of keywords to match LLDP info againts
tag_ports(host, port, username, password, tags)
elif args.subparser_name == 'portmode':
# Task-specific parameters
tags = args.tag.split(",") # A list of keywords to search ports
mode = args.mode # (net) for NETWORK, (tool) for TOOL - no other modes are supported yet
set_port_mode(host, port, username, password, tags, mode)
elif args.subparser_name == 'pgform':
# Task-specific parameters
tags = args.tag.upper().split(",") # A list of keywords to match port keywords info againts. NTO keywords are always in upper case
port_group_name = args.name # Name for the group to use (in order to avoid referencing automatically generated group number)
port_group_mode = args.mode # (net) for NETWORK, (lb) for LOAD_BALANCE - no other modes are supported yet
form_port_groups(host, port, username, password, tags, port_group_name, port_group_mode)
elif args.subparser_name == 'dfform':
# Task-specific parameters
df_name = args.name # Name for Dynamic Filter to work with
df_input = args.input # Name for the network port group to connect to the DF or tag for input ports in tag mode
df_output = args.output # Name for the tool port group to connect to the DF or tag for output ports in tag mode
df_mode = args.mode # Mode for Dynamic Filter
criteria_file = args.criteria # File with dynamic filter criteria in JSON format
df_criteria = None # Criteria for Dynamic Filter after pasing criteria_file
if args.tag_mode:
tag_mode = True
else:
tag_mode = False
if df_criteria_required(df_mode):
if criteria_file == None:
print ("Error: criteria file is requied for dynamic filter mode %s" % (df_mode))
sys.exit(2)
else:
df_criteria = load_json_from_file(criteria_file)
if df_criteria == None:
print("Error: can't parse filter criteria from %s" % criteria_file)
sys.exit(2)
form_dynamic_filter(host, port, username, password, df_name, df_input, df_output, df_mode, df_criteria, tag_mode)
elif args.subparser_name == 'dfupdate':
# Task-specific parameters
df_name = args.name # Name for Dynamic Filter to work with
df_criteria_field = args.field # Criteria field to update
df_append_file = args.append # File with values to append to the criteria field, in JSON format
df_remove_file = args.remove # File with values to remove from the criteria field, in JSON format
df_append_values = {}
df_remove_values = {}
if df_criteria_field not in df_criteria_fields_supported.keys():
print("Error: unsupported criteria field, use one from the list: %s" % " | ".join(df_criteria_fields_supported.keys()))
sys.exit(2)
if df_append_file == None and df_remove_file == None:
print("Error: both append and remove parameters are empty, need at least one or both")
sys.exit(2)
if df_append_file != None:
df_append_values = load_json_from_file(df_append_file)
if df_append_values == None:
print("Error: can't parse filter values from %s" % df_append_file)
sys.exit(2)
if df_remove_file != None:
df_remove_values = load_json_from_file(df_remove_file)
if df_remove_values == None:
print("Error: can't parse filter values from %s" % df_remove_file)
sys.exit(2)
update_dynamic_filter(host, port, username, password, df_name, df_criteria_field, df_append_values, df_remove_values)
else:
print ('Unsupported action %s' % args.subparser_name)
sys.exit(2)
else:
parser.usage()
sys.exit(2)