概述
首先我们先来看下装完ansible之后 ansible里面是些上面内容
[root@node1 scripts]# cat /bin/ansible #!/usr/bin/python # EASY-INSTALL-SCRIPT: 'ansible==2.3.4.0','ansible' __requires__ = 'ansible==2.3.4.0'
#指定库的版本 指定了要执行的脚本名字 __import__('pkg_resources').run_script('ansible==2.3.4.0', 'ansible')
发现就简单的几行代码。关于这里可以去了解一下python pkg_resources用法。
这几行代码最终会执行/usr/lib/python2.7/site-packages/ansible-2.3.4.0-py2.7.egg/EGG-INFO/scripts下面对应的脚本
上面传来的参数是ansible所以会执行ansible脚本。
所以我们直接看/usr/lib/python2.7/site-packages/ansible-2.3.4.0-py2.7.egg/EGG-INFO/scripts/ansible 文件吧
if __name__ == '__main__':
display = LastResort()
cli = None
me = os.path.basename(sys.argv[0])
try:
display = Display()
display.debug("starting run")
sub = None
###下面这一堆代码都是去找文件名字适配的,和兼容行适配的,无需大多关注
target = me.split('-')
##这里是为了去小版本号的 比如ansible-1.4.2
if target[-1][0].isdigit():
target = target[:-1]
if len(target) > 1:
sub = target[1]
myclass = "%sCLI" % sub.capitalize()
elif target[0] == 'ansible':
sub = 'adhoc'
myclass = 'AdHocCLI'
else:
raise AnsibleError("Unknown Ansible alias: %s" % me)
try:
#反射导入ansible.cli.AdHocCLI类。
mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
except ImportError as e:
if 'msg' in dir(e):
msg = e.msg
else:
msg = e.message
if msg.endswith(' %s' % sub):
raise AnsibleError("Ansible sub-program not implemented: %s" % me)
else:
raise
try:
#各种检查
args = [to_text(a, errors='surrogate_or_strict') for a in sys.argv]
###
except UnicodeError:
display.error('Command line args are not in utf-8, unable to continue.
Ansible currently only understands utf-8')
display.display(u"The full traceback was:nn%s" % to_text(traceback.format_exc()))
exit_code = 6
else:
# 此时的args[u'/usr/bin/ansible', u'jack', u'-o']
cli = mycli(args)
cli.parse()
exit_code = cli.run()
except AnsibleOptionsError as e:
cli.parser.print_help()
display.error(to_text(e), wrap_text=False)
exit_code = 5
except AnsibleParserError as e:
display.error(to_text(e), wrap_text=False)
exit_code = 4
# TQM takes care of these, but leaving comment to reserve the exit codes
#
except AnsibleHostUnreachable as e:
#
display.error(str(e))
#
exit_code = 3
#
except AnsibleHostFailed as e:
#
display.error(str(e))
#
exit_code = 2
except AnsibleError as e:
display.error(to_text(e), wrap_text=False)
exit_code = 1
except KeyboardInterrupt:
display.error("User interrupted execution")
exit_code = 99
except Exception as e:
have_cli_options = cli is not None and cli.options is not None
display.error("Unexpected Exception: %s" % to_text(e), wrap_text=False)
if not have_cli_options or have_cli_options and cli.options.verbosity > 2:
log_only = False
else:
display.display("to see the full traceback, use -vvv")
log_only = True
display.display(u"the full traceback was:nn%s" % to_text(traceback.format_exc()), log_only=log_only)
exit_code = 250
finally:
# Remove ansible tempdir
shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
sys.exit(exit_code)
下面我们看下这个类mycli.parse的源代码:
这个方法是做参数检测的,多了少了,参数不对都将会报错
def parse(self):
''' create an options parser for bin/ansible '''
self.parser = CLI.base_parser(
usage='%prog <host-pattern> [options]',
runas_opts=True,
inventory_opts=True,
async_opts=True,
output_opts=True,
connect_opts=True,
check_opts=True,
runtask_opts=True,
vault_opts=True,
fork_opts=True,
module_opts=True,
)
# options unique to ansible ad-hoc
self.parser.add_option('-a', '--args', dest='module_args',
help="module arguments", default=C.DEFAULT_MODULE_ARGS)
self.parser.add_option('-m', '--module-name', dest='module_name',
help="module name to execute (default=%s)" % C.DEFAULT_MODULE_NAME,
default=C.DEFAULT_MODULE_NAME)
super(AdHocCLI, self).parse()
#没有输入要执行的组或者ip就会报这条语句
if len(self.args) < 1:
raise AnsibleOptionsError("Missing target hosts")
#多输出了 参数也会报错,所以这个 self.args 只能等于一也就是。
elif len(self.args) > 1:
raise AnsibleOptionsError("Extraneous options or arguments")
display.verbosity = self.options.verbosity
self.validate_conflicts(runas_opts=True, vault_opts=True, fork_opts=True)
下面我们看下这个类mycli.run的源代码:
def run(self):
''' use Runner lib to do SSH things '''
###这里其实是实现了接口类。如果当前类中没有run方法就会报错了。
super(AdHocCLI, self).run()
# only thing left should be host pattern
pattern = to_text(self.args[0], errors='surrogate_or_strict')
# ignore connection password cause we are local
#这里的if判断的是执行的命令的主机是否是 local 如果是local话就不会调用远程执行命令方法了。
if self.options.connection == "local":
self.options.ask_pass = False
sshpass
= None
becomepass = None
b_vault_pass = None
self.normalize_become_options()
###从配置文件里面获取账号密码
(sshpass, becomepass) = self.ask_passwords()
passwords = { 'conn_pass': sshpass, 'become_pass': becomepass }
loader = DataLoader()
if self.options.vault_password_file:
# read vault_pass from a file
b_vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=loader)
loader.set_vault_password(b_vault_pass)
elif self.options.ask_vault_pass:
b_vault_pass = self.ask_vault_passwords()
loader.set_vault_password(b_vault_pass)
variable_manager = VariableManager()
variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options)
variable_manager.options_vars = load_options_vars(self.options)
inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory)
variable_manager.set_inventory(inventory)
no_hosts = False
#判断需要执行命令的主机,如果为0的话表示配置文件里面定义的组里面没有主机
if len(inventory.list_hosts()) == 0:
# Empty inventory
display.warning("provided hosts list is empty, only localhost is available")
no_hosts = True
inventory.subset(self.options.subset)
hosts = inventory.list_hosts(pattern)
#下面这驼if就是各种环境参数判断,这里可以忽略不管。
if len(hosts) == 0:
if no_hosts is False and self.options.subset:
# Invalid limit
raise AnsibleError("Specified --limit does not match any hosts")
else:
display.warning("No hosts matched, nothing to do")
if self.options.listhosts:
display.display('
hosts (%d):' % len(hosts))
for host in hosts:
display.display('
%s' % host)
return 0
if self.options.module_name in C.MODULE_REQUIRE_ARGS and not self.options.module_args:
err = "No argument passed to %s module" % self.options.module_name
if pattern.endswith(".yml"):
err = err + ' (did you mean to run ansible-playbook?)'
raise AnsibleOptionsError(err)
# Avoid modules that don't work with ad-hoc
if self.options.module_name in ('include', 'include_role'):
raise AnsibleOptionsError("'%s' is not a valid action for ad-hoc commands" % self.options.module_name)
# dynamically load any plugins from the playbook directory
for name, obj in get_all_plugin_loaders():
if obj.subdir:
plugin_path = os.path.join('.', obj.subdir)
if os.path.isdir(plugin_path):
obj.add_directory(plugin_path)
play_ds = self._play_ds(pattern, self.options.seconds, self.options.poll_interval)
play = Play().load(play_ds, variable_manager=variable_manager, loader=loader)
if self.callback:
cb = self.callback
elif self.options.one_line:
cb = 'oneline'
# Respect custom 'stdout_callback' only with enabled 'bin_ansible_callbacks'
elif C.DEFAULT_LOAD_CALLBACK_PLUGINS and C.DEFAULT_STDOUT_CALLBACK != 'default':
cb = C.DEFAULT_STDOUT_CALLBACK
else:
cb = 'minimal'
run_tree=False
if self.options.tree:
C.DEFAULT_CALLBACK_WHITELIST.append('tree')
C.TREE_DIR = self.options.tree
run_tree=True
# now create a task queue manager to execute the play
self._tqm = None
try:
self._tqm = TaskQueueManager(
inventory=inventory,
variable_manager=variable_manager,
loader=loader,
options=self.options,
passwords=passwords,
stdout_callback=cb,
run_additional_callbacks=C.DEFAULT_LOAD_CALLBACK_PLUGINS,
run_tree=run_tree,
)
#这里的result 就是一个退出状态码,执命令的过程都在self._tqm.run里面
result = self._tqm.run(play)
finally:
if self._tqm:
self._tqm.cleanup()
if loader:
loader.cleanup_all_tmp_files()
return result
转载于:https://www.cnblogs.com/Nolover/p/10979308.html
最后
以上就是高高毛巾为你收集整理的ansible源码分析之程序入口的全部内容,希望文章能够帮你解决ansible源码分析之程序入口所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复