2012年8月29日星期三

PyDev的Debug Console

用PyDev的远程调试器(Remote Debugger)来调试Django程序,只看到调试服务器(Debug Server)的控制台(Console)(见下图),看不到PyDev的交互式调试控制器(Interactive Debug Console):
其实可以在Console视图(View)的Open Console的按钮点击,选择PyDev Console:
在弹出的对话框选择PyDev Debug Console:
然后在Console视图的Display Selected Console选择刚刚开启的PyDev Debug Console:
这样就可以出来了,在这个Console里面可以对断点处各个Frame的状态进行检查,超实用。但是还有个问题,如果鼠标在Debug视图里面点击,Console视图就会切换到Debug Server。可以点击Console视图的Pin Console按钮:
这样Debug Console就不会被自动切换了。

2012-10-12更新:
如果在Open Console对话框不能选PyDev Debug Console:
上面写着:Start the debugger and select the valid frame。在Debug的过程中,在Debug视图选中一个Frame即可选择PyDev Debug Console了。

GCC找不到标准库

一个开发的哥们,说在开发机(CentOS)上可以编译成功的C++程序,在线上机器(Ubuntu)上就不行。我发现是链接不了pthread库,而这个库是安装了的。然后另一个和他一起的哥们,来抱怨Ubuntu的动态库路径不标准。

我在自己的Ubuntu桌面上写的多线程的C程序,又编译了一下是没有问题的啊。后来他发现是应该把动态库放到编译命令行的最后。原来是:
g++ $(INCLUDE) $(CPPFLAG) -g $(LLIB) -o $(OBJ) $^
改成下面的就好了:
g++ $(INCLUDE) $(CPPFLAG) -g -o $(OBJ) $^ $(LLIB)
我又回忆起这是一个C的FAQ。我的Makefile里面-lm -pthread是写到最后的,所以没有问题。

2012年8月27日星期一

SSH批处理执行命令的问题

要在多个主机上执行一个命令,可以用Bash来循环。比如主机名在一个叫hosts的文件里面:
db14
db15
srv06
...
用一个while循环执行结果如下:
$ while read -r host; do ssh $host hostname; done < hosts
db14
只在第一个服务器执行后就退出了。但是这样执行(不推荐):
for host in `cat hosts`; do ssh $host hostname; done
是可以遍历所有服务器的。为什么呢?请先自行思考还再看下面的答案。

经过诊断,是SSH吃掉了标准输入的内容。while循环的标准输入被定向到了hosts文件,< hosts0< hosts的简写,0是该Shell进程的标准输入的文件描述符。注意这里0<之间不能有空格。

类似的问题,曾经在两个脚本里面遇到需要解决,我是让外层循环的标准输入用一个非默认的文件描述符,比如用3的话命令改成这样运行:
while read -u 3 -r host; do ssh $host hostname; done 3< hosts
同时要让read从这个文件描述符来读取内容。或者让SSH不要读取任何内容:
while read -r host; do ssh $host hostname </dev/null; done < hosts
其实SSH已经有这样的选项了,-n即是,所以也可以如下写:
while read -r host; do ssh -n $host hostname; done < hosts

2012年8月22日星期三

Python的文档

程序出了bug。我用rstrip('.py')来去掉文件名的扩展名,但是下面这个结果却出乎意料:
In [6]: 'gt_php.py'.rstrip('.py')
Out[6]: 'gt_ph'
在IPython里面用rstrip?看不到为啥,查Python的官方文档,原来'.py'不是当后缀来处理的,而是从后往前碰到的'.', 'p''y'都会去掉,所以会有上面的结果。

前不久用os.path.join的时候碰到该函数一个诡异的行为,在docstring里面没有说明,在官方文档上才有详细解释。看来docstring还是不完全,要记得查看官方文档。

KVM的桥接网络

按照官方文档在Ubuntu下安装KVM及虚拟机,竟然出奇地顺利。网络自然是桥接(bridge)爽啦,但是在办公室DHCP环境下不能保证虚拟机和宿主机都是固定IP。然后竟然发现即使虚拟机是DHCP,桥接情况下可以从宿主机直接通过虚拟机的主机名来访问。要做的是把libvirt的IP地址:
$ ip a s virbr0
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 2e:7f:c8:81:58:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
192.168.122.1放到宿主机DNS服务器的第一个即可。具体可在宿主机interfaces文件的br0或者eth0配置中增加一行:
dns-nameservers 192.168.122.1 192.168.0.2 192.168.0.3
相关支持参见resolvconf(8)

2012年8月20日星期一

神秘的Cron任务

周末晚上需要暂停一个用cron定期运行来监控SSH Tunnel连通性的脚本。但是无论我把脚本去掉执行权限,还是把脚本改名,最后把Crontab里面的任务删除掉,我的邮箱还是每隔10分钟就收到一封报警邮件,仿佛是一个藏在暗处的幽灵在捉弄我,我都快要抓狂了。

后来用ps发现有好几个脚本进程在运行,把这些进程一一杀死后邮箱才安静了。我分析是脚本运行的(超时)时间太长,在10分钟内没有结束,导致不断积压监控脚本的进程。尽管已经停止了cron任务,但是这些进程还在,它们超时结束的时间间隔也会是10分钟,所以还会以10分钟的间隔发出邮件,让我看起来似乎是cron任务还在运行。

搜了一下类似的情况也有发生,可以用GNU的timeout命令来解决。

2012年8月18日星期六

Python中的*和**

这里说的***不是乘法和次幂的运算符,而是函数定义中的形参(parameters)和函数调用中的实参(arguments)。

文档中把它们的用法很简洁得说清楚了。怎么记住***在函数定义和函数调用时的区别呢?简单地概况,就是“定义的压缩,调用的解开”。
  • 若出现在函数定义中,则实际调用时把接收的一串arguments或keyword arguments,压缩成元组或者字典
  • 如出现在函数调用中,则把接收的iteratable或者mapping,解开为一串arguments或者keyword arguments
在下面这个没有做任何装饰的装饰器里面:
def decorator(target):
    def caller(*args, **kwargs):
        return target(*args, **kwargs)
    return caller
可以看到放在定义和调用时的区别。

2012年8月8日星期三

SSH的公钥登录问题

今天公司有个妹纸的Git不能用了,提示输入密码。我查了Gitosis配置没问题,再去找她,原来她自己照着从网上搜来的一篇博文搞公钥登录,没有搞成。

Git不能用,那就说明Gitosis中的公钥和客户端的私钥不配对,她的确承认应该是把私钥搞乱了。折腾好几次,SSH的公钥登录就是不成功,服务器提示输入密码。最后试着把服务器上她的authorized_keys文件的权限由664改为600,然后就可以了。这个文件别人的确是不应该有写权限的,否则会有安全问题,不过SSH的文档里面貌似没有说权限错误会拒绝登录。

郁闷的是该同学开始没告诉我自己做了什么操作,害我从Gitosis的配置查起,后来才告诉我自己折腾了什么。