Autotest: Update site remote power to use RPM Infrastructure

Updated site_host to include RPM power on, off, and cycle commands,
that implement the client side code of interacting with the RPM
Infrastructure.

Removed all the RPM specific classes from site_remote_power.py and
replaced them with one generic class that utilizes the new methods
in site_host.

Also updated hardreset in SerialHost to utilize these new methods
that it will inherit from site_host.

BUG=chromium-os:34664
TEST=Ran power_IdleServer against a machine in the lab.

Reviewed-on: https://gerrit.chromium.org/gerrit/34001
Commit-Ready: Simran Basi <sbasi@chromium.org>
Reviewed-by: Simran Basi <sbasi@chromium.org>
Tested-by: Simran Basi <sbasi@chromium.org>
(cherry picked from commit d5e5e271f6c8c54bb5242fc95c609032bccb5d95)

Conflicts:

	server/hosts/site_host.py

Change-Id: I23d17ac333f7771ca5672fb4ce5c36054d2ffbdc
Reviewed-on: https://gerrit.chromium.org/gerrit/38064
Reviewed-by: Scott Zawalski <scottz@chromium.org>
Reviewed-by: Simran Basi <sbasi@chromium.org>
Tested-by: Simran Basi <sbasi@chromium.org>
diff --git a/global_config.ini b/global_config.ini
index 979713e..d1527e6 100644
--- a/global_config.ini
+++ b/global_config.ini
@@ -147,3 +147,4 @@
 # the "Sentry Switched CDU" type
 rpm_sentry_username: fake_user
 rpm_sentry_password: fake_password
+rpm_frontend_uri: http://chromeos-rpmserver1.cbf.corp.google.com:9999
diff --git a/server/hosts/base_classes.py b/server/hosts/base_classes.py
index 0759d5f..5316865 100644
--- a/server/hosts/base_classes.py
+++ b/server/hosts/base_classes.py
@@ -78,3 +78,9 @@
 
         if self.job:
             self.job.hosts.discard(self)
+
+
+    @staticmethod
+    def check_for_rpm_support(hostname):
+        """Stub method. RPM support is implemented in site_host."""
+        return False
\ No newline at end of file
diff --git a/server/hosts/serial.py b/server/hosts/serial.py
index d363cb7..e89bff9 100644
--- a/server/hosts/serial.py
+++ b/server/hosts/serial.py
@@ -1,10 +1,14 @@
 import os, sys, subprocess, logging
 
-from autotest_lib.client.common_lib import utils, error
+from autotest_lib.client.common_lib import global_config, utils, error
 from autotest_lib.server import utils as server_utils
 from autotest_lib.server.hosts import remote
 
 
+RPM_FRONTEND_URI = global_config.global_config.get_config_value('CROS',
+        'rpm_frontend_uri', type=str, default='')
+
+
 SiteHost = utils.import_site_class(
     __file__, "autotest_lib.server.hosts.site_host", "SiteHost",
     remote.RemoteHost)
@@ -12,6 +16,8 @@
 
 class SerialHost(SiteHost):
     DEFAULT_REBOOT_TIMEOUT = SiteHost.DEFAULT_REBOOT_TIMEOUT
+    HARD_RESET_CMD = 'hardreset'
+
 
     def _initialize(self, conmux_server=None, conmux_attach=None,
                     console_log="console.log", *args, **dargs):
@@ -53,16 +59,18 @@
                           conmux_attach=None):
         """ Returns a boolean indicating if the remote host with "hostname"
         supports use as a SerialHost """
+        return_value = False
         conmux_attach = cls._get_conmux_attach(conmux_attach)
         conmux_hostname = cls._get_conmux_hostname(hostname, conmux_server)
         cmd = "%s %s echo 2> /dev/null" % (conmux_attach, conmux_hostname)
         try:
             result = utils.run(cmd, ignore_status=True, timeout=10)
-            return result.exit_status == 0
+            return_value = result.exit_status == 0
         except error.CmdError:
             logging.warning("Timed out while trying to attach to conmux")
+            return_value = False
 
-        return False
+        return return_value or SiteHost.check_for_rpm_support(hostname)
 
 
     def start_loggers(self):
