diff --git a/joker/joker/__init__.py b/joker/joker/__init__.py index 3dfb4ed..8b01783 100644 --- a/joker/joker/__init__.py +++ b/joker/joker/__init__.py @@ -1,6 +1,5 @@ -from nodes import NodesDict,Node +from nodes import NodesDict, Node #from os import remove -import os PETYA_ENV_KEY = "-----BEGIN RSA PRIVATE KEY-----\n\ MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI\n\ @@ -32,46 +31,59 @@ NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=\n\ #TMP_PATH="/tmp/%s" + class Joker(): - def __init__(self, key = PETYA_ENV_KEY, *args, **kwargs): - + def __init__(self, key=PETYA_ENV_KEY, *args, **kwargs): + self.default_key = key self.nodes = NodesDict() self.keyPath = None self.name = "EntryPoint" - #self.setKey() - - + #self.setKey() # def __del__(self): -# if (self.keyPath): +# if (self.keyPath): # # look at this. # # epic security hole oneliner # print "os.remove(self.keyPath)" def addNode(self, name, host, port, user): - self.entryPoint = Node(name, host, port); - self.entryPoint.assignCredential(user, self.default_key, None) + self.entryPoint = Node(name, host, port) + self.entryPoint.assignCredential(user, self.default_key, None) return def genStub(self, hostname, ip, port, user, key, proxycommand): return {"name": hostname, "ip": ip, "user": user, - "key": key, "port": port, + "key": key, "port": port, "proxy_command": proxycommand - } + } def discover(self): result = [] - discoveryData = self.entryPoint.discovery() + ep = self.entryPoint + discoveryData = ep.discovery() for node in discoveryData: - result.append(self.genStub(discoveryData[node], discoveryData[node], self.default_key , "vagrant", None, "ssh -i " + "%%PATH_TO_KEY%%" + " -p " + str(self.entryPoint.accessPort) + " -q " + self.entryPoint.user + "@" + self.entryPoint.hostName + " nc -q0 " + discoveryData[node] + " 22")) + proxy_command = ("ssh" + + " -i %%PATH_TO_KEY%%" + + " -p {0}".format(ep.accessPort) + + " -q {0}@{1}".format(ep.user, ep.hostName) + + " nc -q0 {0} 22".format(discoveryData[node])) + + result.append( + self.genStub(hostname=discoveryData[node], + ip=discoveryData[node], + port=ep.accessPort, + user="vagrant", + key=self.default_key, + proxycommand=proxy_command)) return result -joker = Joker(PETYA_ENV_KEY) -joker.addNode("controller1", "172.18.66.112", 2301, "vagrant"); -print joker.discover() +if __name__ == '__main__': + joker = Joker(PETYA_ENV_KEY) + joker.addNode("controller1", "172.18.66.112", 2301, "vagrant") + print joker.discover() diff --git a/joker/joker/nodes.py b/joker/joker/nodes.py index 4162bd9..e91e7af 100644 --- a/joker/joker/nodes.py +++ b/joker/joker/nodes.py @@ -53,39 +53,38 @@ class Node(): self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.setHostName(ip) self.setName(name) - self.setAccessPort(port) + self.setAccessPort(port) self.connected = False - #self.neighbours = NodesDict() - self.neighbours = {} - self.debug = True - + #self.neighbours = NodesDict() + self.neighbours = {} + self.debug = True + self.hwAddr = None - def discoveryHwAddr(self): + def discoveryHwAddr(self): try: - (stdout, stderr) = self.runCommand("ip link | grep -m1 -A1 BROADCAST,MULTICAST,UP,LOWER_UP | awk -F\" \" '/link/ {print $2}'"); + (stdout, stderr) = self.runCommand("ip link | grep -m1 -A1 BROADCAST,MULTICAST,UP,LOWER_UP | awk -F\" \" '/link/ {print $2}'"); except: - raise() - return stdout[0].strip() + raise() + return stdout[0].strip() def setUniqData(self): - self.hwAddr = self.discoveryHwAddr() + self.hwAddr = self.discoveryHwAddr() def getUniqData(self): return self.hwAddr - def debugLog(self, debugData): + def debugLog(self, debugData): if self.debug is True: print debugData - def prepare(self): # install arp-scan on node self.runCommand( - "[ ! -x arp-scan ] && sudo apt-get --force-yes -y install arp-scan") - self.setUniqData() - self.debugLog("Unit data is " + self.getUniqData()); + "which arp-scan || sudo apt-get --force-yes -y install arp-scan") + self.setUniqData() + self.debugLog("Unit data is " + self.getUniqData()) return True def infect(self): @@ -105,7 +104,7 @@ class Node(): self.user = user self.password = password - # from paramiko? + # from paramiko? self.origKey = key self._pkey = RSAKey.from_private_key(StringIO(self.origKey)) @@ -118,15 +117,14 @@ class Node(): # except SSHException: # raise "Unknown private key format" - def setProxyCommand(self, proxyCommand): self.proxyCommand = proxyCommand def connect(self): if self.connected is True: - raise assertionError(self.connected is True) + raise AssertionError(self.connected is True) try: - print self.hostName, " ", self.accessPort, " ", self.user, " " + print self.hostName, " ", self.accessPort, " ", self.user, " " self.ssh.connect(self.hostName, self.accessPort, self.user, pkey=self._pkey) self.connected = True @@ -143,32 +141,32 @@ class Node(): def runCommand(self, command): if (command == ""): - assertionError(command == "") + AssertionError(command == "") if (self.connected is False): self.connect() - self.debugLog("---> " + self.hostName + " " + command) + self.debugLog("---> " + self.hostName + " " + command) stdin, stdout, stderr = self.ssh.exec_command(command) - self.debugLog("OK " + self.hostName + " " + command) + self.debugLog("OK " + self.hostName + " " + command) - return (stdout.readlines(), stderr.readlines()) + return (stdout.readlines(), stderr.readlines()) - def __discovery__(self): + def __discovery__(self): # tuesday discovery (self.discovery_data, _) = self.runCommand( "ip link | awk -F: '/^[0-9]+?: eth/ {print $2}' |\ sudo xargs -I% arp-scan -l -I % 2>&1 | grep -E '^[0-9]+?\.' | grep -E '192.168.(28|30)'.101") - + def discovery(self): self.prepare() - node = {} + node = {} - self.__discovery__() + self.__discovery__() for n in self.discovery_data: - ( node['ip'], node['hwaddr'], _) = n.split("\t") + (node['ip'], node['hwaddr'], _) = n.split("\t") self.neighbours[node['hwaddr']] = node['ip'] self.neighbours[self.getUniqData()] = self.hostName - + return self.neighbours diff --git a/rubick/discovery.py b/rubick/discovery.py index 1bd7e9d..bdf7c07 100644 --- a/rubick/discovery.py +++ b/rubick/discovery.py @@ -1,6 +1,7 @@ import os.path import re import traceback +import tempfile from StringIO import StringIO import logging @@ -71,6 +72,15 @@ class NodeClient(object): private_key=None, proxy_command=None): super(NodeClient, self).__init__() self.use_sudo = (username != 'root') + + if proxy_command and proxy_command.find('%%PATH_TO_KEY%%') != -1: + self._pkey_file = tempfile.NamedTemporaryFile(suffix='.key') + self._pkey_file.write(private_key) + self._pkey_file.flush() + + proxy_command = proxy_command.replace('%%PATH_TO_KEY%%', + self._pkey_file.name) + sock = paramiko.ProxyCommand(proxy_command) if proxy_command else None self.shell = SshShell( @@ -80,6 +90,7 @@ class NodeClient(object): password=password, private_key=private_key, missing_host_key=spur.ssh.MissingHostKey.accept, + connect_timeout=5, sock=sock) def run(self, command, *args, **kwargs): @@ -148,12 +159,22 @@ class JokerNodeDiscovery(object): j = joker.Joker(default_key=private_key) count = 0 for node in parse_nodes_info(initial_nodes): - j.add_node('node%d' % count, - node['host'], - node['port'], - node['username']) + j.addNode('node%d' % count, + node['host'], + node['port'], + node['username']) - nodes = j.discover() + nodes = [] + for j_node_info in j.discover(): + node = dict( + name=j_node_info['name'], + host=j_node_info['ip'], + port=j_node_info['port'], + username=j_node_info['user'], + private_key=j_node_info['key'],) + # proxy_command=j_node_info['proxy_command']) + node = dict((k, v) for k, v in node.iteritems() if v) + nodes.append(node) return nodes @@ -164,7 +185,7 @@ python_re = re.compile('(/?([^/]*/)*)python[0-9.]*') class OpenstackDiscovery(object): logger = logging.getLogger('rubick.discovery') - node_discovery_klass = SimpleNodeDiscovery + node_discovery_klass = JokerNodeDiscovery def test_connection(self, initial_nodes, private_key): d = self.node_discovery_klass()