接xm create 命令解析(一),这次该执行到return True,cmd(args).
通过上一篇博文的分析,这里我们已经知道了cmd在这里等于什么了。这里cmd(args)就是等于xm_importcommand(c,args),想必这里的c都能猜出来了——既然是create,那c当然就等于‘create’了,args就是我们在执行xm create命令事传递进来的参数,如果事xm create xxx.cfg,这里的args就是xxx.cfg,只不过是一列表的形式存在。
二、xm_importcommand(c,args)
到了这里,我们该分析xm_importcommand(c,args)这个函数了,函数定义还是在main.py文件中,源码如下:
点击(此处)折叠或打开
-
def xm_importcommand(command, args):
-
cmd = __import__(command, globals(), locals(), 'xen.xm')
- cmd.main([command] + args)
__import__( name[, globals[, locals[, fromlist]]])这个函数用于动态导入模块(或者包)。作用与import和from xxx import xxx相同,与二者不同的事,import可以动态导入,即在程序执行到该语句时再导入。比如我们可以动态的导入模块module=__import(modle_name),等价与import module_name。这些都不是难点,这个函数比较难理解的地方在与它的第四个参数:fromlist,本人在网上查找资料最终得出的结论是:fromlist和name一起搭配,用于实现from xxx import yyy的形式,这里yyy就是这里的fromlist,而xxx就充当name。比如cmd = __import__('xen.xm',globals(),locals(),'create')就等价与from xen.xm import create,然而实际上却不是如此,__import__这一句只能返回的只是xen.xm,得不到xen.xm.create。至于具体的原因如下:
- This function is invoked by the import statement. It mainly exists so that you can replace it with another function that has a compatible interface, in order to change the semantics of the import statement. For examples of why and how you would do this, see the standard library modules ihooks and rexec. See also the built-in module imp, which defines some useful operations out of which you can build your own __import__() function.
-
- For example, the statement "import spam" results in the following call: __import__('spam', globals(), locals(), []); the statement "from spam.ham import eggs" results in "__import__('spam.ham', globals(), locals(), ['eggs'])". Note that even though locals() and ['eggs'] are passed in as arguments, the __import__() function does not set the local variable named eggs; this is done by subsequent code that is generated for the import statement. (In fact, the standard implementation does not use its locals argument at all, and uses its globals only to determine the package context of the import statement.
- When the name variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned, not the module named by name. However, when a non-empty fromlist argument is given, the module named by name is returned. This is done for compatibility with the bytecode generated for the different kinds of import statement; when using "import spam.ham.eggs", the top-level package spam must be placed in the importing namespace, but when using "from spam.ham import eggs", the spam.ham subpackage must be used to find the eggs variable. As a workaround for this behavior, use getattr() to extract the desired components. For example, you could define the following helper:
- def my_import(name):
- mod = __import__(name)
- components = name.split('.')
- for comp in components[1:]:
- mod = getattr(mod, comp)
- return mod
了解了这些之后,在回来看xm_importcommand()代码,我们就明白了,cmd=__import__(command,globals(),locals(),'xen.xm')返回的就是create,而这里的fromlist参数"xen.xm",大概就是起到注释的作用吧。
再次回到xm_importcommand()这个函数,现在看第而行,就很明显了,这里调用的是xen.xm.create模块中的main函数,下面我们将进入到create.py这个模块中来看一看。
三、create.py模块
按照调用关系,在main.py模块中,调用的是create.py的main函数,所以我们从main函数开始分析。
-
def main(argv):
-
is_xml = False
-
try:
-
(opts, config) = parseCommandLine(argv)
-
except StandardError, ex:
-
err(str(ex))
-
if not opts:
-
return
-
if not opts.is_xml:
-
if type(config) == str:#type() judge the variable's type
-
# here config's type is list
-
-
try:
-
config = sxp.parse(file(config))[0]
-
except IOError, exn:
-
raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
-
if serverType == SERVER_XEN_API:
-
from xen.xm.xenapi_create import sxp2xml
-
sxp2xml_inst = sxp2xml()
-
doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
-
-
if opts.vals.dryrun and not opts.is_xml:
-
SXPPrettyPrint.prettyprint(config)
-
-
if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
-
print doc.toprettyxml()
-
-
if opts.vals.dryrun or opts.vals.xmldryrun:
-
return
-
-
if opts.vals.console_autoconnect:
-
do_console(sxp.child_value(config, 'name', -1))
-
-
if serverType == SERVER_XEN_API: #serverType == SERVER_LEGACY_XMLRPC
-
from xen.xm.xenapi_create import xenapi_create
-
xenapi_create_inst = xenapi_create()
-
if opts.is_xml:
-
vm_refs = xenapi_create_inst.create(filename = config,
-
skipdtd = opts.vals.skipdtd)
-
else:
-
vm_refs = xenapi_create_inst.create(document = doc,
-
skipdtd = opts.vals.skipdtd)
-
-
map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
-
elif not opts.is_xml:
-
dom = make_domain(opts, config)
-
-
if opts.vals.vncconsole:
-
domid = domain_name_to_domid(sxp.child_value(config, 'name', -1))
-
vncviewer_autopass = getattr(opts.vals,'vncviewer-autopass', False)
- console.runVncViewer(domid, vncviewer_autopass, True)
知道了这个函数的功能,下面就来看一看这个蛋疼的函数。
-
def parseCommandLine(argv):
-
gopts.reset()
-
args = gopts.parse(argv)
-
if gopts.vals.help or gopts.vals.help_config:
-
if gopts.vals.help_config:
-
print gopts.val_usage()
-
return (None, None)
-
-
if not gopts.vals.display:
-
gopts.vals.display = os.getenv("DISPLAY")
-
-
if not gopts.vals.xauthority:
-
gopts.vals.xauthority = get_xauthority()
-
-
gopts.is_xml = False
-
for arg in args:
-
if '=' in arg:
-
(var, val) = arg.strip().split('=', 1)
-
gopts.setvar(var.strip(), val.strip())
-
if gopts.vals.config:
-
config = gopts.vals.config
-
else:
-
try:
-
gopts.load_defconfig()
-
preprocess(gopts.vals)
-
if not gopts.getopt('name') and gopts.getopt('defconfig'):
-
gopts.setopt('name', os.path.basename(gopts.getopt('defconfig')))
-
config = make_config(gopts.vals)
-
except XMLFileError, ex:
-
XMLFile = ex.getFile()
-
gopts.is_xml = True
-
config = ex.getFile()
-
- return (gopts, config)
根据gopts的定义:
-
gopts = Opts(use="""[options] [vars]
-
-
Create a domain.
-
-
Domain creation parameters can be set by command-line switches, from
-
a python configuration script or an SXP config file. See documentation
-
for --defconfig, --config. Configuration variables can be set using
-
VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
-
- """)