summaryrefslogtreecommitdiffstats
path: root/chrome/test/pyautolib/chromeos/power_strip.py
blob: b614b676154f521362f573c4cc2b593f3e5eff93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Copyright (c) 2011 The Chromium 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
import re
import telnetlib


class PowerStrip(object):
  """Controls Server Technology CW-16V1-C20M switched CDUs.
  (Cabinet Power Distribution Unit)

  This class is used to control the CW-16V1-C20M unit which
  is a 16 port remote power strip.  The strip supports AC devices
  using 100-120V 50/60Hz input voltages.  The commands in this
  class are supported by switches that use Sentry Switched CDU Version 6.0g.

  Opens a new connection for every command.
  """

  TIMEOUT = 10

  def __init__(self, host, user='admn', password='admn'):
    self._host = host
    self._user = user
    self._password = password

  def PowerOff(self, outlet):
    """Powers off the device that is plugged into the specified outlet.

    Args:
      outlet: The outlet ID defined on the switch (eg. .a14).
    """
    self._DoCommand('off', outlet)

  def PowerOn(self, outlet):
    """Powers on the device that is plugged into the specified outlet.

    Args:
      outlet: The outlet ID defined on the switch (eg. .a14).
    """
    self._DoCommand('on', outlet)

  def _DoCommand(self, command, outlet):
    """Performs power strip commands on the specified outlet.

    Sample telnet interaction:
      Escape character is '^]'.

      Sentry Switched CDU Version 6.0g

      Username: admn
      Password: < password hidden from view >

      Location:

      Switched CDU: on .a1

         Outlet   Outlet                     Outlet      Control
         ID       Name                       Status      State

         .A1      TowerA_Outlet1             On          On

         Command successful

      Switched CDU: < cdu cmd >

    Args:
      command: A valid CW-16V1-C20M command that follows the format
               <command> <outlet>.
      outlet: The outlet ID defined on the switch (eg. .a14).
    """
    tn = telnetlib.Telnet()
    # To avoid 'Connection Reset by Peer: 104' exceptions when rapid calls
    # are made to the telnet server on the power strip, we retry executing
    # a command.
    retry = range(5)
    for attempt in retry:
      try:
        tn.open(self._host, timeout=PowerStrip.TIMEOUT)
        resp = tn.read_until('Username:', timeout=PowerStrip.TIMEOUT)
        assert 'Username' in resp, 'Username not found in response. (%s)' % resp
        tn.write(self._user + '\n')

        resp = tn.read_until('Password:', timeout=PowerStrip.TIMEOUT)
        assert 'Password' in resp, 'Password not found in response. (%s)' % resp
        tn.write(self._password + '\n')

        resp = tn.read_until('Switched CDU:', timeout=PowerStrip.TIMEOUT)
        assert 'Switched CDU' in resp, 'Standard prompt not found in ' \
                                         'response. (%s)' % resp
        tn.write('%s %s\n' % (command, outlet))

        # Obtain the output of command and make sure it matches with the action
        # we performed.
        # Sample valid output:
        #   .A1      TowerA_Outlet1             On          On
        resp = tn.read_until('Switched CDU:', timeout=PowerStrip.TIMEOUT)
        if not re.search('%s\s+\S+\s+%s\s+%s' % (outlet, command, command),
                                                 resp, re.I):
          raise Exception('Command \'%s\' execution failed. (%s)' %
                          (command, resp))

        # Exiting the telnet session cleanly significantly reduces the chance of
        # connection error on initiating the following telnet session.
        tn.write('exit\n')
        tn.read_all()

        # If we've gotten this far, there is no need to retry.
        break
      except Exception as e:
        logging.debug('Power strip retry on cmd "%s".  Reason: %s'
                       % (command, str(e)))
        if attempt == retry[-1]:
          raise Exception('Sentry Command "%s" failed.  '
                          'Reason: %s' % (command, str(e)))
      finally:
        tn.close()