Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions ansible/devutils
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ from devutil.task_runner import TaskRunner
import sys
sys.path.append("..")
from tests.common.connections import ConsoleHost
from tests.common.plugins.psu_controller.snmp_psu_controllers import get_psu_controller
from tests.common.plugins.pdu_controller.snmp_pdu_controllers import get_pdu_controller

g_inv_mgr = None
g_task_runner = None
Expand Down Expand Up @@ -156,21 +156,21 @@ def pdu_action_on_dut(host, attrs, action):
rec = { 'PDU' : p_name, 'PDU_IP' : pdu_host, 'status' : [] }
ret['PDU status'].append(rec)

controller = get_psu_controller(pdu_host, host, pdu_info)
controller = get_pdu_controller(pdu_host, host, pdu_info)

if not controller:
ret['Summary'].append('Failed to communicate with controller {}'.format(p_name))
continue

rec['status'] = controller.get_psu_status()
rec['status'] = controller.get_outlet_status()
if action == 'off':
for outlet in rec['status']:
controller.turn_off_psu(outlet['psu_id'])
rec['status'] = controller.get_psu_status()
controller.turn_off_outlet(outlet['outlet_id'])
rec['status'] = controller.get_outlet_status()
elif action == 'on':
for outlet in rec['status']:
controller.turn_on_psu(outlet['psu_id'])
rec['status'] = controller.get_psu_status()
controller.turn_on_outlet(outlet['outlet_id'])
rec['status'] = controller.get_outlet_status()
elif action != 'status':
ret['Summary'].append('Unsupported action {}.'.format(action))
continue
Expand Down
2 changes: 1 addition & 1 deletion docs/tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Plugins:
- [ptfadapter](/tests/common/ptfadapter/README.md)
- [DUT monitor](/tests/common/dut_monitor/README.md)
- [Log Analyzer](/tests/common/loganalyzer/README.md)
- [PSU Controller](/tests/common/psu_controller/README.md)
- [PSU Controller](/tests/common/pdu_controller/README.md)
- [Sanity Check](/tests/common/sanity_check/README.md)
- [Test Completeness](/tests/common/test_completeness/README.md)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# psu_controller fixture user guide
# pdu_controller fixture user guide

PSU controller is usually a PDU device which can supply power to PSUs of SONiC switch. The PDU devices usually provide management interface like SNMP, web GUI, telnet, SSH, etc.

This plugin defined a fixture named psu_controller. It returns a python object implements the interface of PsuControllerBase defined in controller_base.py.
This plugin defined a fixture named pdu_controller. It returns a python object implements the interface of PsuControllerBase defined in controller_base.py.

## Add PDU information in inventory file

To get a psu_controller object using the psu_controller fixture, PDU host information must be known.
To get a pdu_controller object using the pdu_controller fixture, PDU host information must be known.

PDU information of each DUT device need to be added to the inventory file. The minimum required information information of PDU host is:
* IP address of the PDU host
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,34 @@
import pytest


def psu_controller_factory(controller_ip, controller_protocol, dut_hostname, pdu):
def pdu_controller_factory(controller_ip, controller_protocol, dut_hostname, pdu):
"""
@summary: Factory function for creating PSU controller according to different management protocol.
@param controller_ip: IP address of the PSU controller host.
@param controller_protocol: Management protocol supported by the PSU controller host.
@param dut_hostname: Hostname of the DUT to be controlled by the PSU controller.
@summary: Factory function for creating PDU controller according to different management protocol.
@param controller_ip: IP address of the PDU controller host.
@param controller_protocol: Management protocol supported by the PDU controller host.
@param dut_hostname: Hostname of the DUT to be controlled by the PDU controller.
"""
logging.info("Creating psu controller object")
logging.info("Creating pdu controller object")
if controller_protocol == "snmp":
import snmp_psu_controllers
return snmp_psu_controllers.get_psu_controller(controller_ip, dut_hostname, pdu)
import snmp_pdu_controllers
return snmp_pdu_controllers.get_pdu_controller(controller_ip, dut_hostname, pdu)


@pytest.fixture(scope="module")
def psu_controller(duthosts, rand_one_dut_hostname, pdu):
def pdu_controller(duthosts, rand_one_dut_hostname, pdu):
"""
@summary: Fixture for controlling power supply to PSUs of DUT
@param duthost: Fixture duthost defined in sonic-mgmt/tests/conftest.py
@returns: Returns a psu controller object implementing the BasePsuController interface defined in
@returns: Returns a pdu controller object implementing the BasePduController interface defined in
controller_base.py.
"""
duthost = duthosts[rand_one_dut_hostname]