@@ -114,7 +122,7 @@
 
 
     def hardreset(self, timeout=DEFAULT_REBOOT_TIMEOUT, wait=True,
-                  conmux_command='hardreset', num_attempts=1, halt=False,
+                  conmux_command=HARD_RESET_CMD, num_attempts=1, halt=False,
                   **wait_for_restart_kwargs):
         """
         Reach out and slap the box in the power switch.
@@ -141,7 +149,9 @@
         def reboot():
             if halt:
                 self.halt()
-            if not self.run_conmux(conmux_command):
+            if self.HARD_RESET_CMD in conmux_command and RPM_FRONTEND_URI:
+                self.power_cycle()
+            elif not self.run_conmux(conmux_command):
                 self.record("ABORT", None, "reboot.start",
                             "hard reset unavailable")
                 raise error.AutoservUnsupportedError(
@@ -158,7 +168,11 @@
                     except error.AutoservShutdownError:
                         logging.warning(warning_msg, attempt+1, num_attempts)
                         # re-send the hard reset command
-                        self.run_conmux(conmux_command)
+                        if (self.HARD_RESET_CMD in conmux_command and
+                                RPM_FRONTEND_URI):
+                            self.power_cycle()
+                        else:
+                            self.run_conmux(conmux_command)
                     else:
                         break
                 else:
diff --git a/server/hosts/site_host.py b/server/hosts/site_host.py
index 305de1e..5552038 100644
--- a/server/hosts/site_host.py
+++ b/server/hosts/site_host.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import logging
+import re
 import subprocess
 import time
 import xmlrpclib
@@ -12,11 +13,19 @@
 from autotest_lib.client.common_lib.cros import autoupdater
 from autotest_lib.server import autoserv_parser
 from autotest_lib.server import site_host_attributes
-from autotest_lib.server import site_remote_power
 from autotest_lib.server.cros import servo
 from autotest_lib.server.hosts import remote
 
 
+RPM_FRONTEND_URI = global_config.global_config.get_config_value('CROS',
+        'rpm_frontend_uri', type=str, default='')
+
+
+class RemotePowerException(Exception):
+    """This is raised when we fail to set the state of the device's outlet."""
+    pass
+
+
 def make_ssh_command(user='root', port=22, opts='', hosts_file=None,
                      connect_timeout=None, alive_interval=None):
     """Override default make_ssh_command to use options tuned for Chrome OS.
@@ -87,6 +96,11 @@
     SHUTDOWN_TIMEOUT = 5
     REBOOT_TIMEOUT = SHUTDOWN_TIMEOUT + BOOT_TIMEOUT
 
+    LAB_MACHINE_FILE = '/mnt/stateful_partition/.labmachine'
+    RPM_HOSTNAME_REGEX = ('chromeos[0-9]+(-row[0-9]+)?-rack[0-9]+[a-z]*-'
+                          'host[0-9]+')
+
+
 
     def _initialize(self, hostname, servo_host=None, servo_port=None,
                     *args, **dargs):
@@ -203,9 +217,8 @@
     def cleanup(self):
         """Special cleanup method to make sure hosts always get power back."""
         super(SiteHost, self).cleanup()
-        remote_power = site_remote_power.RemotePower(self.hostname)
-        if remote_power:
-            remote_power.set_power_on()
+        if self.has_power():
+            self.power_on()
 
 
     def reboot(self, **dargs):
@@ -323,7 +336,7 @@
             #
             # 'pkill' helpfully exits with status 1 if no target
             # process  is found, for which run() will throw an
-            # exception.  We don't want that, so we ignore the
+            # exception.  We don't want that, so we the ignore
             # status.
             self.run("pkill -f '%s'" % remote_name, ignore_status=True)
 
@@ -492,3 +505,43 @@
                 raise error.TestFail(
                     'client is back up, but did not reboot'
                     ' (boot %s)' % old_boot_id)
+
+
+    @staticmethod
+    def check_for_rpm_support(hostname):
+        """For a given hostname, return whether or not it is powered by an RPM.
+
+        @return None if this host does not follows the defined naming format
+                for RPM powered DUT's in the lab. If it does follow the format,
+                it returns a regular expression MatchObject instead.
+        """
+        return re.match(SiteHost.RPM_HOSTNAME_REGEX, hostname)
+
+
+    def has_power(self):
+        """For this host, return whether or not it is powered by an RPM.
+
+        @return True if this host is in the CROS lab and follows the defined
+                naming format.
+        """
+        return SiteHost.check_for_rpm_support(self.hostname)
+
+
+    def _set_power(self, new_state):
+        client = xmlrpclib.ServerProxy(RPM_FRONTEND_URI, verbose=False)
+        if not client.queue_request(self.hostname, new_state):
+            raise RemotePowerException('Failed to change outlet status for'
+                                       'host: %s to state: %s', self.hostname,
+                                       new_state)
+
+
+    def power_off(self):
+        self._set_power('OFF')
+
+
+    def power_on(self):
+        self._set_power('ON')
+
+
+    def power_cycle(self):
+        self._set_power('CYCLE')
diff --git a/server/site_remote_power.py b/server/site_remote_power.py
deleted file mode 100755
index 7c90843..0000000
--- a/server/site_remote_power.py
+++ /dev/null
@@ -1,221 +0,0 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging, os, re, urllib
-
-# If you create site_remote_power_config.py and remote_power_switch_machines
-# there, we will use it to configure the power switch.
-#
-# Example configuration:
-#   remote_power_switch_machines = {
-#     "myserver": "rps,cyclades-acs,powerswitch1,device1,password"
-#   }
-try:
-    from site_remote_power_config import remote_power_switch_machines
-except:
-    remote_power_switch_machines = {}
-
-# If remote_power_switch_machines was not defined in site_remote_power_config,
-# we look in the AFE database for a label which defines how we should behave.
-#
-# Here is an example label:
-#   "rps,cyclades-acs,powerswitch1,device1,password"
-#
-# If you attach the above label to device1, then we will use the "cyclades-acs"
-# powerswitch to turn the power to device1 on and off, and pass in the above
-# configuration to the CycladesACSRemotePowerSwitch class.
-if not remote_power_switch_machines:
-    try:
-        settings = 'autotest_lib.frontend.settings'
-        os.environ['DJANGO_SETTINGS_MODULE'] = settings
-        from autotest_lib.frontend.afe import models
-        has_models = True
-    except ImportError, e:
-        has_models = False
-
-# factory function for choosing which remote power class to return
-
-def ParseConfig(config):
-    type = config.split(",", 3)[1]
-    cls = power_switch_types[type]
-    if cls:
-        return cls(config)
-    else:
-        raise AssertionError
-
-def RemotePower(host):
-    if remote_power_switch_machines and host in remote_power_switch_machines:
-        return ParseConfig(remote_power_switch_machines[host])
-    elif has_models:
-        host_obj = models.Host.valid_objects.get(hostname=host)
-        for label in host_obj.labels.all():
-            name = label.name
-            if name.startswith("rps,"):
-                return ParseConfig(name)
-
-    return None
-
-class SentrySwitchedCDU(object):
-    """
-    This class implements power control for Sentry Switched CDU
-    http://www.servertech.com/products/switched-pdus/
-
-    It assumes that machine
-    chromeos-rackX-hostY
-    is controlled by an RPM at
-    chromeos-rackX-rpm1.
-
-    Example usage:
-      switch = SentrySwitchedCDU('chromeos-rack7-host3')
-      switch.set_power_off()
-      switch.set_power_on()
-    """
-
-
-    def __init__(self, machine):
-        self.machine = machine
-        self.rpm_host = re.sub('host[^.]*', 'rpm1', machine, count=1)
-
-
-    def set_power_on(self):
-        self._set_power('on')
-
-
-    def set_power_off(self):
-        self._set_power('off')
-
-
-    def _set_power(self, command):
-        from autotest_lib.client.common_lib import pexpect
-        from autotest_lib.client.common_lib import global_config
-        password = global_config.global_config.get_config_value(
-                'CROS', 'rpm_sentry_password', type=str)
-        username = global_config.global_config.get_config_value(
-                'CROS', 'rpm_sentry_username', type=str)
-        rpm_host = self.rpm_host
-        # In case machine comes with a full domain name, cut it off
-        machine_name = self.machine.split('.', 1)[0]
-        prompt = 'Switched CDU:'
-        cmd = ('ssh -l %s '
-               '-o StrictHostKeyChecking=no '
-               '-o UserKnownHostsFile=/dev/null '
-               '%s' % (username, rpm_host))
-        ssh = pexpect.spawn(cmd)
-        ssh.expect('Password:', timeout=30)
-        ssh.sendline(password)
-        ssh.expect(prompt, timeout=30)
-        logging.info('Connecting to power switch (%s@%s)', username, rpm_host)
-        # Command looks like: off chromeos-rack7-host3
-        ssh.sendline('%s %s' %(command, machine_name))
-        try:
-            ssh.expect('Command successful', timeout=30)
-        except pexpect.TIMEOUT:
-            logging.error('Timed out while switching AC power %s for host %s',
-                    command, machine_name)
-            raise
-        finally:
-            ssh.sendline('logout')
-        logging.info('Power turned %s for %s', command, machine_name)
-
-
-class CycladesACSRemotePowerSwitch(object):
-    """
-    This class implements power control for Cyclades ACS boxes.
-
-    The config string contains five components, separated by commas:
-      1) prefix ("rps")
-      2) type ("cyclades-acs")
-      3) hostname of power switch box
-      4) port to use on power switch box
-      5) password to enter when connecting to power switch box
-
-    Example usage:
-      config = "rps,cyclades-acs,powerswitch1,device1,password"
-      switch = CycladesACSRemotePowerSwitch(config)
-      switch.set_power_off()
-      switch.set_power_on()
-    """
-
-
-    def __init__(self, config):
-        self.power_ip, self.power_port, self.password = config.split(",")[2:]
-
-
-    def _set_power(self, state):
-        from autotest_lib.client.common_lib import pexpect
-        hostname = self.power_ip
-        username = 'root:%s' % self.power_port
-        cmd = ('ssh -l %s '
-               '-o StrictHostKeyChecking=no '
-               '-o UserKnownHostsFile=/dev/null '
-               '%s' % (username, hostname))
-        ssh = pexpect.spawn(cmd)
-        ssh.expect('password:', timeout=30)
-        ssh.sendline(self.password)
-        ssh.expect('\n', timeout=30)
-        ssh.send('\020')
-        logging.info('Connecting to power switch (%s@%s)' % (username,
-                                                             hostname))
-        ssh.expect('Please choose an option:', timeout=30)
-
-        if state:
-           ssh.sendline('5')
-           ssh.expect('Outlet turned on', timeout=30)
-           logging.info('Power turned on for %s' % self.dict['power_port'])
-        else:
-           ssh.sendline('4')
-           ssh.expect('Outlet turned off', timeout=30)
-           logging.info('Power turned off for %s' % self.dict['power_port'])
-
-
-    def set_power_on(self):
-        self._set_power(1)
-
-
-    def set_power_off(self):
-        self._set_power(0)
-
-
-class HTTPPowerSwitch(object):
-    """
-    This class implements power control via standard HTTP GET requests.
-
-    The config string contains four components, separated by commas:
-      1) prefix ("rps")
-      2) type ("cyclades-acs")
-      3) URL to turn power on
-      4) URL to turn power off
-
-    Example usage:
-      url_prefix = "http://user:password@powerswitch1/Set.cmd?CMD=SetPower&P"
-      config = "rps,http,%s1=1,%s1=0" % (url_prefix, url_prefix)
-      switch = HTTPPowerSwitch(config)
-      switch.set_power_off()
-      switch.set_power_on()
-
-    """
-
-
-    def __init__(self, config):
-        self.on_url, self.off_url = config.split(",")[2:]
-
-
-    def _get_url(self, url):
-        logging.info(url)
-        f = urllib.urlopen(url)
-        f.read()
-
-
-    def set_power_on(self):
-        self._get_url(self.on_url)
-
-
-    def set_power_off(self):
-        self._get_url(self.off_url)
-
-
-power_switch_types = {
-    'cyclades-acs': CycladesACSRemotePowerSwitch,
-    'http': HTTPPowerSwitch
-}
diff --git a/server/site_tests/power_IdleServer/control b/server/site_tests/power_IdleServer/control
index 52154d3..ced7c1c 100644
--- a/server/site_tests/power_IdleServer/control
+++ b/server/site_tests/power_IdleServer/control
@@ -14,22 +14,21 @@
 draw at idle.
 """
 
