36
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ansibleのyumにwith_itemsを指定するときの落とし穴と回避策

Last updated at Posted at 2014-07-12

以前調べたけど記事にしていなかったので、Ansible 最新版の1.6.6で再度確認した上で書いておくことにしました。

yumモジュールのname属性

Ansibleのyumモジュールのname属性には以下のものが指定可能です。

  • パッケージ名
  • name-1.0 のようにパッケージ名にパージョンを追加したもの
  • rpmファイルのURL
  • rpmファイルのローカルパス

yumモジュールのマニュアルに例が出ていますのでご参照ください。

落とし穴の例

IIJのミラーからMySQLのクライアント用のrpmをダウンロードしてインストールしようと、以下の様なplaybookを書きました。

cent65-mysql.yml
- hosts: cent65
  user: vagrant
  sudo: yes
  vars:
    mysql_download_base_url: http://ftp.iij.ad.jp/pub/db/mysql/Downloads/MySQL-5.6
    mysql_download_dest_dir: /usr/local/src
    mysql_common_rpms:
      - MySQL-shared-5.6.19-1.el6.x86_64.rpm
      - MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm
      - MySQL-client-5.6.19-1.el6.x86_64.rpm
      - MySQL-devel-5.6.19-1.el6.x86_64.rpm
  tasks:
    - file: path={{ mysql_download_dest_dir }} state=directory
    - get_url: >
        url={{ mysql_download_base_url }}/{{ item }}
        dest={{ mysql_download_dest_dir }}
      with_items: mysql_common_rpms
    - yum: name="{{ mysql_download_dest_dir }}/{{ item }}" state=present
      with_items: mysql_common_rpms

しかし、これはエラーになってしまいます。例によって ansible-playbook-vvvv オプションをつけて実行すると、ログに以下のような行がありました。

$ ansible-playbook -vvvv cent65-mysql.yml
…(略)…
<cent65> REMOTE_MODULE yum name="/usr/local/src/MySQL-shared-5.6.19-1.el6.x86_64.rpm,MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm,MySQL-client-5.6.19-1.el6.x86_64.rpm,MySQL-devel-5.6.19-1.el6.x86_64.rpm" state=present
…(略)…
failed: [cent65] => (item=MySQL-shared-5.6.19-1.el6.x86_64.rpm,MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm,MySQL-client-5.6.19-1.el6.x86_64.rpm,MySQL-devel-5.6.19-1.el6.x86_64.rpm) => {"changed": false, "failed": true, "item": "MySQL-shared-5.6.19-1.el6.x86_64.rpm,MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm,MySQL-client-5.6.19-1.el6.x86_64.rpm,MySQL-devel-5.6.19-1.el6.x86_64.rpm", "rc": 0, "results": []}
msg: No Package file matching 'MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm' found on system

yumのname属性にカンマ区切りの文字列が指定され、最初の要素は /usr/local/src/MySQL-shared-5.6.19-1.el6.x86_64.rpm とフルパスになっているのですが、2つめ以降は MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm のようにファイル名のみになっています。

上記のplaybookでは /usr/local/src/ にrpmをダウンロードしているので、これでは見つからずエラーになっているというわけです。

yumモジュールにwith_itemsを指定した場合の最適化

これはAnsibleのyumモジュールをwith_itemsと組み合わせて使うと {{ item }} の部分をwith_itemsに指定した要素をカンマで連結した値に展開して、yumを実行するようになっています。Ansibleのソースコードで言うと以下の部分です。

https://github.com/ansible/ansible/blob/v1.6.6/lib/ansible/runner/__init__.py#L618-L626
            if len(items) and utils.is_list_of_strings(items) and self.module_name in [ 'apt', 'yum', 'pkgng' ]:
                # hack for apt, yum, and pkgng so that with_items maps back into a single module call
                use_these_items = []
                for x in items:
                    inject['item'] = x
                    if not self.conditional or utils.check_conditional(self.conditional, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars):
                        use_these_items.append(x)
                inject['item'] = ",".join(use_these_items)
                items = None

通常は with_items で配列を指定した場合は、要素のそれぞれについてモジュールの処理を実行します。 apt, yum, pkgng の場合は上記のような最適化が入るのです。

回避策

with_items に文字列の配列ではなくハッシュの配列を指定すれば回避できます。

cent65-mysql.yml
- hosts: cent65
  user: vagrant
  sudo: yes
  vars:
    mysql_download_base_url: http://ftp.iij.ad.jp/pub/db/mysql/Downloads/MySQL-5.6
    mysql_download_dest_dir: /usr/local/src
    mysql_common_rpms:
      - filename: MySQL-shared-5.6.19-1.el6.x86_64.rpm
      - filename: MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm
      - filename: MySQL-client-5.6.19-1.el6.x86_64.rpm
      - filename: MySQL-devel-5.6.19-1.el6.x86_64.rpm
  tasks:
    - file: path={{ mysql_download_dest_dir }} state=directory
    - get_url: >
        url={{ mysql_download_base_url }}/{{ item.filename }}
        dest={{ mysql_download_dest_dir }}
      with_items: mysql_common_rpms
    - yum: name="{{ mysql_download_dest_dir }}/{{ item.filename }}" state=present
      with_items: mysql_common_rpms

こうすると with_items の配列の要素それぞれについて yum モジュールが実行され、エラーを回避できます。

$ ansible-playbook -vvvv cent65-mysql.yml
…(略)…
<cent65> REMOTE_MODULE yum name="/usr/local/src/MySQL-shared-5.6.19-1.el6.x86_64.rpm" state=present
…(略)…
<cent65> REMOTE_MODULE yum name="/usr/local/src/MySQL-shared-compat-5.6.19-1.el6.x86_64.rpm" state=present
…(略)…

get_urlの使い方の改善

上記のplaybookはさらに改善することができます。
Ansibleのget_urlはdestをファイル名にしてsha256sumを指定するのがお勧め - Qiitaに書きましたので、そちらをご参照ください。

36
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?