2014年12月26日金曜日

[Python] Fabric を pyenv + virtualenv 環境で使ったら楽しかったよ!


メリークリスマス! なのまる です。

NTPの脆弱性(英語)の対応しよーと思って、手作業はツラすぎるのである程度の自動化をしようと思いました。


もくじ



Fabricが楽しかった理由

そもそもCapistrano (Ruby) を使っていたんですがなんとなく、一度だけ勉強会で使わせてもらったFabricの勉強をしてみたいと思って使いました!

Fabricを使ってみて、楽しいなぁ~って思った理由を自分なりにまとめてみたので書いておきます。
  • Capistranoでは、そのままでは煩わしい部分が簡単に解決できた!(認証関連)
  • 出来上がった、コードが短くて済んだ!
  • 出来上がった、コードがわかりやすい!
  • 上記もあって、使っていて楽しい!w


Fabric を使ってみる!


前提条件

  • OSシステム環境のPythonに影響を及ぼさない
  • pyenv + virtualenv
  • Linux (CentOS 6)
  • fabric
システム環境に初めて入れるので、使い捨てができるようにしておきたかった。
そのため「pyenv + virtualenv」で実装した。

「pyenv + virtualenv」 インストール・設定

ここの部分長いので、わかる人は飛ばしていいと思います!

pyenv インストール

pyenvはinstallerがあって、インストールが簡単です!
以下を実行するだけ!
1
curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

インストール状況
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[snickerjp@localhost ~]$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
101  2126  101  2126    0     0   6321      0 --:--:-- --:--:-- --:--:--  6858
Initialized empty Git repository in /home/snickerjp/.pyenv/.git/
remote: Counting objects: 8056, done.
remote: Total 8056 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (8056/8056), 1.44 MiB | 374 KiB/s, done.
Resolving deltas: 100% (5898/5898), done.
Initialized empty Git repository in /home/snickerjp/.pyenv/plugins/pyenv-doctor/.git/
remote: Counting objects: 26, done.
~中略~
Resolving deltas: 100% (8/8), done.
 
WARNING: seems you still have not added 'pyenv' to the load path.
 
# Load pyenv automatically by adding
# the following to ~/.bash_profile:
 
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

~/.bash_profileに以下を追記
1
2
3
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

かっこよく編集してみたりw
1
2
3
4
5
6
cat << 'EOF' >> ~/.bash_profile
# for pyenv
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
EOF

localにPythonのインストール

なんとなく2.x系をインストールしました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Pythonの現在のバージョンを確認
[snickerjp@localhost ~]$ python --version
Python 2.6.6
 
[snickerjp@localhost ~]$ pyenv install 2.7.8
Downloading Python-2.7.8.tgz...
~略~
Installed Python-2.7.8 to /home/snickerjp/.pyenv/versions/2.7.8
 
[snickerjp@localhost ~]$ pyenv versions
* system (set by /home/snickerjp/.pyenv/version)
  2.7.8
 
[snickerjp@localhost ~]$ pyenv install 2.7.9
Downloading Python-2.7.9.tgz...
~略~
 
[snickerjp@localhost ~]$ pyenv versions
* system (set by /home/snickerjp/.pyenv/version)
  2.7.8
  2.7.9

Pythonのインストールでエラーが出たので、追加でdevelパッケージを入れました。
1
2
3
4
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

yumでインストール!
1
sudo yum install readline-devel bzip2-devel openssl-devel sqlite-devel


virtualenvのインストール

virtualenvのインストール~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[snickerjp@localhost fabric-bin]$ pyenv virtualenv 2.7.9 fabric
Collecting virtualenv
  Downloading virtualenv-12.0.3-py2.py3-none-any.whl (1.8MB)
    100% |################################| 1.8MB 6.2MB/s
Installing collected packages: virtualenv
 
 
Successfully installed virtualenv-12.0.3
New python executable in /home/snickerjp/.pyenv/versions/fabric/bin/python2.7
Also creating executable in /home/snickerjp/.pyenv/versions/fabric/bin/python
Installing setuptools, pip...done.
Ignoring indexes: https://pypi.python.org/simple/
Requirement already satisfied (use --upgrade to upgrade): setuptools in /home/snickerjp/.pyenv/versions/fabric/lib/python2.7/site-packages
Requirement already satisfied (use --upgrade to upgrade): pip in /home/snickerjp/.pyenv/versions/fabric/lib/python2.7/site-packages
Cleaning up...
[snickerjp@localhost fabric-bin]$
  
[snickerjp@localhost fabric-bin]$ pyenv versions
* system (set by /home/snickerjp/.pyenv/version)
  2.7.8
  2.7.9
  fabric


localのPythonを使う場所を作る

localバージョンのPythonを使う場所を作ります!
1
2
3
4
5
6
7
8
9
10
11
[snickerjp@localhost ~]$ mkdir fabric-bin
[snickerjp@localhost fabric-bin]$ cd fabric-bin/
[snickerjp@localhost fabric-bin]$ pyenv local fabric
pyenv-virtualenv: activate fabric
(fabric)[snickerjp@localhost fabric-bin]$
(fabric)[snickerjp@localhost fabric-bin]$ pyenv rehash
(fabric)[snickerjp@localhost fabric-bin]$ python --version
Python 2.7.9
(fabric)[snickerjp@localhost fabric-bin]$ pip list
pip (6.0.3)
setuptools (8.2.1)
参考



fabric インストール

