2016年11月27日日曜日

pyenv で構築した Ansible 実行環境で apt モジュールを利用するとエラーとなる事象を解決する

はじめに


この解決方法が正しいのかは、疑問が残る。
その内、正当な方法が見つかるかもしれない。

今回は、自分自身をプロビジョニングする場合に発生した事象となる。


環境


Debian 8.6 (jessie)
pyenv 1.0.2
Python 2.7.12
ansible 2.2.0.0


Ansible 実行環境の構築


ユーザは、 user1 で作業
ansible2 という名称で、python 2.7.12 の環境を定義している。
pyenv のインストール方法は、割愛。

# python のビルドに必要なパッケージをインストール
sudo aptitude install libssl-dev libbz2-dev libreadline-dev libsqlite3-dev zlib1g-dev libffi-dev
pyenv install 2.7.12
pyenv global 2.7.12
pip install --upgrade pip
pyenv virtualenv 2.7.12 ansible2
pyenv global ansible2
pip install ansible


python のパッケージ状態


(ansible2) user1@record2:~$ pip list --format=columns
Package                      Version
---------------------------- --------
ansible                      2.2.0.0
backports.ssl-match-hostname 3.5.0.1
cffi                         1.8.3
cryptography                 1.5.2
enum34                       1.1.6
idna                         2.1  
ipaddress                    1.0.17
Jinja2                       2.8  
MarkupSafe                   0.23  
paramiko                     2.0.2
pip                          9.0.1
pyasn1                       0.1.9
pycparser                    2.17  
pycrypto                     2.6.1
PyYAML                       3.12  
requests                     2.12.1
setuptools                   29.0.0
six                          1.10.0
websocket-client             0.37.0
wheel                        0.30.0a0



Ansible インベントリファイル


[localhost]
localhost
[localhost:vars]
ansible_python_interpreter=/home/user1/.pyenv/versions/ansible2/bin/python
ansible_connection=local


ansible を実行する場合に、pyenv で設定した python をデフォルトでは、利用しない。
したがって、ansible_python_interpreter に、指定する必要がある。
システム標準の python には、色々とパッケージがデフォルトでインストールされているが、pyenv の python を利用する場合には、別途パッケージをインストールする必要がある。

今回は、pip search で、見つからないパッケージが必要となったため、ソースファイルを pip に指定してインストールしているものがある。


事象


Ansible プレイブックを実行


上記状態で、apt モジュールを使用した Ansible プレイブックを実行
以下のようなエラーが発生。

failed: [localhost] (item=[u'pkg-config', u'autoconf', u'automake']) => {"failed": true, "item": ["pkg-config", "autoconf", "automake"], "msg": "Could not import python modules: apt, apt_pkg. Please install python-apt package."}


python-apt パッケージが必要だと怒られる。そりゃそうだ。

python-apt をインストール(失敗)


pip でインストールを試すが・・・

(ansible2) user1@record2:~/selfprov$ pip install python-apt
Collecting python-apt
  Using cached python-apt-0.7.8.tar.bz2
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "", line 1, in
      File "/tmp/pip-build-UZriTI/python-apt/setup.py", line 6, in
        from DistUtilsExtra.command import *
    ImportError: No module named DistUtilsExtra.command
 
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-UZriTI/python-apt/


DistUtilsExtra.command などというモジュールは無いわっ!と怒られる。

このモジュールは、どうやら python-distutils-extra パッケージをインストールすると利用できるようになるようだ。


python-distutils-extra のインストール


pip search で探すも、それらしいものがない。
aptitude search python-distutils-extra で探すと、ある。
でも、これでインストールしても、システム標準の python にインストールされるため、pyenv 環境の python にインストールすることは、できない。

しょうがないので、直接ソースファイルからインストールする。

pip install https://launchpad.net/python-distutils-extra/trunk/2.39/+download/python-distutils-extra-2.39.tar.gz


インストールに成功した。

python-apt をインストール(また失敗)


では、気を取り直して、再び python-apt をインストールしてみる。

