Уведомления

Группа в Telegram: @pythonsu

#1 Июль 22, 2015 10:20:56

apanyovin
От:
Зарегистрирован: 2008-12-25
Сообщения: 23
Репутация: +  0  -
Профиль   Отправить e-mail  

twisted ssh conch

Добрый день, Коллеги.

Прошу помощи.

Хочу нарисовать модуль, который подключается к 5 сервера по ssh и выполняет определенные команды + sftp команды (копировать - удалять файлы/директории).
Команды буду скармливать через txredisapi.

У меня сложность с conch.

Нарисовал для себя такой пример:

[code python]#!/usr/bin/env python
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.

if __name__ == '__main__':
import sys
import p3
from twisted.internet.task import react
react(p3.main)

import os, getpass

from twisted.python.filepath import FilePath
from twisted.python.usage import Options
from twisted.internet.defer import Deferred
from twisted.internet.protocol import Factory, Protocol, ReconnectingClientFactory
from twisted.internet.endpoints import UNIXClientEndpoint
from twisted.conch.ssh.keys import EncryptedKeyError, Key
from twisted.conch.client.knownhosts import KnownHostsFile
from twisted.conch.endpoints import SSHCommandClientEndpoint

class NoiseProtocol(Protocol):
def connectionMade(self):
print "Connected to SSH"
self.finished = Deferred()

def dataReceived(self, data):
print "Server says:\n", data

class ConnectionParameters(object):
def __init__(self, reactor):
self.reactor = reactor
self.host = "192.168.87.100"
self.port = 22
self.username = "root"
self.password = None
self.keys = None
self.knownHosts = None
self.agent = None
self.keys = []
self.keys.append(Key.fromFile(os.path.expanduser("~/.ssh/id_rsa")))

knownHostsPath = FilePath(os.path.expanduser("~/.ssh/known_hosts"))
if knownHostsPath.exists():
self.knownHosts = KnownHostsFile.fromPath(knownHostsPath)
else:
self.knownHosts = None

def endpointForCommand(self, command):
return SSHCommandClientEndpoint.newConnection(
self.reactor, command, self.username, self.host,
port=self.port, keys=self.keys,
knownHosts=self.knownHosts)


def main(reactor):
parameters = ConnectionParameters(reactor)
endpoint = parameters.endpointForCommand(b"")

factory = ReconnectingClientFactory()
factory.protocol = NoiseProtocol

d = endpoint.connect(factory)
d.addCallback(lambda proto: proto.finished)

r = endpoint.existingConnection(factory.protocol.transport, b"/bin/ls")

d = endpoint.connect(factory)
d.addCallback(lambda proto: proto.finished)

r.addCallback(lambda proto: proto.finished)


return d[/code]

В логах на сервере видно - подключается и что то делает))
Но, мне не понятно 2 вещи:
1 - почему он пытается 2 раза подключиться, точнее устанавливает 2 раза соединие
из консоли
<twisted.conch.endpoints.SSHCommandClientEndpoint object at 0x104fc4790>
Connected to SSH
Connected to SSH

В идеале мне нужно делать команды в рамках одного соединения. Ну и реконектить, если отвалился.

Можно ли пример, если не сложно?
2 подключения по 2 команды + если можно с одной передачей чайла.

извините за наглость, просто не догоняю.



Офлайн

#2 Июль 22, 2015 16:06:27

apanyovin
От:
Зарегистрирован: 2008-12-25
Сообщения: 23
Репутация: +  0  -
Профиль   Отправить e-mail  

twisted ssh conch

отвечаю себе)))

пока такой вариант

from twisted.conch.ssh import transport, connection, userauth, channel, common, keys
from twisted.internet import defer, protocol, reactor
import sys, struct  
USER = 'root'
CMD  = b'/bin/ls'
from twisted.python import log
import sys, os
log.startLogging(sys.stdout)
class ClientCommandTransport(transport.SSHClientTransport):
    def __init__(self, username, command, factory):
        self.username = username
        self.command = command
        self.factory = factory
    def verifyHostKey(self, pubKey, fingerprint):
        print fingerprint 
        return defer.succeed(True)
    def connectionSecure(self):
        self.requestService(
            SSHKeyAuth(self.username, ClientConnection(self.command, self.factory)))
class SSHKeyAuth(userauth.SSHUserAuthClient):
    def getPublicKey(self):
        path = os.path.expanduser('~/.ssh/id_rsa')
        if not os.path.exists(path) or self.lastPublicKey:
            return
        return keys.Key.fromFile(filename=path+'.pub').blob()
    def getPrivateKey(self):
        path = os.path.expanduser('~/.ssh/id_rsa')
        return defer.succeed(keys.Key.fromFile(path).keyObject)
class ClientConnection(connection.SSHConnection):
    def __init__(self, cmd, *args, **kwargs):
        connection.SSHConnection.__init__(self)
        self.command = cmd
        self.factory = factory
    def serviceStarted(self):
        self.openChannel(CommandChannel(self.command, self.factory, conn=self))
        self.openChannel(CommandChannel(b"/bin/ls /var/log/", self.factory, conn=self))
        # self.openChannel(CommandChannel(self.command, self.factory, conn=self))
        # self.openChannel(CommandChannel(self.command, self.factory, conn=self))
class CommandChannel(channel.SSHChannel):
    name = 'session'
    def __init__(self, command, factory, *args, **kwargs):
        channel.SSHChannel.__init__(self, *args, **kwargs)
        self.command = command
        self.data = ''
        self.factory = factory
        self.factory.num_connections += 1
        self.factory.connections.append(self)
    def channelOpen(self, data):
        print ">>>>>>> Try send exec"
        self.conn.sendRequest(self, 'exec', common.NS(self.command), wantReply=True).addCallback(self._gotResponse)
    def _gotResponse(self, _):
        pass
        self.conn.sendEOF(self)
        self.loseConnection()
        # self.factory.num_connections -= 1
        # self.factory.connections.remove(self)
        # if self.factory.num_connections == 0:
        #     reactor.stop()
    def dataReceived(self, data):
        self.data += data
        # print ">>>>>>>>>>>>>>", data
        print "|", self.data, "|"
    # def request_exit_status(self, data):
    #     (status,) = struct.unpack('>L', data)
        # print 'exit status = ', status  
class ClientCommandFactory(protocol.ClientFactory):
    def __init__(self, command=CMD):
        self.username = USER
        self.command = command
        self.connections = []
        self.num_connections = 0
    def buildProtocol(self, addr):
        protocol = ClientCommandTransport(self.username, self.command, self)
        return protocol    
    def test1(self):
        pass
masters = ['192.168.87.100', '10.30.50.27', '10.30.50.110']
factory = ClientCommandFactory()
for server in masters:
    print server
    reactor.connectTCP(server, 22, factory)
reactor.run()

Что получили - поднимается коннект, проходит авторизация по ключам, выполняем команду.
Идем дальше - нужно сделать обвес для удобного выполнения

Я буду писать, может кому пригодиться))



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version