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
129 changes: 64 additions & 65 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.pdu_controller.snmp_pdu_controllers import get_pdu_controller
from tests.common.plugins.pdu_controller.pdu_manager import pdu_manager_factory

g_inv_mgr = None
g_task_runner = None
Expand Down Expand Up @@ -53,12 +53,12 @@ def get_pdu_info(pdu_host):
return g_pdu_dict[pdu_host]

hosts = retrieve_hosts('all', pdu_host)
pdus=[]
pdus = {}
g_pdu_dict[pdu_host] = pdus
for ph in pdu_host.split(','):
if ph in hosts:
pdu = hosts[ph]
pdus.append(pdu)
pdus[ph] = pdu

return pdus

Expand All @@ -79,7 +79,7 @@ def action_list(parameters):
data.append(dict(zip(header, (name, vars['ansible_host']))))
else:
for name, vars in hosts.items():
data.append((name, vars['ansible_host']))
data.append((name, vars['ansible_host'] if 'ansible_host' in vars else 'not_available'))
show_data_output(header, data, parameters['json'])


Expand All @@ -92,7 +92,8 @@ def action_ping(parameters):
g_task_runner.submit_task(name + '|' + vars['ansible_host'], run_cmd, cmd=cmd)
if parameters['json']:
for name, result in g_task_runner.task_results():
data.append(dict(zip(header, (name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))))
data.append(
dict(zip(header, (name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))))
else:
for name, result in g_task_runner.task_results():
data.append((name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))
Expand All @@ -104,7 +105,8 @@ def action_ping(parameters):
g_task_runner.submit_task(name + '|' + vars['ansible_hostv6'], run_cmd, cmd=cmd)
if parameters['json']:
for name, result in g_task_runner.task_results():
data.append(dict(zip(header, (name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))))
data.append(
dict(zip(header, (name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))))
else:
for name, result in g_task_runner.task_results():
data.append((name.split('|')[0], name.split('|')[1], 'Success' if result['result'][0] == 0 else "Fail"))
Expand All @@ -116,7 +118,8 @@ def action_ssh(parameters):
hosts = parameters['hosts']
for _, vars in hosts.items():
client = SSHClient()
client.connect(hostname=vars['ansible_host'], username=vars['creds']['username'], passwords=vars['creds']['password'])
client.connect(hostname=vars['ansible_host'], username=vars[
'creds']['username'], passwords=vars['creds']['password'])
client.posix_shell()


Expand All @@ -125,17 +128,17 @@ def action_console(parameters):
# Todo: Retrieve console vars from conn_graph_fact
for _, vars in hosts.items():
console_host = ConsoleHost(console_type=vars['console_type'],
console_host=vars['console_host'],
console_port=vars['console_port'],
sonic_username=vars['creds']['username'],
sonic_password=vars['creds']['password'],
console_username=vars['creds']['console_user'][vars['console_type']],
console_password=vars['creds']['console_password'][vars['console_type']])
console_host=vars['console_host'],
console_port=vars['console_port'],
sonic_username=vars['creds']['username'],
sonic_password=vars['creds']['password'],
console_username=vars['creds']['console_user'][vars['console_type']],
console_password=vars['creds']['console_password'][vars['console_type']])
console_host.posix_shell()


def pdu_action_on_dut(host, attrs, action):
ret = { 'Host' : host, 'PDU status' : [], 'Summary' : [], 'Action' : action }
ret = {'Host': host, 'PDU status': [], 'Summary': [], 'Action': action}
pdu_name = attrs['pdu_host'] if 'pdu_host' in attrs else None
if not pdu_name:
ret['Summary'].append('DUT has no PDU configuration')
Expand All @@ -146,43 +149,35 @@ def pdu_action_on_dut(host, attrs, action):
ret['Summary'].append('PDU not found in inventory')
return ret

for pdu_info in pdu_list:
pdu_host = pdu_info['ansible_host'] if pdu_info and 'ansible_host' in pdu_info else None
p_name = pdu_info['inventory_hostname'] if pdu_info and 'inventory_hostname' in pdu_info else None
if not pdu_host or not p_name:
ret['Summary'].append('No PDU IP or name')
continue

controller = get_pdu_controller(pdu_host, host, pdu_info)

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

status = controller.get_outlet_status()
if action == 'off':
for outlet in status:
controller.turn_off_outlet(outlet['outlet_id'])
status = controller.get_outlet_status()
elif action == 'on':
for outlet in status:
controller.turn_on_outlet(outlet['outlet_id'])
status = controller.get_outlet_status()
elif action != 'status':
ret['Summary'].append('Unsupported action {}.'.format(action))
continue

for outlet in status:
outlet.update({ 'PDU' : p_name, 'PDU_IP' : pdu_host })
ret['PDU status'].append(outlet)
# TODO: fake graph data to force building pdu manager from inventory until
# we add code to read and construct the conn_graph_facts
fake_graph = {'device_pdu_info': {}, 'device_pdu_links': {}}

pduman = pdu_manager_factory(host, pdu_list, fake_graph, pdu_list.values()[0])

if not pduman:
ret['Summary'].append('Failed to communicate with PDU controller {}'.format(pdu_name))
return ret

if action == 'off':
pduman.turn_off_outlet()
elif action == 'on':
pduman.turn_on_outlet()
elif action != 'status':
ret['Summary'].append('Unsupported action {}.'.format(action))
return ret

