用jsch实现简单的命令交互和批量处理

其实gradle ssh plugin已经很方便了,就是我们公司的内网没有外网环境,配置gradle依赖有点麻烦。
所以就模仿写了一个,发现还是挺好用的,附上一个例子,扫描一些目标机器并添加ssh key免登陆。

只依赖了commons-net/jsch

import org.apache.commons.net.telnet.TelnetClient

def mkHostTrust = {String hostToBeTrust, String targetHosts ->
	JschUtils.session(hostToBeTrust){session ->
		JschUtils.exeSh("ssh-keygen -t rsa", session, 1000){str ->
			if(str.contains("The key's"))
				return null
			else if(str.contains("Overwrite"))
				return "y"
			else
				return "\n"
		}

		targetHosts.split(',').each{
			def arr = it.split(':')

			JschUtils.exeSh("scp /root/.ssh/id_rsa.pub ${arr[-2]}@${arr[0]}:~/.ssh/authorized_keys", session, 2000){str ->
				if(str.contains("yes/no"))
					return "yes"
				else if(str.contains("password"))
					return "${arr[-1]}"
				else
					return null
			}

			println 'done copy pub key to ' + arr[0]

			JschUtils.exeSh("ssh ${arr[0]}", session, 1000){str ->
				if(str.contains("yes/no"))
					return "yes"
				if(str.contains("known hosts"))
					return "exit"
				else
					return null
			}
		}
	}
}

String pre = '172.16.0.'
List ips = [35..49, 188..194].flatten()

List ipsOkList = []

def tc = new TelnetClient()

for(it in ips){
	try{
	    tc.connect(pre + it, 22)
		ipsOkList << it
	}catch(e){
		println 'error telnet 22 4 ' + it
	}finally{
		try{
			tc.disconnect()
		}catch(e){
		}
	}
}

String ss = ipsOkList.collect{
	pre + it + ':22:root:xxx'
}.join(',')

mkHostTrust(pre + '34:22:root:xxx', ss)

下面是JschUtils的代码

import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.SftpATTRS

import com.jcraft.jsch.*

import org.slf4j.Logger
import org.slf4j.LoggerFactory

class JschUtils {
	// *** log
	static Logger l = LoggerFactory.getLogger(JschUtils.class)

	private static Properties config = [StrictHostKeyChecking: 'no']

	public static int timeout = 10000

	private static String read(InputStream is){
		def buf = new StringBuilder(1024)
		def tmp = new byte[1024]
		while ( is.available() > 0 ) {
			int i = is.read( tmp, 0, 1024 )
			if ( i < 0 ) break;
			buf << new String( tmp, 0, i )
		}
		buf.toString()
	}

	private static String exeInner(String cmd, long wait, OutputStream os, InputStream is, Closure cl){
		l.info  'begin exe ' + cmd
		os.write("${cmd.trim()}\r".getBytes())
		Thread.currentThread().sleep(wait)

		String result = read(is)
		l.info result
		cl.call(result)
	}

	public static void exeSh(String cmd, s, long wait = 500, Closure cl = null){
		def ch = s.openChannel('shell')

		def pipeIn = new PipedInputStream() 
		def pipeOut = new PipedOutputStream(pipeIn)

		def pipeIn2 = new PipedInputStream() 
		def pipeOut2 = new PipedOutputStream(pipeIn2)

		ch.inputStream = pipeIn
		ch.outputStream = pipeOut2

		ch.connect(timeout)

		Thread.currentThread().sleep(wait)
		l.info read(pipeIn2)

		// -i
		if(cl != null){
			String nextCmd = exeInner(cmd, wait, pipeOut, pipeIn2, cl)
			while(nextCmd != null){
				Thread.currentThread().sleep(wait)
				nextCmd = exeInner(nextCmd, wait, pipeOut, pipeIn2, cl)
			}
		}else{
			cmd.split(',').each{
				l.info  'begin exe ' + it
				pipeOut.write("${it.trim()}\r".getBytes())
				Thread.currentThread().sleep(wait)
			}
		}

		pipeOut.close()
		pipeIn.close()

		pipeOut2.close()
		pipeIn2.close()

		ch.disconnect()
	}

	public static void exe(String cmd, s){
		def ch = s.openChannel('exec')
		ch.command = cmd
		ch.errStream = System.err

		def is = ch.inputStream

		ch.connect() 
		int res = -1
		def buf = new StringBuffer(1024)
		def tmp = new byte[1024]
		while ( true ) {  
			while ( is.available() > 0 ) {
				int i = is.read( tmp, 0, 1024 );
				if ( i < 0 ) break;
				buf.append( new String( tmp, 0, i ) );
			}
			if ( ch.isClosed() ) {
				res = ch.exitStatus
				l.info  'exist status ' + res
				break
			}
		}

		l.info  buf.toString()
		ch.disconnect()
	}

	public static void put(s, String local, dst){
		l.info 'put ' + local + ' -> ' + dst

		// upload script
		def channel = s.openChannel('sftp')
		channel.connect()
		l.info  'sftp channel connected'

		channel.put(local, dst, null, ChannelSftp.OVERWRITE)
		channel.quit()
		channel.disconnect()
	}

	// sinfo -> host:port:username:password
	public static void session(String hostInfo, Closure cl){
		Map sinfo = [:]
		def arr = hostInfo.split(':')
		sinfo.host = arr[0]
		sinfo.port = arr[1] as int
		sinfo.username = arr[2]
		sinfo.password = arr[3]

		def session
		try{
			def jsch = new JSch()
			session = jsch.getSession(sinfo.username, sinfo.host, sinfo.port)
			session.password = sinfo.password

			session.config = config
			session.timeout = timeout
			session.connect()
			l.info  'session opened ' + sinfo.host

			cl.call(session)
		}catch(e){
			l.error('ex get', e)
		}finally{
			if(session){
				session.disconnect()
				l.info  'session disconnected ' + sinfo.host
			}
		}
	}
}

猜你喜欢

转载自key232323.iteye.com/blog/2353560