-from autotest_lib.server import site_remote_power, utils
+from autotest_lib.server import utils
 
 
 def run_system_power_idle(machine):
-    remote_power = site_remote_power.RemotePower(machine)
-    if remote_power:
-        remote_power.set_power_off()
-
     host = hosts.create_host(machine)
+    if host.has_power():
+        host.power_off()
+
     host_at = autotest.Autotest(host)
     host_test = 'power_Idle'
 
     host_at.run_test(host_test)
 
-    if remote_power:
-        remote_power.set_power_on()
+    if host.has_power()):
+        host.power_on()
 
 
 (tuple, failures) = utils.form_ntuples_from_machines(machines, 1)
diff --git a/server/site_tests/suites/control.network_wifi b/server/site_tests/suites/control.network_wifi
index ca8d148..dfa481f 100644
--- a/server/site_tests/suites/control.network_wifi
+++ b/server/site_tests/suites/control.network_wifi
@@ -30,7 +30,7 @@
 import time
 
 from autotest_lib.client.common_lib import error
-from autotest_lib.server import site_host_attributes, site_remote_power
+from autotest_lib.server import site_host_attributes
 from autotest_lib.server import site_wifitest
 from autotest_lib.server.hosts import ssh_host
 
@@ -47,20 +47,19 @@
 
 def run_server_tests(machine):
   client_attributes = site_host_attributes.HostAttributes(machine)
