def _get_poe_powerunit_info(self, device_hostname): """Get the power management unit information for a POE controller. Servo is managed by POE. The related information we need to know include poe hostname, poe interface. Such information is stored in a local file and read into memory. @param device_hostname: A string representing the device's hostname. @returns: A PowerUnitInfo object. @raises RPMInfrastructureException if failed to get the power unit info. """ with self._lock: reload_info = utils.reload_servo_interface_mapping_if_necessary( self._mapping_last_modified) if reload_info: self._mapping_last_modified, self._servo_interface = reload_info switch_if_tuple = self._servo_interface.get(device_hostname) if not switch_if_tuple: raise RPMInfrastructureException( 'Could not determine POE hostname for %s. ' 'Please check the servo-interface mapping file.', device_hostname) else: return utils.PowerUnitInfo( device_hostname=device_hostname, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.POE, powerunit_hostname=switch_if_tuple[0], outlet=switch_if_tuple[1], hydra_hostname=None)
def set_power_via_rpm(self, device_hostname, rpm_hostname, rpm_outlet, hydra_hostname, new_state): """Sets power state of a device to the requested state via RPM. Unlike the special case of POE, powerunit information is not available on the RPM server, so must be provided as arguments. @param device_hostname: Hostname of the servo to control. @param rpm_hostname: Hostname of the RPM to use. @param rpm_outlet: The RPM outlet to control. @param hydra_hostname: If required, the hydra device to SSH through to get to the RPM. @param new_state: [ON, OFF, CYCLE] State to which we want to set the device's outlet to. @return: True if the attempt to change power state was successful, False otherwise. @raise RPMInfrastructureException: No dispatchers are available or can be reached. """ powerunit_info = utils.PowerUnitInfo( device_hostname=device_hostname, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, powerunit_hostname=rpm_hostname, outlet=rpm_outlet, hydra_hostname=hydra_hostname, ) try: return self._queue_once(powerunit_info, new_state) except DispatcherDownException: # Retry forwarding the request. return self.set_power_via_rpm(device_hostname, rpm_hostname, rpm_outlet, hydra_hostname, new_state)
def test_parrallel_sshrequests(): """Simple integration testing.""" rpm = rpm_controller.SentryRPMController('chromeos-rack8-rpm1') info_1 = utils.PowerUnitInfo( device_hostname='chromeos-rack8-hostbs1', powerunit_hostname='chromeos-rack8-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='.A14') info_2 = utils.PowerUnitInfo( device_hostname='chromeos-rack8-hostbs2', powerunit_hostname='chromeos-rack8-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='.A11') threading.Thread(target=rpm.queue_request, args=(info_1, 'CYCLE')).start() threading.Thread(target=rpm.queue_request, args=(info_2, 'CYCLE')).start()
def test_in_order_poerequests(): """Simple integration testing for poe controller.""" poe_controller = rpm_controller.CiscoPOEController('chromeos1-poe-switch1') info_1 = utils.PowerUnitInfo( device_hostname='chromeos1-rack4-host1bs-servo', powerunit_hostname='chromeos1-poe-switch1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='fa33') info_2 = utils.PowerUnitInfo( device_hostname='chromeos1-rack4-host2bs-servo', powerunit_hostname='chromeos1-poe-switch1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='fa34') poe_controller.queue_request(info_1, 'OFF') poe_controller.queue_request(info_1, 'ON') poe_controller.queue_request(info_2, 'CYCLE')
def _get_powerunit_info(self, device_hostname): """Get the power management unit information for a device. A device could be a chromeos dut or a servo. 1) ChromeOS dut Chromeos dut is managed by RPM. The related information we need to know include rpm hostname, rpm outlet, hydra hostname. Such information can be retrieved from afe_host_attributes table from afe. A local LRU cache is used avoid hitting afe too often. 2) Servo Servo is managed by POE. The related information we need to know include poe hostname, poe interface. Such information is stored in a local file and read into memory. @param device_hostname: A string representing the device's hostname. @returns: A PowerUnitInfo object. @raises RPMInfrastructureException if failed to get the power unit info. """ with self._lock: if device_hostname.endswith('servo'): # Servos are managed by Cisco POE switches. reload_info = utils.reload_servo_interface_mapping_if_necessary( self._mapping_last_modified) if reload_info: self._mapping_last_modified, self._servo_interface = reload_info switch_if_tuple = self._servo_interface.get(device_hostname) if not switch_if_tuple: raise RPMInfrastructureException( 'Could not determine POE hostname for %s. ' 'Please check the servo-interface mapping file.', device_hostname) else: return utils.PowerUnitInfo( device_hostname=device_hostname, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.POE, powerunit_hostname=switch_if_tuple[0], outlet=switch_if_tuple[1], hydra_hostname=None) else: # Regular DUTs are managed by RPMs. if device_hostname in self._rpm_info: return self._rpm_info[device_hostname] else: hosts = self._afe.get_hosts(hostname=device_hostname) if not hosts: raise RPMInfrastructureException( 'Can not retrieve rpm information ' 'from AFE for %s, no host found.' % device_hostname) else: info = utils.PowerUnitInfo.get_powerunit_info(hosts[0]) self._rpm_info[device_hostname] = info return info
def setUp(self): super(TestRPMControllerQueue, self).setUp() self.rpm = rpm_controller.SentryRPMController('chromeos-rack1-host8') self.powerunit_info = utils.PowerUnitInfo( device_hostname='chromos-rack1-host8', powerunit_hostname='chromeos-rack1-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, outlet='.A100', hydra_hostname=None)
def test_parrallel_poerequests(): """Simple integration testing for poe controller.""" poe_controller = rpm_controller.CiscoPOEController('chromeos1-poe-switch1') info_1 = utils.PowerUnitInfo( device_hostname='chromeos1-rack4-host1bs-servo', powerunit_hostname='chromeos1-poe-switch1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='fa33') info_2 = utils.PowerUnitInfo( device_hostname='chromeos1-rack4-host2bs-servo', powerunit_hostname='chromeos1-poe-switch1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='fa34') threading.Thread(target=poe_controller.queue_request, args=(info_1, 'CYCLE')).start() threading.Thread(target=poe_controller.queue_request, args=(info_2, 'CYCLE')).start()
def setUp(self): super(TestSentryRPMController, self).setUp() self.ssh = self.mox.CreateMockAnything() rpm_controller.pexpect.spawn = self.mox.CreateMockAnything() rpm_controller.pexpect.spawn(mox.IgnoreArg()).AndReturn(self.ssh) self.rpm = rpm_controller.SentryRPMController('chromeos-rack1-host8') self.powerunit_info = utils.PowerUnitInfo( device_hostname='chromos-rack1-host8', powerunit_hostname='chromeos-rack1-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, outlet='.A100', hydra_hostname=None)
def setUp(self): super(TestFrontendServer, self).setUp() self.frontend = frontend_server.RPMFrontendServer() self.frontend._rpm_info[DUT_HOSTNAME] = utils.PowerUnitInfo( device_hostname=DUT_HOSTNAME, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, powerunit_hostname=POWERUNIT_HOSTNAME, outlet=OUTLET, hydra_hostname=None) self.xmlrpc_mock = self.mox.CreateMockAnything() frontend_server.xmlrpclib.ServerProxy = self.mox.CreateMockAnything() frontend_server.xmlrpclib.ServerProxy(FAKE_DISPATCHER_URI1, allow_none=True).AndReturn(self.xmlrpc_mock)
def test_in_order_requests(): """Simple integration testing.""" rpm = rpm_controller.WebPoweredRPMController('chromeos-rack8e-rpm1') info_1 = utils.PowerUnitInfo( device_hostname='chromeos1-rack8e-hostbs1', powerunit_hostname='chromeos-rack8e-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='') info_2 = utils.PowerUnitInfo( device_hostname='chromeos1-rack8e-hostbs2', powerunit_hostname='chromeos-rack8e-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='') info_3 = utils.PowerUnitInfo( device_hostname='chromeos1-rack8e-hostbs3', powerunit_hostname='chromeos-rack8e-rpm1', powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, hydra_hostname=None, outlet='') rpm.queue_request(info_1, 'OFF') rpm.queue_request(info_2, 'OFF') rpm.queue_request(info_3, 'CYCLE')
def setUp(self): super(TestWebPoweredRPMController, self).setUp() self.dli_ps = self.mox.CreateMock(dli.powerswitch) hostname = 'chromeos-rack8a-rpm1' self.web_rpm = rpm_controller.WebPoweredRPMController( hostname, self.dli_ps) outlet = 8 dut = 'chromeos-rack8a-host8' # Outlet statuses are in the format "u'ON'" initial_state = 'u\'ON\'' self.test_status_list_initial = [[outlet, dut, initial_state]] self.powerunit_info = utils.PowerUnitInfo( device_hostname=dut, powerunit_hostname=hostname, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.RPM, outlet=outlet, hydra_hostname=None)
def queue_request(self, powerunit_info_dict, new_state): """ Looks up the appropriate RPMController instance for the device and queues up the request. @param powerunit_info_dict: A dictionary, containing the attribute/values of an unmarshalled PowerUnitInfo instance. @param new_state: [ON, OFF, CYCLE] state we want to the change the outlet to. @return: True if the attempt to change power state was successful, False otherwise. """ powerunit_info = utils.PowerUnitInfo(**powerunit_info_dict) logging.info('Received request to set device: %s to state: %s', powerunit_info.device_hostname, new_state) rpm_controller = self._get_rpm_controller( powerunit_info.powerunit_hostname, powerunit_info.hydra_hostname) return rpm_controller.queue_request(powerunit_info, new_state)
class TestCiscoPOEController(mox.MoxTestBase): """Test CiscoPOEController.""" DEVICE = 'chromeos2-poe-sw8#' MATCHER = 'Port\\s+.*%s(\\s+(\\S+)){6,6}.*%s' PORT = 'fa32' PWD = 'Password:'******'chromeos1-rack3-host12-servo' SWITCH = 'chromeos2-poe-switch8' POWERUNIT_INFO = utils.PowerUnitInfo( device_hostname=PORT, powerunit_hostname=SERVO, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.POE, outlet=PORT, hydra_hostname=None) def testLogin(self): """Test we can log into the switch.""" rpm_controller.pexpect.spawn = self.mox.CreateMockAnything() mock_ssh = self.mox.CreateMockAnything() rpm_controller.pexpect.spawn(mox.IgnoreArg()).AndReturn(mock_ssh) sut = rpm_controller.CiscoPOEController(self.SWITCH) mock_ssh.expect(sut.POE_USERNAME_PROMPT, timeout=sut.LOGIN_TIMEOUT) mock_ssh.sendline(mox.IgnoreArg()) mock_ssh.expect(self.PWD, timeout=sut.LOGIN_TIMEOUT) mock_ssh.sendline(mox.IgnoreArg()) mock_ssh.expect(self.DEVICE, timeout=sut.LOGIN_TIMEOUT) self.mox.ReplayAll() self.assertIsNotNone(sut._login()) self.mox.VerifyAll() def testSuccessfullyChangePowerState(self): """Should return True if change was successful.""" sut = rpm_controller.CiscoPOEController(self.SWITCH) mock_ssh = self.mox.CreateMockAnything() self.mox.StubOutWithMock(sut, '_login') sut._login().AndReturn(mock_ssh) self.mox.StubOutWithMock(sut, '_verify_state') sut._verify_state(self.PORT, 'ON', mock_ssh).AndReturn(True) # _enter_configuration_terminal mock_ssh.sendline(sut.CONFIG) mock_ssh.expect(sut.config_prompt, timeout=sut.CMD_TIMEOUT) mock_ssh.sendline(sut.CONFIG_IF % self.PORT) mock_ssh.expect(sut.config_if_prompt, timeout=sut.CMD_TIMEOUT) # _change_state mock_ssh.sendline(sut.SET_STATE_ON) # _exit_configuration_terminal mock_ssh.sendline(sut.END_CMD) mock_ssh.expect(sut.poe_prompt, timeout=sut.CMD_TIMEOUT) # exit mock_ssh.sendline(sut.EXIT_CMD) mock_ssh.close(force=True) self.mox.ReplayAll() self.assertTrue(sut.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll() def testUnableToEnterConfigurationTerminal(self): """Should return False if unable to enter configuration terminal.""" exception = pexpect.TIMEOUT('Could not enter configuration terminal.') sut = rpm_controller.CiscoPOEController(self.SWITCH) timeout = sut.CMD_TIMEOUT mock_ssh = self.mox.CreateMockAnything() self.mox.StubOutWithMock(sut, '_login') sut._login().AndReturn(mock_ssh) mock_ssh.sendline(sut.CONFIG) mock_ssh.expect(sut.config_prompt, timeout=timeout) mock_ssh.sendline(sut.CONFIG_IF % self.PORT) config_if_prompt = sut.config_if_prompt mock_ssh.expect(config_if_prompt, timeout=timeout).AndRaise(exception) mock_ssh.sendline(sut.END_CMD) mock_ssh.sendline(sut.EXIT_CMD) mock_ssh.close(force=True) self.mox.ReplayAll() self.assertFalse(sut.set_power_state(self.POWERUNIT_INFO, mock_ssh)) self.mox.VerifyAll() def testUnableToExitConfigurationTerminal(self): """Should return False if unable to exit configuration terminal.""" exception = pexpect.TIMEOUT('Could not exit configuration terminal.') sut = rpm_controller.CiscoPOEController(self.SWITCH) mock_ssh = self.mox.CreateMockAnything() self.mox.StubOutWithMock(sut, '_login') self.mox.StubOutWithMock(sut, '_enter_configuration_terminal') sut._login().AndReturn(mock_ssh) sut._enter_configuration_terminal(self.PORT, mock_ssh).AndReturn(True) mock_ssh.sendline(sut.SET_STATE_ON) mock_ssh.sendline(sut.END_CMD) mock_ssh.expect(self.DEVICE, timeout=sut.CMD_TIMEOUT).AndRaise(exception) mock_ssh.sendline(sut.EXIT_CMD) mock_ssh.close(force=True) self.mox.ReplayAll() self.assertFalse(sut.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll() def testUnableToVerifyState(self): """Should return False if unable to verify current state.""" sut = rpm_controller.CiscoPOEController(self.SWITCH) mock_ssh = self.mox.CreateMockAnything() self.mox.StubOutWithMock(sut, '_login') self.mox.StubOutWithMock(sut, '_enter_configuration_terminal') self.mox.StubOutWithMock(sut, '_exit_configuration_terminal') sut._login().AndReturn(mock_ssh) sut._enter_configuration_terminal(self.PORT, mock_ssh).AndReturn(True) sut._exit_configuration_terminal(mock_ssh).AndReturn(True) mock_ssh.sendline(sut.SET_STATE_ON) mock_ssh.sendline(sut.CHECK_INTERFACE_STATE % self.PORT) exception = pexpect.TIMEOUT('Could not verify state.') matcher = self.MATCHER % (self.PORT, self.DEVICE) mock_ssh.expect(matcher, timeout=sut.CMD_TIMEOUT).AndRaise(exception) mock_ssh.sendline(sut.EXIT_CMD) mock_ssh.close(force=True) self.mox.ReplayAll() self.assertFalse(sut.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll()
class TestCiscoPOEController(mox.MoxTestBase): """Test CiscoPOEController.""" STREAM_WELCOME = 'This is a POE switch.\n\nUser Name:' STREAM_PWD = 'Password:'******'\nchromeos2-poe-sw8#' STREAM_CONFIG = 'chromeos2-poe-sw8(config)#' STREAM_CONFIG_IF = 'chromeos2-poe-sw8(config-if)#' STREAM_STATUS = ('\n ' 'Flow Link Back Mdix\n' 'Port Type Duplex Speed Neg ' 'ctrl State Pressure Mode\n' '-------- ------------ ------ ----- -------- ' '---- ----------- -------- -------\n' 'fa32 100M-Copper Full 100 Enabled ' 'Off Up Disabled Off\n') SERVO = 'chromeos1-rack3-host12-servo' SWITCH = 'chromeos2-poe-switch8' PORT = 'fa32' POWERUNIT_INFO = utils.PowerUnitInfo( device_hostname=PORT, powerunit_hostname=SERVO, powerunit_type=utils.PowerUnitInfo.POWERUNIT_TYPES.POE, outlet=PORT, hydra_hostname=None) def setUp(self): super(TestCiscoPOEController, self).setUp() self.mox.StubOutWithMock(pexpect.spawn, '_spawn') self.mox.StubOutWithMock(pexpect.spawn, 'read_nonblocking') self.mox.StubOutWithMock(pexpect.spawn, 'sendline') self.poe = rpm_controller.CiscoPOEController(self.SWITCH) pexpect.spawn._spawn(mox.IgnoreArg(), mox.IgnoreArg()) pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_WELCOME) pexpect.spawn.sendline(self.poe._username) pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_PWD) pexpect.spawn.sendline(self.poe._password) pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE) def testLogin(self): """Test we can log into the switch.""" self.mox.ReplayAll() self.assertNotEqual(self.poe._login(), None) self.mox.VerifyAll() def _EnterConfigurationHelper(self, success=True): """A helper function for testing entering configuration terminal. @param success: True if we want the process to pass, False if we want it to fail. """ pexpect.spawn.sendline('configure terminal') pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_CONFIG) pexpect.spawn.sendline('interface %s' % self.PORT) if success: pexpect.spawn.read_nonblocking(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( self.STREAM_CONFIG_IF) else: self.mox.StubOutWithMock(pexpect.spawn, '__str__') exception = pexpect.TIMEOUT( 'Could not enter configuration terminal.') pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndRaise(exception) pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.') pexpect.spawn.sendline('end') def testSuccessfullyChangeOutlet(self): """Should return True if change was successful.""" self._EnterConfigurationHelper() pexpect.spawn.sendline('power inline auto') pexpect.spawn.sendline('end') pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE) pexpect.spawn.sendline('show interface status %s' % self.PORT) pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_STATUS) pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(self.STREAM_DEVICE) pexpect.spawn.sendline('exit') self.mox.ReplayAll() self.assertTrue(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll() def testUnableToEnterConfigurationTerminal(self): """Should return False if unable to enter configuration terminal.""" self._EnterConfigurationHelper(success=False) pexpect.spawn.sendline('exit') self.mox.ReplayAll() self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll() def testUnableToExitConfigurationTerminal(self): """Should return False if unable to exit configuration terminal.""" self.mox.StubOutWithMock(pexpect.spawn, '__str__') self.mox.StubOutWithMock(rpm_controller.CiscoPOEController, '_enter_configuration_terminal') self.poe._enter_configuration_terminal(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(True) pexpect.spawn.sendline('power inline auto') pexpect.spawn.sendline('end') exception = pexpect.TIMEOUT('Could not exit configuration terminal.') pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndRaise(exception) pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.') pexpect.spawn.sendline('exit') self.mox.ReplayAll() self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll() def testUnableToVerifyState(self): """Should return False if unable to verify current state.""" self.mox.StubOutWithMock(pexpect.spawn, '__str__') self.mox.StubOutWithMock(rpm_controller.CiscoPOEController, '_enter_configuration_terminal') self.mox.StubOutWithMock(rpm_controller.CiscoPOEController, '_exit_configuration_terminal') self.poe._enter_configuration_terminal(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(True) pexpect.spawn.sendline('power inline auto') self.poe._exit_configuration_terminal(mox.IgnoreArg()).AndReturn(True) pexpect.spawn.sendline('show interface status %s' % self.PORT) exception = pexpect.TIMEOUT('Could not verify state.') pexpect.spawn.read_nonblocking( mox.IgnoreArg(), mox.IgnoreArg()).MultipleTimes().AndRaise(exception) pexpect.spawn.__str__().AndReturn('A pexpect.spawn object.') pexpect.spawn.sendline('exit') self.mox.ReplayAll() self.assertFalse(self.poe.set_power_state(self.POWERUNIT_INFO, 'ON')) self.mox.VerifyAll()