如果在Docker容器中运行ansible_spec时遇到错误
如果在Docker容器内执行ansible_spec时出现错误。
首先
在使用Docker进行Ansible开发和编写测试代码的过程中,遇到以下错误并陷入困境,因此会记录下来作为备忘。
$ bundle exec rake all
rake aborted!
NoMethodError: private method `select' called for nil:NilClass
/workspace/rakefile:6:in `<top (required)>'
/usr/local/rbenv/versions/2.6.1/bin/bundle:23:in `load'
/usr/local/rbenv/versions/2.6.1/bin/bundle:23:in `<main>'
(See full trace by running task with --trace)
环境
首先,使用Windows 10 + Docker for Windows,通过容器内的方式开发Ansible。
将Ansible的定义文件放置在Windows磁盘上,并通过卷挂载将其挂载到容器中。
Ansible的目录结构
$ tree
.
|____.ansiblespec
|____.rspec
|____Gemfile
|____Gemfile.lock
|____group_vars
| |____webserver.yml
|____hosts
|____Rakefile
|____README.md
|____roles
| |____configure_nginx
| | |____spec
| | | |____configure_nginx_spec.rb
| | |____tasks
| | | |____main.yml
| | |____templates
| | | |____nginx.conf.j2
| |____install_nginx
| | |____spec
| | | |____install_nginx_spec.rb
| | |____tasks
| | | |____main.yml
|____site.yml
|____spec
| |____spec_helper.rb
导致这个问题的原因是什么?
由于存货文件 hosts 具有执行权限,因此发生错误。
当将 Windows 目录挂载为卷时,权限将变为 777,
ansible_spec 会错误地将其视为动态清单而出错。
$ # 今回のインベントリーファイルは静的インベントリーです。
$ ls -l hosts
-rwxrwxrwx 1 root root 17 Jun 22 10:37 hosts
$ cat hosts
[webserver]
127.0.0.1
处理
将Ansible文件完全复制到容器内,并将hosts权限设置为644。
由于完全复制会很麻烦,所以部分采用符号链接。
mkdir -p /tmp/ansible
cp -p /workspace/hosts /tmp/ansible
chmod 644 /tmp/ansible//hosts
ln -s /workspace/site.yml /tmp/ansible/site.yml
ln -s /workspace/Gemfile /tmp/ansible/Gemfile
ln -s /workspace/Gemfile.lock /tmp/ansible/Gemfile.lock
ln -s /workspace/Rakefile /tmp/ansible/Rakefile
ln -s /workspace/group_vars /tmp/ansible/group_vars
ln -s /workspace/roles /tmp/ansible/roles
ln -s /workspace/spec /tmp/ansible/spec
ln -s /workspace/.ansiblespec /tmp/ansible/.ansiblespec
ln -s /workspace/.rspec /tmp/ansible/.rspec
cd /tmp/ansible
原因的细节
看一下堆栈跟踪。
$ bundle exec rake all --trace 2>&1 | head
rake aborted!
NoMethodError: private method `select' called for nil:NilClass
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/ansible_spec-0.3.1/lib/ansible_spec/load_ansible.rb:133:in `get_dynamic_inventory'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/ansible_spec-0.3.1/lib/ansible_spec/load_ansible.rb:24:in `load_targets'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/ansible_spec-0.3.1/lib/ansible_spec/load_ansible.rb:425:in `get_properties'
/workspace/rakefile:6:in `<top (required)>'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_module.rb:29:in `load'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_module.rb:29:in `load_rakefile'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/application.rb:703:in `raw_load_rakefile'
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/application.rb:104:in `block in load_rakefile'
逐一从上到下进行检查,本次与之相关的是这部分。
/usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/ansible_spec-0.3.1/lib/ansible_spec/load_ansible.rb 第24行:在`load_targets`函数中
當查看相應的源代碼時,可以在第23行檢查 inventory 文件是否具有執行權限。
$ cat -n /usr/local/rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/ansible_spec-0.3.1/lib/ansible_spec/load_ansible.rb | head -n 30
1 # -*- coding: utf-8 -*-
2 require 'hostlist_expression'
3 require 'oj'
4 require 'open3'
5 require 'yaml'
6 require 'inifile'
7 require 'ansible_spec/vendor/hash'
8 if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1')
9 require 'ansible/vault'
10 end
11
12 module AnsibleSpec
13 # param: inventory file of Ansible
14 # param: return_type 'groups' or 'groups_parent_child_relationships'
15 # return: Hash {"group" => ["192.168.0.1","192.168.0.2"]}
16 # return: Hash {"group" => [{"name" => "192.168.0.1","uri" => "192.168.0.1", "port" => 22},...]}
17 # return: Hash {"pg" => ["server", "databases"]}
18 def self.load_targets(file, return_type = 'groups')
19 if not ['groups', 'groups_parent_child_relationships'].include?(return_type)
20 raise ArgumentError, "Variable return_type must be value 'groups' or 'groups_parent_child_relationships'"
21 end
22
23 if File.executable?(file)
24 return get_dynamic_inventory(file)
25 end
26 f = File.open(file).read
27 groups = Hash.new
28 group = ''
29 hosts = Hash.new
30 hosts.default = Hash.new
这是为了判断动态库存而进行的操作,由于这次的hosts文件是静态库存,所以只需取消执行权限即可。
废话
如果现在是的话,我本可以在WSL2上进行开发,但是用于工作的Windows设备还没有支持WSL2的版本,所以我做了这样的事情。
我尽力搜索了,但是没有找到太多有用的信息,希望有类似经历的人可以受益。
如果我有Ruby等相关技能,可能就不会遇到这样的困境了。