AnsibleでCentOS6のeasy_installが失敗する時はcommandモジュールを使う

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。 CentOS6とAnsibleでちょっとハマったので共有します。

AmazonLinux以外でAWS CLIをインストールする場合、pipでインストールするのが基本です。 pipはeasy_installでインストールできるので、コマンドは次のようになります。

$ sudo easy_install pip
$ sudo pip install awscli

これをAnsibleのタスクで定義すると次のようになります。

- name: pip installed
  easy_install:
    name: pip
- name: awscli installed
  pip:
    name: awscli

ところが、CentOS6で、このPlaybookは失敗します。

TASK [aws/awscli : pip installed] **********************************************
fatal: [test.centos]: FAILED! => {"changed": false, "failed": true, "msg": "/usr/lib64/python2.6/distutils/dist.py:266: UserWarning: Unknown distribution option: 'python_requires'\n  warnings.warn(msg)\nwarning: install_lib: 'build/lib' does not exist -- no Python modules to install\nTraceback (most recent call last):\n  File \"/usr/bin/easy_install\", line 9, in <module>\n    load_entry_point('distribute==0.6.10', 'console_scripts', 'easy_install')()\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 1715, in main\n    with_ei_usage(lambda:\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 1696, in with_ei_usage\n    return f()\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 1719, in <lambda>\n    distclass=DistributionWithoutHelpCommands, **kw\n  File \"/usr/lib64/python2.6/distutils/core.py\", line 152, in setup\n    dist.run_commands()\n  File \"/usr/lib64/python2.6/distutils/dist.py\", line 975, in run_commands\n    self.run_command(cmd)\n  File \"/usr/lib64/python2.6/distutils/dist.py\", line 995, in run_command\n    cmd_obj.run()\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 236, in run\n    self.easy_install(spec, not self.no_deps)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 472, in easy_install\n    return self.install_item(spec, dist.location, tmpdir, deps)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 502, in install_item\n    dists = self.install_eggs(spec, download, tmpdir)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 681, in install_eggs\n    return self.build_and_install(setup_script, setup_base)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 958, in build_and_install\n    self.run_setup(setup_script, setup_base, args)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/easy_install.py\", line 947, in run_setup\n    run_setup(setup_script, args)\n  File \"/usr/lib/python2.6/site-packages/setuptools/sandbox.py\", line 29, in run_setup\n    lambda: execfile(\n  File \"/usr/lib/python2.6/site-packages/setuptools/sandbox.py\", line 70, in run\n    return func()\n  File \"/usr/lib/python2.6/site-packages/setuptools/sandbox.py\", line 31, in <lambda>\n    {'__file__':setup_script, '__name__':'__main__'}\n  File \"setup.py\", line 92, in <module>\n  File \"/usr/lib64/python2.6/distutils/core.py\", line 152, in setup\n    dist.run_commands()\n  File \"/usr/lib64/python2.6/distutils/dist.py\", line 975, in run_commands\n    self.run_command(cmd)\n  File \"/usr/lib64/python2.6/distutils/dist.py\", line 995, in run_command\n    cmd_obj.run()\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/bdist_egg.py\", line 236, in run\n    dry_run=self.dry_run, mode=self.gen_header())\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/bdist_egg.py\", line 533, in make_zipfile\n    visit(None, dirname, file)\n  File \"/usr/lib/python2.6/site-packages/setuptools/command/bdist_egg.py\", line 514, in visit\n    for name in names:\nTypeError: 'instancemethod' object is not iterable\n"}

一方、SSHログインし、サーバでコマンドを実行すれば問題無くインストール可能です。

python-setuptoolsのバグっぽい

エラーメッセージからググってみると、easy_installが含まれるpython-setuptoolsのバージョンで発生するバグのようです。 したがって、python-setuptoolsをアップデートすれば対応可能です。 とはいえ、python-setuptoolsはyum管理のパッケージです。 アップデートするには他のyumリポジトリからインストールしなければならず、別のリスクもでてきます。

