2010-10-27

导出Google Apps里所有的用户组和组员

Google Apps的管理功能很不错,但用户组多了不好管理,时常要拿出来晒晒,调整一下结构。这就经常需要把所有组和组员列出来,幸亏Google提供了API,懒人的办法就是用脚本搞定。下面是python示例,输出比较简单。知道了如何做,你可以自己改成输出csv或者任何其他格式,都会容易。多说无益,上代码。

#!/usr/bin/env python
# Author: xieyanbo@gmail.com
# dump_google_apps_mail_groups.py
# export mail groups and group members from Google Apps service

import gdata.apps.groups.service

def print_all_members(email, domain, password):
group_service = gdata.apps.groups.service.GroupsService(email=email,
domain=domain, password=password)
group_service.ProgrammaticLogin()

def print_members(group_id):
for user in group_service.RetrieveAllMembers(group_id):
print user['memberId']

def shrink(str, max=20):
if not str:
return ''
str = str.replace('\n', ' ').strip().decode('utf8')
if len(str) > max:
short = str[:max-3] + '...'
else:
short = str
return str.encode('utf8')

def print_groups(groups):
for group in groups:
gid = group['groupId']
print '%s, %s, %s' % (gid, group['groupName'],
shrink(group['description']))
print '='*60
print_members(gid)
print

groups = group_service.RetrieveAllGroups()
print_groups(groups)

def main():
from optparse import OptionParser
parser = OptionParser()

parser.add_option('-e', '--email')
parser.add_option('-d', '--domain')
parser.add_option('-p', '--password')
options, args = parser.parse_args()

if not options.email:
parser.error('need email address to login')
if not options.domain:
parser.error('need domain to login')
if not options.password:
import getpass
password = getpass.getpass('Password: ')
else:
password = options.password or login
print_all_members(options.email, options.domain, password)

if __name__ == '__main__':
main()

2010-07-07

在Gentoo里调试新软件包

最近又开始研究web测试的技术,迷上了西门子开发的robot framework。不过服务器用的Gentoo上还没有这东西,只好自力更生。所以先记录一下给Gentoo添加新软件包的过程,下次也好照抄,以后再说robot framework有多好。

Gentoo的包管理器叫做Portage,描述文件叫Portfile。现在的portage很讲究目录结构,就是Gentoo里的PORTDIR structure,所谓category。robot framework是用python开发的,照例是在dev-python下的某个目录中。没想到的是,现在ebuild对目录的检查很严格,即使在调试时安装本地的portfile也要遵循该结构:
mkdir -p dev-python/robotframework
mv robotframework-2.5.ebuild dev-python/robotframework/
cd dev-python/robotframework


然后利用底层的ebuild包管理命令,对本地包生成数字摘要、测试安装和部署:
sudo ebuild robotframework-2.5.ebuild digest
sudo ebuild robotframework-2.5.ebuild install
sudo ebuild robotframework-2.5.ebuild qmerge

digest是最近新增加的指令?有这个命令省事多了,调试起来很happy。

调试过程需要反复修改,得删除已经用qmerge安装到系统目录中的文件,以及portfile的缓存:
sudo emerge -C robotframework-2.5
sudo rm -rf /var/tmp/portage/dev-python/robotframework-2.5/


把dev-python/robotframework和dev-python/robotframework-seleniumlibrary向Gentoo提交了,不知道审核要多久。

完。

2009-04-26

请,给点提示吧,bitten

一直在用bitten做集成测试,效果挺好,现在天天离不了它。不过最近被它搞的很郁闷,因为bitten-slave吐出一行神秘的错误信息:
[DEBUG   ] Sending POST request to 'https://mytrac.com/build/5632/steps/'
[WARNING ] Server returned error 403: Forbidden
[ERROR ] HTTP Error 403: Forbidden

起因是因为最近升级了bitten,顺便想把以前的单个进程拆成多个,加快一下bitten的执行速度。人家说,一个和尚有水吃,两个和尚抬水吃,三个和尚没水吃,没想到软件也是这样。两个slave一块跑起来,就有了问题:有时这个出错,有时那个出错,提示都是神秘的403。观察了一下,出现错误的时候,都是某slave A先执行,B稍后也开始执行,然后A再次向服务器POST数据就会出错。猜测可能用户之间有冲突,试过了几种方式,使用各自独立的用户名,在不同目录执行,在不同机器执行,但问题依旧。今天费了些力气,把bitten的代码跟踪了半天,发现程序调用了这个函数
    def reset_orphaned_builds(self):
