xref: /aosp_15_r20/external/openthread/tools/harness-automation/autothreadharness/pdu_controller.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#    documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#    names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#    derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Workerimport logging
31*cfb92d14SAndroid Build Coastguard Workerimport os
32*cfb92d14SAndroid Build Coastguard Workerimport re
33*cfb92d14SAndroid Build Coastguard Workerimport telnetlib
34*cfb92d14SAndroid Build Coastguard Workerimport time
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard Workertry:
37*cfb92d14SAndroid Build Coastguard Worker    # python 2
38*cfb92d14SAndroid Build Coastguard Worker    from urllib2 import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
39*cfb92d14SAndroid Build Coastguard Workerexcept ImportError:
40*cfb92d14SAndroid Build Coastguard Worker    # python 3
41*cfb92d14SAndroid Build Coastguard Worker    from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
42*cfb92d14SAndroid Build Coastguard Worker
43*cfb92d14SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
44*cfb92d14SAndroid Build Coastguard Worker
45*cfb92d14SAndroid Build Coastguard Workertry:
46*cfb92d14SAndroid Build Coastguard Worker    from pysnmp.hlapi import SnmpEngine, CommunityData, UdpTransportTarget, ContextData, getCmd, setCmd, ObjectType, ObjectIdentity, Integer32
47*cfb92d14SAndroid Build Coastguard Workerexcept ImportError:
48*cfb92d14SAndroid Build Coastguard Worker    logger.warning('PySNMP module is not installed. Install if EATON_PDU_CONTROLLER is used')
49*cfb92d14SAndroid Build Coastguard Worker
50*cfb92d14SAndroid Build Coastguard Worker
51*cfb92d14SAndroid Build Coastguard Workerclass PduController(object):
52*cfb92d14SAndroid Build Coastguard Worker
53*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
54*cfb92d14SAndroid Build Coastguard Worker        """Open PDU controller connection"""
55*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
56*cfb92d14SAndroid Build Coastguard Worker
57*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
58*cfb92d14SAndroid Build Coastguard Worker        """Reboot an outlet or a board passed as params"""
59*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
60*cfb92d14SAndroid Build Coastguard Worker
61*cfb92d14SAndroid Build Coastguard Worker    def close(self):
62*cfb92d14SAndroid Build Coastguard Worker        """Close PDU controller connection"""
63*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Worker
66*cfb92d14SAndroid Build Coastguard Workerclass DummyPduController(PduController):
67*cfb92d14SAndroid Build Coastguard Worker    """Dummy implementation which only says that PDU controller is not connected"""
68*cfb92d14SAndroid Build Coastguard Worker
69*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
70*cfb92d14SAndroid Build Coastguard Worker        pass
71*cfb92d14SAndroid Build Coastguard Worker
72*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
73*cfb92d14SAndroid Build Coastguard Worker        logger.info('No PDU controller connected.')
74*cfb92d14SAndroid Build Coastguard Worker
75*cfb92d14SAndroid Build Coastguard Worker    def close(self):
76*cfb92d14SAndroid Build Coastguard Worker        pass
77*cfb92d14SAndroid Build Coastguard Worker
78*cfb92d14SAndroid Build Coastguard Worker
79*cfb92d14SAndroid Build Coastguard Workerclass ApcPduController(PduController):
80*cfb92d14SAndroid Build Coastguard Worker
81*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
82*cfb92d14SAndroid Build Coastguard Worker        self.tn = None
83*cfb92d14SAndroid Build Coastguard Worker
84*cfb92d14SAndroid Build Coastguard Worker    def __del__(self):
85*cfb92d14SAndroid Build Coastguard Worker        self.close()
86*cfb92d14SAndroid Build Coastguard Worker
87*cfb92d14SAndroid Build Coastguard Worker    def _init(self):
88*cfb92d14SAndroid Build Coastguard Worker        """Initialize the telnet connection
89*cfb92d14SAndroid Build Coastguard Worker        """
90*cfb92d14SAndroid Build Coastguard Worker        self.tn = telnetlib.Telnet(self.ip, self.port)
91*cfb92d14SAndroid Build Coastguard Worker        self.tn.read_until('User Name')
92*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('apc\r\n')
93*cfb92d14SAndroid Build Coastguard Worker        self.tn.read_until('Password')
94*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('apc\r\n')
95*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
96*cfb92d14SAndroid Build Coastguard Worker
97*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
98*cfb92d14SAndroid Build Coastguard Worker        """Open telnet connection
99*cfb92d14SAndroid Build Coastguard Worker
100*cfb92d14SAndroid Build Coastguard Worker        Args:
101*cfb92d14SAndroid Build Coastguard Worker            params (dict), must contain two parameters "ip" - ip address or hostname and "port" - port number
102*cfb92d14SAndroid Build Coastguard Worker
103*cfb92d14SAndroid Build Coastguard Worker        Example:
104*cfb92d14SAndroid Build Coastguard Worker            params = {'port': 23, 'ip': 'localhost'}
105*cfb92d14SAndroid Build Coastguard Worker        """
106*cfb92d14SAndroid Build Coastguard Worker        logger.info('opening telnet')
107*cfb92d14SAndroid Build Coastguard Worker        self.port = params['port']
108*cfb92d14SAndroid Build Coastguard Worker        self.ip = params['ip']
109*cfb92d14SAndroid Build Coastguard Worker        self.tn = None
110*cfb92d14SAndroid Build Coastguard Worker        self._init()
111*cfb92d14SAndroid Build Coastguard Worker
112*cfb92d14SAndroid Build Coastguard Worker    def close(self):
113*cfb92d14SAndroid Build Coastguard Worker        """Close telnet connection"""
114*cfb92d14SAndroid Build Coastguard Worker        logger.info('closing telnet')
115*cfb92d14SAndroid Build Coastguard Worker        if self.tn:
116*cfb92d14SAndroid Build Coastguard Worker            self.tn.close()
117*cfb92d14SAndroid Build Coastguard Worker
118*cfb92d14SAndroid Build Coastguard Worker    def until_done(self):
119*cfb92d14SAndroid Build Coastguard Worker        """Wait until the prompt encountered
120*cfb92d14SAndroid Build Coastguard Worker        """
121*cfb92d14SAndroid Build Coastguard Worker        self.until(r'^>')
122*cfb92d14SAndroid Build Coastguard Worker
123*cfb92d14SAndroid Build Coastguard Worker    def until(self, regex):
124*cfb92d14SAndroid Build Coastguard Worker        """Wait until the regex encountered
125*cfb92d14SAndroid Build Coastguard Worker        """
126*cfb92d14SAndroid Build Coastguard Worker        logger.debug('waiting for %s', regex)
127*cfb92d14SAndroid Build Coastguard Worker        r = re.compile(regex, re.M)
128*cfb92d14SAndroid Build Coastguard Worker        self.tn.expect([r])
129*cfb92d14SAndroid Build Coastguard Worker
130*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
131*cfb92d14SAndroid Build Coastguard Worker        """Reboot outlet
132*cfb92d14SAndroid Build Coastguard Worker
133*cfb92d14SAndroid Build Coastguard Worker        Args:
134*cfb92d14SAndroid Build Coastguard Worker            params (dict), must contain parameter "outlet" - outlet number
135*cfb92d14SAndroid Build Coastguard Worker
136*cfb92d14SAndroid Build Coastguard Worker        Example:
137*cfb92d14SAndroid Build Coastguard Worker            params = {'outlet': 1}
138*cfb92d14SAndroid Build Coastguard Worker        """
139*cfb92d14SAndroid Build Coastguard Worker        outlet = params['outlet']
140*cfb92d14SAndroid Build Coastguard Worker
141*cfb92d14SAndroid Build Coastguard Worker        # main menu
142*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('\x1b\r\n')
143*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
144*cfb92d14SAndroid Build Coastguard Worker        # Device Manager
145*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('1\r\n')
146*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
147*cfb92d14SAndroid Build Coastguard Worker        # Outlet Management
148*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('2\r\n')
149*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
150*cfb92d14SAndroid Build Coastguard Worker        # Outlet Control
151*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('1\r\n')
152*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
153*cfb92d14SAndroid Build Coastguard Worker        # Select outlet
154*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('%d\r\n' % outlet)
155*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
156*cfb92d14SAndroid Build Coastguard Worker        # Control
157*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('1\r\n')
158*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
159*cfb92d14SAndroid Build Coastguard Worker        # off
160*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('2\r\n')
161*cfb92d14SAndroid Build Coastguard Worker        self.until('to cancel')
162*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('YES\r\n')
163*cfb92d14SAndroid Build Coastguard Worker        self.until('to continue')
164*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('\r\n')
165*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
166*cfb92d14SAndroid Build Coastguard Worker
167*cfb92d14SAndroid Build Coastguard Worker        time.sleep(5)
168*cfb92d14SAndroid Build Coastguard Worker        # on
169*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('1\r\n')
170*cfb92d14SAndroid Build Coastguard Worker        self.until('to cancel')
171*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('YES\r\n')
172*cfb92d14SAndroid Build Coastguard Worker        self.until('to continue')
173*cfb92d14SAndroid Build Coastguard Worker        self.tn.write('\r\n')
174*cfb92d14SAndroid Build Coastguard Worker        self.until_done()
175*cfb92d14SAndroid Build Coastguard Worker
176*cfb92d14SAndroid Build Coastguard Worker
177*cfb92d14SAndroid Build Coastguard Workerclass NordicBoardPduController(PduController):
178*cfb92d14SAndroid Build Coastguard Worker
179*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
180*cfb92d14SAndroid Build Coastguard Worker        pass
181*cfb92d14SAndroid Build Coastguard Worker
182*cfb92d14SAndroid Build Coastguard Worker    def _pin_reset(self, serial_number):
183*cfb92d14SAndroid Build Coastguard Worker        os.system('nrfjprog -f NRF52 --snr {} -p'.format(serial_number))
184*cfb92d14SAndroid Build Coastguard Worker
185*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
186*cfb92d14SAndroid Build Coastguard Worker        boards_serial_numbers = params['boards_serial_numbers']
187*cfb92d14SAndroid Build Coastguard Worker
188*cfb92d14SAndroid Build Coastguard Worker        for serial_number in boards_serial_numbers:
189*cfb92d14SAndroid Build Coastguard Worker            logger.info('Resetting board with the serial number: %s', serial_number)
190*cfb92d14SAndroid Build Coastguard Worker            self._pin_reset(serial_number)
191*cfb92d14SAndroid Build Coastguard Worker
192*cfb92d14SAndroid Build Coastguard Worker    def close(self):
193*cfb92d14SAndroid Build Coastguard Worker        pass
194*cfb92d14SAndroid Build Coastguard Worker
195*cfb92d14SAndroid Build Coastguard Worker
196*cfb92d14SAndroid Build Coastguard Workerclass EatonPduController(PduController):
197*cfb92d14SAndroid Build Coastguard Worker
198*cfb92d14SAndroid Build Coastguard Worker    outlet_oid_cmd_get_state_base = '1.3.6.1.4.1.534.6.6.7.6.6.1.2.0.'
199*cfb92d14SAndroid Build Coastguard Worker    outlet_oid_cmd_set_on_base = '1.3.6.1.4.1.534.6.6.7.6.6.1.4.0.'
200*cfb92d14SAndroid Build Coastguard Worker    outlet_oid_cmd_set_off_base = '1.3.6.1.4.1.534.6.6.7.6.6.1.3.0.'
201*cfb92d14SAndroid Build Coastguard Worker    outlet_oid_cmd_reboot_base = '1.3.6.1.4.1.534.6.6.7.6.6.1.5.0.'
202*cfb92d14SAndroid Build Coastguard Worker    outlet_oid_cmd_set_reboot_delay_seconds_base = '1.3.6.1.4.1.534.6.6.7.6.6.1.8.0.'
203*cfb92d14SAndroid Build Coastguard Worker
204*cfb92d14SAndroid Build Coastguard Worker    PDU_COMMAND_TIMEOUT = 5
205*cfb92d14SAndroid Build Coastguard Worker
206*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
207*cfb92d14SAndroid Build Coastguard Worker        missing_fields = ['ip', 'port']
208*cfb92d14SAndroid Build Coastguard Worker        missing_fields = [field for field in missing_fields if field not in params.keys()]
209*cfb92d14SAndroid Build Coastguard Worker        if missing_fields:
210*cfb92d14SAndroid Build Coastguard Worker            raise KeyError('Missing keys in PDU params: {}'.format(missing_fields))
211*cfb92d14SAndroid Build Coastguard Worker        self.params = params
212*cfb92d14SAndroid Build Coastguard Worker        self.type = 'pdu'
213*cfb92d14SAndroid Build Coastguard Worker        self.ip = self.params['ip']
214*cfb92d14SAndroid Build Coastguard Worker        self.snmp_agent_port = int(self.params['port'])
215*cfb92d14SAndroid Build Coastguard Worker        self._community = 'public'
216*cfb92d14SAndroid Build Coastguard Worker        self._snmp_engine = SnmpEngine()
217*cfb92d14SAndroid Build Coastguard Worker        self._community_data = CommunityData(self._community, mpModel=0)
218*cfb92d14SAndroid Build Coastguard Worker        self._udp_transport_target = UdpTransportTarget((self.ip, self.snmp_agent_port))
219*cfb92d14SAndroid Build Coastguard Worker        self._context = ContextData()
220*cfb92d14SAndroid Build Coastguard Worker
221*cfb92d14SAndroid Build Coastguard Worker    def _outlet_oid_get(self, param, socket):
222*cfb92d14SAndroid Build Coastguard Worker        """
223*cfb92d14SAndroid Build Coastguard Worker        Translates command to the OID number representing a command for the specific power socket.
224*cfb92d14SAndroid Build Coastguard Worker
225*cfb92d14SAndroid Build Coastguard Worker        Args:
226*cfb92d14SAndroid Build Coastguard Worker            param (str), command string
227*cfb92d14SAndroid Build Coastguard Worker            socket (int), socket index
228*cfb92d14SAndroid Build Coastguard Worker
229*cfb92d14SAndroid Build Coastguard Worker        Return:
230*cfb92d14SAndroid Build Coastguard Worker            full OID identifying the SNMP object (str)
231*cfb92d14SAndroid Build Coastguard Worker        """
232*cfb92d14SAndroid Build Coastguard Worker        parameters = {
233*cfb92d14SAndroid Build Coastguard Worker            'get_state': self.outlet_oid_cmd_get_state_base,
234*cfb92d14SAndroid Build Coastguard Worker            'set_on': self.outlet_oid_cmd_set_on_base,
235*cfb92d14SAndroid Build Coastguard Worker            'set_off': self.outlet_oid_cmd_set_off_base,
236*cfb92d14SAndroid Build Coastguard Worker            'set_reboot_delay': self.outlet_oid_cmd_set_reboot_delay_seconds_base,
237*cfb92d14SAndroid Build Coastguard Worker            'reboot': self.outlet_oid_cmd_reboot_base
238*cfb92d14SAndroid Build Coastguard Worker        }
239*cfb92d14SAndroid Build Coastguard Worker
240*cfb92d14SAndroid Build Coastguard Worker        return parameters[param.lower()] + str(socket)
241*cfb92d14SAndroid Build Coastguard Worker
242*cfb92d14SAndroid Build Coastguard Worker    # Performs set command to specific OID with a given value by sending a SNMP Set message.
243*cfb92d14SAndroid Build Coastguard Worker    def _oid_set(self, oid, value):
244*cfb92d14SAndroid Build Coastguard Worker        """
245*cfb92d14SAndroid Build Coastguard Worker        Performs set command to specific OID with a given value by sending a SNMP Set message.
246*cfb92d14SAndroid Build Coastguard Worker
247*cfb92d14SAndroid Build Coastguard Worker        Args:
248*cfb92d14SAndroid Build Coastguard Worker            oid (str): Full OID identifying the object to be read.
249*cfb92d14SAndroid Build Coastguard Worker            value (int): Value to be written to the OID as Integer32.
250*cfb92d14SAndroid Build Coastguard Worker        """
251*cfb92d14SAndroid Build Coastguard Worker        errorIndication, errorStatus, errorIndex, varBinds = next(
252*cfb92d14SAndroid Build Coastguard Worker            setCmd(self._snmp_engine, self._community_data, self._udp_transport_target, self._context,
253*cfb92d14SAndroid Build Coastguard Worker                   ObjectType(ObjectIdentity(oid), Integer32(value))))
254*cfb92d14SAndroid Build Coastguard Worker
255*cfb92d14SAndroid Build Coastguard Worker        if errorIndication:
256*cfb92d14SAndroid Build Coastguard Worker            msg = 'Found PDU errorIndication: {}'.format(errorIndication)
257*cfb92d14SAndroid Build Coastguard Worker            logger.exception(msg)
258*cfb92d14SAndroid Build Coastguard Worker            raise RuntimeError(msg)
259*cfb92d14SAndroid Build Coastguard Worker        elif errorStatus:
260*cfb92d14SAndroid Build Coastguard Worker            msg = 'Found PDU errorStatus: {}'.format(errorStatus)
261*cfb92d14SAndroid Build Coastguard Worker            logger.exception(msg)
262*cfb92d14SAndroid Build Coastguard Worker            raise RuntimeError(msg)
263*cfb92d14SAndroid Build Coastguard Worker
264*cfb92d14SAndroid Build Coastguard Worker    def _oid_get(self, oid):
265*cfb92d14SAndroid Build Coastguard Worker        """
266*cfb92d14SAndroid Build Coastguard Worker        Performs SNMP get command and returns OID value by sending a SNMP Get message.
267*cfb92d14SAndroid Build Coastguard Worker
268*cfb92d14SAndroid Build Coastguard Worker        Args:
269*cfb92d14SAndroid Build Coastguard Worker            oid (str): Full OID identifying the object to be read.
270*cfb92d14SAndroid Build Coastguard Worker
271*cfb92d14SAndroid Build Coastguard Worker        Return:
272*cfb92d14SAndroid Build Coastguard Worker            OID value (int)
273*cfb92d14SAndroid Build Coastguard Worker        """
274*cfb92d14SAndroid Build Coastguard Worker        errorIndication, errorStatus, errorIndex, varBinds = next(
275*cfb92d14SAndroid Build Coastguard Worker            getCmd(self._snmp_engine, self._community_data, self._udp_transport_target, self._context,
276*cfb92d14SAndroid Build Coastguard Worker                   ObjectType(ObjectIdentity(oid))))
277*cfb92d14SAndroid Build Coastguard Worker
278*cfb92d14SAndroid Build Coastguard Worker        if errorIndication:
279*cfb92d14SAndroid Build Coastguard Worker            msg = 'Found PDU errorIndication: {}'.format(errorIndication)
280*cfb92d14SAndroid Build Coastguard Worker            logger.exception(msg)
281*cfb92d14SAndroid Build Coastguard Worker            raise RuntimeError(msg)
282*cfb92d14SAndroid Build Coastguard Worker        elif errorStatus:
283*cfb92d14SAndroid Build Coastguard Worker            msg = 'Found PDU errorStatus: {}'.format(errorStatus)
284*cfb92d14SAndroid Build Coastguard Worker            logger.exception(msg)
285*cfb92d14SAndroid Build Coastguard Worker            raise RuntimeError(msg)
286*cfb92d14SAndroid Build Coastguard Worker
287*cfb92d14SAndroid Build Coastguard Worker        return int(str(varBinds[-1]).partition('= ')[-1])
288*cfb92d14SAndroid Build Coastguard Worker
289*cfb92d14SAndroid Build Coastguard Worker    def _outlet_value_set(self, cmd, socket, value=1):
290*cfb92d14SAndroid Build Coastguard Worker        """
291*cfb92d14SAndroid Build Coastguard Worker        Sets outlet parameter value.
292*cfb92d14SAndroid Build Coastguard Worker
293*cfb92d14SAndroid Build Coastguard Worker        Args:
294*cfb92d14SAndroid Build Coastguard Worker            cmd (str): OID base
295*cfb92d14SAndroid Build Coastguard Worker            socket (int): socket index (last OID number)
296*cfb92d14SAndroid Build Coastguard Worker            value (int): value to be set
297*cfb92d14SAndroid Build Coastguard Worker        """
298*cfb92d14SAndroid Build Coastguard Worker        oid = self._outlet_oid_get(cmd, socket)
299*cfb92d14SAndroid Build Coastguard Worker
300*cfb92d14SAndroid Build Coastguard Worker        # Values other than 1 does not make sense with commands other than "set_reboot_delay".
301*cfb92d14SAndroid Build Coastguard Worker        if cmd != 'set_reboot_delay':
302*cfb92d14SAndroid Build Coastguard Worker            value = 1
303*cfb92d14SAndroid Build Coastguard Worker
304*cfb92d14SAndroid Build Coastguard Worker        self._oid_set(oid, value)
305*cfb92d14SAndroid Build Coastguard Worker
306*cfb92d14SAndroid Build Coastguard Worker    def _outlet_value_get(self, cmd, socket):
307*cfb92d14SAndroid Build Coastguard Worker        """
308*cfb92d14SAndroid Build Coastguard Worker        Read outlet parameter value.
309*cfb92d14SAndroid Build Coastguard Worker
310*cfb92d14SAndroid Build Coastguard Worker        Args:
311*cfb92d14SAndroid Build Coastguard Worker            cmd (str): OID base
312*cfb92d14SAndroid Build Coastguard Worker            socket (int): socket index (last OID number)
313*cfb92d14SAndroid Build Coastguard Worker
314*cfb92d14SAndroid Build Coastguard Worker        Return:
315*cfb92d14SAndroid Build Coastguard Worker            parameter value (int)
316*cfb92d14SAndroid Build Coastguard Worker        """
317*cfb92d14SAndroid Build Coastguard Worker        oid = self._outlet_oid_get(cmd, socket)
318*cfb92d14SAndroid Build Coastguard Worker
319*cfb92d14SAndroid Build Coastguard Worker        return self._oid_get(oid)
320*cfb92d14SAndroid Build Coastguard Worker
321*cfb92d14SAndroid Build Coastguard Worker    def validate_state(self, socket, state):
322*cfb92d14SAndroid Build Coastguard Worker        return (self._outlet_value_get('get_state', socket) == state)
323*cfb92d14SAndroid Build Coastguard Worker
324*cfb92d14SAndroid Build Coastguard Worker    def turn_off(self, sockets):
325*cfb92d14SAndroid Build Coastguard Worker        """
326*cfb92d14SAndroid Build Coastguard Worker        Turns the specified socket off.
327*cfb92d14SAndroid Build Coastguard Worker
328*cfb92d14SAndroid Build Coastguard Worker        Args:
329*cfb92d14SAndroid Build Coastguard Worker            sockets (list(int)): sockets to be turned off
330*cfb92d14SAndroid Build Coastguard Worker        """
331*cfb92d14SAndroid Build Coastguard Worker        logger.info('Executing turn OFF for: {}'.format(sockets))
332*cfb92d14SAndroid Build Coastguard Worker
333*cfb92d14SAndroid Build Coastguard Worker        for socket in sockets:
334*cfb92d14SAndroid Build Coastguard Worker            self._outlet_value_set('set_off', socket)
335*cfb92d14SAndroid Build Coastguard Worker            time.sleep(2)
336*cfb92d14SAndroid Build Coastguard Worker
337*cfb92d14SAndroid Build Coastguard Worker            timeout = time.time() + self.PDU_COMMAND_TIMEOUT
338*cfb92d14SAndroid Build Coastguard Worker            while ((time.time() < timeout) and not self.validate_state(socket, 0)):
339*cfb92d14SAndroid Build Coastguard Worker                time.sleep(0.1)
340*cfb92d14SAndroid Build Coastguard Worker
341*cfb92d14SAndroid Build Coastguard Worker            if self.validate_state(socket, 0):
342*cfb92d14SAndroid Build Coastguard Worker                logger.debug('Turned OFF socket {} at {}'.format(socket, self.ip))
343*cfb92d14SAndroid Build Coastguard Worker            else:
344*cfb92d14SAndroid Build Coastguard Worker                logger.error('Failed to turn OFF socket {} at {}'.format(socket, self.ip))
345*cfb92d14SAndroid Build Coastguard Worker
346*cfb92d14SAndroid Build Coastguard Worker    def turn_on(self, sockets):
347*cfb92d14SAndroid Build Coastguard Worker        """
348*cfb92d14SAndroid Build Coastguard Worker        Turns the specified socket on.
349*cfb92d14SAndroid Build Coastguard Worker
350*cfb92d14SAndroid Build Coastguard Worker        Args:
351*cfb92d14SAndroid Build Coastguard Worker            sockets (list(int)): sockets to be turned on
352*cfb92d14SAndroid Build Coastguard Worker        """
353*cfb92d14SAndroid Build Coastguard Worker
354*cfb92d14SAndroid Build Coastguard Worker        logger.info('Executing turn ON for: {}'.format(sockets))
355*cfb92d14SAndroid Build Coastguard Worker
356*cfb92d14SAndroid Build Coastguard Worker        for socket in sockets:
357*cfb92d14SAndroid Build Coastguard Worker            self._outlet_value_set('set_on', socket)
358*cfb92d14SAndroid Build Coastguard Worker            time.sleep(2)
359*cfb92d14SAndroid Build Coastguard Worker
360*cfb92d14SAndroid Build Coastguard Worker            timeout = time.time() + self.PDU_COMMAND_TIMEOUT
361*cfb92d14SAndroid Build Coastguard Worker            while ((time.time() < timeout) and not self.validate_state(socket, 1)):
362*cfb92d14SAndroid Build Coastguard Worker                time.sleep(0.1)
363*cfb92d14SAndroid Build Coastguard Worker
364*cfb92d14SAndroid Build Coastguard Worker            if self.validate_state(socket, 1):
365*cfb92d14SAndroid Build Coastguard Worker                logger.debug('Turned ON socket {} at {}'.format(socket, self.ip))
366*cfb92d14SAndroid Build Coastguard Worker            else:
367*cfb92d14SAndroid Build Coastguard Worker                logger.error('Failed to turn ON socket {} at {}'.format(socket, self.ip))
368*cfb92d14SAndroid Build Coastguard Worker
369*cfb92d14SAndroid Build Coastguard Worker    def close(self):
370*cfb92d14SAndroid Build Coastguard Worker        self._community = None
371*cfb92d14SAndroid Build Coastguard Worker        self._snmp_engine = None
372*cfb92d14SAndroid Build Coastguard Worker        self._community_data = None
373*cfb92d14SAndroid Build Coastguard Worker        self._udp_transport_target = None
374*cfb92d14SAndroid Build Coastguard Worker        self._context = None
375*cfb92d14SAndroid Build Coastguard Worker
376*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
377*cfb92d14SAndroid Build Coastguard Worker        """
378*cfb92d14SAndroid Build Coastguard Worker        Reboots the sockets specified in the constructor with off and on delays.
379*cfb92d14SAndroid Build Coastguard Worker
380*cfb92d14SAndroid Build Coastguard Worker        Args:
381*cfb92d14SAndroid Build Coastguard Worker            sockets (list(int)): sockets to reboot
382*cfb92d14SAndroid Build Coastguard Worker        """
383*cfb92d14SAndroid Build Coastguard Worker
384*cfb92d14SAndroid Build Coastguard Worker        logger.info('Executing power cycle for: {}'.format(params['sockets']))
385*cfb92d14SAndroid Build Coastguard Worker        self.turn_off(params['sockets'])
386*cfb92d14SAndroid Build Coastguard Worker        time.sleep(10)
387*cfb92d14SAndroid Build Coastguard Worker        self.turn_on(params['sockets'])
388*cfb92d14SAndroid Build Coastguard Worker        time.sleep(5)
389*cfb92d14SAndroid Build Coastguard Worker
390*cfb92d14SAndroid Build Coastguard Worker
391*cfb92d14SAndroid Build Coastguard Workerclass IpPowerSocketPduController(PduController):
392*cfb92d14SAndroid Build Coastguard Worker
393*cfb92d14SAndroid Build Coastguard Worker    def open(self, **params):
394*cfb92d14SAndroid Build Coastguard Worker        self._base_url = 'http://{}/outs.cgi?out'.format(params['ip'])
395*cfb92d14SAndroid Build Coastguard Worker        password_manager = HTTPPasswordMgrWithDefaultRealm()
396*cfb92d14SAndroid Build Coastguard Worker        password_manager.add_password(None, self._base_url, params['user'], params['pass'])
397*cfb92d14SAndroid Build Coastguard Worker        authentication_handler = HTTPBasicAuthHandler(password_manager)
398*cfb92d14SAndroid Build Coastguard Worker        self._opener = build_opener(authentication_handler)
399*cfb92d14SAndroid Build Coastguard Worker
400*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **params):
401*cfb92d14SAndroid Build Coastguard Worker        logger.info('Executing power cycle')
402*cfb92d14SAndroid Build Coastguard Worker        for socket in params['sockets']:
403*cfb92d14SAndroid Build Coastguard Worker            self._turn_off(socket)
404*cfb92d14SAndroid Build Coastguard Worker            time.sleep(2)
405*cfb92d14SAndroid Build Coastguard Worker            self._turn_on(socket)
406*cfb92d14SAndroid Build Coastguard Worker            time.sleep(2)
407*cfb92d14SAndroid Build Coastguard Worker
408*cfb92d14SAndroid Build Coastguard Worker    def _change_state(self, socket, state):
409*cfb92d14SAndroid Build Coastguard Worker        self._opener.open('{}{}={}'.format(self._base_url, socket, state))
410*cfb92d14SAndroid Build Coastguard Worker
411*cfb92d14SAndroid Build Coastguard Worker    def _turn_off(self, socket):
412*cfb92d14SAndroid Build Coastguard Worker        self._change_state(socket, 1)
413*cfb92d14SAndroid Build Coastguard Worker
414*cfb92d14SAndroid Build Coastguard Worker    def _turn_on(self, socket):
415*cfb92d14SAndroid Build Coastguard Worker        self._change_state(socket, 0)
416*cfb92d14SAndroid Build Coastguard Worker
417*cfb92d14SAndroid Build Coastguard Worker    def close(self):
418*cfb92d14SAndroid Build Coastguard Worker        self._base_url = None
419*cfb92d14SAndroid Build Coastguard Worker        self._opener = None
420*cfb92d14SAndroid Build Coastguard Worker
421*cfb92d14SAndroid Build Coastguard Worker
422*cfb92d14SAndroid Build Coastguard Workerclass ManualPduController(PduController):
423*cfb92d14SAndroid Build Coastguard Worker
424*cfb92d14SAndroid Build Coastguard Worker    def open(self, **kwargs):
425*cfb92d14SAndroid Build Coastguard Worker        pass
426*cfb92d14SAndroid Build Coastguard Worker
427*cfb92d14SAndroid Build Coastguard Worker    def reboot(self, **kwargs):
428*cfb92d14SAndroid Build Coastguard Worker        input('Reset all devices and press enter to continue..')
429*cfb92d14SAndroid Build Coastguard Worker
430*cfb92d14SAndroid Build Coastguard Worker    def close(self):
431*cfb92d14SAndroid Build Coastguard Worker        pass
432