随笔-14  评论-72  文章-0  trackbacks-0
  2010年3月10日

最近用SSH比较多了,需要连接到一些远程的服务器上,然后执行一些命令。次数多了,渐渐就觉得比较麻烦。于是写了一个脚本用来让程序自动去执行一些重复的动作。

ruby下的SSH库最常用的是net/ssh。可以从它的网站去找一些信息。(http://net-ssh.rubyforge.org/)上面有一些例子,来告诉用户到底怎么使用这个东西。其实模式很简单,先是通过start方法链接到服务器,开启一个session,然后在这个session的上下文上去用exec方法执行一些命令。当然还有更复杂一些的用法,不过鉴于需求只是执行命令,那么复杂的东西就放一放。

如果你愿意,每写一个脚本都用Net::SSH.start(...)开头可以,不过这个看上去并不方便。至少打的字还是比较多的。那就封装一下吧。其实怎么对这些库进行封装是仁者见仁智者见智的事情。我的想法是抽象出2个概念,配置(config)和一批命令(batch)。由此对于这个封装的用法自然就可以想到:

1 config = SSHConfig.new(:host => 'server.domain', :user => 'user', :password => 'pass')
2 batch = config.create_batch
3 batch << 'ls'
4 batch << 'ps -Al'
5 puts batch.run

有了这个蓝图,剩下的就是照着这个蓝图写代码了。首先SSHConfig就是用来保存服务器的配置,并且创建一个Batch对象。当然,通过前面看过net/ssh例子,可以想起来其实SSHConfig应该还有一个功能就是根据这些配置创建一个session

代码
 1 class SSHConfig
 2   attr_accessor :user
 3   attr_accessor :host
 4   attr_accessor :password
 5   
 6   def initialize(args = {})
 7     @user = args[:user] unless args[:user].nil?
 8     @host = args[:host] unless args[:host].nil?
 9     @password = args[:password] unless args[:password].nil?
10   end
11   
12   def create_session
13     Net::SSH.start(host, user, :password => password) do |ssh|
14       sess = Session.new(ssh)
15       yield sess
16     end
17   end
18   
19   def create_batch
20     Batch.new(self)
21   end
22 end

这里我还是把net/sshsession又包装了一下,只暴露出了一些自己用到的方法。下面就是Session类的代码:

代码
 1 class Session
 2   def initialize(ssh)
 3     @ssh = ssh
 4     @stdout = ""
 5     @stderr = ""
 6   end
 7   
 8   def exec!(cmd)
 9     @ssh.exec!(cmd) do |ch, stream, data|
10       if stream == :stdout
11         stdout << data
12       elsif stream == :stderr
13         stderr << data
14       end
15     end
16   end
17   
18   def stdout
19     @stdout
20   end
21   
22   def stderr
23     @stderr
24   end
25 end

Session对象截获了通过它执行的命令所造成的输出,供命令执行过后为脚本打印结果使用。

最后的重头戏是Batch,他用来保存一系列的命令,然后执行他们。

代码
 1 class Batch
 2   def initialize(config, &block)
 3     @config = config
 4     @commands = []
 5     @after_exec = block
 6   end
 7   
 8   def commands
 9     @commands
10   end
11   
12   def <<(item)
13     @commands << item
14   end
15   
16   def add_command(cmd)
17     @commands << cmd
18   end
19   
20   def run
21     ret = ""
22     @config.create_session do |sess|
23       @commands.each do |cmd|
24         sess.exec!(cmd)
25       end
26       unless @after_exec.nil?
27         @after_exec.call(sess)
28       end
29       ret = sess.stdout
30     end
31     ret
32   end
33 end

最后还有一个提示,就是通过SSH执行命令的话,两个不同的命令并不集成路径。也就是说如果先执行 cd ~\web, 然后执行 ls,那么ls返回的结果是 ~ 这个目录的,而不是~\web 。那么如何让cd这个命令起效果呢?用“; ” ── cd ~\web; ls

 


posted @ 2010-03-10 17:02 blacktear 阅读(225) 评论(0) 编辑
  2009年10月1日
有人说,当你真正沉浸在回忆中,你就老了。也许吧。
下班,坐在回家的公交车上,听着耳机中Michael的歌声,渐渐陷入了沉思……
我想起了小学的数学老师,一个大善人。记得她曾经在课上给我们讲她带着我们班的几个差生把从市场买回来的鲫鱼带到河边放生。我不知道为什么会想到她,不过心中的失落感总是有的,那段时光已经过去好久了。而我的老师那时候最推崇的就是“真善忍”。但我知道从她的角度看来,这并不是错的。
突然,自己又“回到”了初中的团部办公室,老师正用那个刚戳盖那个绿色的团员证。那是刚刚中考完毕,要转团的关系,而我那时候发现自己最初是忘记搞定这个绿色的本本了。说来也许有点讽刺,我现在反而想不明白自己为什么要入团。
“你前门,我中门,你后门”。高中放学时跟两位死党一起挤车的日子还是挺快乐的。虽然哥几个住的地方并不相近,但配合起来还是挺顺手的。不知你还记得曾经的红黄相间的大通道的公交车吗?那已经成为了回忆的一部分了。
“别等到一千年以后……”站在苟各庄的一户农家院的二层楼顶,感受着迎面拂来的晨风。秋天的旅游让人难得的心旷神怡。那次算是第一次真正的喝醉了。
恩,是该回来了。车也快到站了。也许是真的老了,这些零星的回忆总是给自己一种莫名的寂寞,渐渐地由寂寞过度到向往。人总是在失去之后才懂得珍惜,这句话真的很对。
posted @ 2009-10-01 23:35 blacktear 阅读(18) 评论(0) 编辑
  2009年9月8日
    最近收到一个任务,有N个数据,然后通过一个第三方的Web API对数据进行处理,并记录下处理的结果。初想起来,这个感觉很容易就能解决,比如用python写一个脚本,通过httplib库调用第三方的Web API,然后获取结果并记录。代码可能看起来像这样:
1def getAPIResult(somedata):
2    conn = httplib.HTTPConnection('www.host.com')
3    conn.request('GET''/path/?arg1=' + somedata + '&arg2=value2')
4    resp = conn.getresponse()
5    data = resp.read()
6    conn.close()
7    return processResultData(data)
    现在的网络质量已经很好了,不过对于网络来说,发生超时错误或者是因为某种特殊原因而导致的请求失败还是有发生的可能的。因此,如果直接调用上面的getAPIResult函数其本身是不负责任的。也许你的程序会因为网络超时而崩溃。
    对于很少的数据量来说,我们可以忽略网络质量问题所导致的错误,但是当N非常大的时候呢?如果一个程序,跑了一段时间,结果在最后一秒钟因为网络问题崩溃了,你是什么心情?关于处理网络质量问题的解决方法很简单,就是重试。想想看,平时某个页面第一次打不开,你会做什么?单击刷新按钮吧?(这里不考虑你不想看这个页面的情况)如果刷新了好几次都没能打开,你可能就离开这个页面了——因为这个页面根本没法看。
    把上面的情况放在程序里,代码多半会看起来像这样:
1def getAPIResultWithRetry(somedata):
2    for i in range(5):
3        try:
4            return getAPIResult(somedata)
5        except:
6            print "retry"
7    #The service must crashed!
    这里用了上面的getAPIResult函数。这里我们就是捕获所有的异常,然后重试一次。不过总共重试5次,这样可以避免如果第三方的服务器当掉我们的程序还在傻傻地重试。当然,5次重试过后,你可能会有自己的想法,不过我个人觉得抛出一个异常可能更合适,毕竟第三方的服务器当掉的话,程序再怎么运行,结果也是不正确的。
    最后,如果处理的数据比较多,那么对结果进行记录的过程最好能在处理过程中逐步地记录,即使程序崩溃了,前面处理好的数据也会保存在结果文件中,这样就不会丢失之前已经处理过的结果了。当然,如果当程序出问题时,能告诉显示器面前的人程序已经处理到哪里了更好。
posted @ 2009-09-08 16:56 blacktear 阅读(198) 评论(0) 编辑
  2009年7月22日
摘要: Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 最近正在读云风的《游戏之旅》,看着看着就读到了A*寻路算法,虽然以前没有接触过,但总觉得好奇。于是从网上找了一些资料便开始研究。 当然,主要参考的算法文档是“http://www.vckbase.com/document/viewdoc/?id=1422&#...阅读全文
posted @ 2009-07-22 15:01 blacktear 阅读(1984) 评论(6) 编辑
  2009年6月8日
摘要: 树上的疯子阅读全文
posted @ 2009-06-08 15:24 blacktear 阅读(214) 评论(0) 编辑
  2009年5月21日
摘要: 最近在用.Net写程序时遇到一个问题:有N个互不相关的任务要在线程池中跑,但有一个线程要等待N个任务完成之后才能继续。而这个N是个未知数,可能会 很大(因此才会想到使用线程池而不是手动去new一个therad)。翻了翻.Net类库的文档,发现一个叫WaitHandle的类。这个类的用法挺有 意思,需要为每个线程创建一个WaitHandle对象并把它们放在一个数组中,然后用WaitHandle类中的...阅读全文
posted @ 2009-05-21 11:45 blacktear 阅读(1206) 评论(6) 编辑
  2009年5月19日
摘要: 最近翻出了电脑硬盘中的MP3,无意间找到了上大学音乐选修课时为考试准备的一些古典音乐的MP3,其中有一个文件夹中的文件都是Beethoven的 音乐。遂考到MP3中找些时间慢慢听。逐渐,发现自己开始喜欢上了古典交响乐,尤其是Beethoven的《第五交响曲 命运》。 一日无意在网上寻找,也许是缘分,我居然去搜索《命运》的MP3,更巧合的是我并没有找到任何可以下载的MP3,反而发现了Youku上大量...阅读全文
posted @ 2009-05-19 15:00 blacktear 阅读(77) 评论(0) 编辑
  2009年3月16日
摘要: 前两天用Python写了个小脚本,其中有个需求是从一个文本文件A中读取数据,然后处理一下写进一个新的文本文件B中。不过A文件中既有英文也有中文。写出处理这个需求的代码并不复杂,随手就能写下类似的代码:[代码]不过这段程序一旦碰到有汉字的字符串时,可能就会遇到下面的问题:Traceback (most recent call last):File "<stdin>", line 1, i...阅读全文
posted @ 2009-03-16 11:05 blacktear 阅读(1816) 评论(5) 编辑
  2009年1月6日
摘要: 最近跟个朋友的聊天,谈到了Java的Memcached客户端的问题。他提到Java的Memcached客户端的性能并不乐观,而这激起了我的兴趣。于是下载了一个MemCachedClient,开始研究。既然说它慢,但是光看源代码来进行“大脑编译运行”太累,而且还不容易找到病根,所以借助了一下JProfiler。在eclipse下写了个简单的UnitTest,不过是循环地向me...阅读全文
posted @ 2009-01-06 11:16 blacktear 阅读(1092) 评论(0) 编辑
  2008年11月26日
摘要: Ajax已经如日中天,很多Ajax的框架让我们已经能轻松享受Ajax技术的美妙。不过Ajax也有美中不足。如果我们使用jQuery的话,用Ajax进行一个异步的调用,我们会发现一个小问题,如果请求一个以GB2312编码的页面,更新后的结果就会是乱码。无论是在FF还是在IE上都是如此:[代码] 其原因在于jQuery的Ajax只支持UTF-8编码。当我们传入GB2312编码时,在解码的过程中会出现问...阅读全文
posted @ 2008-11-26 13:35 blacktear 阅读(2926) 评论(16) 编辑
昵称:blacktear
园龄:3年3个月
粉丝:0
关注:0
<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

搜索

 

常用链接

我的标签

随笔档案

YouMayNeed

最新评论

阅读排行榜

评论排行榜

推荐排行榜