Skip to content

Commit

Permalink
Merge pull request #2 from QualiSystems/dev
Browse files Browse the repository at this point in the history
Rewrite Enable\Disable SNMP actions. Added OS Version determination
  • Loading branch information
alexquali committed Jul 6, 2017
2 parents d64d6fb + 678affc commit 83ddeda
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 34 deletions.
Expand Up @@ -602,22 +602,25 @@ def _filter_entity_table(self, raw_entity_table):
self.exclusion_list.append(element)

def _get_ipv4_interface_address(self, port_index):
"""Get IP address details for provided port
"""Get IPv4 address details for provided port
:param port_index: port index in ifTable
:return interface_details: detected info for provided interface dict{'IPv4 Address': '', 'IPv6 Address': ''}
:return ipv4 address
"""

if self.ip_v4_table and len(self.ip_v4_table) > 1:
for key, value in self.ip_v4_table.iteritems():
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == port_index:
return key
for key, value in self.ip_v4_table.iteritems():
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == port_index:
return key

def _get_ipv6_interface_address(self, port_index):
if self.ip_v6_table and len(self.ip_v6_table) > 1:
for key, value in self.ip_v6_table.iteritems():
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == port_index:
return key
"""Get IPv6 address details for provided port
:param port_index: port index in ifTable
:return ipv6 address
"""
for key, value in self.ip_v6_table.iteritems():
if 'ipAdEntIfIndex' in value and int(value['ipAdEntIfIndex']) == port_index:
return key

def _get_port_duplex(self, port_index):
for key, value in self.duplex_table.iteritems():
Expand All @@ -641,15 +644,24 @@ def _get_device_details(self):
self.logger.info("Building Root")
vendor = "Cisco"
model = self._get_device_model()
os_version = ''

self.resource.contact_name = self.snmp_handler.get_property('SNMPv2-MIB', 'sysContact', '0')
self.resource.system_name = self.snmp_handler.get_property('SNMPv2-MIB', 'sysName', '0')
self.resource.location = self.snmp_handler.get_property('SNMPv2-MIB', 'sysLocation', '0')
self.resource.os_version = os_version
self.resource.os_version = self._get_device_os_version()
self.resource.vendor = vendor
self.resource.model = model

def _get_device_os_version(self):
""" Determine device OS version using SNMP """

system_description = self.snmp_handler.get_property('SNMPv2-MIB', 'sysDescr', '0')
result = re.search(r"[Vv]ersion (?P<version>\S+)", system_description)
if result:
return result.groupdict()["version"]
else:
return ""

def _get_adjacent(self, interface_id):
"""Get connected device interface and device name to the specified port id, using cdp or lldp protocols
Expand Down
17 changes: 12 additions & 5 deletions package/cloudshell/firewall/cisco/asa/cli/cisco_asa_cli_handler.py
Expand Up @@ -5,11 +5,11 @@
import time

from cloudshell.cli.command_mode_helper import CommandModeHelper
from cloudshell.cli.session.ssh_session import SSHSession
from cloudshell.cli.session.telnet_session import TelnetSession
from cloudshell.devices.cli_handler_impl import CliHandlerImpl
from cloudshell.firewall.cisco.asa.cli.cisco_asa_command_modes import EnableCommandMode, DefaultCommandMode,\
ConfigCommandMode
from cloudshell.firewall.cisco.asa.sessions.asa_ssh_session import ASASSHSession
from cloudshell.firewall.cisco.asa.sessions.asa_telnet_session import ASATelnetSession
from cloudshell.firewall.cisco.asa.sessions.console_ssh_session import ConsoleSSHSession
from cloudshell.firewall.cisco.asa.sessions.console_telnet_session import ConsoleTelnetSession

Expand Down Expand Up @@ -55,10 +55,16 @@ def _console_telnet_session(self):
start_with_new_line=True)
]

def _ssh_session(self):
return ASASSHSession(self.resource_address, self.username, self.password, self.port, self.on_session_start)

def _telnet_session(self):
return ASATelnetSession(self.resource_address, self.username, self.password, self.port, self.on_session_start)

def _new_sessions(self):
if self.cli_type.lower() == SSHSession.SESSION_TYPE.lower():
if self.cli_type.lower() == ASASSHSession.SESSION_TYPE.lower():
new_sessions = self._ssh_session()
elif self.cli_type.lower() == TelnetSession.SESSION_TYPE.lower():
elif self.cli_type.lower() == ASATelnetSession.SESSION_TYPE.lower():
new_sessions = self._telnet_session()
elif self.cli_type.lower() == "console":
new_sessions = list()
Expand Down Expand Up @@ -114,7 +120,8 @@ def _enter_enable_mode(self, session, logger):

