copy module (backup時のタイムスタンプの話)
はじめに
本記事は Ansible Blogger 2018 (sponsored by Red Hat) Advent Calendar 2018 の14日目の記事です。 qiita.com
早速本日分を書かせていただきます。
みなさん backup使ってますか?
好きなモジュールについてのお題では御座いますが、 本日はcopy moduleを含めいくつかのmoduleに実装されている backupパラメータについてをお話させて頂ければと思います。
今回のお話の環境
・Centos7
・Python3.6 + Pipenv
・Ansible Version
# ansible --version ansible 2.7.4
とりあえずbackup=yesでcopyをしてみる
まずはplaybook
playbookといってもcopyモジュールを使ってパラメータとして backup=yes
を引き渡すシンプルなものです。
今回は昔お試しで使ってたplaybookがsnmpd.confの差し替えだったのでそのまま使いました。
内容については大きな意味はありません。
しかも検証環境でlocalでrootアクセスです。
実際にご利用の際は環境にあわせて適宜設定ください。
--- - hosts: all user: root tasks: - name: Replace file template : src=replace_template dest=/etc/snmp/snmpd.conf mode=0600 owner=root group=root backup=yes tags: - replace_file
フォルダの構成はこんな感じで差し替えファイルはtemplatesに入れておきました
# ls -F Pipfile ansible.cfg hosts playbook.yml templates/
いざ実行
# ansible-playbook playbook.yml PLAY [all] ***************************************************************** TASK [Gathering Facts] *************************************************** ok: [127.0.0.1] TASK [Replace file] ******************************************************** changed: [127.0.0.1] PLAY RECAP ************************************************************** 127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 #
changed=1
になりました。
完了したようです。
どれどれ ターゲット先を見てみますか。
# ls -ltr /etc/snmp/snmpd.conf* -rw------- 1 root root 18861 10月 31 08:52 /etc/snmp/snmpd.conf.2699.2018-11-10@13:01:39~ -rw------- 1 root root 0 11月 10 13:01 /etc/snmp/snmpd.conf
ちゃんとバックアップされファイルが差し変わっており、
想定とおりの動作が確認できました!
(今回はplaybookのsrcに指定したファイルは空ファイルです。。)
しかし、ちょっと待った!
バックアップのタイムスタンプフォーマットが好みではない
ではなく、今まで手作業でやってた頃のフォーマットにしてみたいなぁなど
自分に見やすい形のフォーマットに変更したいっ!!!!!
そう、本日のメインはここです。
backupパラメータのコードを改変する
Ansibleのソースを探す
Ansibleのソースをpipで落とします
# pip download ansible --no-deps Collecting ansible Using cached https://files.pythonhosted.org/packages/9e/df/b7ce359f9cc16864e0d5c9c93efe69f576fc437e74549bcc142f02cd4216/ansible-2.7.4.tar.gz Saved ./ansible-2.7.4.tar.gz Successfully downloaded ansible #
展開してソースがあるディレクトリへ
# tar zxvf ansible-2.7.4.tar.gz # cd ansible-2.7.4
該当のPythonコードをみつける(たぶんこれ)
# ls -l lib/ansible/module_utils/basic.py -rw-r--r-- 1 root root 117169 12月 1 2018 lib/ansible/module_utils/basic.py
grepするとこんな感じ
# fgrep backup lib/ansible/module_utils/basic.py backup=dict(), # Used by a few modules to create a remote backup before updating the file def backup_local(self, fn): '''make a date-marked backup of the specified file, return True or False on success or failure''' backupdest = '' # backups named basename.PID.YYYY-MM-DD@HH:MM:SS~ backupdest = '%s.%s.%s' % (fn, os.getpid(), ext) self.preserved_copy(fn, backupdest) self.fail_json(msg='Could not make backup of %s to %s: %s' % (fn, backupdest, to_native(e))) return backupdest
コードを修正してみる
以下な感じにしてみました。
今回はわかりやすように時間表記に含まれている記号とpidを消し去りました。
# diff -up lib/ansible/module_utils/basic.py{.org,} --- lib/ansible/module_utils/basic.py.org 2018-12-01 04:11:03.000000000 +0900 +++ lib/ansible/module_utils/basic.py 2018-11-10 13:05:07.151889137 +0900 @@ -2437,8 +2437,8 @@ class AnsibleModule(object): backupdest = '' if os.path.exists(fn): # backups named basename.PID.YYYY-MM-DD@HH:MM:SS~ - ext = time.strftime("%Y-%m-%d@%H:%M:%S~", time.localtime(time.time())) - backupdest = '%s.%s.%s' % (fn, os.getpid(), ext) + ext = time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time())) + backupdest = '%s.%s' % (fn, ext) try: self.preserved_copy(fn, backupdest)
インストール
tar.gzで固め直してpipインストールをします。
長々と表示されていますが依存関係のあるパッケージで、
一度インストールされているのでこのような感じで表示されます。
また、ansible-rebuild
の部分はtarで固める前にsetup.py
を
変更しています。(前のバージョンを消すのをお忘れなく)
(サンプルではpipでのインストールで説明します)
固めます
# tar zcvf ansible-2.7.4.tar.gz ansible-2.7.4
インストール!!!
# pip install ./ansible-2.7.4.tar.gz Processing ./ansible-2.7.4.tar.gz Requirement already satisfied: jinja2 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from ansible-rebuild==2.7.4) (2.10) Requirement already satisfied: PyYAML in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from ansible-rebuild==2.7.4) (3.13) Requirement already satisfied: paramiko in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from ansible-rebuild==2.7.4) (2.4.2) Requirement already satisfied: cryptography in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from ansible-rebuild==2.7.4) (2.4.2) Requirement already satisfied: setuptools in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from ansible-rebuild==2.7.4) (40.6.2) Requirement already satisfied: MarkupSafe>=0.23 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from jinja2->ansible-rebuild==2.7.4) (1.1.0) Requirement already satisfied: pynacl>=1.0.1 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from paramiko->ansible-rebuild==2.7.4) (1.3.0) Requirement already satisfied: bcrypt>=3.1.3 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from paramiko->ansible-rebuild==2.7.4) (3.1.4) Requirement already satisfied: pyasn1>=0.1.7 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from paramiko->ansible-rebuild==2.7.4) (0.4.4) Requirement already satisfied: six>=1.4.1 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from cryptography->ansible-rebuild==2.7.4) (1.12.0) Requirement already satisfied: idna>=2.1 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from cryptography->ansible-rebuild==2.7.4) (2.8) Requirement already satisfied: cffi!=1.11.3,>=1.7 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from cryptography->ansible-rebuild==2.7.4) (1.11.5) Requirement already satisfied: asn1crypto>=0.21.0 in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from cryptography->ansible-rebuild==2.7.4) (0.24.0) Requirement already satisfied: pycparser in /root/.local/share/virtualenvs/ANSIBLE-mn6ZODMw/lib/python3.6/site-packages (from cffi!=1.11.3,>=1.7->cryptography->ansible-rebuild==2.7.4) (2.19) Building wheels for collected packages: ansible-rebuild Running setup.py bdist_wheel for ansible-rebuild ... done Stored in directory: /root/.cache/pip/wheels/e5/1a/f7/1d3a8103d7ad08bbfe992efcf6d67e2e3eaad12774818f5cb8 Successfully built ansible-rebuild Installing collected packages: ansible-rebuild Successfully installed ansible-rebuild-2.7.4
インストール状況を確認
# pip list Package Version --------------- ------- ansible-rebuild 2.7.4 asn1crypto 0.24.0 bcrypt 3.1.4 cffi 1.11.5 cryptography 2.4.2 idna 2.8 Jinja2 2.10 MarkupSafe 1.1.0 paramiko 2.4.2 pip 18.1 pyasn1 0.4.4 pycparser 2.19 PyNaCl 1.3.0 PyYAML 3.13 setuptools 40.6.2 six 1.12.0 wheel 0.32.3
実行テスト
実行されました
# ansible-playbook playbook.yml SSH password: PLAY [all] ******************************************************************************************************************************** TASK [Gathering Facts] ******************************************************************************************************************** ok: [127.0.0.1] TASK [Replace file] *********************************************************************************************************************** changed: [127.0.0.1] PLAY RECAP ******************************************************************************************************************************** 127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 #
さぁバックアップファイル名フォーマットの確認
変更した指定のフォーマットになりました!!
# ls -ltr /etc/snmp/snmpd.conf* -rw------- 1 root root 18861 10月 31 08:52 /etc/snmp/snmpd.conf.20181110-131439 -rw------- 1 root root 0 11月 10 13:14 /etc/snmp/snmpd.conf
いかがでしたでしょうか。
拘っても仕方ない部分ですが@
や~
がついたフォーマット形式は今まで使ってこなかった事もあり、手で運用していた時代のポリシーに合わせる事を目的にこの様な修正をやっていました。
恐らく簡単に修正できるものなので既にやられている方も多いのではないかと思いますが、何かの参考にでもなりましたら。
(数年前の話ですが実際に私の昔の同僚も全く同じ事を思っていて同じ事してました・・・)
注意
・全てのmoduleを使用してでの動作確認はしていません
・いきなり本番環境ではつかわない
・冪等性が崩れる可能性がありますのでナンセンスとも思う