Ansibleでリモート先にsimplejsonをインストールするときのメモ

2015.02.20

はじめに

パネポン対戦者絶賛募集中の横山です。 今回はちょっとしたTipsでsimplejsonが入ってないリモート環境にAnsible+yumを使って、simplejsonをインストールメモです。

前提

今回は検証用にvagrantを使い確認しました。

準備

boxを登録します。

$ vagrant box add centos5 http://dl.dropbox.com/u/9227672/centos-5.6-x86_64-netinstall-4.1.6.box
vagrant box add centos6 http://dl.dropbox.com/u/9227672/centos-5.6-x86_64-netinstall-4.1.6.box
==> box: Adding box 'centos5' (v0) for provider:
    box: Downloading: http://dl.dropbox.com/u/9227672/centos-5.6-x86_64-netinstall-4.1.6.box
    box: Progress: 13% (Rate: 4092k/s, Estimated time remaining: 0:02:15)
==> box: Adding box 'centos5' (v0) for provider:
    box: Downloading: http://dl.dropbox.com/u/9227672/centos-5.6-x86_64-netinstall-4.1.6.box
==> box: Successfully added box 'centos5' (v0) for 'virtualbox'!

vagrant initをしてVagrantfileを作成します。

$ Vagrant init

Vagrantfileの中で先ほど追加したBoxを指定します。

$ vim Vagrantfile
# config.vm.box = "Base"
↓
config.vm.box = "centos5"

VMを起動させます。

$ vagrant up

sshの情報を~/.ssh/configに登録したら準備完了です。

$ vagrant ssh-config --host test
Host test
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/yokoyamafumihito/work/vagrant/test-centos5/.vagrant/machines/default/virtualbox/private_key
  IdentitiesOnly yes
  LogLevel FATAL
$ vagrant ssh-config --host test >> ~/.ssh/config

結果

とりあえず、紆余曲折を経てこうなりました

  • playbook.yml
- hosts: all
  sudo: True
  gather_facts: no

  tasks:
    - name: install python-simplejson
      raw: yum install -y python-simplejson
  • hosts
test
  • 実行画面
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

TASK: [install python-simplejson] *********************************************
ok: [test]

PLAY RECAP ********************************************************************
test                       : ok=1    changed=0    unreachable=0    failed=0

過程

とりあえず素直に書いた。

- hosts: all
  sudo: True
    
  tasks:
    - name: install python-simplejson
      yum: name=python-simplejson state=present
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
failed: [test] => {"failed": true, "parsed": false}
SUDO-SUCCESS-eqgrtgvmrgwqagqelneaupfktufktwse
Error: ansible requires a json module, none found!

TASK: [install python-simplejson] *********************************************
FATAL: no hosts matched or all hosts have already failed -- aborting


PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/yokoyamafumihito/playbook.retry

test                       : ok=0    changed=0    unreachable=0    failed=1

ダメだったのでshellとrawを試した。

- hosts: all
  sudo: True
    
  tasks:
    - name: install python-simplejson
      shell: yum install -y python-simplejson
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
failed: [test] => {"failed": true, "parsed": false}
SUDO-SUCCESS-gqkrwgeyymwfokfuohjxtqrrjzevgkhq
Error: ansible requires a json module, none found!

TASK: [install python-simplejson] *********************************************
FATAL: no hosts matched or all hosts have already failed -- aborting


PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/yokoyamafumihito/playbook.retry

test                       : ok=0    changed=0    unreachable=0    failed=1
- hosts: all
  sudo: True
    
  tasks:
    - name: install python-simplejson
      raw: yum install -y python-simplejson
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
failed: [test] => {"failed": true, "parsed": false}
SUDO-SUCCESS-omxeipeafvujdfetwooodupdrgatiwgb
Error: ansible requires a json module, none found!

TASK: [install python-simplejson] *********************************************
FATAL: no hosts matched or all hosts have already failed -- aborting


PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/yokoyamafumihito/playbook.retry

test                       : ok=0    changed=0    unreachable=0    failed=1

ダメでした。梶さんに相談したら AnsibleでCiscoルータのIOSバージョン情報を一括取得してみた の中でコマンドだけを投げる例があるということで参考にさせてもらった。 この時初めて、gather_factsの存在を知る。

参考

factに関しては上記がわかりやすいと思いました。

gather_factsの項目の単体実行は以下のようになります。

  • simplejsonインストール前
