2012年9月25日星期二

Django模板的forloop出错

在Django模板的for循环中用了一句:
 {% if not forloop.last %}
出错了:
Exception Type: UndefinedError
Exception Value: 'forloop' is undefined
Google搜索未解,再看出错信息:
Exception Location: /usr/local/lib/python2.7/dist-packages/jinja2/environment.py in getattr, line 372

原来用的是Jinja2。加上Jinja再搜索找到了文档,原来Jinja2里面forlooploop,把forloop改为loop就好了。

2012年9月1日星期六

NetworkManager和Upstart

Ubuntu桌面下,网络是由NetworkManager管理的。NM很好用,但是有时要配置复杂网络,只能用interfaces等网络配置文件搞定。

我给eth0设置了静态IP,用于办公室环境(其实也是DHCP网络)。回家之后这个静态IP得不到,开机的时候会等待2分钟时间让网络起来,先显示:
Waiting for network configuration...
1分钟后是:
Waiting up to 60 more seconds for network configuration...
最后是:
Booting system without full network configuration...
这在Launchpad上有N个bug报告。之后进入Ubuntu,interfaces文件没有生效,而且NM都没自动启动呢。来分析一下这个问题。

现在的Ubuntu在/etc/init.d下,System V Init任务和Upstart任务都有。如果是Upstart任务,则都链接到/lib/init/upstart-job,如NM:
tux@macbook:/etc/init.d(0)$ ls -l network-manager
lrwxrwxrwx 1 root root 21 May 25 12:01 network-manager -> /lib/init/upstart-job
开始我看到NM在/etc/rc?.d下没有启动脚本,就用update-rc.d创建了链接,但还是不能自动启动。后来才明白Upstart任务的启动和停止控制不在/etc/rc?.d目录下,而是在/etc/init目录。NM的配置文件为/etc/init/network-manager.conf。里面有:
start on (local-filesystems
      and started dbus
      and static-network-up)
就是说NM要在local-filesystem, dbusstatic-network-up之后才会启动,而这个Upstart Event(事件)应该是要在interfaces中的网络接口启用之后才会发生(Emit)。所以如果interfaces文件失效,NW也起不来。

那么开机等待的两分钟在哪里配置的呢?看了这个文章后才知道,是在/etc/init/failsafe.conf里面配置的。具体看该文件可以知道个大概。

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)