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