1# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5
6import optparse
7import pickle
8import re
9import subprocess
10
11import common
12from autotest_lib.client.cros.cellular import cellular
13from autotest_lib.client.cros.cellular import cellular_logging
14from autotest_lib.client.cros.cellular import labconfig_data
15
16log = cellular_logging.SetupCellularLogging('labconfig')
17
18
19class LabConfigError(Exception):
20    """Exception thrown on bad lab configuration"""
21    pass
22
23
24def get_interface_ip(interface='eth0'):
25    """Returns the IP address for an interface, or None if not found.
26    @param interface: the interface to request IP address for.
27    """
28
29    # We'd like to use
30    #  utils.system_output('ifconfig eth0 2>&1', retain_output=True)
31    # but that gives us a dependency on the rest of autotest, which
32    # means that running the unit test requires pythonpath manipulation
33    stdout = subprocess.Popen(['ip', '-4', 'addr', 'show', 'dev', interface],
34                              stdout=subprocess.PIPE).communicate()[0]
35
36    match = re.search(r'inet ([0-9.]+)[/ ]', stdout)
37    if not match:
38        return None
39    return match.group(1)
40
41
42class Configuration(object):
43    """Configuration for a cellular test.
44
45    This includes things like the address of the cell emulator device
46    and details of the RF switching between the emulated basestation
47    and the DUT."""
48
49    def __init__(self, args):
50        # For server tests, this constructor runs as part of the
51        # server control file, on whatever machine the test was
52        # started on.
53        parser = optparse.OptionParser()
54
55        # Record our args so we can serialize ourself.
56        self.args = args
57
58        self.ip = None
59
60        parser.add_option('--cell', dest='cell', default=None,
61                          help='Cellular test cell to use')
62        parser.add_option(
63            '--technology', dest='technology', default='all',
64            help='Radio access technologies to use (e.g. "WCDMA")')
65        (self.options, _) = parser.parse_args(args)
66
67        self.cell = self._get_cell(self.options.cell)
68
69    def _get_cell(self, name):
70        """Extracts the named cell from labconfig_data.CELLS."""
71        if not name:
72            raise LabConfigError(
73                'Could not find --cell argument.  ' +
74                'To specify a cell, pass --args=--cell=foo to test_that')
75
76        if name not in labconfig_data.CELLS:
77            raise LabConfigError(
78                'Could not find cell %s, valid cells are %s' % (
79                    name, labconfig_data.CELLS.keys()))
80
81        return labconfig_data.CELLS[name]
82
83    def _get_dut(self, machine=None):
84        """Returns the DUT record for machine from cell["duts"]
85        Args:
86            machine:  name or IP of machine.  None: for "the current machine".
87
88        Right now, we use the interface of eth0 to figure out which
89        machine we're running on.  The important thing is that this
90        matches the IP address in the cell duts configuration.  We'll
91        have to come up with a better way if this proves brittle."""
92
93        # TODO(byronk) : crosbug.com/235911:
94        # autotest: Getting IP address from eth0 by name is brittle
95        if self.ip and not machine:
96            machine = self.ip
97        ifconfig = ''
98        if not machine:
99            log.debug('self.ip is : %s ' % self.ip)
100            # TODO(byronk): use sysfs to find network interface
101            possible_interfaces = ['eth0', 'eth1', 'eth_test']
102            log.debug('Looking for an up network interface in : %s' %
103                      possible_interfaces)
104            for interface in possible_interfaces:
105                machine = get_interface_ip(interface)
106                if machine:
107                    log.debug('Got an IP address: %s Stopping the search.. ' %
108                              machine)
109                    self.ip = machine
110                    break
111            else:
112                ifconfig = subprocess.Popen(['ip', 'addr', 'show'],
113                        stdout=subprocess.PIPE).communicate()[0]
114        if not machine:
115            raise LabConfigError(
116                'Could not determine which machine we are.\n'
117                '  Cell =  %s \n' % self.options.cell +
118                'Tried these interface names: %s \n' % possible_interfaces +
119                '`ip addr show` output:\n%s' % ifconfig
120            )
121
122        for dut in self.cell["duts"]:
123            if machine == dut["address"] or machine == dut["name"]:
124                return dut
125
126        raise LabConfigError(
127            'This machine %s not matching: (%s,%s) in config. Cell = %s: %s' %
128            (machine, dut['address'],
129             dut['name'], self.options.cell, self.cell['duts']))
130
131    def get_technologies(self, machine=None):
132        """Gets technologies to use for machine; defaults to all available.
133        @param machine: Machine to get technologies for.
134        """
135        technologies_list = self.options.technology.split(',')
136
137        if 'all' in technologies_list:
138            m = self._get_dut(machine)
139            technologies_list = m["technologies"]
140
141        enums = [getattr(cellular.Technology, t, None)
142                 for t in technologies_list]
143
144        if None in enums:
145            raise LabConfigError(
146                'Could not understand a technology in %s' % technologies_list)
147
148        return enums
149
150    def get_rf_switch_port(self, machine=None):
151        """Get the RF Switch Port for the specified machine.
152        @param machine: machine to get rf switch port for
153        """
154        dut = self._get_dut(machine)
155        print dut
156        return dut['rf_switch_port']
157
158    def get_pickle(self):
159        """Get pickled object."""
160        return pickle.dumps(self)
161