やっと、ここでfabricのインストール!
もうvirtualenvでlocal環境にインストールできる状態です!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(fabric)[snickerjp@localhost fabric-bin]$ pip install fabric
Collecting fabric
  Downloading Fabric-1.10.1.tar.gz (209kB)
    100% |################################| 212kB 9.3MB/s
Collecting paramiko>=1.10 (from fabric)
  Downloading paramiko-1.15.2-py2.py3-none-any.whl (165kB)
    100% |################################| 167kB 10.8MB/s
Collecting ecdsa>=0.11 (from paramiko>=1.10->fabric)
  Downloading ecdsa-0.11.tar.gz (45kB)
    100% |################################| 49kB 10.3MB/s
Collecting pycrypto!=2.4,>=2.1 (from paramiko>=1.10->fabric)
  Downloading pycrypto-2.6.1.tar.gz (446kB)
    100% |################################| 446kB 8.1MB/s
Installing collected packages: pycrypto, ecdsa, paramiko, fabric
  Running setup.py install for pycrypto
    checking for gcc... gcc
    checking whether the C compiler works... yes
    checking for C compiler default output file name... a.out
~略~
    gcc -pthread -shared -L/home/snickerjp/.pyenv/versions/2.7.9/lib build/temp.linux-x86_64-2.7/src/_counter.o -o build/lib.linux-x86_64-2.    7/Crypto/Util/_counter.so
  Running setup.py install for ecdsa
 
 
  Running setup.py install for fabric
    Installing fab script to /home/snickerjp/.pyenv/versions/fabric/bin
Successfully installed ecdsa-0.11 fabric-1.10.1 paramiko-1.15.2 pycrypto-2.6.1

参考



ntp をアップデートしてみる

いよいよ本題ですね!w

ntpup.py
こちらを参考に以下のコードを書いてみました!
(コメント部分は消してください)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#coding:utf-8
from fabric.api import env, run, sudo
from fabric.contrib.console import confirm
 
 
env.use_ssh_config = True
env.key_filename = ['~/.ssh/id_rsa']
 
 
def yum_update_ntp():
    sudo('cat /etc/∗-release',user='root', pty=True) # Linuxのディストリビューションの確認
    sudo('yum -q -y update ntp',user='root', pty=True) # sudo で yum update
 
 
def run_su(command, user="root"): # sudo が無いサーバーなどの対応
    return run('su %s -c "%s"' % (user, command), pty=True)
 
 
def su_update_ntp():
    run_su('cat /etc/∗-release',user='root')
    run_su('yum -y update ntp',user='root') # sudo がないサーバーで yum update

実行例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[192.168.82.xxx] Executing task 'yum_update_ntp'
[192.168.82.xxx] sudo: cat /etc/*-release
[192.168.82.xxx] Login password for 'snickerjp':
[192.168.82.xxx] out:
[192.168.82.xxx] out: We trust you have received the usual lecture from the local System
[192.168.82.xxx] out: Administrator. It usually boils down to these three things:
[192.168.82.xxx] out:
[192.168.82.xxx] out:     #1) Respect the privacy of others.
[192.168.82.xxx] out:     #2) Think before you type.
[192.168.82.xxx] out:     #3) With great power comes great responsibility.
[192.168.82.xxx] out:
[192.168.82.xxx] out: sudo password:
[192.168.82.xxx] out: Sorry, try again.
[192.168.82.xxx] out: sudo password:  ← 公開鍵とPAMで違うパスワードの時は聞いてきてくれる!
[192.168.82.xxx] out: NAME="Amazon Linux AMI"
[192.168.82.xxx] out: VERSION="2014.09"
[192.168.82.xxx] out: ID="amzn"
[192.168.82.xxx] out: ID_LIKE="rhel fedora"
[192.168.82.xxx] out: VERSION_ID="2014.09"
[192.168.82.xxx] out: PRETTY_NAME="Amazon Linux AMI 2014.09"
[192.168.82.xxx] out: ANSI_COLOR="0;33"
[192.168.82.xxx] out: CPE_NAME="cpe:/o:amazon:linux:2014.09:ga"
[192.168.82.xxx] out: HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
[192.168.82.xxx] out: Amazon Linux AMI release 2014.09
[192.168.82.xxx] out:
[192.168.82.xxx] sudo: yum --releasever=2014.09 --disablerepo=epel update ntp
[192.168.82.xxx] out: sudo password:
[192.168.82.xxx] out: Loaded plugins: priorities, update-motd, upgrade-helper
[192.168.82.xxx] out:
[192.168.82.xxx] out: amzn-main/2014.09                                                        | 2.1 kB     00:00
[192.168.82.xxx] out:
[192.168.82.xxx] out: amzn-updates/2014.09                                                     | 2.3 kB     00:00
[192.168.82.xxx] out: 181 packages excluded due to repository priority protections
[192.168.82.xxx] out: No packages marked for update
[192.168.82.xxx] out:
SSH関連について
  • 公開鍵とPAMで違うパスワードでも対話で入力できる!
  • rootパスワードも対話で入力できる!
  • サーバーごとにパスワード違っても対話で入力できる!
  • 前の処理で入れたパスワードは記憶しておいてくれる!
Capistranoでやろうとすると、このあたりが比較的にめんどくさい!
fabricだと、楽だった!のでした!
参考



まとめ


  • Capistranoで不便と思っていた部分が解決できる!(認証関連)
  • コードが短くて、さらに読みやすい!
  • pyenv + virtualenv + fabric でポータビリティもあるんじゃないかと!w


参考サイト


共有

Clip to Evernote
0follow