(ansible2) user1@record2:~/selfprov$ pip install python-apt
Collecting python-apt
  Using cached python-apt-0.7.8.tar.bz2
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "", line 1, in
      File "/tmp/pip-build-RTVyKx/python-apt/setup.py", line 11, in
        string.split(parse_makefile("python/makefile")["APT_PKG_SRC"]))
      File "/home/user1/.pyenv/versions/2.7.12/lib/python2.7/distutils/sysconfig.py", line 293, in parse_makefile
        fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1)
      File "/home/user1/.pyenv/versions/2.7.12/lib/python2.7/distutils/text_file.py", line 103, in __init__
        self.open (filename)
      File "/home/user1/.pyenv/versions/2.7.12/lib/python2.7/distutils/text_file.py", line 120, in open
        self.file = open (self.filename, 'r')
    IOError: [Errno 2] No such file or directory: 'python/makefile'
 
    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-RTVyKx/python-apt/


というわけで、お約束のように失敗。
ファイルが無いという、よくわからないエラー。バグだろ・・・

ググッてもよくわからず、最新版を入れると大丈夫だという問答を見つけたので、最新版をソースからインストールしてみる。


pip install https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz


(ansible2) user1@record2:~/selfprov$ pip install https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
Collecting https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
  Using cached https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
Building wheels for collected packages: python-apt
  Running setup.py bdist_wheel for python-apt ... error
  Complete output from command /home/user1/.pyenv/versions/2.7.12/envs/ansible2/bin/python2.7 -u -c "import setuptools, tokenize;__file__='/tmp/pip-ev3yAq-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /tmp/tmpV9Cq77pip-wheel- --python-tag cp27:
  W: [python2.7] Sphinx import error.

<中略>

  gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/user1/.pyenv/versions/2.7.12/include/python2.7 -c python/acquire.cc -o build/temp.linux-x86_64-2.7/python/acquire.o
  cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
  In file included from python/acquire.cc:26:0:
  python/apt_pkgmodule.h:14:28: fatal error: apt-pkg/hashes.h: No such file or directory
   #include <apt-pkg/hashes.h>

<中略>

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/user1/.pyenv/versions/2.7.12/include/python2.7 -c python/acquire.cc -o build/temp.linux-x86_64-2.7/python/acquire.o
    cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
    In file included from python/acquire.cc:26:0:
    python/apt_pkgmodule.h:14:28: fatal error: apt-pkg/hashes.h: No such file or directory
     #include <apt-pkg/hashes.h>
                                ^
    compilation terminated.
    error: command 'gcc' failed with exit status 1


エラーが出た。
よく見ると、apt-pkg 関連のヘッダが無いのが原因のようだ。


libapt-pkg-dev をインストール


sudo aptitude install libapt-pkg-dev


python-apt をインストール(ようやく成功)


(ansible2) user1@record2:~/selfprov$ pip install https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
Collecting https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
  Using cached https://launchpad.net/python-apt/main/0.7.8/+download/python-apt-0.8.5.tar.gz
Building wheels for collected packages: python-apt
  Running setup.py bdist_wheel for python-apt ... done
  Stored in directory: /home/user1/.cache/pip/wheels/83/8c/5e/d3b5bc92348f4a5c88c8b5903d8fcdb7404cbaa4618bd79049
Successfully built python-apt
Installing collected packages: python-apt
Successfully installed python-apt-0.0.0


よし、インストール成功した。
が、バージョンが、0.0.0 になっとる。リリース前バージョンだから?
まあ、実害はなさそうなので、放置する方向で。


再び、Ansible プレイブックを実行すると、めでたく apt モジュールの実行が出来るようになる。

最初に Ansible の実行環境を作成してるときには、実は、pyenv で設定している python を利用せずに実行していることに気付かなかった。
docker モジュールを Ansible で操作しようとした時に、ようやく気づき、ansible_python_interpreter で python を切り替えたら、この現象が起こって、悶絶したものの、解決できた。

意外と難儀したが、これでようやく先に進める・・・