Skip to content

Commit 7f44592

Browse files
authored
Add 'config' CLI utility; rename 'sonic_cli' -> 'show' (sonic-net#46)
- Add new 'config' command line utility which currently has the following functionality: - Can shut down/start up BGP session with neighbor by neighbor's IP or hostname - Example commands: - config bgp shutdown neighbor ARISTA02T1 - config bgp startup neighbor 192.168.1.1 - Renamed 'sonic_cli' directory to 'show' - Clean up temp files after use in 'show platform' and 'show version'
1 parent e188b5e commit 7f44592

File tree

7 files changed

+170
-3
lines changed

7 files changed

+170
-3
lines changed
File renamed without changes.

config/main.py

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/sbin/env python
2+
3+
import os
4+
import click
5+
import json
6+
import subprocess
7+
8+
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
9+
MINIGRAPH_PATH = '/etc/sonic/minigraph.xml'
10+
MINIGRAPH_BGP_ASN_KEY = 'minigraph_bgp_asn'
11+
MINIGRAPH_BGP_SESSIONS = 'minigraph_bgp'
12+
13+
#
14+
# Helper functions
15+
#
16+
17+
# Returns BGP ASN as a string
18+
def _get_bgp_asn_from_minigraph():
19+
# Get BGP ASN from minigraph
20+
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-m', MINIGRAPH_PATH, '--var-json', MINIGRAPH_BGP_ASN_KEY],
21+
stdout=subprocess.PIPE,
22+
shell=False,
23+
stderr=subprocess.STDOUT)
24+
stdout = proc.communicate()[0]
25+
proc.wait()
26+
return json.loads(stdout.rstrip('\n'))
27+
28+
# Returns True if a neighbor has the IP address <ipaddress>, False if not
29+
def _is_neighbor_ipaddress(ipaddress):
30+
# Get BGP ASN from minigraph
31+
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-m', MINIGRAPH_PATH, '--var-json', MINIGRAPH_BGP_SESSIONS],
32+
stdout=subprocess.PIPE,
33+
shell=False,
34+
stderr=subprocess.STDOUT)
35+
stdout = proc.communicate()[0]
36+
proc.wait()
37+
bgp_session_list = json.loads(stdout.rstrip('\n'))
38+
39+
for session in bgp_session_list:
40+
if session['addr'] == ipaddress:
41+
return True
42+
43+
return False
44+
45+
# Returns string containing IP address of neighbor with hostname <hostname> or None if <hostname> not a neighbor
46+
def _get_neighbor_ipaddress_by_hostname(hostname):
47+
# Get BGP ASN from minigraph
48+
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-m', MINIGRAPH_PATH, '--var-json', MINIGRAPH_BGP_SESSIONS],
49+
stdout=subprocess.PIPE,
50+
shell=False,
51+
stderr=subprocess.STDOUT)
52+
stdout = proc.communicate()[0]
53+
proc.wait()
54+
bgp_session_list = json.loads(stdout.rstrip('\n'))
55+
56+
for session in bgp_session_list:
57+
if session['name'] == hostname:
58+
return session['addr'];
59+
60+
return None
61+
62+
63+
# Run bash command and print output to stdout
64+
def run_command(command, pager=False):
65+
click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green'))
66+
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
67+
if pager is True:
68+
click.echo_via_pager(p.stdout.read())
69+
else:
70+
click.echo(p.stdout.read())
71+
p.wait()
72+
if p.returncode != 0:
73+
sys.exit(p.returncode)
74+
75+
76+
# This is our main entrypoint - the main 'config' command
77+
@click.group()
78+
def cli():
79+
"""SONiC command line - 'config' command"""
80+
pass
81+
82+
83+
#
84+
# 'bgp' group
85+
#
86+
87+
@cli.group()
88+
def bgp():
89+
"""BGP-related tasks"""
90+
pass
91+
92+
#
93+
# 'shutdown' subgroup
94+
#
95+
96+
@bgp.group()
97+
def shutdown():
98+
"""Shut down BGP session(s)"""
99+
pass
100+
101+
102+
# 'neighbor' subcommand
103+
@shutdown.command()
104+
@click.argument('ipaddr_or_hostname', required=True)
105+
def neighbor(ipaddr_or_hostname):
106+
"""Shut down BGP session by neighbor IP address or hostname"""
107+
bgp_asn = _get_bgp_asn_from_minigraph()
108+
109+
if _is_neighbor_ipaddress(ipaddr_or_hostname):
110+
ipaddress = ipaddr_or_hostname
111+
else:
112+
# If <ipaddr_or_hostname> is not the IP address of a neighbor, check to see if it's a hostname
113+
ipaddress = _get_neighbor_ipaddress_by_hostname(ipaddr_or_hostname)
114+
115+
if ipaddress == None:
116+
print "Error: could not locate neighbor '{}'".format(ipaddr_or_hostname)
117+
raise click.Abort
118+
119+
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} shutdown'".format(bgp_asn, ipaddress)
120+
run_command(command)
121+
122+
123+
@bgp.group()
124+
def startup():
125+
"""Start up BGP session(s)"""
126+
pass
127+
128+
129+
# 'neighbor' subcommand
130+
@startup.command()
131+
@click.argument('ipaddr_or_hostname', required=True)
132+
def neighbor(ipaddr_or_hostname):
133+
"""Start up BGP session by neighbor IP address or hostname"""
134+
bgp_asn = _get_bgp_asn_from_minigraph()
135+
136+
if _is_neighbor_ipaddress(ipaddr_or_hostname):
137+
ipaddress = ipaddr_or_hostname
138+
else:
139+
# If <ipaddr_or_hostname> is not the IP address of a neighbor, check to see if it's a hostname
140+
ipaddress = _get_neighbor_ipaddress_by_hostname(ipaddr_or_hostname)
141+
142+
if ipaddress == None:
143+
print "Error: could not locate neighbor '{}'".format(ipaddr_or_hostname)
144+
raise click.Abort
145+
146+
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {} shutdown'".format(bgp_asn, ipaddress)
147+
run_command(command)
148+
149+
150+
if __name__ == '__main__':
151+
cli()
152+

