Skip to content

Commit e73b8c0

Browse files
authored
Merge pull request #68 from QualiSystems/dev
gen1 support
2 parents b4993a4 + 09055c3 commit e73b8c0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1821
-583
lines changed

.coveragerc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[report]
2+
omit =
3+
*/mibs/*
4+
*__init__*

.travis.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
language: python
22
python:
3-
- '2.7'
4-
5-
before_install:
6-
- pip install coveralls
7-
- pip install -r requirements.txt
8-
- pip install -r test_requirements.txt
3+
- "2.7"
94

105
install:
11-
- python setup.py install
6+
- 'if [ ${TRAVIS_BRANCH} \!= "master" ] && [ -f dev_requirements.txt ]; then
7+
pip install --extra-index-url https://testpypi.python.org/pypi -r dev_requirements.txt;
8+
python setup.py develop --no-deps;
9+
else
10+
python setup.py install;
11+
fi'
12+
- pip install -r test_requirements.txt
13+
- pip install coveralls
1214

1315
script:
14-
- nosetests
15-
- python setup.py develop
16-
- python setup.py sdist --format zip
16+
- nosetests --with-coverage --cover-package=cloudshell.networking.cisco tests
1717

1818
after_success:
1919
- coveralls

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,12 @@
1-
# CloudShell shell core package powered by QualiSystems
2-
![alt tag](https://travis-ci.org/QualiSystems/cloudshell-networking-cisco.svg)
1+
# cloudshell-networking-cisco
2+
[![Build status](https://travis-ci.org/QualiSystems/cloudshell-networking-cisco.svg?branch=dev)](https://travis-ci.org/QualiSystems/cloudshell-networking-cisco)
3+
[![Coverage Status](https://coveralls.io/repos/github/QualiSystems/cloudshell-networking-cisco/badge.svg)](https://coveralls.io/github/QualiSystems/cloudshell-networking-cisco)
4+
[![PyPI version](https://badge.fury.io/py/cloudshell-networking-cisco.svg)](https://badge.fury.io/py/cloudshell-networking-cisco)
5+
[![Dependency Status](https://dependencyci.com/github/QualiSystems/cloudshell-networking-cisco/badge)](https://dependencyci.com/github/QualiSystems/cloudshell-networking-cisco)
6+
[![Stories in Ready](https://badge.waffle.io/QualiSystems/cloudshell-networking-cisco.svg?label=ready&title=Ready)](http://waffle.io/QualiSystems/cloudshell-networking-cisco)
7+
8+
<p align="center">
9+
<img src="https://github.com/QualiSystems/devguide_source/raw/master/logo.png"></img>
10+
</p>
11+
12+
# CloudShell Networking Cisco

cloudshell/networking/cisco/autoload/cisco_generic_snmp_autoload.py

Lines changed: 58 additions & 443 deletions
Large diffs are not rendered by default.

cloudshell/networking/cisco/autoload/snmp_entity_table.py

Lines changed: 356 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
class SnmpIfEntity(object):
2+
IF_MIB = "IF-MIB"
3+
IF_TYPE = "ifType"
4+
IF_MTU = "ifMtu"
5+
IF_SPEED = "ifHighSpeed"
6+
IF_NAME = "ifDescr"
7+
IF_MAC = "ifPhysAddress"
8+
IF_ALIAS = "ifAlias"
9+
10+
def __init__(self, snmp_handler, logger, index, port_attributes_snmp_tables):
11+
self.if_index = int(index)
12+
self._snmp = snmp_handler
13+
self._port_attributes_snmp_tables = port_attributes_snmp_tables
14+
self._logger = logger
15+
self._if_type = "other"
16+
self._if_speed = 0
17+
self._if_mtu = 0
18+
self._if_mac = ""
19+
self._ipv4 = ""
20+
self._ipv6 = ""
21+
self._if_alias = ""
22+
self._if_name = None
23+
self._adjacent = ""
24+
self._duplex = ""
25+
self._auto_neg = ""
26+
self._port_channel_associated_port = ""
27+
28+
@property
29+
def if_name(self):
30+
if not self._if_name:
31+
self._if_name = self._snmp.get_property(self.IF_MIB, self.IF_NAME, self.if_index)
32+
return self._if_name
33+
34+
@property
35+
def if_type(self):
36+
if not self._if_type:
37+
self._if_type = self._snmp.get_property(self.IF_MIB, self.IF_TYPE, self.if_index).replace('/', '').replace(
38+
"'", '')
39+
return self._if_type
40+
41+
@property
42+
def if_port_description(self):
43+
if not self._if_alias:
44+
self._if_alias = self._snmp.get_property(self.IF_MIB, self.IF_ALIAS, self.if_index)
45+
return self._if_alias
46+
47+
@property
48+
def if_speed(self):
49+
if not self._if_speed:
50+
self._if_speed = self._snmp.get_property(self.IF_MIB, self.IF_SPEED, self.if_index)
51+
return self._if_speed
52+
53+
@property
54+
def if_mtu(self):
55+
if not self._if_mtu:
56+
self._if_mtu = self._snmp.get_property(self.IF_MIB, self.IF_MTU, self.if_index)
57+
return self._if_mtu
58+
59+
@property
60+
def if_mac(self):
61+
if not self._if_mac:
62+
self._if_mac = self._snmp.get_property(self.IF_MIB, self.IF_MAC, self.if_index)
63+
return self._if_mac
64+
65+
@property
66+
def ipv4_address(self):
67+
if not self._ipv4:
68+
self._ipv4 = self._get_ipv4()
69+
return self._ipv4
70+
71+
@property
72+
def ipv6_address(self):
73+
if not self._ipv6:
74+
self._ipv6 = self._get_ipv6()
75+
return self._ipv6
76+
77+
@property
78+
def adjacent(self):
79+
if not self._adjacent:
80+
self._adjacent = self._get_adjacent()
81+
return self._adjacent
82+
83+
@property
84+
def duplex(self):
85+
if not self._duplex:
86+
self._duplex = self._get_duplex() or "Half"
87+
return self._duplex
88+
89+
@property
90+
def auto_negotiation(self):
91+
if not self._auto_neg:
92+
self._auto_neg = self._get_auto_neg() or "False"
93+
return self._auto_neg
94+
95+
@property
96+
def associated_port_list(self):
97+
if not self._port_channel_associated_port:
98+
self._port_channel_associated_port = self._get_associated_ports()
99+
return self._port_channel_associated_port
100+
101+
def _get_associated_ports(self):
102+
"""Get all ports associated with provided port channel
103+
:return:
104+
"""
105+
106+
result = []
107+
for key, value in self._port_attributes_snmp_tables.port_channel_ports.iteritems():
108+
if str(self.if_index) in value['dot3adAggPortAttachedAggID']:
109+
result.append(key)
110+
return result
111+
112+
def _get_adjacent(self):
113+
"""Get connected device interface and device name to the specified port id, using cdp or lldp protocols
114+
115+
:param interface_id: port id
116+
:return: device's name and port connected to port id
117+
:rtype string
118+
"""
119+
120+
result_template = '{remote_host} through {remote_port}'
121+
result = ''
122+
for key, value in self._port_attributes_snmp_tables.cdp_table.iteritems():
123+
if str(key).startswith(str(self.if_index)):
124+
port = self._snmp.get_property('CISCO-CDP-MIB', 'cdpCacheDevicePort', key)
125+
result = result_template.format(remote_host=value.get('cdpCacheDeviceId', ''), remote_port=port)
126+
break
127+
if result == '' and self._port_attributes_snmp_tables.lldp_local_table:
128+
interface_name = self.if_name.lower()
129+
if interface_name:
130+
key = self._port_attributes_snmp_tables.lldp_local_table.get(interface_name, None)
131+
if key:
132+
for port_id, rem_table in self._port_attributes_snmp_tables.lldp_remote_table.iteritems():
133+
if ".{0}.".format(key) in port_id:
134+
remoute_sys_name = rem_table.get('lldpRemSysName', "")
135+
remoute_port_name = self._snmp.get_property('LLDP-MIB', 'lldpRemPortDesc', port_id)
136+
if remoute_port_name and remoute_sys_name:
137+
result = result_template.format(remote_host=remoute_sys_name,
138+
remote_port=remoute_port_name)
139+
break
140+
return result
141+
142+
def _get_auto_neg(self):
143+
"""Get port auto negotiation status
144+
145+
:return return "True"
146+
"""
147+
148+
try:
149+
auto_negotiation = self._snmp.get(('MAU-MIB', 'ifMauAutoNegAdminStatus', self.if_index, 1)).values()[0]
150+
if 'enabled' in auto_negotiation.lower():
151+
return 'True'
152+
except Exception as e:
153+
self._logger.error('Failed to load auto negotiation property for interface {0}'.format(e.message))
154+
155+
def _get_duplex(self):
156+
"""Get current duplex state
157+
158+
:return str "Full"
159+
"""
160+
161+
for key, value in self._port_attributes_snmp_tables.duplex_table.iteritems():
162+
if 'dot3StatsIndex' in value.keys() and value['dot3StatsIndex'] == str(self.if_index):
163+
interface_duplex = self._snmp.get_property('EtherLike-MIB', 'dot3StatsDuplexStatus', key)
164+
if 'fullDuplex' in interface_duplex:
165+
return 'Full'
166+
167+
def _get_ipv4(self):
168+
"""Get IPv4 address details for provided port
169+
170+
:return str IPv4 Address
171+
"""
172+
173+
if self._port_attributes_snmp_tables.ip_v4_table:
174+
for key, value in self._port_attributes_snmp_tables.ip_v4_table.iteritems():
175+
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == self.if_index:
176+
return key
177+
178+
def _get_ipv6(self):
179+
"""Get IPv6 address details for provided port
180+
181+
:return str IPv6 Address
182+
"""
183+
184+
if self._port_attributes_snmp_tables.ip_v6_table:
185+
for key, value in self._port_attributes_snmp_tables.ip_v6_table.iteritems():
186+
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == self.if_index:
187+
return key
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import re
2+
from cloudshell.networking.cisco.autoload.snmp_if_entity import SnmpIfEntity
3+
from cloudshell.networking.cisco.autoload.snmp_port_attr_tables import SnmpPortAttrTables
4+
5+
6+
class SnmpIfTable(object):
7+
def __init__(self, snmp_handler, logger):
8+
self._snmp = snmp_handler
9+
self._logger = logger
10+
self._load_snmp_tables()
11+
self._if_entities_dict = dict()
12+
self.port_attributes_snmp_tables = SnmpPortAttrTables(snmp_handler, logger)
13+
14+
@property
15+
def if_entities(self):
16+
if not self._if_entities_dict:
17+
self._get_if_entities()
18+
return self._if_entities_dict.values()
19+
20+
def get_if_entity_by_index(self, if_index):
21+
if not self._if_entities_dict:
22+
self._get_if_entities()
23+
return self._if_entities_dict.get(if_index)
24+
25+
def _get_if_entities(self):
26+
for index in self._if_table.keys():
27+
self._if_entities_dict[index] = SnmpIfEntity(snmp_handler=self._snmp, logger=self._logger,
28+
index=index,
29+
port_attributes_snmp_tables=self.port_attributes_snmp_tables)
30+
31+
def _load_snmp_tables(self):
32+
""" Load all cisco required snmp tables
33+
34+
:return:
35+
"""
36+
37+
self._logger.info('Start loading MIB tables:')
38+
self._if_table = self._snmp.get_table('IF-MIB', "ifIndex")
39+
self._logger.info('ifIndex table loaded')
40+
41+
self._logger.info('MIB Tables loaded successfully')
42+
43+
def get_if_index_from_port_name(self, port_name, port_filter_list):
44+
port_if_re = re.findall('\d+', port_name)
45+
if port_if_re:
46+
if_table_re = "/".join(port_if_re)
47+
for interface in self.if_entities:
48+
if not re.search("ethernet|other", interface.if_type, re.IGNORECASE):
49+
continue
50+
if re.search(r"^(?!.*null|.*{0})\D*{1}(/\D+|$)".format(port_filter_list, if_table_re),
51+
interface.if_name, re.IGNORECASE):
52+
return interface
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
class SnmpPortAttrTables(object):
2+
def __init__(self, snmp_handler, logger):
3+
self._snmp = snmp_handler
4+
self._logger = logger
5+
self._lldp_remote_table = dict()
6+
self._lldp_local_table = dict()
7+
self._cdp_table = dict()
8+
self._duplex_table = dict()
9+
self._ip_v4_table = dict()
10+
self._ip_v6_table = dict()
11+
self._port_channel_ports = dict()
12+
13+
@property
14+
def lldp_remote_table(self):
15+
if not self._lldp_remote_table:
16+
self._lldp_remote_table = self._snmp.get_table('LLDP-MIB', 'lldpRemSysName')
17+
self._logger.info('lldpRemSysName table loaded')
18+
return self._lldp_remote_table
19+
20+
@property
21+
def lldp_local_table(self):
22+
if not self._lldp_remote_table:
23+
lldp_local_table = self._snmp.get_table('LLDP-MIB', 'lldpLocPortDesc')
24+
if lldp_local_table:
25+
self._lldp_local_table = dict([(v['lldpLocPortDesc'].lower(), k) for k, v in lldp_local_table.iteritems()])
26+
self._logger.info('lldpLocPortDesc table loaded')
27+
return self._lldp_remote_table
28+
29+
@property
30+
def cdp_table(self):
31+
if not self._cdp_table:
32+
self._cdp_table = self._snmp.get_table('CISCO-CDP-MIB', 'cdpCacheDeviceId')
33+
self._logger.info('cdpCacheDeviceId table loaded')
34+
return self._cdp_table
35+
36+
@property
37+
def duplex_table(self):
38+
if not self._duplex_table:
39+
self._duplex_table = self._snmp.get_table('EtherLike-MIB', 'dot3StatsIndex')
40+
self._logger.info('dot3StatsIndex table loaded')
41+
return self._duplex_table
42+
43+
@property
44+
def ip_v4_table(self):
45+
if not self._ip_v4_table:
46+
self._ip_v4_table = self._snmp.get_table('IP-MIB', 'ipAddrTable')
47+
self._logger.info('ipAddrTable table loaded')
48+
return self._ip_v4_table
49+
50+
@property
51+
def ip_v6_table(self):
52+
if not self._ip_v6_table:
53+
self._ip_v6_table = self._snmp.get_table('IPV6-MIB', 'ipv6AddrEntry')
54+
self._logger.info('ipv6AddrEntry table loaded')
55+
return self._ip_v6_table
56+
57+
@property
58+
def port_channel_ports(self):
59+
if not self._port_channel_ports:
60+
self._port_channel_ports = self._snmp.get_table('IEEE8023-LAG-MIB', 'dot3adAggPortAttachedAggID')
61+
self._logger.info('dot3adAggPortAttachedAggID table loaded')
62+
return self._port_channel_ports

cloudshell/networking/cisco/cli/cisco_cli_handler.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,17 @@ def _enter_config_mode(self, session, logger):
9696
output = session.hardware_expect(ConfigCommandMode.ENTER_COMMAND,
9797
'{0}|{1}'.format(ConfigCommandMode.PROMPT, EnableCommandMode.PROMPT), logger)
9898

99-
if not re.search(ConfigCommandMode.PROMPT, output):
100-
retries = 0
101-
while not re.search(r"[Cc]onfiguration [Ll]ocked", output, re.IGNORECASE) or retries == max_retries:
102-
time.sleep(5)
103-
output = session.hardware_expect(ConfigCommandMode.ENTER_COMMAND,
104-
'{0}|{1}'.format(ConfigCommandMode.PROMPT, EnableCommandMode.PROMPT),
105-
logger)
106-
if not re.search(ConfigCommandMode.PROMPT, output):
107-
raise Exception('_enter_config_mode', error_message)
99+
config_mode_match = re.search(ConfigCommandMode.PROMPT, output)
100+
retries = 0
101+
while (not config_mode_match) and retries <= max_retries:
102+
time.sleep(5)
103+
output = session.hardware_expect(ConfigCommandMode.ENTER_COMMAND,
104+
'{0}|{1}'.format(ConfigCommandMode.PROMPT, EnableCommandMode.PROMPT),
105+
logger)
106+
config_mode_match = re.search(ConfigCommandMode.PROMPT, output)
107+
retries += 1
108+
if not config_mode_match:
109+
raise Exception('_enter_config_mode', error_message)
108110

109111
def _enter_enable_mode(self, session, logger):
110112
"""

cloudshell/networking/cisco/command_actions/add_remove_vlan_actions.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ def verify_interface_configured(vlan_range, current_config):
3838
def create_vlan(self, vlan_range, action_map=None, error_map=None):
3939
"""Create vlan entity on the device
4040
41-
:param session: current session
42-
:param logger: logger
4341
:param vlan_range: range of vlans to be created
4442
:param action_map: actions will be taken during executing commands, i.e. handles yes/no prompts
4543
:param error_map: errors will be raised during executing commands, i.e. handles Invalid Commands errors

0 commit comments

Comments
 (0)