2017年3月28日火曜日

[serverspec] MSYS2 で serverspec を使えるようにする手順

MSYS2 を利用して Windows で serverspec を実行するための環境を作成します。
ここに記載の手順を実行することで MSYS2 で serverspec 2.38.0 が使えるようになります。

MSYS2 のインストール

ansible の実行環境を作成した時の手順を参考にしてください。
http://itsp0.blogspot.jp/2017/03/ansible-msys2-ansible.html

必要パッケージのインストール

ruby パッケージをインストールします。
$ pacman -S ruby

ruby のパッケージインストール領域をシステム領域に変更します。
$ cd /etc
$ cp -p gemrc gemrc_20170328
$ sed -e "s/gem: --user-install/gem: --no-user-install/g" gemrc_20170328 > gemrc
$ cd ~/

serverspec のインストール

gem を使用して serverspec をインストールします。
$ gem install serverspec

serverspec のインストール確認

インストールされた serverspec のパッケージを確認します。
$ gem list

*** LOCAL GEMS ***

bigdecimal (1.2.8)
did_you_mean (1.0.0)
diff-lcs (1.3)
io-console (0.4.5)
json (1.8.3)
minitest (5.8.5)
multi_json (1.12.1)
net-scp (1.2.1)
net-ssh (4.1.0)
net-telnet (0.1.1)
power_assert (0.2.6)
psych (2.1.0)
rake (10.4.2)
rdoc (4.2.1)
rspec (3.5.0)
rspec-core (3.5.4)
rspec-expectations (3.5.0)
rspec-its (1.2.0)
rspec-mocks (3.5.0)
rspec-support (3.5.0)
serverspec (2.38.0)
sfl (2.3)
specinfra (2.67.6)
test-unit (3.1.5)

serverspec の動作確認

serverspec を初期化します。
$ serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 1

Vagrant instance y/n: n
Input target host name: 192.168.1.1
 + spec/
 + spec/192.168.1.1/
 + spec/192.168.1.1/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
 + .rspec

リモートホストに接続するユーザが sudo コマンドを使えるようにします。
※centosの場合、ユーザにwheelグループを追加します。
$ usermod -G wheel username

serverspec を実行します。
$ SUDO_PASSWORD=password rake spec
/usr/bin/ruby.exe -I/usr/lib/ruby/gems/2.3.0/gems/rspec-support-3.5.0/lib:/usr/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.4/lib /usr/lib/ruby/gems/2.3.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/192.168.1.1/\*_spec.rb

Package "httpd"
  should be installed

Service "httpd"
  should be enabled
  should be running

Port "80"
  should be listening

Finished in 3.28 seconds (files took 1 minute 9 seconds to load)
4 examples, 0 failures

参考情報

利用可能なリソースタイプ
http://serverspec.org/resource_types.html

2017年3月27日月曜日

[ansible] MSYS2でansibleの実行環境を構築した際のトラブルシューティング

pipインストール時にerror code 1で終了する。

