summaryrefslogtreecommitdiffstats
path: root/Monitoring/src/main/python/Driver/SshExec.py
blob: 5de70519a80f184a8644138f81eec5b8484d6e7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from __future__ import with_statement
'''
Created on Feb 29, 2012

@summary: A Jython compatible ssh driver
@author: Sandor Laki
@organization: ELTE
@contact: lakis@inf.elte.hu
'''


from java.io import BufferedReader
from java.io import IOException
from java.io import InputStream
from java.io import InputStreamReader
from java.io import File
from jarray import zeros
from java.lang import String
from com.jcraft.jsch import JSch
from StringIO import StringIO
#import libssh2
#import socket
from tempfile import mkstemp
from os import close, write, unlink, path, access, R_OK
#from SshKeygen import SshKeygen
from threading import Lock
from Credential.credentialtypes import Credential, UsernameRSAKey,\
    UsernamePassword
from Driver import Driver
import org.python.core.util.FileUtil as FileUtil
import java.lang.Exception
#from org.slf4j import Logger
#from org.slf4j import LoggerFactory
#import org.python.core.PyFile as PyFile
#driverlock = Lock()

class SshExec(Driver):
    '''
    @summary: this class handles control of a monitoring tool over an ssh channel
    @author: steger, jozsef 
    @todo: get rid of global lock if possible
    @note: if no global lock is there, a lot os segmentation faults occur in a concurrent session opening and program execution
    '''
    #lock = Lock() #driverlock
#    log = LoggerFactory.getLogger("eu.novi.monitoring.Driver.SshExec")

    def __init__(self, host, credential, port = 22, command = "echo helloworld @ `hostname`", known_host = None):
        '''
        @summary: initiates a class to execute a single remote command via ssh protocol, tekes care of opening ssh session
        @param host: name of the hos machine
        @type host: string
        @param credential: authentication details
        @type credential: Credential
        @param port: port of the ssh service
        @type port: integer
        @param command: the remote command to execute later
        @type command: string
        @raise Exception: wrong authentication type
        
        @note: only a single command can be run by the class
        
        
        @todo: check what happens with commands run in the background         
        '''
        self.lock = Lock()
        self.session = None
        self.channel = None
        if host is None: return

        if not isinstance(credential, Credential):
            raise Exception("wrong type of credential")
        with self.lock:
            self._result = ""
#            self.session = libssh2.Session()
#            self.session.set_banner()
            self.command = command
            self.fn_pub = None
#            self.pemfile = None
            
            try:
                self.jsch = JSch()
#                self.log.info("Host:%s Username:%s Port:%s Command:%s" % (host, credential.username, port, self.command))
                print "h:%s un:%s p:%s" % (host, credential.username, port)
		self.session = self.jsch.getSession(credential.username, host, port)
		#self.jsch.setKnownHosts("/home/maven/.ssh/known_hosts")

                if isinstance(credential, UsernameRSAKey):
                    privatekey = credential.rsakey
#                    self.log.info("Credential: %s" % privatekey)
                    self.jsch.addIdentity(privatekey)
                    self.session.setConfig("StrictHostKeyChecking", "no")
                    self.session.setTimeout(5000);
                    print "identity file %s\n" % privatekey
                    PATH=privatekey
                    if path.exists(PATH) and path.isfile(PATH) and access(PATH, R_OK):
                        print "File exists and is readable"
#                        self.log.info("Privatekey exists and is readable")
                    else:
#                        self.log.info("RSA key is missing: %s" % PATH)
                        raise Exception("RSA key file is missing or not readable: %s" % PATH)

#                    publickey_srt = SshKeygen.convert_key_from_file(privatekey)
#                    fd, publickey = mkstemp(suffix = ".pub", prefix = "rsa", text = True)
#                    write(fd, "ssh-rsa %s" % publickey_srt)
#                    close(fd)
#                    self.fn_pub = publickey
#                    self.session._session.userauth_publickey_fromfile(credential.username, publickey, privatekey, credential.password)
                elif isinstance(credential, UsernamePassword):
                    self.session.setPassword( credential.password )
                else:
                    raise Exception("wrong type of credential")
                
                self.session.connect()
            except java.lang.Exception, e:
#                self.log.info("Connection error")
                print "Connection Error"
                print "Exc:%s" % e
                self.session = None
                self.channel = None
                #raise e
            
#            self.channel = self.session.open_session()
        
    def execute(self):
        '''
        @summary: invokes the remote command to run. The standard output of the command is stored in the result variable.
        '''
        with self.lock:
#            self.log.info("Execute:%s" % self.command)
            if self.session is None: return StringIO("")
            self.channel = self.session.openChannel("exec")
            self.channel.setCommand(self.command)
            self.channel.setInputStream(None)

            stdo = self.channel.getInputStream()
#            br = BufferedReader( InputStreamReader( stdo ) )
            self.channel.connect()

            return FileUtil.wrap( stdo )

#            buffer = 4096
#            buf = zeros(1024,'b')
#            while True:
#                while stdo.available()>0:
#                    i=stdo.read(buf,0,1024)
#                    if i<0: break
#                    self._result += str(String(buf,0,i))
#                if channel.isClosed(): break
#            channel.disconnect()
#            return StringIO(self._result)

#    def _get_result(self):
#        '''
#        @summary: the copy of the standard output of the remote command
#        @return: the standard output of the remote command
#        @rtype: string
#        '''
#        return str(self._result)

    def close(self):
        '''
        @summary: the destructor takes care of closing the session and removing the public key file stored temporary
        '''
        with self.lock:
            if self.channel is not None:
                self.channel.disconnect()
                self.channel = None
            if self.session is not None:
                self.session.disconnect()
#            if self.fn_pub is not None:
#                unlink(self.fn_pub)

#    result = property(_get_result,None,None)

    def __del__(self):
        self.close()

    def _isConnected(self):
        try:
            if self.channel is not None: return True
            else: return False
        except:
            return False

    isConnected = property(_isConnected,None, None)