data/etc/bash_completion.d/config

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
_config_completion() {
2+
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
3+
COMP_CWORD=$COMP_CWORD \
4+
_CONFIG_COMPLETE=complete $1 ) )
5+
return 0
6+
}
7+
8+
complete -F _config_completion -o default config;

setup.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
url='https://github.com/Azure/sonic-utilities',
1111
maintainer='Joe LeVeque',
1212
maintainer_email='[email protected]',
13-
packages=['sonic_cli', 'sonic_eeprom', 'sonic_sfp', "sonic_installer"],
13+
packages=['config', 'show', 'sonic_eeprom', 'sonic_sfp', "sonic_installer"],
1414
package_data={
15-
'sonic_cli': ['aliases.ini']
15+
'show': ['aliases.ini']
1616
},
1717
scripts=[
1818
'scripts/aclshow',
@@ -27,12 +27,14 @@
2727
'scripts/teamshow',
2828
],
2929
data_files=[
30+
('/etc/bash_completion.d', ['data/etc/bash_completion.d/config']),
3031
('/etc/bash_completion.d', ['data/etc/bash_completion.d/show']),
3132
('/etc/bash_completion.d', ['data/etc/bash_completion.d/sonic_installer']),
3233
],
3334
entry_points={
3435
'console_scripts': [
35-
'show = sonic_cli.main:cli',
36+
'config = config.main:cli',
37+
'show = show.main:cli',
3638
'sonic_installer = sonic_installer.main:cli'
3739
]
3840
},

show/__init__.py

Whitespace-only changes.
File renamed without changes.

sonic_cli/main.py renamed to show/main.py

+5
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ def summary():
252252
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
253253
click.echo(p.stdout.read())
254254

255+
# Clean up
256+
os.remove(PLATFORM_TEMPLATE_FILE)
257+
255258
# 'syseeprom' subcommand ####
256259
@platform.command()
257260
def syseeprom():
@@ -316,6 +319,8 @@ def version():
316319
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
317320
click.echo(p.stdout.read())
318321

322+
# Clean up
323+
os.remove(VERSION_TEMPLATE_FILE)
319324

320325
#
321326
# 'environment' command ###

0 commit comments

Comments
 (0)