1# Copyright (c) 2012 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 5import ConfigParser 6import logging 7import os 8import time 9 10from autotest_lib.client.common_lib.cros.network import ap_constants 11from autotest_lib.site_utils.rpm_control_system import rpm_client 12from autotest_lib.server.cros.ap_configurators import ap_spec 13 14AP_CONFIG_FILES = { ap_constants.AP_TEST_TYPE_CHAOS: 15 ('chaos_dynamic_ap_list.conf', 'chaos_shadow_ap_list.conf'), 16 ap_constants.AP_TEST_TYPE_CLIQUE: 17 ('clique_ap_list.conf',)} 18 19TIMEOUT = 100 20 21def get_ap_list(ap_test_type): 22 """ 23 Returns the list of AP's from the corresponding configuration file. 24 25 @param ap_test_type: Used to determine which type of test we're 26 currently running (Chaos vs Clique). 27 @returns a list of AP objects. 28 29 """ 30 aps = [] 31 ap_config_files = AP_CONFIG_FILES.get(ap_test_type, None) 32 for filename in ap_config_files: 33 ap_config = ConfigParser.RawConfigParser( 34 {AP.CONF_RPM_MANAGED: 'False'}) 35 path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 36 filename) 37 if not os.path.exists(path): 38 logging.warning('Skipping missing config: "%s"', path) 39 continue 40 41 logging.debug('Reading config from: "%s"', path) 42 ap_config.read(path) 43 for bss in ap_config.sections(): 44 aps.append(AP(bss, ap_config)) 45 return aps 46 47 48class APPowerException(Exception): 49 """ Exception raised when AP fails to power on. """ 50 pass 51 52class APSectionError(Exception): 53 """ Exception raised when AP instance does not exist in the config. """ 54 pass 55 56class AP(object): 57 """ An instance of an ap defined in the chaos config file. 58 59 This object is a wrapper that can be used to retrieve information 60 about an AP in the chaos lab, and control its power. 61 62 """ 63 64 65 # Keys used in the config file. 66 CONF_SSID = 'ssid' 67 CONF_BRAND = 'brand' 68 CONF_MODEL = 'model' 69 CONF_WAN_MAC = 'wan mac' 70 CONF_WAN_HOST = 'wan_hostname' 71 CONF_RPM_MANAGED = 'rpm_managed' 72 CONF_BSS = 'bss' 73 CONF_BSS5 = 'bss5' 74 CONF_BANDWIDTH = 'bandwidth' 75 CONF_SECURITY = 'security' 76 CONF_PSK = 'psk' 77 CONF_FREQUENCY = 'frequency' 78 CONF_BAND = 'band' 79 CONF_CHANNEL = 'channel' 80 CONF_CLASS = 'class_name' 81 CONF_ADMIN = 'admin_url' 82 83 84 def __init__(self, bss, config): 85 """ 86 Intialize object 87 88 @param bss: string containing bssid 89 @param config: ConfigParser read from file 90 91 """ 92 if not config.has_section(bss): 93 raise APSectionError('BSS (%s) not defined.' % bss) 94 self.bss = bss 95 self.ap_config = config 96 97 98 def get_ssid(self): 99 """@return string ssid for AP from config file""" 100 return self.ap_config.get(self.bss, self.CONF_SSID) 101 102 103 def get_brand(self): 104 """@return string brand for AP from config file""" 105 return self.ap_config.get(self.bss, self.CONF_BRAND) 106 107 108 def get_model(self): 109 """@return string model for AP from config file""" 110 return self.ap_config.get(self.bss, self.CONF_MODEL) 111 112 113 def get_wan_mac(self): 114 """@return string mac for WAN port of AP from config file""" 115 return self.ap_config.get(self.bss, self.CONF_WAN_MAC) 116 117 118 def get_wan_host(self): 119 """@return string host for AP from config file""" 120 return self.ap_config.get(self.bss, self.CONF_WAN_HOST) 121 122 123 def get_rpm_managed(self): 124 """@return bool for AP power via rpm from config file""" 125 return self.ap_config.getboolean(self.bss, self.CONF_RPM_MANAGED) 126 127 128 def get_bss(self): 129 """@return string bss for AP from config file""" 130 try: 131 bss = self.ap_config.get(self.bss, self.CONF_BSS) 132 except ConfigParser.NoOptionError as e: 133 bss = 'N/A' 134 return bss 135 136 137 def get_bss5(self): 138 """@return string bss5 for AP from config file""" 139 try: 140 bss5 = self.ap_config.get(self.bss, self.CONF_BSS5) 141 except ConfigParser.NoOptionError as e: 142 bss5 = 'N/A' 143 return bss5 144 145 def get_bandwidth(self): 146 """@return string bandwidth for AP from config file""" 147 return self.ap_config.get(self.bss, self.CONF_BANDWIDTH) 148 149 150 def get_security(self): 151 """@return string security for AP from config file""" 152 return self.ap_config.get(self.bss, self.CONF_SECURITY) 153 154 155 def get_psk(self): 156 """@return string psk for AP from config file""" 157 return self.ap_config.get(self.bss, self.CONF_PSK) 158 159 160 def get_frequency(self): 161 """@return int frequency for AP from config file""" 162 return int(self.ap_config.get(self.bss, self.CONF_FREQUENCY)) 163 164 def get_channel(self): 165 """@return int channel for AP from config file""" 166 return ap_spec.CHANNEL_TABLE[self.get_frequency()] 167 168 169 def get_band(self): 170 """@return string band for AP from config file""" 171 if self.get_frequency() < 4915: 172 return ap_spec.BAND_2GHZ 173 else: 174 return ap_spec.BAND_5GHZ 175 176 177 def get_class(self): 178 """@return string class for AP from config file""" 179 return self.ap_config.get(self.bss, self.CONF_CLASS) 180 181 182 def get_admin(self): 183 """@return string admin for AP from config file""" 184 return self.ap_config.get(self.bss, self.CONF_ADMIN) 185 186 187 def power_off(self): 188 """call rpm_client to power off AP""" 189 rpm_client.set_power(self.get_wan_host(), 'OFF') 190 191 192 def power_on(self): 193 """call rpm_client to power on AP""" 194 rpm_client.set_power(self.get_wan_host(), 'ON') 195 196 # Hard coded timer for now to wait for the AP to come alive 197 # before trying to use it. We need scanning code 198 # to scan until the AP becomes available (crosbug.com/36710). 199 time.sleep(TIMEOUT) 200 201 202 def __str__(self): 203 """@return string description of AP""" 204 ap_info = { 205 'brand': self.get_brand(), 206 'model': self.get_model(), 207 'ssid' : self.get_ssid(), 208 'bss' : self.get_bss(), 209 'hostname': self.get_wan_host(), 210 } 211 return ('AP Info:\n' 212 ' Name: %(brand)s %(model)s\n' 213 ' SSID: %(ssid)s\n' 214 ' BSS: %(bss)s\n' 215 ' Hostname: %(hostname)s\n' % ap_info) 216