欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-05 23:11:13
...

其实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
			}
		}
	}
}