misc_methods.py revision 1f749d9b
1#!/router/bin/python
2import sys
3if sys.version_info >= (3, 0):
4    import configparser
5else:
6    import ConfigParser
7
8import outer_packages
9import yaml
10from collections import namedtuple
11import subprocess, shlex
12import os
13
14TRexConfig = namedtuple('TRexConfig', 'trex, router, tftp')
15
16# debug/development purpose, lists object's attributes and their values
17def print_r(obj):
18    for attr in dir(obj):
19        print('obj.%s %s' % (attr, getattr(obj, attr)))
20
21def mix_string (str):
22    """Convert all string to lowercase letters, and replaces spaces with '_' char"""
23    return str.replace(' ', '_').lower()
24
25# executes given command, returns tuple (return_code, stdout, stderr)
26def run_command(cmd, background = False):
27    if background:
28        print('Running command in background:', cmd)
29        with open(os.devnull, 'w') as tempf:
30            subprocess.Popen(shlex.split(cmd), stdin=tempf, stdout=tempf, stderr=tempf)
31        return (None,)*3
32    else:
33        print('Running command:', cmd)
34        proc = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
35        (stdout, stderr) = proc.communicate()
36        if stdout:
37            print('Stdout:\n%s' % stdout)
38        if proc.returncode:
39            if stderr:
40                print('Stderr:\n%s' % stderr)
41            print('Return code: %s' % proc.returncode)
42        return (proc.returncode, stdout, stderr)
43
44
45def run_remote_command(host, command_string, background = False, timeout = 20):
46    cmd = 'ssh -tt %s \'sudo%s sh -ec "%s"\'' % (host, (' timeout %s' % timeout) if (timeout and not background) else '', command_string)
47    return run_command(cmd, background)
48
49
50def generate_intf_lists (interfacesList):
51    retDict = {
52        'relevant_intf'       : [],
53        'relevant_ip_addr'    : [],
54        'relevant_mac_addr'   : [],
55        'total_pairs'         : None
56        }
57
58    for intf in interfacesList:
59        retDict['relevant_intf'].append(intf['client'])
60        retDict['relevant_ip_addr'].append(intf['client_config']['ip_addr'])
61        retDict['relevant_mac_addr'].append(intf['client_config']['mac_addr'])
62        retDict['relevant_intf'].append(intf['server'])
63        retDict['relevant_ip_addr'].append(intf['server_config']['ip_addr'])
64        retDict['relevant_mac_addr'].append(intf['server_config']['mac_addr'])
65
66    retDict['total_pairs'] = len(interfacesList)
67
68    return retDict
69
70def get_single_net_client_addr (ip_addr, octetListDict = {'3' : 1}, ip_type = 'ipv4'):
71    """ get_single_net_client_addr(ip_addr, octetListDict, ip_type) -> str
72
73        Parameters
74        ----------
75        ip_addr : str
76            a string an IP address (by default, of type A.B.C.D)
77        octetListDict : dict
78            a ditionary representing the octets on which to act such that ip[octet_key] = ip[octet_key] + octet_value
79        ip_type : str
80            a string that defines the ip type to parse. possible inputs are 'ipv4', 'ipv6'
81
82        By default- Returns a new ip address - A.B.C.(D+1)
83    """
84    if ip_type == 'ipv4':
85        ip_lst = ip_addr.split('.')
86
87        for octet,increment in octetListDict.items():
88            int_octet = int(octet)
89            if ((int_octet < 0) or (int_octet > 3)):
90                raise ValueError('the provided octet is not legal in {0} format'.format(ip_type) )
91            else:
92                if (int(ip_lst[int_octet]) + increment) < 255:
93                    ip_lst[int_octet] = str(int(ip_lst[int_octet]) + increment)
94                else:
95                    raise ValueError('the requested increment exceeds 255 client address limit')
96
97        return '.'.join(ip_lst)
98
99    else: # this is a ipv6 address, handle accordingly
100        ip_lst = ip_addr.split(':')
101
102        for octet,increment in octetListDict.items():
103            int_octet = int(octet)
104            if ((int_octet < 0) or (int_octet > 7)):
105                raise ValueError('the provided octet is not legal in {0} format'.format(ip_type) )
106            else:
107                if (int(ip_lst[int_octet]) + increment) < 65535:
108                    ip_lst[int_octet] = format( int(ip_lst[int_octet], 16) + increment, 'X')
109                else:
110                    raise ValueError('the requested increment exceeds 65535 client address limit')
111
112        return ':'.join(ip_lst)
113
114
115def load_complete_config_file (filepath):
116    """load_complete_config_file(filepath) -> list
117
118    Loads a configuration file (.yaml) for both trex config and router config
119    Returns a list with a dictionary to each of the configurations
120    """
121
122    # create response dictionaries
123    trex_config = {}
124    rtr_config  = {}
125    tftp_config = {}
126
127    try:
128        with open(filepath, 'r') as f:
129            config = yaml.load(f)
130
131            # Handle T-Rex configuration
132            trex_config['trex_name']         = config["trex"]["hostname"]
133            trex_config['trex_password']     = config["trex"].get("password")
134            #trex_config['trex_is_dual']      = config["trex"]["is_dual"]
135            trex_config['trex_cores']        = int(config["trex"]["cores"])
136            #trex_config['trex_latency']      = int(config["trex"]["latency"])
137#           trex_config['trex_version_path'] = config["trex"]["version_path"]
138            trex_config['modes']          = config['trex'].get('modes', [])
139
140            if 'loopback' not in trex_config['modes']:
141                trex_config['router_interface']  = config["router"]["ip_address"]
142
143                # Handle Router configuration
144                rtr_config['model']              = config["router"]["model"]
145                rtr_config['hostname']           = config["router"]["hostname"]
146                rtr_config['ip_address']         = config["router"]["ip_address"]
147                rtr_config['image']              = config["router"]["image"]
148                rtr_config['line_pswd']          = config["router"]["line_password"]
149                rtr_config['en_pswd']            = config["router"]["en_password"]
150                rtr_config['interfaces']         = config["router"]["interfaces"]
151                rtr_config['clean_config']       = config["router"]["clean_config"]
152                rtr_config['intf_masking']       = config["router"]["intf_masking"]
153                rtr_config['ipv6_mask']          = config["router"]["ipv6_mask"]
154                rtr_config['mgmt_interface']     = config["router"]["mgmt_interface"]
155
156                # Handle TFTP configuration
157                tftp_config['hostname']          = config["tftp"]["hostname"]
158                tftp_config['ip_address']        = config["tftp"]["ip_address"]
159                tftp_config['images_path']       = config["tftp"]["images_path"]
160
161                if rtr_config['clean_config'] is None:
162                    raise ValueError('A clean router configuration wasn`t provided.')
163
164    except ValueError:
165        print("")
166        raise
167
168    except Exception as inst:
169        print("\nBad configuration file provided: '{0}'\n".format(filepath))
170        raise inst
171
172    return TRexConfig(trex_config, rtr_config, tftp_config)
173
174def load_object_config_file (filepath):
175    try:
176        with open(filepath, 'r') as f:
177            config = yaml.load(f)
178            return config
179    except Exception as inst:
180        print("\nBad configuration file provided: '{0}'\n".format(filepath))
181        print(inst)
182        exit(-1)
183
184
185def query_yes_no(question, default="yes"):
186    """Ask a yes/no question via raw_input() and return their answer.
187
188    "question" is a string that is presented to the user.
189    "default" is the presumed answer if the user just hits <Enter>.
190        It must be "yes" (the default), "no" or None (meaning
191        an answer is required of the user).
192
193    The "answer" return value is True for "yes" or False for "no".
194    """
195    valid = { "yes": True, "y": True, "ye": True,
196              "no": False, "n": False }
197    if default is None:
198        prompt = " [y/n] "
199    elif default == "yes":
200        prompt = " [Y/n] "
201    elif default == "no":
202        prompt = " [y/N] "
203    else:
204        raise ValueError("invalid default answer: '%s'" % default)
205
206    while True:
207        sys.stdout.write(question + prompt)
208        choice = input().lower()
209        if default is not None and choice == '':
210            return valid[default]
211        elif choice in valid:
212            return valid[choice]
213        else:
214            sys.stdout.write("Please respond with 'yes' or 'no' "
215                             "(or 'y' or 'n').\n")
216
217
218def load_benchmark_config_file (filepath):
219    """load_benchmark_config_file(filepath) -> list
220
221    Loads a configuration file (.yaml) for both trex config and router config
222    Returns a list with a dictionary to each of the configurations
223    """
224
225    # create response dictionary
226    benchmark_config = {}
227
228    try:
229        with open(filepath, 'r') as f:
230            benchmark_config = yaml.load(f)
231
232    except Exception as inst:
233        print("\nBad configuration file provided: '{0}'\n".format(filepath))
234        print(inst)
235        exit(-1)
236
237    return benchmark_config
238
239
240def get_benchmark_param (benchmark_path, test_name, param, sub_param = None):
241
242    config = load_benchmark_config_file(benchmark_path)
243    if sub_param is None:
244        return config[test_name][param]
245    else:
246        return config[test_name][param][sub_param]
247
248def gen_increment_dict (dual_port_mask):
249    addr_lst    = dual_port_mask.split('.')
250    result      = {}
251    for idx, octet_increment in enumerate(addr_lst):
252        octet_int = int(octet_increment)
253        if octet_int>0:
254            result[str(idx)] = octet_int
255
256    return result
257
258
259def get_network_addr (ip_type = 'ipv4'):
260    ipv4_addr = [1, 1, 1, 0]  # base ipv4 address to start generating from- 1.1.1.0
261    ipv6_addr = ['2001', 'DB8', 0, '2222', 0, 0, 0, 0]  # base ipv6 address to start generating from- 2001:DB8:1111:2222:0:0
262    while True:
263        if ip_type == 'ipv4':
264            if (ipv4_addr[2] < 255):
265                yield [".".join( map(str, ipv4_addr) ), '255.255.255.0']
266                ipv4_addr[2] += 1
267            else:   # reached defined maximum limit of address allocation
268                return
269        else:   # handling ipv6 addressing
270            if (ipv6_addr[2] < 4369):
271                tmp_ipv6_addr = list(ipv6_addr)
272                tmp_ipv6_addr[2] = hex(tmp_ipv6_addr[2])[2:]
273                yield ":".join( map(str, tmp_ipv6_addr) )
274                ipv6_addr[2] += 1
275            else:   # reached defined maximum limit of address allocation
276                return
277
278
279
280
281if __name__ == "__main__":
282    pass
283