[autotest] servod: add ability to address multiple servos

Both in the test lab via AFE ( site_host_attributes ) and at
developers desk users via run_remote_tests.sh we need capability to
address multiple servos.  This CL adds that functionality to ServoTest
class by accepting arguments from 3 sources:
  1. servo defaults
  2. AFE host_attributes
  3. cmdline arguments

Where 3. overrides 2. overrides 1.

Note, CL also makes assumption that

1. if servo_host=='localhost' -> servod should be invoked
2. else servod invocation is managed elsewhere and test should just
connect via xmlrpc

BUG=chrome-os-partner:5279
TEST=manual
./run_remote_tests.sh --remote 172.22.75.117 platform_CloseOpenLid -a "servo_serial=498432-00028"
./run_remote_tests.sh --remote 172.22.75.117 platform_LongPressPower -a "servo_serial=498432-00028"
./run_remote_tests.sh --remote 172.22.75.117 platform_LongPressPower -a "servo_host=myhost servo_serial=498432-00028"

All passed.  Also tried versions where serial DNE and they failed.

Note, recently pushed http://gerrit.chromium.org/gerrit/6133 handles
guaranteeing that there's only one unique servo when invoking servod

Change-Id: Ib765a3edbce11d68a1a7083ce1cca79fc9aede9c
Reviewed-on: http://gerrit.chromium.org/gerrit/6327
Reviewed-by: Todd Broch <tbroch@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
diff --git a/server/cros/servotest.py b/server/cros/servotest.py
index 5a6e27a..b314a7e 100755
--- a/server/cros/servotest.py
+++ b/server/cros/servotest.py
@@ -3,12 +3,13 @@
 # found in the LICENSE file.
 
 import logging
+import re
 import subprocess
 import time
 import xmlrpclib
 
 from autotest_lib.client.common_lib import error
-from autotest_lib.server import test, autotest
+from autotest_lib.server import autotest, site_host_attributes, test
 import autotest_lib.server.cros.servo
 
 
@@ -35,17 +36,34 @@
     _rpc_port = 9988
 
 
-    def initialize(self, host, servo_port, xml_config='servo.xml',
-                   servo_vid=None, servo_pid=None, servo_serial=None,
-                   use_pyauto=False):
+    def initialize(self, host, cmdline_args, use_pyauto=False):
         """Create a Servo object and install the PyAuto dependency.
 
         If use_pyauto is True the PyAuto dependency is installed on the client
         and a remote PyAuto server is launched and connected.
-        """
-        self.servo = autotest_lib.server.cros.servo.Servo(
-                servo_port, xml_config, servo_vid, servo_pid, servo_serial)
 
+        """
+        # Assign default arguments for servo invocation.
+        args = {
+            'servo_host': 'localhost', 'servo_port': 9999,
+            'xml_config': 'servo.xml', 'servo_vid': None, 'servo_pid': None,
+            'servo_serial': None, 'use_pyauto': False}
+
+        # Parse arguments from AFE and override servo defaults above.
+        client_attributes = site_host_attributes.HostAttributes(host.hostname)
+        if hasattr(site_host_attributes, 'servo_serial'):
+            args['servo_serial'] = client_attributes.servo_serial
+
+        # Parse arguments from command line and override previous AFE or servo
+        # defaults
+        for arg in cmdline_args:
+            match = re.search("^(\w+)=(.+)", arg)
+            if match:
+                args[match.group(1)] = match.group(2)
+
+        self.servo = autotest_lib.server.cros.servo.Servo(
+            args['servo_host'], args['servo_port'], args['xml_config'],
+            args['servo_vid'], args['servo_pid'], args['servo_serial'])
         # Initializes dut, may raise AssertionError if pre-defined gpio
         # sequence to set GPIO's fail.  Autotest does not handle exception
         # throwing in initialize and will cause a test to hang.