commandモジュールで回避する

今回のケースではコマンド実行でもバグを回避できました。 そこで、commandモジュールを利用することにします。

- name: check pip command
  stat:
    path: /usr/bin/pip
  register: _pip_stat_result
- name: install pip
  command: "easy_install pip"
  when: _pip_stat_result.stat.exists == false
- name: awscli installed
  pip:
    name: awscli

statモジュールで存在チェックを行い、存在しない場合にcommandモジュールを実行という王道パターンです。

実行してみます。

TASK [aws/awscli : command] ****************************************************
changed: [test.centos] => {"changed": true, "cmd": ["easy_install", "pip"], "delta": "0:00:02.123304", "end": "2017-02-21 09:04:11.301080", "rc": 0, "start": "2017-02-21 09:04:09.177776", "stderr": "/usr/lib64/python2.6/distutils/dist.py:266: UserWarning: Unknown distribution option: 'python_requires'\n  warnings.warn(msg)", "stdout": "Searching for pip\nReading http://pypi.python.org/simple/pip/\nBest match: pip 9.0.1\nDownloading https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz#md5=35f01da33009719497f01a4ba69d63c9\nProcessing pip-9.0.1.tar.gz\nRunning pip-9.0.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-XmjhRs/pip-9.0.1/egg-dist-tmp-Vlsxzv\nwarning: no previously-included files found matching '.coveragerc'\nwarning: no previously-included files found matching '.mailmap'\nwarning: no previously-included files found matching '.travis.yml'\nwarning: no previously-included files found matching '.landscape.yml'\nwarning: no previously-included files found matching 'pip/_vendor/Makefile'\nwarning: no previously-included files found matching 'tox.ini'\nwarning: no previously-included files found matching 'dev-requirements.txt'\nwarning: no previously-included files found matching 'appveyor.yml'\nno previously-included directories found matching '.github'\nno previously-included directories found matching '.travis'\nno previously-included directories found matching 'docs/_build'\nno previously-included directories found matching 'contrib'\nno previously-included directories found matching 'tasks'\nno previously-included directories found matching 'tests'\nAdding pip 9.0.1 to easy-install.pth file\nInstalling pip script to /usr/bin\nInstalling pip2.6 script to /usr/bin\nInstalling pip2 script to /usr/bin\n\nInstalled /usr/lib/python2.6/site-packages/pip-9.0.1-py2.6.egg\nProcessing dependencies for pip\nFinished processing dependencies for pip", "stdout_lines": ["Searching for pip", "Reading http://pypi.python.org/simple/pip/", "Best match: pip 9.0.1", "Downloading https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz#md5=35f01da33009719497f01a4ba69d63c9", "Processing pip-9.0.1.tar.gz", "Running pip-9.0.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-XmjhRs/pip-9.0.1/egg-dist-tmp-Vlsxzv", "warning: no previously-included files found matching '.coveragerc'", "warning: no previously-included files found matching '.mailmap'", "warning: no previously-included files found matching '.travis.yml'", "warning: no previously-included files found matching '.landscape.yml'", "warning: no previously-included files found matching 'pip/_vendor/Makefile'", "warning: no previously-included files found matching 'tox.ini'", "warning: no previously-included files found matching 'dev-requirements.txt'", "warning: no previously-included files found matching 'appveyor.yml'", "no previously-included directories found matching '.github'", "no previously-included directories found matching '.travis'", "no previously-included directories found matching 'docs/_build'", "no previously-included directories found matching 'contrib'", "no previously-included directories found matching 'tasks'", "no previously-included directories found matching 'tests'", "Adding pip 9.0.1 to easy-install.pth file", "Installing pip script to /usr/bin", "Installing pip2.6 script to /usr/bin", "Installing pip2 script to /usr/bin", "", "Installed /usr/lib/python2.6/site-packages/pip-9.0.1-py2.6.egg", "Processing dependencies for pip", "Finished processing dependencies for pip"], "warnings": []}

無事、pipがインストールできました。