if re.search(DefaultCommandMode.PROMPT, result):
enable_password = self._api.DecryptPassword(self.resource_config.enable_password).Value
expect_map = {'[Pp]assword': lambda session, logger: session.send_line(enable_password, logger)}
expect_map = {'[Pp]assword': lambda session, logger: session.send_line(enable_password, logger),
'[Uu]ser(name)?|[Ll]ogin': lambda session, logger: session.send_line(self.username, logger)}
session.hardware_expect('enable', EnableCommandMode.PROMPT, action_map=expect_map, logger=logger)
result = session.hardware_expect('', '{0}|{1}'.format(DefaultCommandMode.PROMPT, EnableCommandMode.PROMPT),
logger)
Expand Down
@@ -1,6 +1,8 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import re

from cloudshell.cli.cli_service_impl import CliServiceImpl as CliService
from cloudshell.cli.command_template.command_template_executor import CommandTemplateExecutor
from cloudshell.firewall.cisco.asa.command_templates import enable_disable_snmp
Expand All @@ -19,6 +21,22 @@ def __init__(self, cli_service, logger):
self._cli_service = cli_service
self._logger = logger

@property
def client_ip_address(self):
""" Client IP Address """

try:
return self._cli_service.session.get_local_address()
except Exception, err:
self._logger.error("Failed to determine client local IP Address: {}".format(err))
raise Exception(self.__class__.__name__, "Failed to determine client local IP Address: {}".format(err))

@property
def interface_name(self):
""" Device interface name """

return self.get_interface_name(cli_service=self._cli_service)

def get_current_snmp_communities(self, cli_service=None, action_map=None, error_map=None):
"""Retrieve current snmp communities
Expand All @@ -30,10 +48,37 @@ def get_current_snmp_communities(self, cli_service=None, action_map=None, error_

if not cli_service:
cli_service = self._cli_service
return CommandTemplateExecutor(cli_service=cli_service,
command_template=enable_disable_snmp.SHOW_SNMP_COMMUNITY,
action_map=action_map,
error_map=error_map).execute_command()
output = CommandTemplateExecutor(cli_service=cli_service,
command_template=enable_disable_snmp.SHOW_SNMP_COMMUNITY,
action_map=action_map,
error_map=error_map).execute_command()

return re.findall(r"community (\S+) version", output, flags=re.DOTALL)

def get_interface_name(self, cli_service=None, action_map=None, error_map=None):
""" Get interface name
:param cli_service:
:param action_map: actions will be taken during executing commands, i.e. handles yes/no prompts
:param error_map: errors will be raised during executing commands, i.e. handles Invalid Commands errors
:return:
"""

if not cli_service:
cli_service = self._cli_service
output = CommandTemplateExecutor(cli_service=cli_service,
command_template=enable_disable_snmp.SHOW_IP_ADDR,
action_map=action_map,
error_map=error_map).execute_command(ip_address=self._cli_service.session.host)

match = re.search(r"\S+\s+(?P<iface_name>\S+)\s+{}".format(self._cli_service.session.host), output, flags=re.DOTALL)
if match:
iface_name = match.group("iface_name")
if iface_name:
return iface_name

self._logger("Failed to determine interface name")
raise Exception(self.__class__.__name__, "Failed to determine interface name")

def enable_snmp(self, snmp_community, action_map=None, error_map=None):
"""Enable SNMP on the device
Expand All @@ -43,10 +88,17 @@ def enable_snmp(self, snmp_community, action_map=None, error_map=None):
:param error_map: errors will be raised during executing commands, i.e. handles Invalid Commands errors
"""

return CommandTemplateExecutor(cli_service=self._cli_service,
command_template=enable_disable_snmp.ENABLE_SNMP,
action_map=action_map,
error_map=error_map).execute_command(snmp_community=snmp_community)
CommandTemplateExecutor(cli_service=self._cli_service,
command_template=enable_disable_snmp.ENABLE_SNMP_SERVER,
action_map=action_map,
error_map=error_map).execute_command()

CommandTemplateExecutor(cli_service=self._cli_service,
command_template=enable_disable_snmp.ENABLE_SNMP,
action_map=action_map,
error_map=error_map).execute_command(snmp_community=snmp_community,
iface_name=self.interface_name,
hostname=self.client_ip_address)

def disable_snmp(self, snmp_community, action_map=None, error_map=None):
"""Disable SNMP on the device
Expand All @@ -59,4 +111,6 @@ def disable_snmp(self, snmp_community, action_map=None, error_map=None):
return CommandTemplateExecutor(cli_service=self._cli_service,
command_template=enable_disable_snmp.DISABLE_SNMP,
action_map=action_map,
error_map=error_map).execute_command(snmp_community=snmp_community)
error_map=error_map).execute_command(snmp_community=snmp_community,
iface_name=self.interface_name,
hostname=self.client_ip_address)
Expand Up @@ -3,6 +3,8 @@