Collecting cffi>=1.4.1 (from cryptography>=1.1->paramiko->ansible)
  Using cached cffi-1.9.1.tar.gz
    Complete output from command python setup.py egg_info:

        No working compiler found, or bogus compiler options
        passed to the compiler from Python's distutils module.
        See the error messages above.
        (If they are about -mno-fused-madd and you are on OS/X 10.8,
        see http://stackoverflow.com/questions/22313407/ .)

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in c:/users/username/appdata/local/temp/pip-build-5imbxi/cffi/

原因:Cコンパイラが見つからない。
対処:gcc パッケージのインストール($ pacman -S gcc)を行う。

ansibleインストール時に不明な型名'u_int'で失敗する。

  gcc -fno-strict-aliasing -march=i686 -mtune=generic -pipe -march=i686 -mtune=generic -pipe -std=c99 -O3 -fomit-frame-pointer -Isrc/ -I/usr/include/python2.7 -c src/MD2.c -o build/temp.msys-2.7.0-i686-2.7/src/MD2.o
  In file included from /usr/include/python2.7/Python.h:8:0,
                   from src/MD2.c:31:
  /usr/include/python2.7/pyconfig.h:1218:0: 警告: "__BSD_VISIBLE" が再定義されました
   #define __BSD_VISIBLE 1

  In file included from /usr/include/sys/config.h:5:0,
                   from /usr/include/_ansi.h:16,
                   from /usr/include/string.h:10,
                   from src/MD2.c:30:
  /usr/include/sys/features.h:250:0: 備考: ここが以前の宣言がある位置です
   #define __BSD_VISIBLE  0

  In file included from /usr/include/python2.7/pyport.h:332:0,
                   from /usr/include/python2.7/Python.h:58,
                   from src/MD2.c:31:
  /usr/include/sys/time.h:104:34: エラー: 不明な型名 ‘u_int’ です
   bintime_mul(struct bintime *_bt, u_int _x)
                                    ^~~~~
  error: command 'gcc' failed with exit status 1

原因:__BSD_VISIBLE が誤って再定義され 'u_int' 型が宣言されない。
対処:/usr/include/python2.7/pyconfig.h #defind __BSD_VISIBLE 1 を、#defind __BSD_VISIBLE 0 に変更する。

ansibleインストール時に致命的エラー: ffi.h: No such file or directoryが発生する。

  Running setup.py bdist_wheel for cryptography ... error
  Complete output from command /usr/bin/python2 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-mL2y4U/cryptography/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/tmppoXtiypip-wheel- --python-tag cp27:
  c/_cffi_backend.c:15:17: 致命的エラー: ffi.h: No such file or directory
   #include <ffi.h>
                   ^
  コンパイルを停止しました。

原因:libffi-devel パッケージの欠落。
対処:libffi-devel パッケージのインストール($ pacman -S libffi-devel)する。 ansible インストール時に CFLAGS を設定(CFLAGS=-I/usr/lib/libffi-3.2.1/include)する。

ansibleインストール時に致命的エラー: openssl/opensslv.h: No such file or directoryが発生する。

  gcc -DNDEBUG -march=i686 -mtune=generic -O2 -pipe -DNDEBUG -I/usr/lib/libffi-3.2.1/include -I/usr/include/python2.7 -c build/temp.msys-2.7.0-i686-2.7/_openssl.c -o build/temp.msys-2.7.0-i686-2.7/build/temp.msys-2.7.0-i686-2.7/_openssl.o
  build/temp.msys-2.7.0-i686-2.7/_openssl.c:434:30: 致命的エラー: openssl/opensslv.h: No such file or directory
   #include <openssl/opensslv.h>
                                ^
  コンパイルを停止しました。

原因:openssl-devel パッケージの欠落。
対処:openssl-devel パッケージのインストール($ pacman -S openssl-devel)する。

ansible でリモートホストに接続する際にエラーが発生する。

192.168.1.1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: mux_client_request_session: read from master failed: Connection reset by peer\r\nFailed to connect to new control master\r\n",
    "unreachable": true
}

原因:MSYS2 の open-ssh は複数の SSH セッションを束ねる ControlMaster 機能が使用できないため。
対処:ssh の引数から ControlMaster 機能に関する設定を削除する。

$ vim /etc/ansible/ansible.cfg
[ssh_connection]
ssh_args=""

with_itemsモジュールでエラーが発生する。

- name: Show OS_USER
  shell: echo "user name={{ item.name }}"
  with_items:
          OS_USER

fatal: [192.168.1.1]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable that is undefined. The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'group'

The error appears to have been in '/home/username/roles/cent7_build/tasks/show_env.yml': line 4, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:


- name: Show OS_USER
  ^ here
"}

原因:with_items モジュールの変数の指定方法に誤りがあった。
対処:変数の指定を - '{{ OS_USER }}' に変更する。最近のバージョンはこのように書く。

- name: Show OS_USER
  shell: echo "user name={{ item.name }}"
  with_items:
         - '{{ OS_USER }}'

