1 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
10 class PowerStrip(object):
11 """Controls Server Technology CW-16V1-C20M switched CDUs.
12 (Cabinet Power Distribution Unit)
14 This class is used to control the CW-16V1-C20M unit which
15 is a 16 port remote power strip. The strip supports AC devices
16 using 100-120V 50/60Hz input voltages. The commands in this
17 class are supported by switches that use Sentry Switched CDU Version 6.0g.
19 Opens a new connection for every command.
24 def __init__(self
, host
, user
='admn', password
='admn'):
27 self
._password
= password
29 def PowerOff(self
, outlet
):
30 """Powers off the device that is plugged into the specified outlet.
33 outlet: The outlet ID defined on the switch (eg. .a14).
35 self
._DoCommand
('off', outlet
)
37 def PowerOn(self
, outlet
):
38 """Powers on the device that is plugged into the specified outlet.
41 outlet: The outlet ID defined on the switch (eg. .a14).
43 self
._DoCommand
('on', outlet
)
45 def _DoCommand(self
, command
, outlet
):
46 """Performs power strip commands on the specified outlet.
48 Sample telnet interaction:
49 Escape character is '^]'.
51 Sentry Switched CDU Version 6.0g
54 Password: < password hidden from view >
60 Outlet Outlet Outlet Control
63 .A1 TowerA_Outlet1 On On
67 Switched CDU: < cdu cmd >
70 command: A valid CW-16V1-C20M command that follows the format
72 outlet: The outlet ID defined on the switch (eg. .a14).
74 tn
= telnetlib
.Telnet()
75 # To avoid 'Connection Reset by Peer: 104' exceptions when rapid calls
76 # are made to the telnet server on the power strip, we retry executing
81 tn
.open(self
._host
, timeout
=PowerStrip
.TIMEOUT
)
82 resp
= tn
.read_until('Username:', timeout
=PowerStrip
.TIMEOUT
)
83 assert 'Username' in resp
, 'Username not found in response. (%s)' % resp
84 tn
.write(self
._user
+ '\n')
86 resp
= tn
.read_until('Password:', timeout
=PowerStrip
.TIMEOUT
)
87 assert 'Password' in resp
, 'Password not found in response. (%s)' % resp
88 tn
.write(self
._password
+ '\n')
90 resp
= tn
.read_until('Switched CDU:', timeout
=PowerStrip
.TIMEOUT
)
91 assert 'Switched CDU' in resp
, 'Standard prompt not found in ' \
92 'response. (%s)' % resp
93 tn
.write('%s %s\n' % (command
, outlet
))
95 # Obtain the output of command and make sure it matches with the action
97 # Sample valid output:
98 # .A1 TowerA_Outlet1 On On
99 resp
= tn
.read_until('Switched CDU:', timeout
=PowerStrip
.TIMEOUT
)
100 if not re
.search('%s\s+\S+\s+%s\s+%s' % (outlet
, command
, command
),
102 raise Exception('Command \'%s\' execution failed. (%s)' %
105 # Exiting the telnet session cleanly significantly reduces the chance of
106 # connection error on initiating the following telnet session.
110 # If we've gotten this far, there is no need to retry.
112 except Exception as e
:
113 logging
.debug('Power strip retry on cmd "%s". Reason: %s'
115 if attempt
== retry
[-1]:
116 raise Exception('Sentry Command "%s" failed. '
117 'Reason: %s' % (command
, str(e
)))