-  remote_power = site_remote_power.RemotePower(machine)
-
-  if remote_power:
-    remote_power.set_power_on()
+  client = hosts.create_host(machine)
+  if client.has_power():
+    client.power_on()
   else:
     raise error.TestNAError('No power switch configured.')
 
   # Power cycle the entire unit prior to testing. Not expecting any exceptions,
   # but shouldn't leave power off no matter what happens.
   try:
-    remote_power.set_power_off()
+    client.power_off()
     time.sleep(POWER_CYCLE_TIME_SECS)
   finally:
-    remote_power.set_power_on()
+    client.power_on()
 
   # Wait for devices to come back.
   router = ssh_host.SSHHost(client_attributes.router_addr)
diff --git a/server/site_tests/suites/control.power b/server/site_tests/suites/control.power
index 28691f8..8f41140 100644
--- a/server/site_tests/suites/control.power
+++ b/server/site_tests/suites/control.power
@@ -11,11 +11,10 @@
 
 DOC = """
 This test suite runs automated power tests that should all pass and that
-require the power to be connected with a remote power control.
+require the power to be connected with a remote power manager.
 """
 
 from autotest_lib.server import site_host_attributes
-from autotest_lib.server import site_remote_power
 from autotest_lib.client.common_lib import error
 
 # Run power tests that don't take a long time
