
Rework some imports to work with py27 and py33, also fix unittests for config schemas and version checking. This commit is not garantee that application will fully worked on python3.3 Task: https://blueprints.launchpad.net/rubick/+spec/python33-support Signed-off-by: Peter Lomakin <plomakin@mirantis.com> Change-Id: Iffa564d52fd2bf83cebe9f31cca74e27c0b6baad
195 lines
5.4 KiB
Python
195 lines
5.4 KiB
Python
import paramiko
|
|
|
|
import os
|
|
from paramiko.dsskey import DSSKey
|
|
from paramiko.rsakey import RSAKey
|
|
import stat
|
|
import sys
|
|
if sys.version < '3':
|
|
from StringIO import StringIO
|
|
else:
|
|
from io import StringIO
|
|
|
|
TMP_KEY_PATH = "/tmp/joker_%s_%d"
|
|
|
|
|
|
class Node():
|
|
|
|
def __init__(self, name, ip, port):
|
|
|
|
self.ssh = paramiko.SSHClient()
|
|
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
self.setHostName(ip)
|
|
self.setName(name)
|
|
self.setAccessPort(port)
|
|
self.connected = False
|
|
|
|
self.neighbours = []
|
|
self.debug = True
|
|
|
|
self.proxyCommandTxt = self.proxyCommand = None
|
|
self.link = None
|
|
|
|
self.origKey = self._pkey = None
|
|
self.keyPath = TMP_KEY_PATH % (name, os.getpid())
|
|
|
|
def dumpKey(self, path, key):
|
|
if (key):
|
|
f = open(path, "w", stat.S_IRUSR | stat.S_IWUSR)
|
|
f.write(key)
|
|
f.close()
|
|
|
|
# def __del__(self):
|
|
# print "Del %s" % self.keyPath
|
|
# if os.path.exists(self.keyPath):
|
|
# print "Remove %s" % self.keyPath
|
|
# os.remove(self.keyPath)
|
|
|
|
def proxyCommandGen(self, masterHost, masterPort, masterUser,
|
|
masterKeyfile):
|
|
return "ssh -i %s -o StrictHostChecking=no -p%d %s@%s nc -q0 %s %d" % (
|
|
masterKeyfile, masterPort, masterUser, masterHost,
|
|
self.hostName, self.accessPort)
|
|
|
|
def discoverHwAddr(self):
|
|
try:
|
|
(stdout, stderr) = self.runCommand(
|
|
"ip addr | grep -A2 BROADCAST,MULTICAST,UP,LOWER_UP | "
|
|
"awk '/link\/ether/ {ether=$2} /inet/ {print $2 \" \" ether}'")
|
|
|
|
except Exception:
|
|
raise ()
|
|
|
|
macDict = {}
|
|
|
|
for line in stdout:
|
|
(ip, hwAddr) = line.strip().split(" ")
|
|
macDict[hwAddr] = ip
|
|
|
|
return macDict
|
|
|
|
def setUniqData(self):
|
|
self.link = self.discoverHwAddr()
|
|
|
|
def getUniqData(self):
|
|
return self.link
|
|
|
|
def debugLog(self, debugData):
|
|
if self.debug is True:
|
|
print debugData
|
|
|
|
def prepare(self):
|
|
# install arp-scan on node
|
|
try:
|
|
self.runCommand(
|
|
"[ ! -x arp-scan ] && sudo apt-get --force-yes -y install "
|
|
"arp-scan")
|
|
except Exception:
|
|
raise ()
|
|
self.setUniqData()
|
|
|
|
return True
|
|
|
|
def infect(self):
|
|
# infect node
|
|
return True
|
|
|
|
def setName(self, name):
|
|
self.name = name
|
|
|
|
def setHostName(self, hostname):
|
|
self.hostName = hostname
|
|
|
|
def setAccessPort(self, port):
|
|
self.accessPort = port
|
|
|
|
def assignKey(self, key):
|
|
self.origKey = key
|
|
# dump key to file
|
|
self.dumpKey(self.keyPath, self.origKey)
|
|
|
|
try:
|
|
self._pkey = RSAKey.from_private_key(StringIO(self.origKey))
|
|
except paramiko.SSHException:
|
|
try:
|
|
self._pkey = DSSKey.from_private_key(StringIO(self.origKey))
|
|
except paramiko.SSHException:
|
|
raise "Unknown private key format"
|
|
|
|
def assignCredential(self, user, key, password=None):
|
|
self.user = user
|
|
self.password = password
|
|
|
|
if (key):
|
|
self.assignKey(key)
|
|
|
|
def setProxyCommand(self, masterHost, masterPort, masterUser,
|
|
masterKeyfile):
|
|
self.proxyCommandTxt = self.proxyCommandGen(
|
|
masterHost, masterPort, masterUser, masterKeyfile)
|
|
self.proxyCommand = paramiko.ProxyCommand(self.proxyCommandTxt)
|
|
|
|
def connect(self):
|
|
|
|
if self.connected is True:
|
|
raise AssertionError(self.connected is True)
|
|
|
|
try:
|
|
|
|
self.ssh.connect(self.hostName, self.accessPort, self.user,
|
|
pkey=self._pkey, sock=self.proxyCommand,
|
|
timeout=5, password=self.password)
|
|
|
|
self.connected = True
|
|
return True
|
|
|
|
except paramiko.BadHostKeyException, e:
|
|
print "Host key could not be verified: ", e
|
|
return False
|
|
except paramiko.AuthenticationException, e:
|
|
print "Error unable to authenticate: ", e
|
|
return False
|
|
except paramiko.SSHException, e:
|
|
return False
|
|
except EOFError, e:
|
|
return False
|
|
|
|
def runCommand(self, command):
|
|
if (command == ""):
|
|
AssertionError(command == "")
|
|
|
|
if self.connected is False:
|
|
self.connect()
|
|
|
|
self.debugLog("---> " + self.hostName + " " + command)
|
|
stdin, stdout, stderr = self.ssh.exec_command(command)
|
|
self.debugLog("OK " + self.hostName + " " + command)
|
|
|
|
return (stdout.readlines(), stderr.readlines())
|
|
|
|
def __discover__(self):
|
|
|
|
(data, _) = self.runCommand(
|
|
"(test -x arp-scan && ip link |\
|
|
awk -F: '/^[0-9]+?: eth/ {print $2}' |\
|
|
sudo xargs -I% arp-scan -l -I % 2>&1 | grep -E '^[0-9]+?\.';\
|
|
arp -an | awk -F\" \" '{ gsub(\"[^0-9\\.]\", \"\", $2);\
|
|
printf(\"%s\\t%s\\t%s\\n\", $2, $4, $7)}'\
|
|
)")
|
|
|
|
for line in data:
|
|
(ip, hwAddr, _) = line.strip().split("\t")
|
|
self.neighbours.append({"hwAddr": hwAddr, "ip": ip})
|
|
self.debugLog("%s -> %s" % (self.hostName, ip))
|
|
|
|
return self.neighbours
|
|
|
|
def discover(self):
|
|
|
|
if self.connect() is False:
|
|
return None
|
|
|
|
self.prepare()
|
|
|
|
return self.__discover__()
|