$ ansible all -m setup -i hosts
test | FAILED >> {
    "failed": true,
    "msg": "Error: ansible requires a json module, none found!",
    "parsed": false
}
  • simplejsonインストール後
$ ansible all -m setup -i hosts
test | success >> {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.0.2.15"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::a00:27ff:fe09:d64"
        ],
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "NA",
        "ansible_bios_version": "NA",
        "ansible_cmdline": {
            "divider": "10",
            "notsc": true,
            "ro": true,
            "root": "/dev/VolGroup00/LogVol00"
        },
        "ansible_date_time": {
            "date": "2015-02-20",
            "day": "20",
            "epoch": "1424416835",
            "hour": "02",
            "iso8601": "2015-02-20T07:20:35Z",
            "iso8601_micro": "2015-02-20T07:20:35.%fZ",
            "minute": "20",
            "month": "02",
            "second": "35",
            "time": "02:20:35",
            "tz": "EST",
            "tz_offset": "-0500",
            "weekday": "Friday",
            "year": "2015"
        },
        "ansible_default_ipv4": {
            "address": "10.0.2.15",
            "alias": "eth0",
            "gateway": "10.0.2.2",
            "interface": "eth0",
            "macaddress": "08:00:27:09:0d:64",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "10.0.2.0",
            "type": "ether"
        },
        "ansible_default_ipv6": {},
        "ansible_devices": {
            "hdc": {
                "holders": [],
                "host": "",
                "model": null,
                "partitions": {},
                "removable": "1",
                "rotational": null,
                "scheduler_mode": "cfq",
                "sectors": "8388604",
                "sectorsize": 512,
                "size": "4.00 GB",
                "support_discard": null,
                "vendor": null
            },
            "sda": {
                "holders": [],
                "host": "",
                "model": "VBOX HARDDISK",
                "partitions": {
                    "sda1": {
                        "sectors": "208782",
                        "sectorsize": 512,
                        "size": "101.94 MB",
                        "start": "63"
                    },
                    "sda2": {
                        "sectors": "20547135",
                        "sectorsize": 512,
                        "size": "9.80 GB",
                        "start": "208845"
                    }
                },
                "removable": "0",
                "rotational": null,
                "scheduler_mode": "cfq",
                "sectors": "20766720",
                "sectorsize": 512,
                "size": "9.90 GB",
                "support_discard": null,
                "vendor": "ATA"
            }
        },
        "ansible_distribution": "CentOS",
        "ansible_distribution_major_version": "5",
        "ansible_distribution_release": "Final",
        "ansible_distribution_version": "5.6",
        "ansible_domain": "ap-northeast-1.compute.internal",
        "ansible_env": {
            "HOME": "/home/vagrant",
            "LANG": "en_US.UTF-8",
            "LC_CTYPE": "en_US.UTF-8",
            "LOGNAME": "vagrant",
            "MAIL": "/var/mail/vagrant",
            "PATH": "/usr/local/bin:/bin:/usr/bin",
            "PWD": "/home/vagrant",
            "SHELL": "/bin/bash",
            "SHLVL": "2",
            "SSH_CLIENT": "10.0.2.2 56061 22",
            "SSH_CONNECTION": "10.0.2.2 56061 10.0.2.15 22",
            "SSH_TTY": "/dev/pts/1",
            "TERM": "xterm-256color",
            "USER": "vagrant",
            "_": "/usr/bin/python"
        },
        "ansible_eth0": {
            "active": true,
            "device": "eth0",
            "ipv4": {
                "address": "10.0.2.15",
                "netmask": "255.255.255.0",
                "network": "10.0.2.0"
            },
            "ipv6": [
                {
                    "address": "fe80::a00:27ff:fe09:d64",
                    "prefix": "64",
                    "scope": "link"
                }
            ],
            "macaddress": "08:00:27:09:0d:64",
            "module": "e1000",
            "mtu": 1500,
            "promisc": false,
            "type": "ether"
        },
        "ansible_fips": false,
        "ansible_form_factor": "NA",
        "ansible_fqdn": "ip-10-0-2-15.ap-northeast-1.compute.internal",
        "ansible_hostname": "ip-10-0-2-15",
        "ansible_interfaces": [
            "sit0",
            "lo",
            "eth0"
        ],
        "ansible_kernel": "2.6.18-238.el5",
        "ansible_lo": {
            "active": true,
            "device": "lo",
            "ipv4": {
                "address": "127.0.0.1",
                "netmask": "255.0.0.0",
                "network": "127.0.0.0"
            },
            "ipv6": [
                {
                    "address": "::1",
                    "prefix": "128",
                    "scope": "host"
                }
            ],
            "mtu": 16436,
            "promisc": false,
            "type": "loopback"
        },
        "ansible_machine": "x86_64",
        "ansible_memfree_mb": 843,
        "ansible_memtotal_mb": 1001,
        "ansible_mounts": [
            {
                "device": "/dev/mapper/VolGroup00-LogVol00",
                "fstype": "ext3",
                "mount": "/",
                "options": "rw",
                "size_available": 7575445504,
                "size_total": 9100992512
            },
            {
                "device": "/dev/sda1",
                "fstype": "ext3",
                "mount": "/boot",
                "options": "rw",
                "size_available": 85000192,
                "size_total": 103512064
            }
        ],
        "ansible_nodename": "ip-10-0-2-15.ap-northeast-1.compute.internal",
        "ansible_os_family": "RedHat",
        "ansible_pkg_mgr": "yum",
        "ansible_processor": [
            "GenuineIntel",
            "Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz",
            "GenuineIntel",
            "Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz",
            "GenuineIntel",
            "Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz"
        ],
        "ansible_processor_cores": 3,
        "ansible_processor_count": 1,
        "ansible_processor_threads_per_core": 1,
        "ansible_processor_vcpus": 3,
        "ansible_product_name": "NA",
        "ansible_product_serial": "NA",
        "ansible_product_uuid": "NA",
        "ansible_product_version": "NA",
        "ansible_python_version": "2.4.3",
        "ansible_selinux": {
            "status": "disabled"
        },
        "ansible_sit0": {
            "active": false,
            "device": "sit0",
            "macaddress": "00:00:00:00",
            "mtu": 1480,
            "promisc": false
        },
        "ansible_ssh_host_key_dsa_public": "AAAAB3NzaC1kc3MAAACBAOct9HY8HNBInGPNS9IWx8nYunpwI7tgmnIMTnRNXslEzXdztefKsvwGi5AyzEAzZ",
        "ansible_ssh_host_key_rsa_public": "AAAABb+AHqVP3ZOVpmxOj6am9MS2R7Bb2G01Tlo4Iri9//Zi77WGYNrBvbQKG6rYUruUpfvWXz2LpeVD2empb0lu/FKBSA+XWliKJ57QN59pm+/sEODcnx5IVmw==",
        "ansible_swapfree_mb": 1055,
        "ansible_swaptotal_mb": 1055,
        "ansible_system": "Linux",
        "ansible_system_vendor": "NA",
        "ansible_user_id": "vagrant",
        "ansible_userspace_architecture": "x86_64",
        "ansible_userspace_bits": "64",
        "ansible_virtualization_role": "NA",
        "ansible_virtualization_type": "NA",
        "module_setup": true
    },
    "changed": false
}