"""Reset all in-progress builds to ``PENDING`` state if they've been
running so long that the configured timeout has been reached.

This is used to cleanup after slaves that have unexpectedly cancelled
a build without notifying the master, or are for some other reason not
reporting back status updates.
"""

幸亏代码里有注释,这才恍然大悟,原来是timeout参数在作怪。进入trac管理界面,把timeout从10秒调高到500秒,总算解决了问题。

实际上,在bitten描述客户端协议的文档中,已经指出了这一问题:
To handle the case of build slaves going away at some point between having created a build and completing the build, the build master should have a configurable timeout. All in-progress builds would be checked against this timeout; if there has been no activity on the build for an amount of time exceeding the timeout, the master should cancel the build, resetting it the PENDING state. If a slave later does decide to come back to life and post results, it would get 404 (Not Found) or 409 (Conflict) errors, and should cancel the build on its side, too.

但由于未明的原因,bitten的实现用403代替了404、409,并且没有给出进一步的提示信息。要是bitten-slave能打印一条附加信息,告诉我403的原因可能跟timeout设置有关系,那该多好呀。

这个故事告诉我们,别嫌提示信息废话太多,能多写一点是一点,不定什么时候它就会节省自己和别人的若干时间。折腾了三天以后,我现在太喜欢话唠的软件啦。

2007-11-30

用于django中的缓存decorator

myproject/decorators.py代码:
from django.core.cache import cache

def cached(cache_key='', timeout_seconds=1800):
def _cached(func):
def do_cache(*args, **kws):
if isinstance(cache_key, str):
key = cache_key % locals()
elif callable(cache_key):
key = cache_key(*args, **kws)
data = cache.get(key)
if data: return data
data = func(*args, **kws)
cache.set(key, data, timeout_seconds)
return data
return do_cache
return _cached
只能用于静态数据的缓存,如果需要对connection.cursor等对象进行缓存,那需要函数本身做更多的处理,不是这个decorator要解决的问题。

使用范例1,简单的cache key:
from myproject.decorators import cached

class MenuItem(models.Model):
@classmethod
@cached('menu_root')
def get_root(self):
return MenuItem.objects.get(pk=1)

使用范例2,cache key需要根据调用参数来决定:
@cached(lambda u: 'user_privileges_%s' % u.username, 3600)
def get_user_privileges(user):
#...

使用范例3,需要只对直接调用者做缓存,递归的调用不需要,那么把要递归函数独立出来:
class MenuItem(models.Model):
@cached(lambda s,u: 'user_menu_%s_%s' % (u.username, s.id), 3600)
def permit_menu_items(self, user):
return self._permit_menu_items(user)

def _permit_menu_items(self, user):
items = []
for mi in self.children():
items += [n for n in mi._permit_menu_items(user)]
return items

使用范例4,返回结果中部分需要做缓存的,首先把要缓存的部分extract出来,然后对其应用缓存机制:
class Report:
def get_summary(self, day, path='', sort='path', type='daily'):
data = self._get_summary(day, path, type)
# sort ...
return data

@cached(lambda s,d,p,t:'summary_%s_%s_%s'%(d,p,t), 3600*24)
def _get_summary(self, day, path='', type='daily'):
#...

2007-11-16

人们研究android的热情高涨

短短一天时间,又有很多新情况发生。

首先,有人测试了汉字的显示,发现可以支持。我也在模拟器里试了一下,确实很容易。系统内带了几种字体,其中有一款支持CJK字符。

其次,有人成功编译了c版本的hello world,并执行成功。使用的是arm的编译器。而且还编译了全功能的busybox,可以安装到模拟器的系统中。

另外,已经有人成功编译linux放入android模拟器中运行。

邮件列表里很多人都在打听、讨论能不能用C/C++/Python/Ruby之类的语言代替java来开发。今天去jython的项目主页看了看,惊奇的发现项目复苏了,jython 2.2已经正式发布。期待高手把jython打包集成进android吧。