status = pduman.get_outlet_status()
for outlet in status:
ret['PDU status'].append(outlet)

return ret


def action_pdu(parameters, action):
hosts = parameters['hosts']
data = []
header = [ 'Host', 'Action', 'PDU status', 'Summary' ]
header = ['Host', 'Action', 'PDU status', 'Summary']
for host, attrs in hosts.items():
g_task_runner.submit_task(host, pdu_action_on_dut, host=host, attrs=attrs, action=action)

Expand All @@ -191,7 +186,7 @@ def action_pdu(parameters, action):
if parameters['json']:
data.append(status)
else:
data.append([ status[x] for x in header ])
data.append([status[x] for x in header])

return header, data

Expand Down Expand Up @@ -246,17 +241,20 @@ def parallel_run(parameters):
for name, result in g_task_runner.task_results():
print("task result for {} ===============>\n{}".format(name, str(result['result'][1])))


def ssh_run_command(hostname, username, passwords, cmd):
client = SSHClient()
client.connect(hostname=hostname, username=username, passwords=passwords)
return client.run_command(cmd)


def validate_args(args):
if args.action == 'run' and args.cmd == '':
print("command is missing for run action")
return False
return True


def main():
parser = argparse.ArgumentParser(description='Device utilities')
parser.add_argument('-6', '--ipv6', help='Include IPv6', action='store_true',
Expand All @@ -275,34 +273,35 @@ def main():
type=str, required=False)
parser.add_argument('-u', '--user', help='User: user account to login to host with, default admin',
type=str, required=False, default='admin')
parser.add_argument('-c', '--concurrency', help='Concurrency: the max concurrency for tasks that can run simultaneously, default 1',
parser.add_argument(
'-c', '--concurrency', help='Concurrency: the max concurrency for tasks that can run simultaneously, default 1',
type=int, required=False, default=1)
parser.add_argument('-j', '--json', help='json output', action='store_true',
required=False, default=False)

args = parser.parse_args()
if not validate_args(args):
return
build_global_vars(args.concurrency, args.inventory);
build_global_vars(args.concurrency, args.inventory)
hosts = retrieve_hosts(args.group, args.limit)
actions = { 'list' : action_list,
'ping' : action_ping,
'ssh' : action_ssh,
'console' : action_console,
'run' : ssh_run_command,
'pdu_status' : action_pdu_status,
'pdu_off' : action_pdu_off,
'pdu_on' : action_pdu_on,
'pdu_reboot' : action_pdu_reboot,
}
parameters = { 'hosts' : hosts,
'limit' : args.limit,
'action' : actions[args.action],
'user' : args.user,
'ipv6' : args.ipv6,
'cmd': args.cmd,
'json' : args.json,
}
actions = {'list': action_list,
'ping': action_ping,
'ssh': action_ssh,
'console': action_console,
'run': ssh_run_command,
'pdu_status': action_pdu_status,
'pdu_off': action_pdu_off,
'pdu_on': action_pdu_on,
'pdu_reboot': action_pdu_reboot,
}
parameters = {'hosts': hosts,
'limit': args.limit,
'action': actions[args.action],
'user': args.user,
'ipv6': args.ipv6,
'cmd': args.cmd,
'json': args.json,
}
action_dispatcher(parameters)


Expand Down
52 changes: 11 additions & 41 deletions tests/common/plugins/pdu_controller/__init__.py
Original file line number Diff line number Diff line change
@@ -1,63 +1,33 @@
import logging

import pytest
from pdu_manager import pdu_manager_factory


def pdu_controller_factory(controller_ip, controller_protocol, dut_hostname, pdu):
"""
@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 pdu controller object")
if controller_protocol == "snmp":
import snmp_pdu_controllers
return snmp_pdu_controllers.get_pdu_controller(controller_ip, dut_hostname, pdu)
logger = logging.getLogger(__name__)


@pytest.fixture(scope="module")
def pdu_controller(duthosts, rand_one_dut_hostname, pdu):
def pdu_controller(duthosts, rand_one_dut_hostname, conn_graph_facts, 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 pdu controller object implementing the BasePduController interface defined in
controller_base.py.
"""
duthost = duthosts[rand_one_dut_hostname]

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 pdu_controller" %
duthost.hostname)
yield None
return

controller_vars = inv_mgr.get_host(pdu_host).get_vars()

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 pdu_controller for %s" % duthost.hostname)
yield None
return

controller_protocol = controller_vars.get("protocol")
if not controller_protocol:
logging.info("No protocol is defined in inventory file for '%s'. Try to use default 'snmp'" % pdu_host)
controller_protocol = "snmp"
pdu_host_list = inv_mgr.get_host(duthost.hostname).get_vars().get("pdu_host")
pdu_hosts = {}
for ph in pdu_host_list.split(','):
var_list = inv_mgr.get_host(ph).get_vars()
pdu_hosts[ph] = var_list

controller = pdu_controller_factory(controller_ip, controller_protocol, duthost.hostname, pdu)
controller = pdu_manager_factory(duthost.hostname, pdu_hosts, conn_graph_facts, pdu)

yield controller

logging.info("pdu_controller fixture teardown, ensure that all PDU outlets are turned on after test")
logger.info("pdu_controller fixture teardown, ensure that all PDU outlets are turned on after test")
if controller:
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.turn_on_outlet()
controller.close()
Loading