我是靠谱客的博主 高高毛巾,最近开发中收集的这篇文章主要介绍ansible源码分析之程序入口,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

首先我们先来看下装完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源码分析之程序入口所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部