1d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng#! /usr/bin/python 2d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 3d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 4d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng# Use of this source code is governed by a BSD-style license that can be 5d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng# found in the LICENSE file. 6d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 7d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng""" 8d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengThis script generates a csv file containing the mapping of 9d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng(device_hostname, rpm_hostname, outlet, hydra_hostname) for each 10d946f3ffc0c02389e39b9486add0714d6a320e3eFang Denghost in our lab. The csv file is in the following format. 11d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 12d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengchromeos-rack2-host1,chromeos-rack2-rpm1,.A1,chromeos-197-hydra1.mtv 13d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengchromeos-rack2-host2,chromeos-rack2-rpm1,.A2,chromeos-197-hydra1.mtv 14d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng... 15d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 16d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengThe generated csv file can be used as input to add_host_powerunit_info.py 17d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 18d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengWorkflow: 19d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng <Generate the csv file> 20d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng python generate_rpm_mapping.py --csv mapping_file.csv --server cautotest 21d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 22d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng <Upload mapping information in csv file to AFE> 23d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng python add_host_powerunit_info.py --csv mapping_file.csv 24d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 25d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng""" 26d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport argparse 27d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport collections 28d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport logging 29d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport re 30d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport sys 31d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 32d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengimport common 33d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 34d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengfrom autotest_lib.client.common_lib import enum 35d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengfrom autotest_lib.server.cros.dynamic_suite import frontend_wrappers 36d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 37d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengCHROMEOS_LABS = enum.Enum('OysterBay', 'Atlantis', 'Chaos', 'Destiny', start_value=1) 38d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengHOST_REGX = 'chromeos(\d+)(-row(\d+))*-rack(\d+)-host(\d+)' 39d946f3ffc0c02389e39b9486add0714d6a320e3eFang DengDeviceHostname = collections.namedtuple( 40d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'DeviceHostname', ['lab', 'row', 'rack', 'host']) 41d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 42d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 43d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengclass BaseLabConfig(object): 44d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Base class for a lab configuration.""" 45d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng RPM_OUTLET_MAP = {} 46d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng LAB_NUMBER = -1 47d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 48d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 49d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_hostname(cls, device_hostname): 50d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm hostname given a device. 51d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 52047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 53d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 54d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: the rpm hostname, default to empty string. 55d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 56d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 57d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 58d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 59d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 60d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 61d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_outlet(cls, device_hostname): 62d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm outlet given a device. 63d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 64047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 65d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 66d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: the rpm outlet, default to empty string. 67d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 68d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 69d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 70d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 71d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 72d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 73d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_hydra_hostname(cls, device_hostname): 74d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get hydra hostname given a device. 75d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 76047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 77d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 78d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: the hydra hostname, default to empty string. 79d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 80d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 81d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 82d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 83d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 84d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 85d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def is_device_in_the_lab(cls, device_hostname): 86d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Check whether a dut belongs to the lab. 87d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 88047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 89d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 90d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: True if the dut belongs to the lab, 91d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng False otherwise. 92d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 93d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 94d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return device_hostname.lab == cls.LAB_NUMBER 95d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 96d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 97d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengclass OysterBayConfig(BaseLabConfig): 98d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Configuration for OysterBay""" 99d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 100d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng LAB_NUMBER = CHROMEOS_LABS.OYSTERBAY 101d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 102d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 103d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 104d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_hostname(cls, device_hostname): 105d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm hostname. 106d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 107047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 108d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 109d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hostname of the rpm that has the device. 110d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 111d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 112b705433165c2fbacc08f541bb3f314c9376df8f5Fang Deng if not device_hostname.row: 113b705433165c2fbacc08f541bb3f314c9376df8f5Fang Deng return '' 114d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos%d-row%d-rack%d-rpm1' % ( 115d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.lab, device_hostname.row, 116d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.rack) 117d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 118d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 119d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 120d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_outlet(cls, device_hostname): 121d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm outlet. 122d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 123047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 124d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 125d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: rpm outlet, e.g. '.A1' 126d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 127d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 128b705433165c2fbacc08f541bb3f314c9376df8f5Fang Deng if not device_hostname.row: 129b705433165c2fbacc08f541bb3f314c9376df8f5Fang Deng return '' 130d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '.A%d' % device_hostname.host 131d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 132d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 133d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengclass AtlantisConfig(BaseLabConfig): 134d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Configuration for Atlantis lab.""" 135d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 136d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng LAB_NUMBER = CHROMEOS_LABS.ATLANTIS 137d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng # chromeos2, hostX -> outlet 138d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng RPM_OUTLET_MAP = { 139d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 1: 1, 140d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 7: 2, 141d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 2: 4, 142d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 8: 5, 143d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 3: 7, 144d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 9: 8, 145d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 4: 9, 146d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 10: 10, 147d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 5: 12, 148d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 11: 13, 149d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 6: 15, 150d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 12: 16} 151d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 152d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 153d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_hostname(cls, device_hostname): 154d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm hostname. 155d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 156047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 157d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 158d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hostname of the rpm that has the device. 159d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 160d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 161d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos%d-row%d-rack%d-rpm1' % ( 162d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.lab, device_hostname.row, 163d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.rack) 164d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 165d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 166d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 167d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_outlet(cls, device_hostname): 168d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm outlet. 169d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 170047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 171d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 172d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: rpm outlet, e.g. '.A1' 173d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 174d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 175d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '.A%d' % cls.RPM_OUTLET_MAP[device_hostname.host] 176d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 177d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 178d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 179d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_hydra_hostname(cls, device_hostname): 180d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get hydra hostname. 181d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 182047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 183d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 184d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hydra hostname 185d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 186d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 187d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng row = device_hostname.row 188d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rack = device_hostname.rack 189d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if row >= 1 and row <= 5 and rack >= 1 and rack <= 7: 190d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-197-hydra1.cros' 191d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng elif row >= 1 and row <= 5 and rack >= 8 and rack <= 11: 192d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-197-hydra2.cros' 193d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng else: 194d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.error('Could not determine hydra for %s', 195d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname) 196d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 197d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 198d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 199d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengclass ChaosConfig(BaseLabConfig): 200d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Configuration for Chaos lab.""" 201d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 202d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng LAB_NUMBER = CHROMEOS_LABS.CHAOS 203d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 204d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 205d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 206d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_hostname(cls, device_hostname): 207d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm hostname. 208d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 209047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 210d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 211d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hostname of the rpm that has the device. 212d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 213d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 214d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos%d-row%d-rack%d-rpm1' % ( 215d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.lab, device_hostname.row, 216d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.rack) 217d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 218d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 219d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 220d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_outlet(cls, device_hostname): 221d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm outlet. 222d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 223047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 224d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 225d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: rpm outlet, e.g. '.A1' 226d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 227d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 228d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '.A%d' % device_hostname.host 229d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 230d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 231d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengclass DestinyConfig(BaseLabConfig): 232d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Configuration for Desitny lab.""" 233d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 234d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng LAB_NUMBER = CHROMEOS_LABS.DESTINY 235047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # None-densified rack: one host per shelf 236047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # (rowX % 2, hostY) -> outlet 237d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng RPM_OUTLET_MAP = { 238d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 1): 1, 239d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (0, 1): 2, 240d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 2): 4, 241d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (0, 2): 5, 242d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 3): 7, 243d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (0, 3): 8, 244d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 4): 9, 245d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (0, 4): 10, 246d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 5): 12, 247d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (0, 5): 13, 248d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (1, 6): 15, 249047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 6): 16, 250047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng } 251047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 252047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # Densified rack: one shelf can have two chromeboxes or one notebook. 253047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # (rowX % 2, hostY) -> outlet 254047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng DENSIFIED_RPM_OUTLET_MAP = { 255047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 2): 1, (1, 1): 1, 256047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 1): 2, (0, 2): 2, 257047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 4): 3, (1, 3): 3, 258047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 3): 4, (0, 4): 4, 259047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 6): 5, (1, 5): 5, 260047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 5): 6, (0, 6): 6, 261047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 8): 7, (1, 7): 7, 262047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 7): 8, (0, 8): 8, 263047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # outlet 9, 10 are not used 264047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 10): 11, (1, 9): 11, 265047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 9): 12, (0, 10): 12, 266047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 12): 13, (1, 11): 13, 267047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 11): 14, (0, 12): 14, 268047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 14): 15, (1, 13): 15, 269047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 13): 16, (0, 14): 16, 270047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 16): 17, (1, 15): 17, 271047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 15): 18, (0, 16): 18, 272047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 18): 19, (1, 17): 19, 273047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 17): 20, (0, 18): 20, 274047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 20): 21, (1, 19): 21, 275047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 19): 22, (0, 20): 22, 276047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (1, 22): 23, (1, 21): 23, 277047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng (0, 21): 24, (0, 22): 24, 278047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng } 279047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 280047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 281047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @classmethod 282047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng def is_densified(cls, device_hostname): 283047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng """Whether the host is on a densified rack. 284047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 285047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 286047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 287047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @returns: True if on a densified rack, False otherwise. 288047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng """ 289047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng return device_hostname.rack in (0, 12, 13) 290d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 291d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 292d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 293d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_hostname(cls, device_hostname): 294d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm hostname. 295d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 296047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 297d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 298d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hostname of the rpm that has the device. 299d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 300d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 301d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng row = device_hostname.row 302047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng if row == 13: 303047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng logging.warn('Rule not implemented for row 13 in chromeos4') 304047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng return '' 305047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 306047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # rpm row is like chromeos4-row1_2-rackX-rpmY 307047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng rpm_row = ('%d_%d' % (row - 1, row) if row % 2 == 0 else 308047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng '%d_%d' % (row, row + 1)) 309047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng 310047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng if cls.is_densified(device_hostname): 311047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # Densified rack has two rpms, decide which one the host belongs to 312047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # Rule: 313047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # odd row number, even host number -> rpm1 314047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # odd row number, odd host number -> rpm2 315047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # even row number, odd host number -> rpm1 316047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # even row number, even host number -> rpm2 317047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng rpm_number = 1 if (row + device_hostname.host) % 2 == 1 else 2 318d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng else: 319047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng # Non-densified rack only has one rpm 320047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng rpm_number = 1 321047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng return 'chromeos%d-row%s-rack%d-rpm%d' % ( 322d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname.lab, 323047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng rpm_row, device_hostname.rack, rpm_number) 324d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 325d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 326d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 327d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_rpm_outlet(cls, device_hostname): 328d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get rpm outlet. 329d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 330047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 331d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 332d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: rpm outlet, e.g. '.A1' 333d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 334d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 335d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng try: 336047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng outlet_map = (cls.DENSIFIED_RPM_OUTLET_MAP 337047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng if cls.is_densified(device_hostname) else 338047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng cls.RPM_OUTLET_MAP) 339047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng outlet_number = outlet_map[(device_hostname.row % 2, 340047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng device_hostname.host)] 341d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '.A%d' % outlet_number 342d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng except KeyError: 343d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.error('Could not determine outlet for device %s', 344d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname) 345d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 346d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 347d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 348d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @classmethod 349d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng def get_hydra_hostname(cls, device_hostname): 350d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Get hydra hostname. 351d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 352047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @param device_hostname: A DeviceHostname named tuple. 353d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 354d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: hydra hostname 355d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 356d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 357d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng row = device_hostname.row 358d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rack = device_hostname.rack 359d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if row >= 1 and row <= 6 and rack >=1 and rack <= 11: 360d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-destiny-hydra1.cros' 361d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng elif row >= 7 and row <= 12 and rack >=1 and rack <= 11: 362d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-destiny-hydra2.cros' 363d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng elif row >= 1 and row <= 10 and rack >=12 and rack <= 13: 364d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-destiny-hydra3.cros' 365d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng elif row in [3, 4, 5, 6, 9, 10] and rack == 0: 366d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-destiny-hydra3.cros' 367d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng elif row == 13 and rack >= 0 and rack <= 11: 368d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return 'chromeos-destiny-hydra3.cros' 369d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng else: 370d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.error('Could not determine hydra hostname for %s', 371d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname) 372d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return '' 373d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 374d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 375d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengdef parse_device_hostname(device_hostname): 376d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Parse device_hostname to DeviceHostname object. 377d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 378d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @param device_hostname: A string, e.g. 'chromeos2-row2-rack4-host3' 379d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 380047183cbaa217e6b93252b8ee77d7eafef5b78acFang Deng @returns: A DeviceHostname named tuple or None if the 381d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng the hostname doesn't follow the pattern 382d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng defined in HOST_REGX. 383d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 384d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 385d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng m = re.match(HOST_REGX, device_hostname.strip()) 386d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if m: 387d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return DeviceHostname( 388d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng lab=int(m.group(1)), 389d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng row=int(m.group(3)) if m.group(3) else None, 390d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rack=int(m.group(4)), 391d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng host=int(m.group(5))) 392d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng else: 393d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.error('Could not parse %s', device_hostname) 394d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return None 395d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 396d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 397d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengdef generate_mapping(hosts, lab_configs): 398d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Generate device_hostname-rpm-outlet-hydra mapping. 399d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 400d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @param hosts: hosts objects get from AFE. 401d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @param lab_configs: A list of configuration classes, 402d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng each one for a lab. 403d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 404d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @returns: A dictionary that maps device_hostname to 405d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (rpm_hostname, outlet, hydra_hostname) 406d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 407d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 408d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng # device hostname -> (rpm_hostname, outlet, hydra_hostname) 409d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_mapping = {} 410d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng for host in hosts: 411d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng device_hostname = parse_device_hostname(host.hostname) 412d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if not device_hostname: 413d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng continue 414d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng for lab in lab_configs: 415d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if lab.is_device_in_the_lab(device_hostname): 416d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_hostname = lab.get_rpm_hostname(device_hostname) 417d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_outlet = lab.get_rpm_outlet(device_hostname) 418d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng hydra_hostname = lab.get_hydra_hostname(device_hostname) 419d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng if not rpm_hostname or not rpm_outlet: 420d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.error( 421d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'Skipping device %s: could not determine ' 422d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'rpm hostname or outlet.', host.hostname) 423d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng break 424d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_mapping[host.hostname] = ( 425d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_hostname, rpm_outlet, hydra_hostname) 426d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng break 427d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng else: 428d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.info( 429d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng '%s is not in a know lab ' 430d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng '(oyster bay, atlantis, chaos, destiny)', 431d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng host.hostname) 432d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng return rpm_mapping 433d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 434d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 435d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengdef output_csv(rpm_mapping, csv_file): 436d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """Dump the rpm mapping dictionary to csv file. 437d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 438d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @param rpm_mapping: A dictionary that maps device_hostname to 439d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng (rpm_hostname, outlet, hydra_hostname) 440d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng @param csv_file: The name of the file to write to. 441d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 442d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng """ 443d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng with open(csv_file, 'w') as f: 444d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng for hostname, rpm_info in rpm_mapping.iteritems(): 445d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng line = ','.join(rpm_info) 446d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng line = ','.join([hostname, line]) 447d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng f.write(line + '\n') 448d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 449d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 450d946f3ffc0c02389e39b9486add0714d6a320e3eFang Dengif __name__ == '__main__': 451d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.basicConfig(level=logging.DEBUG) 452d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng parser = argparse.ArgumentParser( 453d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng description='Generate device_hostname-rpm-outlet-hydra mapping ' 454d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'file needed by add_host_powerunit_info.py') 455d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng parser.add_argument('--csv', type=str, dest='csv_file', required=True, 456d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng help='The path to the csv file where we are going to ' 457d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'write the mapping information to.') 458d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng parser.add_argument('--server', type=str, dest='server', default=None, 459d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng help='AFE server that the script will be talking to. ' 460d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'If not specified, will default to using the ' 461d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 'server in global_config.ini') 462d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng options = parser.parse_args() 463d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng 464d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng AFE = frontend_wrappers.RetryingAFE(timeout_min=5, delay_sec=10, 465d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng server=options.server) 466d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng logging.info('Connected to %s', AFE.server) 467d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng rpm_mapping = generate_mapping( 468d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng AFE.get_hosts(), 469d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng [OysterBayConfig, AtlantisConfig, ChaosConfig, DestinyConfig]) 470d946f3ffc0c02389e39b9486add0714d6a320e3eFang Deng output_csv(rpm_mapping, options.csv_file) 471