65d9d18c74
Change-Id: I44488ed2f52f3c1fe9a56050e383176d117ca97f
289 lines
8.7 KiB
Python
289 lines
8.7 KiB
Python
# Copyright 2014 Huawei Technologies Co. Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Utility functions
|
|
Including functions of get/getbulk/walk/set of snmp for three versions
|
|
"""
|
|
import imp
|
|
import logging
|
|
import re
|
|
import subprocess
|
|
|
|
from compass.hdsdiscovery.error import TimeoutError
|
|
|
|
|
|
def load_module(mod_name, path, host=None, credential=None):
|
|
"""Load a module instance.
|
|
|
|
:param str mod_name: module name
|
|
:param str path: directory of the module
|
|
:param str host: switch ip address
|
|
:param str credential: credential used to access switch
|
|
"""
|
|
try:
|
|
mod_file, path, descr = imp.find_module(mod_name, [path])
|
|
if mod_file:
|
|
mod = imp.load_module(mod_name, mod_file, path, descr)
|
|
if host and credential:
|
|
instance = getattr(mod, mod.CLASS_NAME)(host, credential)
|
|
else:
|
|
instance = getattr(mod, mod.CLASS_NAME)()
|
|
|
|
return instance
|
|
except ImportError as exc:
|
|
logging.error('No such module found: %s', mod_name)
|
|
logging.exception(exc)
|
|
return None
|
|
|
|
|
|
def ssh_remote_execute(host, username, password, cmd):
|
|
"""SSH to execute script on remote machine
|
|
|
|
:param host: ip of the remote machine
|
|
:param username: username to access the remote machine
|
|
:param password: password to access the remote machine
|
|
:param cmd: command to execute
|
|
"""
|
|
try:
|
|
import paramiko
|
|
if not cmd:
|
|
logging.error("[hdsdiscovery][utils][ssh_remote_execute] command"
|
|
"is None! Failed!")
|
|
return None
|
|
|
|
client = paramiko.SSHClient()
|
|
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
client.connect(host, username=username, password=password, timeout=15)
|
|
stdin, stdout, stderr = client.exec_command(cmd)
|
|
result = stdout.readlines()
|
|
return result
|
|
|
|
except ImportError as exc:
|
|
logging.error("[hdsdiscovery][utils][ssh_remote_execute] failed to"
|
|
"load module 'paramiko', donnot exist!")
|
|
logging.exception(exc)
|
|
return None
|
|
|
|
except Exception as exc:
|
|
logging.error("[hdsdiscovery][utils][ssh_remote_execute] failed: %s",
|
|
cmd)
|
|
logging.exception(exc)
|
|
return None
|
|
|
|
finally:
|
|
stdin.close()
|
|
stdout.close()
|
|
stderr.close()
|
|
client.close()
|
|
|
|
|
|
def valid_ip_format(ip_address):
|
|
"""Valid the format of an Ip address."""
|
|
|
|
if not re.match(r'^((([0-2]?\d{0,2}\.){3}([0-2]?\d{0,2}))'
|
|
r'|(([\da-fA-F]{1,4}:){7}([\da-fA-F]{1,4})))$',
|
|
ip_address):
|
|
# check IP's format is match ipv4 or ipv6 by regex
|
|
return False
|
|
|
|
return True
|
|
|
|
#################################################################
|
|
# Implement snmpwalk and snmpget funtionality
|
|
# The structure of returned dictionary will by tag/iid/value/type
|
|
#################################################################
|
|
AUTH_VERSIONS = {
|
|
'1': 1,
|
|
'2c': 2,
|
|
'3': 3
|
|
}
|
|
|
|
|
|
def snmp_walk(host, credential, *args, **kwargs):
|
|
"""Impelmentation of snmpwalk functionality
|
|
|
|
:param host: switch ip
|
|
:param credential: credential to access switch
|
|
:param args: OIDs
|
|
:param kwargs: key-value pairs
|
|
"""
|
|
try:
|
|
import netsnmp
|
|
|
|
except ImportError:
|
|
logging.error("Module 'netsnmp' do not exist! Please install it first")
|
|
return None
|
|
|
|
if 'version' not in credential or 'community' not in credential:
|
|
logging.error("[utils] missing 'version' and 'community' in %s",
|
|
credential)
|
|
return None
|
|
|
|
version = None
|
|
if credential['version'] in AUTH_VERSIONS:
|
|
version = AUTH_VERSIONS[credential['version']]
|
|
|
|
varbind_list = []
|
|
for arg in args:
|
|
varbind = netsnmp.Varbind(arg)
|
|
varbind_list.append(varbind)
|
|
|
|
var_list = netsnmp.VarList(*varbind_list)
|
|
|
|
netsnmp.snmpwalk(var_list,
|
|
DestHost=host,
|
|
Version=version,
|
|
Community=credential['community'],
|
|
**kwargs)
|
|
|
|
result = []
|
|
if not var_list:
|
|
logging.error("[hsdiscovery][utils][snmp_walk] retrived no record!")
|
|
return result
|
|
|
|
for var in var_list:
|
|
response = {}
|
|
response['elem_name'] = var.tag
|
|
response['iid'] = var.iid
|
|
response['value'] = var.val
|
|
response['type'] = var.type
|
|
result.append(response)
|
|
|
|
return result
|
|
|
|
|
|
def snmp_get(host, credential, object_type, **kwargs):
|
|
"""Impelmentation of snmp get functionality
|
|
|
|
:param object_type: mib object
|
|
:param host: switch ip
|
|
:param credential: the dict of credential to access switch
|
|
"""
|
|
try:
|
|
import netsnmp
|
|
|
|
except ImportError:
|
|
logging.error("Module 'netsnmp' do not exist! Please install it first")
|
|
return None
|
|
|
|
if 'version' not in credential or 'community' not in credential:
|
|
logging.error('[uitls][snmp_get] missing keywords in %s for %s',
|
|
credential, host)
|
|
return None
|
|
|
|
version = None
|
|
if credential['version'] in AUTH_VERSIONS:
|
|
version = AUTH_VERSIONS[credential['version']]
|
|
|
|
varbind = netsnmp.Varbind(object_type)
|
|
res = netsnmp.snmpget(varbind,
|
|
DestHost=host,
|
|
Version=version,
|
|
Community=credential['community'],
|
|
**kwargs)
|
|
if res and res[0]:
|
|
return res[0]
|
|
|
|
logging.info('no result found for %s %s', host, credential)
|
|
return None
|
|
|
|
|
|
SSH_CREDENTIALS = {"username": "", "password": ""}
|
|
SNMP_V2_CREDENTIALS = {"version": "", "community": ""}
|
|
|
|
|
|
def is_valid_snmp_v2_credential(credential):
|
|
"""check if credential is valid snmp v2 credential."""
|
|
if credential.keys() != SNMP_V2_CREDENTIALS.keys():
|
|
return False
|
|
if credential['version'] != '2c':
|
|
logging.error("The value of version in credential is not '2c'!")
|
|
return False
|
|
return True
|
|
|
|
|
|
def is_valid_ssh_credential(credential):
|
|
"""check if credential is valid ssh credential."""
|
|
if credential.keys() != SSH_CREDENTIALS.keys():
|
|
return False
|
|
return True
|
|
|
|
|
|
def snmpget_by_cl(host, credential, oid, timeout=8, retries=3):
|
|
"""snmpget by credential."""
|
|
if not is_valid_snmp_v2_credential(credential):
|
|
logging.error("[utils][snmpget_by_cl] Credential %s cannot be used "
|
|
"for SNMP request!", credential)
|
|
return None
|
|
|
|
version = credential['version']
|
|
community = credential['community']
|
|
cmd = "snmpget -v %s -c %s -Ob -r %s -t %s %s %s" % (
|
|
version, community, retries, timeout, host, oid)
|
|
|
|
returncode, output, err = exec_command(cmd)
|
|
|
|
if returncode and err:
|
|
logging.error("[snmpget_by_cl] %s", err)
|
|
raise TimeoutError(err.strip('\n'))
|
|
|
|
return output.strip('\n')
|
|
|
|
|
|
def snmpwalk_by_cl(host, credential, oid, timeout=5, retries=3):
|
|
"""snmpwalk by credential."""
|
|
if not is_valid_snmp_v2_credential(credential):
|
|
logging.error("[utils][snmpwalk_by_cl] Credential %s cannot be used "
|
|
"for SNMP request!", credential)
|
|
return None
|
|
|
|
version = credential['version']
|
|
community = credential['community']
|
|
cmd = "snmpwalk -v %s -c %s -Cc -r %s -t %s -Ob %s %s" % (
|
|
version, community, retries, timeout, host, oid)
|
|
|
|
returncode, output, err = exec_command(cmd)
|
|
|
|
if returncode and err:
|
|
logging.debug("[snmpwalk_by_cl] %s ", err)
|
|
raise TimeoutError(err)
|
|
|
|
result = []
|
|
if not output:
|
|
return result
|
|
|
|
output = output.split('\n')
|
|
for line in output:
|
|
if not line:
|
|
continue
|
|
temp = {}
|
|
arr = line.split(" ")
|
|
temp['iid'] = arr[0].split('.', 1)[-1]
|
|
temp['value'] = arr[-1]
|
|
result.append(temp)
|
|
|
|
return result
|
|
|
|
|
|
def exec_command(command):
|
|
"""Execute command.
|
|
Return a tuple: returncode, output and error message(None if no error).
|
|
"""
|
|
sub_p = subprocess.Popen(command,
|
|
shell=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
output, err_msg = sub_p.communicate()
|
|
return (sub_p.returncode, output, err_msg)
|