gather_factsとはなんぞということで、simplejsonインストール後に試すと、リモートホストの特定情報が取れるらしい。 そのgather_factsの値がDefaultでONのため、先の「raw」と「shell」どちら共NGだった模様。 以下、検証。

  • gather_facts: no、shellの場合
- hosts: all
  sudo: True
  gather_facts: no
    
  tasks:
    - name: install python-simplejson
      shell: yum install -y python-simplejson
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

TASK: [install python-simplejson] *********************************************
failed: [test] => {"failed": true, "parsed": false}
SUDO-SUCCESS-yrdgyohnnhafomywzzlmvckghyjyvqzr
Error: ansible requires a json module, none found!

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/yokoyamafumihito/playbook.retry

test                       : ok=0    changed=0    unreachable=0    failed=1
  • gather_facts: no、rawの場合
- hosts: all
  sudo: True
  gather_facts: no
    
  tasks:
    - name: install python-simplejson
      raw: yum install -y python-simplejson
$ ansible-playbook -i hosts playbook.yml

PLAY [all] ********************************************************************

TASK: [install python-simplejson] *********************************************
ok: [test]

PLAY RECAP ********************************************************************
test                       : ok=1    changed=0    unreachable=0    failed=0

まとめ

以上のことからActionの「shell」の結果はjsonで返して、「raw」はそのまま返ってくるものと推測出来ます。

gather_factsとか、rawとshellの違いとかが知れてよかったと思います。 今後Python2.4の入った環境自体少なくなるでしょうが、古い環境に一斉に「どんっ!」と入れるときのためのメモです。