-
Notifications
You must be signed in to change notification settings - Fork 715
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[devutils] add utilities to handle devices (#2645)
Summary: Add utilities for device related oeprations. Approach What is the motivation for this PR? Finding DUT information for access is a chore. Checking device status is not easy especially when comes to multiple devices. How did you do it? list hosts defined in an inventory. ping hosts defined in an inventory. ssh to host(s) define din an inventory. (best executed with limited to one host) console connect to host(s). (not implemetned, for future expansion) Signed-off-by: Ying Xie [email protected] How did you verify/test it? yinxi@str-serv-acs-14:~/src/sonic-mgmt/ansible$ ./devutils -h usage: devutils [-h] [-6] [-a {list,ping,ssh,console}] [-c CATEGORY] [-i INVENTORY] [-l LIMIT] [-u USER] Device utilities optional arguments: -h, --help show this help message and exit -6, --ipv6 Include IPv6 -a {list,ping,ssh,console}, --action {list,ping,ssh,console} Action towards host(s): list, ping, ssh, console, default list -c CATEGORY, --category CATEGORY Categories: all, sonic, ptf, pdu, default all -i INVENTORY, --inventory INVENTORY Categories: lab, etc, default lab -l LIMIT, --limit LIMIT Host: limit to a single dut host name, default all -u USER, --user USER User: user account to login to host with, default admin
- Loading branch information
Showing
2 changed files
with
125 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#!/usr/bin/env python | ||
|
||
import argparse | ||
import os | ||
import subprocess | ||
from inv_helpers import get_host_list | ||
|
||
|
||
def run_cmd(cmd): | ||
''' | ||
@summary: Utility that runs a command in a subprocess | ||
@param cmd: Command to be run | ||
@return: stdout of the command run | ||
@return: stderr of the command run | ||
''' | ||
out = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) | ||
stdout, stderr = out.communicate() | ||
return out.returncode, stdout, stderr | ||
|
||
|
||
def action_list(kind, host, details, parameters): | ||
print('type {} host {} details {}'.format(kind, host, details)) | ||
|
||
|
||
def action_ping(kind, host, details, parameters): | ||
if not details or type(details) != dict: | ||
return | ||
|
||
if 'ansible_host' in details: | ||
addr = details['ansible_host'] | ||
rc, _, _ = run_cmd('ping -q -c 1 -w 1 {}'.format(addr)) | ||
if rc != 0: | ||
print('host {} (type {}) is unreachable at address {}'.format(host, kind, addr)) | ||
if parameters['ipv6'] and 'ansible_hostv6' in details: | ||
addr = details['ansible_hostv6'] | ||
rc, _, _ = run_cmd('ping -6 -q -c 1 -w 1 {}'.format(addr)) | ||
if rc != 0: | ||
print('host {} (type {}) is unreachable at address {}'.format(host, kind, addr)) | ||
|
||
|
||
def action_ssh(kind, host, details, parameters): | ||
if not details or type(details) != dict: | ||
return | ||
|
||
if 'ansible_host' in details: | ||
addr = details['ansible_host'] | ||
os.system('ssh {}@{}'.format(parameters['user'], addr)) | ||
|
||
|
||
def action_console(kind, host, details, parameters): | ||
print('Action console is not implemented') | ||
|
||
|
||
def hosts_walker(parameters): | ||
hosts = parameters['hosts'] | ||
limit = parameters['limit'] | ||
for key, val in hosts.items(): | ||
for host, details in val.items(): | ||
if limit == 'all' or limit == host: | ||
parameters['action'](key, host, details, parameters) | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser(description='Device utilities') | ||
parser.add_argument('-6', '--ipv6', help='Include IPv6', action='store_true', | ||
required=False, default=False) | ||
parser.add_argument('-a', '--action', | ||
help='Action towards host(s): list, ping, ssh, console, default list', | ||
type=str, required=False, default='list', | ||
choices=['list', 'ping', 'ssh', 'console']) | ||
parser.add_argument('-c', '--category', help='Categories: all, sonic, ptf, pdu, default all', | ||
type=str, required=False, default='all') | ||
parser.add_argument('-i', '--inventory', help='Categories: lab, etc, default lab', | ||
type=str, required=False, default='lab') | ||
parser.add_argument('-l', '--limit', help='Host: limit to a single dut host name, default all', | ||
type=str, required=False, default='all') | ||
parser.add_argument('-u', '--user', help='User: user account to login to host with, default admin', | ||
type=str, required=False, default='admin') | ||
|
||
args = parser.parse_args() | ||
|
||
hosts = get_host_list(args.inventory, args.category) | ||
actions = { 'list' : action_list, | ||
'ping' : action_ping, | ||
'ssh' : action_ssh, | ||
'console' : action_console, | ||
} | ||
parameters = { 'hosts' : hosts, | ||
'limit' : args.limit, | ||
'action' : actions[args.action], | ||
'user' : args.user, | ||
'ipv6' : args.ipv6, | ||
} | ||
hosts_walker(parameters) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import yaml | ||
|
||
|
||
def get_all_hosts(inventory): | ||
hosts = {} | ||
for key, val in inventory.items(): | ||
vtype = type(val) | ||
if vtype == dict: | ||
if 'hosts' in val: | ||
hosts.update({ key : val['hosts'] }) | ||
else: | ||
hosts.update(get_all_hosts(val)) | ||
return hosts | ||
|
||
|
||
def get_host_list(inventory, category): | ||
with open(inventory, 'r') as file: | ||
inv = yaml.safe_load(file) | ||
|
||
all_hosts = get_all_hosts(inv) | ||
hosts = {} | ||
for key, val in all_hosts.items(): | ||
if category == 'all' or category in key: | ||
hosts.update({key : val}) | ||
|
||
return hosts | ||
|