1823b8294SYaroslav Brustinov#!/router/bin/python
2823b8294SYaroslav Brustinov
3823b8294SYaroslav Brustinovfrom interfaces_e import IFType
4823b8294SYaroslav Brustinovimport CustomLogger
5823b8294SYaroslav Brustinovimport misc_methods
6823b8294SYaroslav Brustinovimport telnetlib
7823b8294SYaroslav Brustinovimport socket
8501fb3b4SYaroslav Brustinovimport time
92bcbca45Simaromfrom collections import OrderedDict
10823b8294SYaroslav Brustinov
11823b8294SYaroslav Brustinovclass CCommandCache(object):
12823b8294SYaroslav Brustinov    def __init__(self):
13823b8294SYaroslav Brustinov        self.__gen_clean_data_structure()
14823b8294SYaroslav Brustinov
15823b8294SYaroslav Brustinov    def __gen_clean_data_structure (self):
162bcbca45Simarom        self.cache =  {"IF"   : OrderedDict(),
17823b8294SYaroslav Brustinov                       "CONF" : [],
18823b8294SYaroslav Brustinov                       "EXEC" : []}
19823b8294SYaroslav Brustinov
20823b8294SYaroslav Brustinov    def __list_append (self, dest_list, cmd):
21823b8294SYaroslav Brustinov        if isinstance(cmd, list):
22823b8294SYaroslav Brustinov            dest_list.extend( cmd )
23823b8294SYaroslav Brustinov        else:
24823b8294SYaroslav Brustinov            dest_list.append( cmd )
25823b8294SYaroslav Brustinov
26823b8294SYaroslav Brustinov    def add (self, cmd_type, cmd, interface = None):
27823b8294SYaroslav Brustinov
28823b8294SYaroslav Brustinov        if interface is not None: # this is an interface ("IF") config command
29823b8294SYaroslav Brustinov            if interface in self.cache['IF']:
30823b8294SYaroslav Brustinov                # interface commands already exists
31823b8294SYaroslav Brustinov                self.__list_append(self.cache['IF'][interface], cmd)
32823b8294SYaroslav Brustinov            else:
33823b8294SYaroslav Brustinov                # no chached commands for this interface
34823b8294SYaroslav Brustinov                self.cache['IF'][interface] = []
35823b8294SYaroslav Brustinov                self.__list_append(self.cache['IF'][interface], cmd)
36823b8294SYaroslav Brustinov        else:                 # this is either a CONF or EXEC command
37823b8294SYaroslav Brustinov            self.__list_append(self.cache[cmd_type.upper()], cmd)
38823b8294SYaroslav Brustinov
39823b8294SYaroslav Brustinov    def dump_config (self):
40823b8294SYaroslav Brustinov        # dump IF config:
4189a2be82Simarom        print("configure terminal")
4289a2be82Simarom        for intf, intf_cmd_list in self.cache['IF'].items():
4389a2be82Simarom            print("interface {if_name}".format( if_name = intf ))
4489a2be82Simarom            print('\n'.join(intf_cmd_list))
45823b8294SYaroslav Brustinov
46823b8294SYaroslav Brustinov        if self.cache['IF']:
47823b8294SYaroslav Brustinov            # add 'exit' note only if if config actually took place
4889a2be82Simarom            print('exit')    # exit to global config mode
49823b8294SYaroslav Brustinov
50823b8294SYaroslav Brustinov        # dump global config
51823b8294SYaroslav Brustinov        if self.cache['CONF']:
5289a2be82Simarom            print('\n'.join(self.cache['CONF']))
53823b8294SYaroslav Brustinov
54823b8294SYaroslav Brustinov        # exit back to en mode
5589a2be82Simarom        print("exit")
56823b8294SYaroslav Brustinov
57823b8294SYaroslav Brustinov        # dump exec config
58823b8294SYaroslav Brustinov        if self.cache['EXEC']:
5989a2be82Simarom            print('\n'.join(self.cache['EXEC']))
60823b8294SYaroslav Brustinov
61823b8294SYaroslav Brustinov    def get_config_list (self):
62823b8294SYaroslav Brustinov        conf_list = []
63823b8294SYaroslav Brustinov
64823b8294SYaroslav Brustinov        conf_list.append("configure terminal")
6589a2be82Simarom        for intf, intf_cmd_list in self.cache['IF'].items():
66823b8294SYaroslav Brustinov            conf_list.append( "interface {if_name}".format( if_name = intf ) )
67823b8294SYaroslav Brustinov            conf_list.extend( intf_cmd_list )
68823b8294SYaroslav Brustinov        if len(conf_list)>1:
69823b8294SYaroslav Brustinov            # add 'exit' note only if if config actually took place
70823b8294SYaroslav Brustinov            conf_list.append("exit")
71823b8294SYaroslav Brustinov
72823b8294SYaroslav Brustinov        conf_list.extend( self.cache['CONF'] )
73823b8294SYaroslav Brustinov        conf_list.append("exit")
74823b8294SYaroslav Brustinov        conf_list.extend( self.cache['EXEC'] )
75823b8294SYaroslav Brustinov
76823b8294SYaroslav Brustinov
77823b8294SYaroslav Brustinov        return conf_list
78823b8294SYaroslav Brustinov
79823b8294SYaroslav Brustinov    def clear_cache (self):
80823b8294SYaroslav Brustinov        # clear all pointers to cache data (erase the data structure)
81823b8294SYaroslav Brustinov        self.cache.clear()
82823b8294SYaroslav Brustinov        # Re-initialize the cache
83823b8294SYaroslav Brustinov        self.__gen_clean_data_structure()
84823b8294SYaroslav Brustinov
85823b8294SYaroslav Brustinov    pass
86823b8294SYaroslav Brustinov
87823b8294SYaroslav Brustinov
88823b8294SYaroslav Brustinovclass CCommandLink(object):
8946455302SYaroslav Brustinov    def __init__(self, silent_mode = False, debug_mode = False):
90823b8294SYaroslav Brustinov        self.history        = []
91823b8294SYaroslav Brustinov        self.virtual_mode   = True
92823b8294SYaroslav Brustinov        self.silent_mode    = silent_mode
93823b8294SYaroslav Brustinov        self.telnet_con     = None
9446455302SYaroslav Brustinov        self.debug_mode     = debug_mode
95823b8294SYaroslav Brustinov
96823b8294SYaroslav Brustinov
97823b8294SYaroslav Brustinov    def __transmit (self, cmd_list, **kwargs):
98823b8294SYaroslav Brustinov        self.history.extend(cmd_list)
9946455302SYaroslav Brustinov        if not self.silent_mode:
10046455302SYaroslav Brustinov            print('\n'.join(cmd_list))   # prompting the pushed platform commands
101823b8294SYaroslav Brustinov        if not self.virtual_mode:
102823b8294SYaroslav Brustinov            # transmit the command to platform.
10346455302SYaroslav Brustinov            return self.telnet_con.write_ios_cmd(cmd_list, debug_mode = self.debug_mode, **kwargs)
104823b8294SYaroslav Brustinov
105823b8294SYaroslav Brustinov    def run_command (self, cmd_list, **kwargs):
106823b8294SYaroslav Brustinov        response = ''
107823b8294SYaroslav Brustinov        for cmd in cmd_list:
108823b8294SYaroslav Brustinov
109823b8294SYaroslav Brustinov            # check which type of cmd we handle
110823b8294SYaroslav Brustinov            if isinstance(cmd, CCommandCache):
111823b8294SYaroslav Brustinov                tmp_response = self.__transmit( cmd.get_config_list(), **kwargs )   # join the commands with new-line delimiter
112823b8294SYaroslav Brustinov            else:
113823b8294SYaroslav Brustinov                tmp_response = self.__transmit([cmd], **kwargs)
114823b8294SYaroslav Brustinov            if not self.virtual_mode:
115823b8294SYaroslav Brustinov                response += tmp_response
116823b8294SYaroslav Brustinov        return response
117823b8294SYaroslav Brustinov
118823b8294SYaroslav Brustinov    def run_single_command (self, cmd, **kwargs):
119823b8294SYaroslav Brustinov        return self.run_command([cmd], **kwargs)
120823b8294SYaroslav Brustinov
121823b8294SYaroslav Brustinov    def get_history (self, as_string = False):
122823b8294SYaroslav Brustinov        if as_string:
123823b8294SYaroslav Brustinov            return '\n'.join(self.history)
124823b8294SYaroslav Brustinov        else:
125823b8294SYaroslav Brustinov            return self.history
126823b8294SYaroslav Brustinov
127823b8294SYaroslav Brustinov    def clear_history (self):
128823b8294SYaroslav Brustinov        # clear all pointers to history data (erase the data structure)
129823b8294SYaroslav Brustinov        del self.history[:]
130823b8294SYaroslav Brustinov        # Re-initialize the histoyr with clear one
131823b8294SYaroslav Brustinov        self.history = []
132823b8294SYaroslav Brustinov
133823b8294SYaroslav Brustinov    def launch_platform_connectivity (self, device_config_obj):
134823b8294SYaroslav Brustinov        connection_info = device_config_obj.get_platform_connection_data()
135823b8294SYaroslav Brustinov        self.telnet_con     = CIosTelnet( **connection_info )
136823b8294SYaroslav Brustinov        self.virtual_mode   = False # if physical connectivity was successful, toggle virtual mode off
137823b8294SYaroslav Brustinov
138823b8294SYaroslav Brustinov    def close_platform_connection(self):
139823b8294SYaroslav Brustinov        if self.telnet_con is not None:
140823b8294SYaroslav Brustinov            self.telnet_con.close()
141823b8294SYaroslav Brustinov
142823b8294SYaroslav Brustinov
143823b8294SYaroslav Brustinov
144823b8294SYaroslav Brustinovclass CDeviceCfg(object):
145823b8294SYaroslav Brustinov    def __init__(self, cfg_yaml_path = None):
146823b8294SYaroslav Brustinov        if cfg_yaml_path is not None:
147823b8294SYaroslav Brustinov            (self.platform_cfg, self.tftp_cfg) = misc_methods.load_complete_config_file(cfg_yaml_path)[1:3]
148823b8294SYaroslav Brustinov
149823b8294SYaroslav Brustinov            self.interfaces_cfg = self.platform_cfg['interfaces'] # extract only the router interface configuration
150823b8294SYaroslav Brustinov
151823b8294SYaroslav Brustinov    def set_platform_config(self, config_dict):
152823b8294SYaroslav Brustinov        self.platform_cfg = config_dict
153823b8294SYaroslav Brustinov        self.interfaces_cfg = self.platform_cfg['interfaces']
154823b8294SYaroslav Brustinov
155823b8294SYaroslav Brustinov    def set_tftp_config(self, tftp_cfg):
156823b8294SYaroslav Brustinov        self.tftp_cfg = tftp_cfg
157823b8294SYaroslav Brustinov
158823b8294SYaroslav Brustinov    def get_interfaces_cfg (self):
159823b8294SYaroslav Brustinov        return self.interfaces_cfg
160823b8294SYaroslav Brustinov
161823b8294SYaroslav Brustinov    def get_ip_address (self):
162823b8294SYaroslav Brustinov        return self.__get_attr('ip_address')
163823b8294SYaroslav Brustinov
164823b8294SYaroslav Brustinov    def get_line_password (self):
165823b8294SYaroslav Brustinov        return self.__get_attr('line_pswd')
166823b8294SYaroslav Brustinov
167823b8294SYaroslav Brustinov    def get_en_password (self):
168823b8294SYaroslav Brustinov        return self.__get_attr('en_pswd')
169823b8294SYaroslav Brustinov
170823b8294SYaroslav Brustinov    def get_mgmt_interface (self):
171823b8294SYaroslav Brustinov        return self.__get_attr('mgmt_interface')
172823b8294SYaroslav Brustinov
173823b8294SYaroslav Brustinov    def get_platform_connection_data (self):
174823b8294SYaroslav Brustinov        return { 'host' : self.get_ip_address(), 'line_pass' : self.get_line_password(), 'en_pass' : self.get_en_password() }
175823b8294SYaroslav Brustinov
176823b8294SYaroslav Brustinov    def get_tftp_info (self):
177823b8294SYaroslav Brustinov        return self.tftp_cfg
178823b8294SYaroslav Brustinov
179823b8294SYaroslav Brustinov    def get_image_name (self):
180823b8294SYaroslav Brustinov        return self.__get_attr('image')
181823b8294SYaroslav Brustinov
182823b8294SYaroslav Brustinov    def __get_attr (self, attr):
183823b8294SYaroslav Brustinov        return self.platform_cfg[attr]
184823b8294SYaroslav Brustinov
185823b8294SYaroslav Brustinov    def dump_config (self):
186823b8294SYaroslav Brustinov        import yaml
18789a2be82Simarom        print(yaml.dump(self.interfaces_cfg, default_flow_style=False))
188823b8294SYaroslav Brustinov
189823b8294SYaroslav Brustinovclass CIfObj(object):
190823b8294SYaroslav Brustinov    _obj_id = 0
191823b8294SYaroslav Brustinov
19268c71be2SIdo Barnea    def __init__(self, if_name, ipv4_addr, ipv6_addr, src_mac_addr, dest_mac_addr, dest_ipv6_mac_addr, if_type):
193823b8294SYaroslav Brustinov        self.__get_and_increment_id()
194823b8294SYaroslav Brustinov        self.if_name        = if_name
195823b8294SYaroslav Brustinov        self.if_type        = if_type
196823b8294SYaroslav Brustinov        self.src_mac_addr   = src_mac_addr
197823b8294SYaroslav Brustinov        self.dest_mac_addr  = dest_mac_addr
19868c71be2SIdo Barnea        self.dest_ipv6_mac_addr  = dest_ipv6_mac_addr
199501fb3b4SYaroslav Brustinov        self.ipv4_addr      = ipv4_addr
200501fb3b4SYaroslav Brustinov        self.ipv6_addr      = ipv6_addr
201823b8294SYaroslav Brustinov        self.pair_parent    = None     # a pointer to CDualIfObj which holds this interface and its pair-complement
202823b8294SYaroslav Brustinov
203823b8294SYaroslav Brustinov    def __get_and_increment_id (self):
204823b8294SYaroslav Brustinov        self._obj_id = CIfObj._obj_id
205823b8294SYaroslav Brustinov        CIfObj._obj_id += 1
206823b8294SYaroslav Brustinov
207823b8294SYaroslav Brustinov    def get_name (self):
208823b8294SYaroslav Brustinov        return self.if_name
209823b8294SYaroslav Brustinov
210823b8294SYaroslav Brustinov    def get_src_mac_addr (self):
211823b8294SYaroslav Brustinov        return self.src_mac_addr
212823b8294SYaroslav Brustinov
213823b8294SYaroslav Brustinov    def get_dest_mac (self):
214823b8294SYaroslav Brustinov        return self.dest_mac_addr
215823b8294SYaroslav Brustinov
21668c71be2SIdo Barnea    def get_ipv6_dest_mac (self):
21768c71be2SIdo Barnea        if self.dest_mac_addr != 0:
21868c71be2SIdo Barnea            return self.dest_mac_addr
21968c71be2SIdo Barnea        else:
22068c71be2SIdo Barnea            return self.dest_ipv6_mac_addr
22168c71be2SIdo Barnea
222823b8294SYaroslav Brustinov    def get_id (self):
223823b8294SYaroslav Brustinov        return self._obj_id
224823b8294SYaroslav Brustinov
225823b8294SYaroslav Brustinov    def get_if_type (self):
226823b8294SYaroslav Brustinov        return self.if_type
227823b8294SYaroslav Brustinov
228823b8294SYaroslav Brustinov    def get_ipv4_addr (self):
229823b8294SYaroslav Brustinov        return self.ipv4_addr
230823b8294SYaroslav Brustinov
231823b8294SYaroslav Brustinov    def get_ipv6_addr (self):
232823b8294SYaroslav Brustinov        return self.ipv6_addr
233823b8294SYaroslav Brustinov
234823b8294SYaroslav Brustinov    def set_ipv4_addr (self, addr):
235823b8294SYaroslav Brustinov        self.ipv4_addr = addr
236823b8294SYaroslav Brustinov
237823b8294SYaroslav Brustinov    def set_ipv6_addr (self, addr):
238823b8294SYaroslav Brustinov        self.ipv6_addr = addr
239823b8294SYaroslav Brustinov
240823b8294SYaroslav Brustinov    def set_pair_parent (self, dual_if_obj):
241823b8294SYaroslav Brustinov        self.pair_parent = dual_if_obj
242823b8294SYaroslav Brustinov
243823b8294SYaroslav Brustinov    def get_pair_parent (self):
244823b8294SYaroslav Brustinov        return self.pair_parent
245823b8294SYaroslav Brustinov
246823b8294SYaroslav Brustinov    def is_client (self):
247823b8294SYaroslav Brustinov        return (self.if_type == IFType.Client)
248823b8294SYaroslav Brustinov
249823b8294SYaroslav Brustinov    def is_server (self):
250823b8294SYaroslav Brustinov        return (self.if_type == IFType.Server)
251823b8294SYaroslav Brustinov
252823b8294SYaroslav Brustinov    pass
253823b8294SYaroslav Brustinov
254823b8294SYaroslav Brustinov
255823b8294SYaroslav Brustinovclass CDualIfObj(object):
256823b8294SYaroslav Brustinov    _obj_id = 0
257823b8294SYaroslav Brustinov
258823b8294SYaroslav Brustinov    def __init__(self, vrf_name, client_if_obj, server_if_obj):
259823b8294SYaroslav Brustinov        self.__get_and_increment_id()
260823b8294SYaroslav Brustinov        self.vrf_name       = vrf_name
261823b8294SYaroslav Brustinov        self.client_if      = client_if_obj
262823b8294SYaroslav Brustinov        self.server_if      = server_if_obj
263823b8294SYaroslav Brustinov
264823b8294SYaroslav Brustinov        # link if_objects to its parent dual_if
265823b8294SYaroslav Brustinov        self.client_if.set_pair_parent(self)
266823b8294SYaroslav Brustinov        self.server_if.set_pair_parent(self)
267823b8294SYaroslav Brustinov        pass
268823b8294SYaroslav Brustinov
269823b8294SYaroslav Brustinov    def __get_and_increment_id (self):
270823b8294SYaroslav Brustinov        self._obj_id = CDualIfObj._obj_id
271823b8294SYaroslav Brustinov        CDualIfObj._obj_id += 1
272823b8294SYaroslav Brustinov
273823b8294SYaroslav Brustinov    def get_id (self):
274823b8294SYaroslav Brustinov        return self._obj_id
275823b8294SYaroslav Brustinov
276823b8294SYaroslav Brustinov    def get_vrf_name (self):
277823b8294SYaroslav Brustinov        return self.vrf_name
278823b8294SYaroslav Brustinov
279823b8294SYaroslav Brustinov    def is_duplicated (self):
280823b8294SYaroslav Brustinov        return self.vrf_name != None
281823b8294SYaroslav Brustinov
282823b8294SYaroslav Brustinovclass CIfManager(object):
283823b8294SYaroslav Brustinov    _ipv4_gen = misc_methods.get_network_addr()
284823b8294SYaroslav Brustinov    _ipv6_gen = misc_methods.get_network_addr(ip_type = 'ipv6')
285823b8294SYaroslav Brustinov
286823b8294SYaroslav Brustinov    def __init__(self):
2872bcbca45Simarom        self.interfarces     = OrderedDict()
288823b8294SYaroslav Brustinov        self.dual_intf       = []
289823b8294SYaroslav Brustinov        self.full_device_cfg = None
290823b8294SYaroslav Brustinov
291823b8294SYaroslav Brustinov    def __add_if_to_manager (self, if_obj):
292823b8294SYaroslav Brustinov        self.interfarces[if_obj.get_name()] = if_obj
293823b8294SYaroslav Brustinov
294823b8294SYaroslav Brustinov    def __add_dual_if_to_manager (self, dual_if_obj):
295823b8294SYaroslav Brustinov        self.dual_intf.append(dual_if_obj)
296823b8294SYaroslav Brustinov
297823b8294SYaroslav Brustinov    def __get_ipv4_net_client_addr(self, ipv4_addr):
298823b8294SYaroslav Brustinov        return misc_methods.get_single_net_client_addr (ipv4_addr)
299823b8294SYaroslav Brustinov
300823b8294SYaroslav Brustinov    def __get_ipv6_net_client_addr(self, ipv6_addr):
301823b8294SYaroslav Brustinov        return misc_methods.get_single_net_client_addr (ipv6_addr, {'7' : 1}, ip_type = 'ipv6')
302823b8294SYaroslav Brustinov
303823b8294SYaroslav Brustinov    def load_config (self, device_config_obj):
304823b8294SYaroslav Brustinov        self.full_device_cfg = device_config_obj
305823b8294SYaroslav Brustinov        # first, erase all current config
306823b8294SYaroslav Brustinov        self.interfarces.clear()
307823b8294SYaroslav Brustinov        del self.dual_intf[:]
308823b8294SYaroslav Brustinov
309823b8294SYaroslav Brustinov        # than, load the configuration
310823b8294SYaroslav Brustinov        intf_config = device_config_obj.get_interfaces_cfg()
311823b8294SYaroslav Brustinov
312823b8294SYaroslav Brustinov        # finally, parse the information into data-structures
313823b8294SYaroslav Brustinov        for intf_pair in intf_config:
314823b8294SYaroslav Brustinov            # generate network addresses for client side, and initialize client if object
315823b8294SYaroslav Brustinov            tmp_ipv4_addr = self.__get_ipv4_net_client_addr (next(CIfManager._ipv4_gen)[0])
316823b8294SYaroslav Brustinov            tmp_ipv6_addr = self.__get_ipv6_net_client_addr (next(CIfManager._ipv6_gen))
317823b8294SYaroslav Brustinov
3189c6e6d4bSIdo Barnea            if 'dest_mac_addr' in intf_pair['client']:
3199c6e6d4bSIdo Barnea                client_dest_mac = intf_pair['client']['dest_mac_addr']
3209c6e6d4bSIdo Barnea            else:
3219c6e6d4bSIdo Barnea                client_dest_mac = 0
32268c71be2SIdo Barnea            if 'dest_ipv6_mac_addr' in intf_pair['client']:
32368c71be2SIdo Barnea                client_dest_ipv6_mac = intf_pair['client']['dest_ipv6_mac_addr']
32468c71be2SIdo Barnea            else:
32568c71be2SIdo Barnea                client_dest_ipv6_mac = 0
326823b8294SYaroslav Brustinov            client_obj = CIfObj(if_name = intf_pair['client']['name'],
327823b8294SYaroslav Brustinov                ipv4_addr = tmp_ipv4_addr,
328823b8294SYaroslav Brustinov                ipv6_addr = tmp_ipv6_addr,
329823b8294SYaroslav Brustinov                src_mac_addr  = intf_pair['client']['src_mac_addr'],
3309c6e6d4bSIdo Barnea                dest_mac_addr = client_dest_mac,
33168c71be2SIdo Barnea                dest_ipv6_mac_addr = client_dest_ipv6_mac,
332823b8294SYaroslav Brustinov                if_type   = IFType.Client)
333823b8294SYaroslav Brustinov
334823b8294SYaroslav Brustinov            # generate network addresses for server side, and initialize server if object
335823b8294SYaroslav Brustinov            tmp_ipv4_addr = self.__get_ipv4_net_client_addr (next(CIfManager._ipv4_gen)[0])
336823b8294SYaroslav Brustinov            tmp_ipv6_addr = self.__get_ipv6_net_client_addr (next(CIfManager._ipv6_gen))
3379c6e6d4bSIdo Barnea
3389c6e6d4bSIdo Barnea            if 'dest_mac_addr' in intf_pair['server']:
3399c6e6d4bSIdo Barnea                server_dest_mac = intf_pair['server']['dest_mac_addr']
3409c6e6d4bSIdo Barnea            else:
3419c6e6d4bSIdo Barnea                server_dest_mac = 0
34268c71be2SIdo Barnea            if 'dest_ipv6_mac_addr' in intf_pair['server']:
34368c71be2SIdo Barnea                server_dest_ipv6_mac = intf_pair['server']['dest_ipv6_mac_addr']
34468c71be2SIdo Barnea            else:
34568c71be2SIdo Barnea                server_dest_ipv6_mac = 0
346823b8294SYaroslav Brustinov            server_obj = CIfObj(if_name = intf_pair['server']['name'],
347823b8294SYaroslav Brustinov                ipv4_addr = tmp_ipv4_addr,
348823b8294SYaroslav Brustinov                ipv6_addr = tmp_ipv6_addr,
349823b8294SYaroslav Brustinov                src_mac_addr  = intf_pair['server']['src_mac_addr'],
3509c6e6d4bSIdo Barnea                dest_mac_addr = server_dest_mac,
35168c71be2SIdo Barnea                dest_ipv6_mac_addr = server_dest_ipv6_mac,
352823b8294SYaroslav Brustinov                if_type   = IFType.Server)
353823b8294SYaroslav Brustinov
354823b8294SYaroslav Brustinov            dual_intf_obj = CDualIfObj(vrf_name = intf_pair['vrf_name'],
355823b8294SYaroslav Brustinov                client_if_obj = client_obj,
356823b8294SYaroslav Brustinov                server_if_obj = server_obj)
357823b8294SYaroslav Brustinov
358823b8294SYaroslav Brustinov            # update single interfaces pointers
359823b8294SYaroslav Brustinov            client_obj.set_pair_parent(dual_intf_obj)
360823b8294SYaroslav Brustinov            server_obj.set_pair_parent(dual_intf_obj)
361823b8294SYaroslav Brustinov
362823b8294SYaroslav Brustinov            # finally, update the data-structures with generated objects
363823b8294SYaroslav Brustinov            self.__add_if_to_manager(client_obj)
364823b8294SYaroslav Brustinov            self.__add_if_to_manager(server_obj)
365823b8294SYaroslav Brustinov            self.__add_dual_if_to_manager(dual_intf_obj)
366823b8294SYaroslav Brustinov
367823b8294SYaroslav Brustinov
368823b8294SYaroslav Brustinov    def get_if_list (self, if_type = IFType.All, is_duplicated = None):
369823b8294SYaroslav Brustinov        result = []
37089a2be82Simarom        for if_name,if_obj in self.interfarces.items():
371823b8294SYaroslav Brustinov            if (if_type == IFType.All) or ( if_obj.get_if_type() == if_type) :
372823b8294SYaroslav Brustinov                if (is_duplicated is None) or (if_obj.get_pair_parent().is_duplicated() == is_duplicated):
373823b8294SYaroslav Brustinov                    # append this if_obj only if matches both IFType and is_duplicated conditions
374823b8294SYaroslav Brustinov                    result.append(if_obj)
375823b8294SYaroslav Brustinov        return result
376823b8294SYaroslav Brustinov
377823b8294SYaroslav Brustinov    def get_duplicated_if (self):
378823b8294SYaroslav Brustinov        result = []
379823b8294SYaroslav Brustinov        for dual_if_obj in self.dual_intf:
380823b8294SYaroslav Brustinov            if dual_if_obj.get_vrf_name() is not None :
381823b8294SYaroslav Brustinov                result.extend( (dual_if_obj.client_if, dual_if_obj.server_if) )
382823b8294SYaroslav Brustinov        return result
383823b8294SYaroslav Brustinov
384823b8294SYaroslav Brustinov    def get_dual_if_list (self, is_duplicated = None):
385823b8294SYaroslav Brustinov        result = []
386823b8294SYaroslav Brustinov        for dual_if in self.dual_intf:
387823b8294SYaroslav Brustinov            if (is_duplicated is None) or (dual_if.is_duplicated() == is_duplicated):
388823b8294SYaroslav Brustinov                result.append(dual_if)
389823b8294SYaroslav Brustinov        return result
390823b8294SYaroslav Brustinov
391823b8294SYaroslav Brustinov    def dump_if_config (self):
392823b8294SYaroslav Brustinov        if self.full_device_cfg is None:
39389a2be82Simarom            print("Device configuration isn't loaded.\nPlease load config and try again.")
394823b8294SYaroslav Brustinov        else:
395823b8294SYaroslav Brustinov            self.full_device_cfg.dump_config()
396823b8294SYaroslav Brustinov
397823b8294SYaroslav Brustinov
398823b8294SYaroslav Brustinovclass AuthError(Exception):
399823b8294SYaroslav Brustinov    pass
400823b8294SYaroslav Brustinov
401823b8294SYaroslav Brustinovclass CIosTelnet(telnetlib.Telnet):
402823b8294SYaroslav Brustinov    AuthError = AuthError
403501fb3b4SYaroslav Brustinov
404501fb3b4SYaroslav Brustinov    # wrapper for compatibility with Python2/3, convert input to bytes
405501fb3b4SYaroslav Brustinov    def str_to_bytes_wrapper(self, func, text, *args, **kwargs):
406501fb3b4SYaroslav Brustinov        if type(text) in (list, tuple):
407501fb3b4SYaroslav Brustinov            text = [elem.encode('ascii') if type(elem) is str else elem for elem in text]
408501fb3b4SYaroslav Brustinov        res = func(self, text.encode('ascii') if type(text) is str else text, *args, **kwargs)
409501fb3b4SYaroslav Brustinov        return res.decode() if type(res) is bytes else res
410501fb3b4SYaroslav Brustinov
411f91190c7SYaroslav Brustinov    def read_until(self, *args, **kwargs):
412f91190c7SYaroslav Brustinov        return self.str_to_bytes_wrapper(telnetlib.Telnet.read_until, *args, **kwargs)
413501fb3b4SYaroslav Brustinov
414f91190c7SYaroslav Brustinov    def write(self, *args, **kwargs):
415f91190c7SYaroslav Brustinov        return self.str_to_bytes_wrapper(telnetlib.Telnet.write, *args, **kwargs)
416501fb3b4SYaroslav Brustinov
417f91190c7SYaroslav Brustinov    def expect(self, *args, **kwargs):
418f91190c7SYaroslav Brustinov        res = self.str_to_bytes_wrapper(telnetlib.Telnet.expect, *args, **kwargs)
419f91190c7SYaroslav Brustinov        return [elem.decode() if type(elem) is bytes else elem for elem in res]
420501fb3b4SYaroslav Brustinov
421823b8294SYaroslav Brustinov    def __init__ (self, host, line_pass, en_pass, port = 23, str_wait = "#"):
422823b8294SYaroslav Brustinov        telnetlib.Telnet.__init__(self)
423823b8294SYaroslav Brustinov        self.host           = host
424823b8294SYaroslav Brustinov        self.port           = port
425823b8294SYaroslav Brustinov        self.line_passwd    = line_pass
426823b8294SYaroslav Brustinov        self.enable_passwd  = en_pass
427823b8294SYaroslav Brustinov        self.pr             = str_wait
428823b8294SYaroslav Brustinov#       self.set_debuglevel (1)
429823b8294SYaroslav Brustinov        try:
430823b8294SYaroslav Brustinov            self.open(self.host,self.port, timeout = 5)
431823b8294SYaroslav Brustinov            self.read_until("word:",1)
432823b8294SYaroslav Brustinov            self.write("{line_pass}\n".format(line_pass = self.line_passwd) )
433823b8294SYaroslav Brustinov            res = self.read_until(">",1)
434823b8294SYaroslav Brustinov            if 'Password' in res:
435823b8294SYaroslav Brustinov                raise AuthError('Invalid line password was provided')
436823b8294SYaroslav Brustinov            self.write("enable 15\n")
437823b8294SYaroslav Brustinov            self.read_until("d:",1)
438823b8294SYaroslav Brustinov            self.write("{en_pass}\n".format(en_pass = self.enable_passwd) )
439823b8294SYaroslav Brustinov            res = self.read_until(self.pr,1)
440823b8294SYaroslav Brustinov            if 'Password' in res:
441823b8294SYaroslav Brustinov                raise AuthError('Invalid en password was provided')
442823b8294SYaroslav Brustinov            self.write_ios_cmd(['terminal length 0'])
443823b8294SYaroslav Brustinov
444823b8294SYaroslav Brustinov        except socket.timeout:
445823b8294SYaroslav Brustinov            raise socket.timeout('A timeout error has occured.\nCheck platform connectivity or the hostname defined in the config file')
446823b8294SYaroslav Brustinov        except Exception as inst:
447823b8294SYaroslav Brustinov            raise
448823b8294SYaroslav Brustinov
4496c46ecabSYaroslav Brustinov    def write_ios_cmd (self, cmd_list, result_from = 0, timeout = 60, **kwargs):
450823b8294SYaroslav Brustinov        assert (isinstance (cmd_list, list) == True)
451501fb3b4SYaroslav Brustinov        self.read_until(self.pr, timeout = 1)
452823b8294SYaroslav Brustinov
453823b8294SYaroslav Brustinov        res = ''
454823b8294SYaroslav Brustinov        if 'read_until' in kwargs:
455823b8294SYaroslav Brustinov            wf = kwargs['read_until']
456823b8294SYaroslav Brustinov        else:
457823b8294SYaroslav Brustinov            wf = self.pr
458823b8294SYaroslav Brustinov
459823b8294SYaroslav Brustinov        for idx, cmd in enumerate(cmd_list):
4606c46ecabSYaroslav Brustinov            start_time = time.time()
461823b8294SYaroslav Brustinov            self.write(cmd+'\r\n')
46246455302SYaroslav Brustinov            if kwargs.get('debug_mode'):
4636c46ecabSYaroslav Brustinov                print('-->\n%s' % cmd)
4646c46ecabSYaroslav Brustinov            if type(wf) is list:
4656c46ecabSYaroslav Brustinov                output = self.expect(wf, timeout)[2]
466823b8294SYaroslav Brustinov            else:
4676c46ecabSYaroslav Brustinov                output = self.read_until(wf, timeout)
4686c46ecabSYaroslav Brustinov            if idx >= result_from:
4696c46ecabSYaroslav Brustinov                res += output
47046455302SYaroslav Brustinov            if kwargs.get('debug_mode'):
4716c46ecabSYaroslav Brustinov                print('<-- (%ss)\n%s' % (round(time.time() - start_time, 2), output))
4726c46ecabSYaroslav Brustinov            if time.time() - start_time > timeout - 1:
4736c46ecabSYaroslav Brustinov                raise Exception('Timeout while performing telnet command: %s' % cmd)
4746c46ecabSYaroslav Brustinov        if 'Invalid' in res:
4756c46ecabSYaroslav Brustinov            print('Warning: telnet command probably failed.\nCommand: %s\nResponse: %s' % (cmd_list, res))
476823b8294SYaroslav Brustinov#       return res.split('\r\n')
477823b8294SYaroslav Brustinov        return res  # return the received response as a string, each line is seperated by '\r\n'.
478823b8294SYaroslav Brustinov
479823b8294SYaroslav Brustinov
480823b8294SYaroslav Brustinovif __name__ == "__main__":
481823b8294SYaroslav Brustinov#   dev_cfg = CDeviceCfg('config/config.yaml')
482823b8294SYaroslav Brustinov#   print dev_cfg.get_platform_connection_data()
483823b8294SYaroslav Brustinov#   telnet = CIosTelnet( **(dev_cfg.get_platform_connection_data() ) )
484823b8294SYaroslav Brustinov
485823b8294SYaroslav Brustinov#   if_mng  = CIfManager()
486823b8294SYaroslav Brustinov#   if_mng.load_config(dev_cfg)
487823b8294SYaroslav Brustinov#   if_mng.dump_config()
488823b8294SYaroslav Brustinov    pass
489