@@ -37,9 +36,8 @@
   client_attributes = site_host_attributes.HostAttributes(machine)
   client_at = autotest.Autotest(client)
 
-  remote_power = site_remote_power.RemotePower(machine)
-  if remote_power:
-    remote_power.set_power_on()
+  if client.has_power():
+    client.power_on()
   else:
     raise error.TestNAError("No power switch configured")
 
@@ -50,7 +48,7 @@
   client_at.run_test('power_BatteryCharge', percent_target_charge=50,
                      max_run_time=60*60*4, tag='CHARGE_50')
 
-  remote_power.set_power_off()
+  client.power_off()
   try:
     for test in TESTS:
         client_at.run_test(test)
@@ -59,7 +57,7 @@
         client_at.run_test('power_Resume')
 
   finally:
-    remote_power.set_power_on()
+    client.power_on()
 
   # Run the 60/20/10/10 load test
   # Charge the battery to at least 99% in preparation for the load
@@ -73,7 +71,7 @@
   # 1. Make the test run over wifi instead of ethernet
   # 2. Make the test login automatically to facebook and gmail
   # 3. Add audiovideo_V4L2 webcam test
-  remote_power.set_power_off()
+  client.power_off()
 
   try:
     if hasattr(client_attributes, 'wifi'):
@@ -86,7 +84,7 @@
       client_at.run_test('power_LoadTest', loop_count=9, loop_time=3600,
                          check_network=False, tag='WIRED')
   finally:
-    remote_power.set_power_on()
+    client.power_on()
 
 
 job.parallel_on_machines(run_client_test, machines)
