如果在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等相关技能,可能就不会遇到这样的困境了。

广告
将在 10 秒后关闭
bannerAds