logging.info("Creating psu_controller fixture")
logging.info("Creating pdu_controller fixture")
inv_mgr = duthost.host.options["inventory_manager"]
pdu_host = inv_mgr.get_host(duthost.hostname).get_vars().get("pdu_host")
if not pdu_host:
logging.info("No 'pdu_host' is defined in inventory file for '%s'. Unable to create psu_controller" %
logging.info("No 'pdu_host' is defined in inventory file for '%s'. Unable to create pdu_controller" %
duthost.hostname)
yield None
return
Expand All @@ -40,7 +40,7 @@ def psu_controller(duthosts, rand_one_dut_hostname, pdu):
controller_ip = controller_vars.get("ansible_host")
if not controller_ip:
logging.info("No 'ansible_host' is defined in inventory file for '%s'" % pdu_host)
logging.info("Unable to create psu_controller for %s" % duthost.hostname)
logging.info("Unable to create pdu_controller for %s" % duthost.hostname)
yield None
return

Expand All @@ -49,15 +49,15 @@ def psu_controller(duthosts, rand_one_dut_hostname, pdu):
logging.info("No protocol is defined in inventory file for '%s'. Try to use default 'snmp'" % pdu_host)
controller_protocol = "snmp"

controller = psu_controller_factory(controller_ip, controller_protocol, duthost.hostname, pdu)
controller = pdu_controller_factory(controller_ip, controller_protocol, duthost.hostname, pdu)

yield controller

logging.info("psu_controller fixture teardown, ensure that all PSUs are turned on after test")
logging.info("pdu_controller fixture teardown, ensure that all PDU outlets are turned on after test")
if controller:
psu_status = controller.get_psu_status()
if psu_status:
for psu in psu_status:
if not psu["psu_on"]:
controller.turn_on_psu(psu["psu_id"])
outlet_status = controller.get_outlet_status()
if outlet_status:
for outlet in outlet_status:
if not outlet["outlet_on"]:
controller.turn_on_outlet(outlet["outlet_id"])
controller.close()
Original file line number Diff line number Diff line change
@@ -1,56 +1,54 @@
"""
Base class for controlling PSUs of DUT
Base class for controlling PDU(s) connected to DUT power supplies

This file defines the base class for controlling PSUs of DUT. The base class defined the basic interface of
PSU controllers.
This file defines the base class for controlling PDU outlets. The base class defined the basic interface of
PDU controllers.

The PSU controller for actually controlling PSUs must be a subclass of the PsuControllerBase class and must
The PDU controller for PDUs must be a subclass of the PduControllerBase class and must
implement the methods defined in the base class.
"""
import os
import sys
import subprocess


class PsuControllerBase():
class PduControllerBase():
"""
@summary: Base class for PSU controller
@summary: Base class for PDU controller

This base class defines the basic interface to be provided by PSU controller.
This base class defines the basic interface to be provided by PDU controller.

The PSU controller for actually controlling PSUs must be a subclass of the PsuControllerBase class and must
The PDU controller for PDUs must be a subclass of the PduControllerBase class and must
implement the methods defined in the base class.
"""
def __init__(self):
pass

def turn_on_psu(self, psu_id):
def turn_on_outlet(self, outlet):
"""
@summary: Turn on power for specified PSU.
@summary: Turn on power for specified PDU.

@param psu_id: PSU ID, it could be integer of string digit. For example: 0 or '1'
@param outlet: PDU ID, it could be integer of string digit. For example: 0 or '1'
@return: Returns True if operation is successful. Otherwise, returns False
"""
raise NotImplementedError

def turn_off_psu(self, psu_id):
def turn_off_outlet(self, outlet):
"""
@summary: Turn off power for specified PSU.
@summary: Turn off power for specified PDU.

@param psu_id: PSU ID, it could be integer of string digit. For example: 0 or '1'
@param outlet: PDU ID, it could be integer of string digit. For example: 0 or '1'
@return: Returns True if operation is successful. Otherwise, returns False
"""
raise NotImplementedError

def get_psu_status(self, psu_id=None):
def get_outlet_status(self, outlet=None):
"""
@summary: Get current power status of PSUs
@summary: Get current power status of PDU outlets

@param psu_id: Optional PSU ID, it could be integer or string digit. If no psu_id is specified, power status of
all PSUs should be returned
@param outlet: Optional outlet ID, it could be integer or string digit. If no outlet is specified, power status of
all PDU outlets should be returned
@return: Returns a list of dictionaries. For example:
[{"psu_id": 0, "psu_on": True}, {"psu_id": 1, "psu_on": True}]
If getting PSU status failed, an empty list should be returned.
[{"outlet_id": 0, "outlet_on": True}, {"outlet_id": 1, "outlet_on": True}]
If getting outlet(s) status failed, an empty list should be returned.
"""
raise NotImplementedError

Expand Down
Loading