xm是xen提供的在dom0中管理domU命令,主要包括xm create ,xm shutdown,xm destroy,
xm migrate(迁移)等许多命令,全部都是python脚本语言实现的。这些命令是我们在在linux的终端中输入的命令,但是实际负责功能的执行却不是这些命令,而是xen的xend服务负责执行,xend服务同样也是python脚本实现的。
带着学习python的目的,决定对xen tools(xm与xend)的脚本代码进行分析,然而这部分的代码实在太多,最终选择了其中的一个——xm create命令进行了跟踪分析。
一、xm与xend之间的链接
刚刚开始分析之前需要了解至关重要的一点,xm create负责创建虚拟机,最终却由xend服务负责完成实际的创建工作,xm与xend之间是怎么联系起来的呢?这其中利用了python的xmlrpc机制,即远程过程调用。这个xmlrpc的其中原理,br不慎了解,但是使用起来却十分方便,只需要在服务端进行注册函数或者事实例(对象),客户但通过链接之后便可以直接调用。这在后面的代码分析中一看便知。二、xm create
首先从最开始的部分开始,xm的源码:在终端运行vim /esr/sbin/xm可以看到xm代码如下:
-
#!/usr/bin/python
-
# -*- mode: python; -*-
-
import sys
-
-
from xen.xm import main
-
- main.main(sys.argv)
['/usr/sbin/xm', 'create', 'winxp.cfg']。
至于xen.xm目录的寻找,可以根据sys.path寻找。这里不多说,直接到/esr/lib64/python2.7/site-packages/xen目录,其中python2.7根据具体的python版本可能不同。在这个目录下可以看到如下内容:
__init__.py __init__.pyc lowlevel remus sv util web xend xm xsview
其中只有__init__.py和__init__.pyc是文件,其他均是目录,这里__init__.py 在这个目录,说明这个目录就是一个目录包,而__init_.pyc是由于import之后产生的,无关紧要。好了,直接就如到xm目录,xm目录下有很多.py文件,这些就是pthon脚本。找到我们需要的main.py,这就是我们在xm源码中看到的main。打开main.py,分析其中的main函数。
点击(此处)折叠或打开
-
def main(argv=sys.argv):
-
if len(argv) < 2:
-
usage()
-
-
# intercept --help(-h) and output our own help
-
for help in ['--help', '-h']:
-
if help in argv[1:]:
-
if help == argv[1]:
-
longHelp()
-
sys.exit(0)
-
else:
-
usage(argv[1])
-
-
cmd_name = argv[1]
-
cmd = xm_lookup_cmd(cmd_name)
-
if cmd:
-
# strip off prog name and subcmd
-
args = argv[2:]
-
_, rc = _run_cmd(cmd, cmd_name, args)
-
sys.exit(rc)
-
else:
-
err('Subcommand %s not found!' % cmd_name)
- usage()
点击(此处)折叠或打开
-
ef xm_lookup_cmd(cmd):
-
if commands.has_key(cmd):
-
return commands[cmd]
-
elif aliases.has_key(cmd):
-
deprecated(cmd,aliases[cmd])
-
return commands[aliases[cmd]]
-
elif cmd == 'help':
-
longHelp()
-
sys.exit(0)
-
else:
- # simulate getopt
点击(此处)折叠或打开
-
for c in IMPORTED_COMMANDS:
- commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c)
commands['create'] = eval('lambda args :xm_importcommand("%s",args)' %c),
因c = create,所以
commands['create'] = eval('lambda args:xm_importcommand(“create”,args)')。既然事抱着学习python的目的,所以这句里面的两个python的知识点还是有必要回忆一下的。
首先事lambda,这里采用了lambda args: expression这种用法。其实lambda就相当与定义了一个函数,args就是参数,后面的expression就相当与函数体(必须是表达式)。这样理解这一句就相当与:
def f(args):
return xm_importcommand("create",args)
另一方面eval也是python中的一个知识点,对表达式求值。lambda不同函数,它是表达式。在具体的需要查看资料进行补充。这里我么只需要知道,以后可以这样使用:commands[c](args).而他实际上就是等价与xm_importcommand(c,args)
从xm_lookup_cmd返回,继续回到main。继续看第19行,这里有一个关于python中下滑线的知识点,详情参见:http://blog.chinaunix.net/uid-29680694-id-4369071.html。先面我们进入到_run_cmd这个函数。先记住我们传进去的参数,对于xm create,cmd和cmd_name不用多说,而args=argv[2:](这里是深度复制)。所有,args就是我们的domU的配置文件。
点击(此处)折叠或打开
-
def _run_cmd(cmd, cmd_name, args):
-
global server
-
-
try:
-
if server is None:
-
if serverType == SERVER_XEN_API:
-
server = XenAPI.Session(serverURI)
-
username, password = parseAuthentication()
-
server.login_with_password(username, password)
-
def logout():
-
try:
-
server.xenapi.session.logout()
-
except:
-
pass
-
atexit.register(logout)
-
else:
-
server = ServerProxy(serverURI)
-
-
return True, cmd(args)
-
点击(此处)折叠或打开
-
##
-
# Configuration File Parsing
-
##
-
-
xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
-
config = None
-
if os.path.isfile(xmConfigFile):
-
try:
-
config = xml.dom.minidom.parse(xmConfigFile)
-
except:
-
print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
-
xmConfigFile)
-
print config,'main.py'
-
def parseServer():
-
if config:
-
server = config.getElementsByTagName('server')
-
if server:
-
-
st = server[0].getAttribute('type')
-
if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC:
-
print >>sys.stderr, ('Invalid server type %s; using %s.' %
-
(st, SERVER_LEGACY_XMLRPC))
-
st = SERVER_LEGACY_XMLRPC
-
return (st, server[0].getAttribute('uri'))
-
-
return SERVER_LEGACY_XMLRPC, XendClient.uri
-
-
def parseAuthentication():
-
server = config.getElementsByTagName('server')[0]
-
return (server.getAttribute('username'),
-
server.getAttribute('password'))
-
-
serverType, serverURI = parseServer()
- server = None
首先看第五行,xmConfigureFile = os.getenv(),os也是python的一个系统库,它的的getenv函数是为了获得系统的环境变量值,通常我们是没有XM_CONFIG_FILE_ENVVAR这个环境变量的,所以xmConfigureFile就等于了XM_CONFIG_FILE_DEFAULT这个默认值,即/etc/xen/ xm-config.xml
这个xml文件的内容很简单,下面就是其关键部分
点击(此处)折叠或打开
-
<xm>
-
<server type='Xen-API'
-
uri=''
-
username='me'
-
password='mypassword' />
-
-->
- </xm>
继续回到_run_cmd(),既然server=None并且serverType是“LegacyXMLRPC”,所以直接到第十七行,
server=ServerProxy(serverURI)。
这一行看起来好像很复杂,但其实我们只需要知道怎么使用的就行了。这是python中xmlrpc机制在client端的用法。首先客户端需要由一个这样的server对象,而这个server对象的创建就是通过ServerProxy(uri)来完成的,其中uri就是服务端的ip和端口。这样之后,客户端就可以通过server.xxx调用服务端注册过的函数了。