from cloudshell.cli.command_template.command_template import CommandTemplate

SHOW_SNMP_COMMUNITY = CommandTemplate("more system:running-config | inc snmp-server community")
ENABLE_SNMP = CommandTemplate("snmp-server community {snmp_community} ro")
DISABLE_SNMP = CommandTemplate("no snmp-server community {snmp_community}")
SHOW_IP_ADDR =CommandTemplate("show ip address | inc {ip_address}")
SHOW_SNMP_COMMUNITY = CommandTemplate("more system:running-config | inc snmp-server host .* community")
ENABLE_SNMP_SERVER = CommandTemplate("snmp-server enable")
ENABLE_SNMP = CommandTemplate("snmp-server host {iface_name} {hostname} poll community {snmp_community} version 2c")
DISABLE_SNMP = CommandTemplate("no snmp-server host {iface_name} {hostname} poll community {snmp_community} version 2c")
Expand Up @@ -21,12 +21,12 @@ def execute_flow(self, snmp_parameters):
""" Configure SNMP Read Community or raise Exception """

if not isinstance(snmp_parameters, SNMPV2Parameters):
message = 'Unsupported SNMP version'
message = "Unsupported SNMP version"
self._logger.error(message)
raise Exception(self.__class__.__name__, message)

if not snmp_parameters.snmp_community:
message = 'SNMP community cannot be empty'
message = "SNMP community cannot be empty"
self._logger.error(message)
raise Exception(self.__class__.__name__, message)

Expand Down
Expand Up @@ -29,9 +29,11 @@ def execute_flow(self, path, configuration_type, restore_method, vrf_management_
restore_action = SystemActions(enable_session, self._logger)
copy_action_map = restore_action.prepare_action_map(path, configuration_type)

if configuration_type == "startup-config":
if configuration_type == "startup-config" and restore_method == "append":
raise Exception(self.__class__.__name__,
"Restore 'startup-config' with method 'append' is not supported")
elif configuration_type == "startup-config" and restore_method == "override":
restore_action.copy(path, configuration_type, action_map=copy_action_map)

elif configuration_type == "running-config" and restore_method == "override":
self._logger.debug("Start backup process for 'startup-config' config")
try:
Expand Down
25 changes: 25 additions & 0 deletions package/cloudshell/firewall/cisco/asa/sessions/asa_ssh_session.py
@@ -0,0 +1,25 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from cloudshell.cli.session.ssh_session import SSHSession


class ASASSHSession(SSHSession):
def __init__(self, host, username, password, port=None, on_session_start=None, *args, **kwargs):
super(ASASSHSession, self).__init__(host, username, password, port, on_session_start, *args, **kwargs)

def connect(self, prompt, logger):
"""Connect to device through ssh
:param prompt: expected string in output
:param logger: logger
"""
try:
super(ASASSHSession, self).connect(prompt, logger)
except Exception:
self.disconnect()
raise

def get_local_address(self):
""" Determine local device (device that initiate connection) IP address """

return self._handler._transport.sock.getsockname()[0]
@@ -0,0 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

from cloudshell.cli.session.telnet_session import TelnetSession


class ASATelnetSession(TelnetSession):
def __init__(self, host, username, password, port=None, on_session_start=None, *args, **kwargs):
super(ASATelnetSession, self).__init__(host, username, password, port, on_session_start, *args, **kwargs)

def get_local_address(self):
""" Determine local device (device that initiate connection) IP address """

return self._handler.sock.getsockname()[0]
Expand Up @@ -18,3 +18,8 @@ def connect(self, prompt, logger):
except Exception:
self.disconnect()
raise

def get_local_address(self):
""" Determine local device (device that initiate connection) IP address """

return self._handler._transport.sock.getsockname()[0]
Expand Up @@ -58,3 +58,8 @@ def empty_action(ses, log):
self.disconnect()
raise
self._active = True

def get_local_address(self):
""" Determine local device (device that initiate connection) IP address """

return self._handler.sock.getsockname()[0]
2 changes: 1 addition & 1 deletion package/version.txt
@@ -1 +1 @@
3.0.1
3.0.5

0 comments on commit 83ddeda

Please sign in to comment.