Home | History | Annotate | Download | only in network_EthCapsServer
      1 # Copyright (c) 2009 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 import logging, os, socket, subprocess, tempfile, threading, time
      6 
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.server import autotest, hosts, site_host_attributes
      9 from autotest_lib.server import subcommand, test, utils
     10 
     11 
     12 class WolWake(threading.Thread):
     13     """Class to allow waking of DUT via Wake-on-LAN capabilities (WOL)."""
     14 
     15 
     16     def __init__(self, hostname, mac_addr, sleep_secs):
     17         """Constructor for waking DUT.
     18 
     19         Args:
     20           mac_addr: string of mac address tuple
     21           sleep_secs: seconds to sleep prior to attempting WOL
     22         """
     23         threading.Thread.__init__(self)
     24         self._hostname = hostname
     25         self._mac_addr = mac_addr
     26         self._sleep_secs = sleep_secs
     27 
     28 
     29     # TODO(tbroch) Borrowed from class ServoTest.  Refactor for code re-use
     30     def _ping_test(self, hostname, timeout=5):
     31         """Verify whether a host responds to a ping.
     32 
     33         Args:
     34           hostname: Hostname to ping.
     35           timeout: Time in seconds to wait for a response.
     36 
     37         Returns: True if success False otherwise
     38         """
     39         with open(os.devnull, 'w') as fnull:
     40             ping_good = False
     41             elapsed_time = 0
     42             while not ping_good and elapsed_time < timeout:
     43                 ping_good = subprocess.call(
     44                     ['ping', '-c', '1', '-W', str(timeout), hostname],
     45                     stdout=fnull, stderr=fnull) == 0
     46                 time.sleep(1)
     47                 elapsed_time += 1
     48             return ping_good
     49 
     50 
     51     def _send_wol_magic_packet(self):
     52         """Perform Wake-on-LAN magic wake.
     53 
     54         WOL magic packet consists of:
     55           0xff repeated for 6 bytes
     56           <mac addr> repeated 16 times
     57 
     58         Sent as a broadcast packet.
     59         """
     60         mac_tuple = self._mac_addr.split(':')
     61         assert len(mac_tuple) == 6
     62         magic = '\xff' * 6
     63         submagic = ''.join("%c" % int(value, 16) for value in mac_tuple)
     64         magic += submagic * 16
     65         assert len(magic) == 102
     66 
     67         sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     68         sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
     69         sock.sendto(magic, ('<broadcast>', 7))
     70         sock.close()
     71         logging.info("Wake thread sent WOL wakeup")
     72 
     73 
     74     def run(self):
     75         # ping device to make sure its network is off presumably from suspend
     76         # not another malfunction.
     77         ping_secs = 0
     78         while self._ping_test(self._hostname, timeout=2) and \
     79                 ping_secs < self._sleep_secs:
     80             time.sleep(1)
     81             ping_secs += 1
     82 
     83         self._send_wol_magic_packet()
     84 
     85 
     86 class network_EthCapsServer(test.test):
     87     version = 1
     88 
     89     def _parse_ifconfig(self, filename):
     90         """Retrieve ifconfig information.
     91 
     92         Raises
     93           error.TestError if unable to parse mac address
     94         """
     95         self._mac_addr = None
     96 
     97         fd = open(filename)
     98         for ln in fd.readlines():
     99             info_str = ln.strip()
    100             logging.debug(ln)
    101             index = info_str.find('HWaddr ')
    102             if index != -1:
    103                 self._mac_addr = info_str[index + len('HWaddr '):]
    104                 logging.info("mac addr = %s" % self._mac_addr)
    105                 break
    106         fd.close()
    107 
    108         if not self._mac_addr:
    109             raise error.TestError("Unable to find mac addresss")
    110 
    111 
    112     def _client_cmd(self, cmd, results=None):
    113         """Execute a command on the client.
    114 
    115         Args:
    116           results: string of filename to save results on client.
    117 
    118         Returns:
    119           string of filename on server side with stdout results of command
    120         """
    121         if results:
    122             client_tmpdir = self._client.get_tmp_dir()
    123             client_results = os.path.join(client_tmpdir, "%s" % results)
    124             cmd = "%s > %s 2>&1" % (cmd, client_results)
    125 
    126         logging.info("Client cmd = %s", cmd)
    127         self._client.run(cmd)
    128 
    129         if results:
    130             server_tmpfile = tempfile.NamedTemporaryFile(delete=False)
    131             server_tmpfile.close()
    132             self._client.get_file(client_results, server_tmpfile.name)
    133             return server_tmpfile.name
    134 
    135         return None
    136 
    137 
    138     def run_once(self, client_ip=None, ethname='eth0'):
    139         """Run the test.
    140 
    141         Args:
    142           client_ip: string of client's ip address
    143           ethname: string of ethernet device under test
    144         """
    145         if not client_ip:
    146             error.TestError("Must provide client's IP address to test")
    147 
    148         sleep_secs = 20
    149 
    150         self._ethname = ethname
    151         self._client_ip = client_ip
    152         self._client = hosts.create_host(client_ip)
    153         client_at = autotest.Autotest(self._client)
    154 
    155         # retrieve ifconfig info for mac address of client
    156         cmd = "ifconfig %s" % self._ethname
    157         ifconfig_filename = self._client_cmd(cmd, results="ifconfig.log")
    158         self._parse_ifconfig(ifconfig_filename)
    159 
    160         # thread to wake the device using WOL
    161         wol_wake = WolWake(self._client_ip, self._mac_addr, sleep_secs)
    162         wol_wake.start()
    163 
    164         # create and run client test to prepare and suspend device
    165         client_at.run_test("network_EthCaps", ethname=ethname,
    166                            threshold_secs=sleep_secs * 2)
    167 
    168         wol_wake.join()
    169