diff --git a/server/site_tests/suites/control.power_build b/server/site_tests/suites/control.power_build
index 45c3346..4d76aa5 100644
--- a/server/site_tests/suites/control.power_build
+++ b/server/site_tests/suites/control.power_build
@@ -17,7 +17,6 @@
 """
 
 from autotest_lib.server import site_host_attributes
-from autotest_lib.server import site_remote_power
 
 # Tests that should run both on AC and battery power
 TESTS = [
@@ -39,8 +38,7 @@
     ]
 
 
-def _iterate_tests(machine, on_ac=True):
-    client = hosts.create_host(machine)
+def _iterate_tests(client, machine, on_ac=True):
     client_attributes = site_host_attributes.HostAttributes(machine)
     client_at = autotest.Autotest(client)
 
@@ -60,18 +58,18 @@
 
 
 def _run_client_test(machine):
-    remote_power = site_remote_power.RemotePower(machine)
-    if remote_power:
-        remote_power.set_power_on()
+    client = hosts.create_host(machine)
+    if client.has_power():
+        client.power_on()
 
-    _iterate_tests(machine, on_ac=True)
+    _iterate_tests(client, machine, on_ac=True)
 
-    if remote_power:
-        remote_power.set_power_off()
+    if client.has_power():
+        client.power_off()
         try:
-            _iterate_tests(machine, on_ac=False)
+            _iterate_tests(client, machine, on_ac=False)
         finally:
-            remote_power.set_power_on()
+            client.power_on()
 
 
 job.parallel_on_machines(_run_client_test, machines)
diff --git a/server/site_tests/suites/control.power_daily b/server/site_tests/suites/control.power_daily
index 51a6ac6..69affda 100644
--- a/server/site_tests/suites/control.power_daily
+++ b/server/site_tests/suites/control.power_daily
@@ -16,7 +16,6 @@
 """
 
 from autotest_lib.server import site_host_attributes
-from autotest_lib.server import site_remote_power
 from autotest_lib.client.common_lib import error
 
 def _run_client_test(machine):
@@ -24,9 +23,8 @@
     client_attributes = site_host_attributes.HostAttributes(machine)
     client_at = autotest.Autotest(client)
 
-    remote_power = site_remote_power.RemotePower(machine)
-    if remote_power:
-        remote_power.set_power_on()
+    if client.has_power():
+        client.power_on()
     else:
         raise error.TestNAError("No power switch configured")
 
@@ -36,12 +34,12 @@
                      max_run_time=60*60*4, tag='CHARGE_50')
 
     # Turn off power and run power_Consumption test.
-    remote_power.set_power_off()
+    client.power_off()
 
     try:
         client_at.run_test('power_Consumption')
     finally:
-        remote_power.set_power_on()
+        client.power_on()
 
     # Charge the battery to at least 99% in preparation for the load
     # test. Charging the battery from empty to full can take up to 4 hours.
@@ -53,7 +51,7 @@
     # TODO (snanda):
     # 1. Make the test login automatically to facebook and gmail
     # 2. Add audiovideo_V4L2 webcam test
-    remote_power.set_power_off()
+    client.power_off()
 
     try:
         if hasattr(client_attributes, 'wifi'):
@@ -65,7 +63,7 @@
             client_at.run_test('power_LoadTest', loop_count=9, loop_time=3600,
                                 check_network=False, tag='WIRED')
     finally:
-        remote_power.set_power_on()
+        client.power_on()
 
 
 job.parallel_on_machines(_run_client_test, machines)
diff --git a/server/site_tests/suites/control.power_weekly b/server/site_tests/suites/control.power_weekly
index a98d021..4379fdc 100644
--- a/server/site_tests/suites/control.power_weekly
+++ b/server/site_tests/suites/control.power_weekly
@@ -24,17 +24,14 @@
 #    https://sites.google.com/a/chromium.org/dev/chromium-os/testing/test-suites
 #    has ability to assure power states pre/post conditions.
 from autotest_lib.server import site_host_attributes
-from autotest_lib.server import site_remote_power
 from autotest_lib.client.common_lib import error
 
 def _run_client_test(machine):
     client = hosts.create_host(machine)
     client_attributes = site_host_attributes.HostAttributes(machine)
     client_at = autotest.Autotest(client)
-
-    remote_power = site_remote_power.RemotePower(machine)
-    if remote_power:
-        remote_power.set_power_on()
+    if client.has_power():
+        client.power_on()
     else:
         raise error.TestNAError("No power switch configured")
 
@@ -42,12 +39,12 @@
     client_at.run_test('power_BatteryCharge', percent_target_charge=50,
                      max_run_time=60*60*3, tag='CHARGE_50')
 
-    remote_power.set_power_off()
+    client.power_off()
     try:
         client_at.run_test('power_Standby', test_hours=12.0, sample_hours=1.0,
                            constraints=['milliwatts_standby_power <= 500.0'],
                            max_milliwatts_standby=500.0)
     finally:
-        remote_power.set_power_on()
+        client.power_on()
 
 job.parallel_on_machines(_run_client_test, machines)