リモートホストがSolarisの場合、TASK [setup]でエラーが発生する。

fatal: [192.168.1.1]: FAILED! => {"changed": false, "failed": true, "module_stderr": "",
"module_stdout": "/tmp/ansible_Cck5DI/ansible_modlib.zip/ansible/module_utils/facts.py:954: DeprecationWarning: object.__new__() taskes no parameters
Traceback (most recent call last):
  File \"/tmp/ansible_Cck5DI/ansible_module_setup.py\", line 134, in <module>
    main()
  File \"/tmp/ansible_Cck5DI/ansible_module_setup.py\", line 126, in main
    data = get_all_facts(module)
  File \"/tmp/ansible_Cck5DI/ansible_module.zip/ansible/module_utils/facts.py\", line 3518, in get_all_facts
  File \"/tmp/ansible_Cck5DI/ansible_module.zip/ansible/module_utils/facts.py\", line 3461, in ansible_facts
  File \"/tmp/ansible_Cck5DI/ansible_module.zip/ansible/module_utils/facts.py\", line 1482, in populate
  File \"/tmp/ansible_Cck5DI/ansible_module.zip/ansible/module_utils/facts.py\", line 1539, in get_memory_facts
ValueError: invalid literal for int() with base 10: '\\xcd\\xbd\\xcc\\xf3\\xba\\xd1\\xa4'
", "msg": "MODULE FAILURE"}

原因:/usr/sbin/swap -s の実行結果からスワップ領域を取得して int に変換しているが、取得した値が文字列のためエラーが発生している。

問題のコード int(out.split()[5][:-1])

対処:ansible が動作するロケールの設定を C に変更する。

$ vim /etc/ansible/ansible.cfg
[defaults]
module_lang=C
module_set_locale=true

参考

  • なし。

[ansible] MSYS2 で ansible を使えるようにする手順

MSYS2 を利用して Windows で ansible を実行するための環境を作成します。
ここに記載の手順を実行することで MSYS2 で ansible 2.2.1.0 が使えるようになります。

MSYS2 のインストール

http://www.msys2.org/ より、インストールファイルをダウンロードします。

  32bit 環境の場合:msys2-i686-20161025.exe
  64bit 環境の場合:msys2-x86_64-20161025.exe

ダウンロードしたファイルを実行し、画面に表示されるメッセージに従って、インストールを行います。

 インストール先フォルダ:C:\msys32
 スタートメニュー:MSYS2 32bit

コアシステムの更新

インターネットに接続するために proxy が必要な場合は、C:\msys32\etc\profile.d に http_proxy.sh を作成し、
その中に proxy を設定します。

 export http_proxy=http://{user}:{password}@{proxy_server}:{port}/
 export export https_proxy=http://{user}:{password}@{proxy_server}:{port}/
 export export HTTP_PROXY=http://{user}:{password}@{proxy_server}:{port}/
 export export HTTPS_PROXY=http://{user}:{password}@{proxy_server}:{port}/

シェルを起動します。
 [スタート]-[すべてのプログラム]-[MSYS2 32bit]-[MSYS2 MSYS]

パッケージを更新します。更新が完了し「警告: for example close your terminal window instead of calling exit」が
表示されたら、×でシェルを閉じます。
$ pacman -Syu

  ※リポジトリに含まれているパッケージの一覧を表示:pacman -Sl
  ※パッケージ情報を表示:pacman -Sii パッケージ名

システム全体の更新

シェルを起動します。
 [スタート]-[すべてのプログラム]-[MSYS2 32bit]-[MSYS2 MSYS]

パッケージを更新します。
$ pacman -Su

必要パッケージのインストール

ansible の実行に必要なパッケージをインストールします。
$ pacman -S python2
$ pacman -S vim
$ pacman -S openssh
$ pacman -S openssl-devel
$ pacman -S sshpass
$ pacman -S gcc
$ pacman -S libffi-devel

ansible のインストール

python のパッケージ管理システムをインストールします。
$ curl -kL https://bootstrap.pypa.io/get-pip.py | python2

ansible インストール時のエラーを回避するためヘッダーファイルを修正します。
$ cd /usr/include/python2.7
$ cp -p pyconfig.h pyconfig.h_YYYYMMDD
# sed -e "s/__BSD_VISIBLE 1/__BSD_VISIBLE 0/g"  pyconfig.h_YYYYMMDD > pyconfig.h

ansible をインストールします。
$ CFLAGS=-I/usr/lib/libffi-3.2.1/include pip install ansible

ansible のインストール確認

インストールされた python のパッケージを確認します。
$ pip list

ansible (2.2.1.0)
appdirs (1.4.3)
asn1crypto (0.21.1)
cffi (1.9.1)
cryptography (1.8.1)
enum34 (1.1.6)
idna (2.5)
ipaddress (1.0.18)
Jinja2 (2.8.1)
MarkupSafe (1.0)
packaging (16.8)
paramiko (2.1.2)
pip (9.0.1)
pyasn1 (0.2.3)
pycparser (2.17)
pycrypto (2.6.1)
pyparsing (2.2.0)
PyYAML (3.12)
setuptools (34.3.2)
six (1.10.0)
wheel (0.29.0)

ansible のバージョンを確認します。
$ ansible --version
ansible 2.2.1.0
  config file =
  configured module search path = Default w/o overrides

ローカルホストに対してコマンドが実行できることを確認します。
$ ansible localhost -a "/bin/echo hello. world!"
 [WARNING]: Host file not found: /etc/ansible/hosts

 [WARNING]: provided hosts list is empty, only localhost is available

localhost | SUCCESS | rc=0 >>
hello. world!

リモートホストを ansible で操作するための準備
(秘密鍵を利用する場合)

シェルを起動します。
 [スタート]-[すべてのプログラム]-[MSYS2 32bit]-[MSYS2 MinGW 32-bit]

SOCKS5 経由でインターネット上にあるサーバに接続する場合は connect パッケージをインストールします。
$ pacman -S mingw-w64-i686-connect

秘密鍵を ~/.ssh/config に格納します。

SSH の設定をします。ProxyCommand は SOCKS5 経由で接続する場合のみ必要になります。
$ vim ~/.ssh/config
Host 192.168.1.1
  IdentityFile ~/.ssh/id_rsa
  User username
  ProxyCommand /mingw32/bin/connect -S {proxy_server}:{port} %h %p

fingerprint を known_hosts に登録します。SOCKS5_USER と SOCKS5_PASSWD の設定は SOCKS5 経由で接続する場合のみ必要になります。
$ export SOCKS5_USER=username
$ export SOCKS5_PASSWD=password
$ ssh 192.168.1.1
The authenticity of host '192.168.1.1 (<no hostip for proxy command>)' can't be established.
ECDSA key fingerprint is SHA256:kBpvduX5+6j06Zns4tT7VWJCV6XeUtdmRnJZOYLAU4g.
Are you sure you want to continue connecting (yes/no)? yes を入力
Warning: Permanently added '192.168.1.1' (ECDSA) to the list of known hosts.
Enter passphrase for key '/home/username/.ssh/id_rsa': passphrase を入力

ansible.cfg ファイルを作成します。
$ vim /etc/ansible/ansible.cfg
[defaults]
log_path=/var/log/ansible.log
module_lang=C
module_set_locale=true

[ssh_connection]
ssh_args=""

hosts ファイルを作成します。
$ vim /etc/ansible/hosts
[prototype]
192.168.1.1

リモートホストとの接続を確認します。
$ ansible prototype -a "/bin/echo hello. world!"
Enter passphrase for key '/home/username/.ssh/id_rsa':
 [WARNING]: sftp transfer mechanism failed on [192.168.1.1]. Use
ANSIBLE_DEBUG=1 to see detailed information

Enter passphrase for key '/home/username/.ssh/id_rsa': passphrase を入力
Enter passphrase for key '/home/username/.ssh/id_rsa': passphrase を入力
Enter passphrase for key '/home/username/.ssh/id_rsa': passphrase を入力
192.168.1.1 | SUCCESS | rc=0 >>
hello. world!

passphrase の入力を省略するためには ssh-agent を使用します。
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa
Enter passphrase for /home/username/.ssh/id_rsa: passphrase を入力
Identity added: /home/username/.ssh/id_rsa (/home/username/.ssh/id_rsa)
$ ansible prototype -a "/bin/echo hello. world!"
192.168.1.1 | SUCCESS | rc=0 >>
hello. world!

リモートホストを ansible で操作するための準備
(秘密鍵を利用しない場合)

ansible.cfg ファイルを作成します。
$ vim /etc/ansible/ansible.cfg
[defaults]
log_path=/var/log/ansible.log
module_lang=C
module_set_locale=true

hosts ファイルを作成します。
$ vim /etc/ansible/hosts
[prototype]
192.168.1.1

[prototype:vars]
ansible_ssh_user=username
ansible_ssh_pass=password

リモートホストとの接続を確認します。
$ ansible prototype -a "/bin/echo hello. world!" -c paramiko
192.168.1.1 | SUCCESS | rc=0 >>
hello. world!

ansible-playbook を利用するための準備

playbookは以下の構成とします。
グループやホスト毎に動作を変えたい場合は、group_vars や host_vars に変数を定義します。

  ~/site.yml
      ~/cent7_build.yml
          ~/group_vars/prototype.yml
              ~/host_vars/192.168.1.1.yml
                  ~/roles/cent7_build/tasks/main.yml
                      ~/roles/cent7_build/tasks/show_env.yml
                      yml ファイルはタスク毎に作成し main.yml から include します。

ディレクトリ構成はベストプラクティスに倣います。
  参考:http://docs.ansible.com/ansible/playbooks_best_practices.html

Directory Layout
The top level of the directory would contain files and directories like so:

production                # inventory file for production servers
staging                   # inventory file for staging environment
group_vars/
   group1                 # here we assign variables to particular groups
   group2                 # ""
host_vars/
   hostname1              # if systems need specific variables, put them here
   hostname2              # ""
library/                  # if any custom modules, put them here (optional)
filter_plugins/           # if any custom filter plugins, put them here (optional)
site.yml                  # master playbook
webservers.yml            # playbook for webserver tier
dbservers.yml             # playbook for dbserver tier
roles/
    common/               # this hierarchy represents a "role"
        tasks/            #
            main.yml      #  <-- tasks file can include smaller files if warranted
        handlers/         #
            main.yml      #  <-- handlers file
        templates/        #  <-- files for use with the template resource
            ntp.conf.j2   #  <------- templates end in .j2
        files/            #
            bar.txt       #  <-- files for use with the copy resource
            foo.sh        #  <-- script files for use with the script resource
        vars/             #
            main.yml      #  <-- variables associated with this role
        defaults/         #
            main.yml      #  <-- default lower priority variables for this role
        meta/             #
            main.yml      #  <-- role dependencies
        library/          # roles can also include custom modules
        lookup_plugins/   # or other types of plugins, like lookup in this case
    webtier/              # same kind of structure as "common" was above, done for the webtier role
    monitoring/           # ""
    fooapp/               # ""


site.yml を作成します。
$ vim ~/site.yml
- include: cent7_build.yml

cent7_build.yml を作成します。
$ vim ~/cent7_build.yml
- hosts: prototype
  vars: ROLE_NAME: 'cent7_build'
  roles:
    - {role: '{{ ROLE_NAME }}'}

prototype.yml を作成します。グループで共通の設定を行います。
$ vim ~/group_vars/prototype.yml

192.168.1.1.yml を作成します。サーバ毎に異なる値を変数で定義します。
$ vim ~/host_vars/192.168.1.1.yml
ansible_become: true
ansible_become_method: su
ansible_become_user: root
ansible_become_pass: password
HOST_NAME: CENT7001
OS_GROUP:
- name: testgroup1
  id: 2000
- name: testgroup2
  id: 2001
OS_USER:
- name: testuser1
  id: 2000
  pass: testpass1
  login: "/bin/bash"
  home: "/home/testuser1"
  group: testgroup1
- name: testuser2
  id: 2001
  pass: testpass2
  login: "/bin/bash"
  home: "/home/testuser2"
  group: testgroup2

main.yml を作成します。タスクが複数ある場合は全て include します。
$ vim ~/roles/cent7_build/tasks/main.yml
- include: show_env.yml

show_env.yml を作成します。
$ vim ~/roles/cent7_build/tasks/show_env.yml
- name: Show ROLE_NAME
  debug: msg="role name={{ ROLE_NAME }}"

- name: Show OS_USER
  debug: msg="user name={{ item.name }}"
  with_items:
          - '{{ OS_USER }}'

ansible-playbook の実行

ansible-playbook を実行します。(秘密鍵を利用する場合)
$ ansible-playbook -l prototype site.yml

ansible-playbook を実行します。(秘密鍵を利用しない場合)
$ ansible-playbook -l prototype site.yml -c paramiko

※詳細な結果を表示させたい場合は ansible-playbook 実行時に -v または -vvv オプションを付けます。
※ANSIBLE_KEEP_REMOTE_FILES=1 を実行時に指定すると、リモートホストで作成される一時ファイルが削除されなくなり、
  エラーが発生した場合に調査可能となる。

実行結果
PLAY [prototype] ***************************************************************

TASK [setup] *******************************************************************
ok: [192.168.1.1]

TASK [cent7_build : Show ROLE_NAME] ********************************************
ok: [192.168.1.1] => {
    "msg": "role name=cent7_build"
}

TASK [cent7_build : Show OS_USER] **********************************************
ok: [192.168.1.1] => (item={u'group': u'testgroup1', u'name': u'testuser1', u'pass': u'testpass1', u'home': u'/home/testuser1', u'login': u'/bin/bash', u'id': 2000}) => {
    "item": {
        "group": "testgroup1",
        "home": "/home/testuser1",
        "id": 2000,
        "login": "/bin/bash",
        "name": "testuser1",
        "pass": "testpass1"
    },
    "msg": "user name=testuser1"
}
ok: [192.168.1.1] => (item={u'group': u'testgroup2', u'name': u'testuser2', u'pass': u'testpass2', u'home': u'/home/testuser2', u'login': u'/bin/bash', u'id': 2001}) => {
    "item": {
        "group": "testgroup2",
        "home": "/home/testuser2",
        "id": 2001,
        "login": "/bin/bash",
        "name": "testuser2",
        "pass": "testpass2"
    },
    "msg": "user name=testuser2"
}

PLAY RECAP *********************************************************************
192.168.1.1                : ok=3    changed=0    unreachable=0    failed=0

2017年3月2日木曜日

[Python3] OpenCV3 を使用して顔部分のみを書き出す

# pylint: disable-msg=C0103

"""
指定フォルダ内にある画像から顔部分のみを書き出す
"""
import os
import glob
import cv2

search_path = '/tmp'
result_path = search_path + '/' + 'result'

"""
haarcascade_frontalface_default.xml ファイルは anaconda のインストール
ディレクトリ配下にある
(anaconda)/pkgs/opencv3-3.1.0-py35_0/share/OpenCV/haarcascades/
"""
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

if not os.path.exists(result_path):
    os.mkdir(result_path)

files = glob.glob(search_path + '/*.jpg')

for f in files:
    img = cv2.imread(f)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.1, 3)
    count = 1
    filename, ext = os.path.splitext(os.path.basename(f))
    # 顔認識で得られた部分を書き出す
    for (x, y, w, h) in faces:
        dst = result_path + '/' + filename + '_' + str(count) + ext
        cv2.imwrite(dst, cv2.resize(gray[y:y + h, x:x + w], (64, 64)))
        count += 1