LoginSignup
5
4

More than 5 years have passed since last update.

Ansibleで WindowsServerへセキュリティアップデート(KB)を個別にインストールする その2 ~ ディレクトリ配下にある複数MSUファイルをlsコマンドで動的に取得してループしてインストール

Last updated at Posted at 2016-07-04

0.はじめに

Windows2012ServerR2へAnsibleからMSUファイルを利用してKBをインストールするサンプルのAnsible playbookです。
Chefでも似たようなことはできると思います。

本投稿は前回の投稿のアップデート版です。
patchディレクトリ配下にあるMSUファイルをlsコマンドで動的に取得し、MSUファイル分ループしてインストールする形へアップデートしたもの(blockのloopをwith_itmes * include , jinja2 filter regex_replace をなどを駆使)
なお、前回には無い、blook処理とKBインストール前後でKBのインストールチェックを追加していますが
再起動をしないと反映されないKBの場合?は、
インストール後のチェックコマンド部分(win_patch_child.ymlの17~20行目、)をコメントアウトするか、
インストール後のチェックについては別のプレイブックで実施、またはServerspec等で確認をお願いします。

以下は前回より変更ありません。
rawモジュールなどを使った泥臭いやり方ですが、Windows関連の事例が少ないのであくまで参考までに。
実際にはserviceの上げ下げやreboot、上位のLB制御なども必要だと思いますがシンプルにKBのインストールのみを記載しています。
また、インストールについてはDISMではなくpkgmgrを使用しています。

1.大まかな流れ

Ansibleサーバ側で

0. 事前にプレイブック実行ディレクトリにpatchディレクトリ作成と配下に対象のmsuファイルを手動/自動でダウンロードしておく

win_patch.yml
1. ls コマンドでpatchディレクトリ配下のファイル名を動的に取得し、playbookのlsコマンド結果変数へ格納
2. lsコマンド結果変数で存在するファイル分、動的にループ(with_items)し、拡張子がMSUファイルの場合のみ、KBファイルのインストールを行うプレイブックwin_patch_child.ymlを呼出す(include) 、取得したMSUファイル名をregex_replaceにより正規表現で動的に加工し、KB番号など変数としてセット

以下Ansible ServerからターゲットのWindowsへ

win_patch_child.yml
1. msuファイルをコピーするためのディレクトリを作成
2. msuファイルをコピー
3. msuファイルを圧縮解凍
4. pkgmgrでサイレントインストール

2.playbook等

win_patch.yml
---
- hosts: win
# Don't gather hosts facts for performance
  gather_facts: no
# Setting the task
  tasks:
   - name: "Get Win pacth name"
     shell: ls patch
     delegate_to: localhost
     register: command_result

   - name: "Install Win patch"
     include: win_patch_child.yml kb_msu={{ item }}
     with_items: "{{ command_result.stdout_lines }}"
     when: "'.msu' in item"
     vars:
       kb_src_dr:             "patch"
       kb_dest_dr:            "c:/work/"
       kb_src:                "{{ kb_src_dr }}/{{ kb_msu }}"
       kb_dest:               "{{ kb_dest_dr }}/{{ kb_msu }}"
       kb_xml:                "{{ kb_msu | regex_replace('.msu','.xml') }}"
       kb_no:                 "{{ kb_msu | regex_replace('^.*-KB(\\d*)-.*msu$','\\1') }}"
       check_command:         "wmic qfe | findstr {{ kb_no }}"
# When I use wusa/pkgmagr as follows vars.
       decompression_command: "wusa {{kb_dest}} /extract:{{ kb_dest_dr }}"
       install_command:       "pkgmgr /n:{{ kb_dest_dr }}{{ kb_xml }} /quiet /norestart"
       uninstall_command:     "wusa /uninstall /kb:{{ kb_no }} /quiet /norestart"
# When you use expand/Dism, you comment out a line of wusa/pkgmagr, and please use a variable as follows.
#       kb_cab:                "{{ kb_msu | regex_replace('.msu','.cab') }}"
#       decompression_command: "expand -f:{{kb_cab}} {{ kb_dest_dr }}{{ kb_msu }} {{ kb_dest_dr }}KB{{ kb_no }}"
#       install_command:       "Dism /Online /Add-Package /PackagePath:{{ kb_dest_dr }}KB{{ kb_no }} /quiet /norestart"
#       uninstall_command:     "wusa /uninstall /kb:{{ kb_no }} /quiet /norestart"
win_patch_child.yml
---
  - name: Check KB
    raw: "{{ check_command }}"
    register: command1_result
    failed_when: command1_result.rc not in [ 0 , 1 ]

  - block:
      - debug: msg="Block START ----------------------"
      - name: create directory
        win_file: path={{ kb_dest_dr  }} state=directory
      - name: copy the file
        win_copy: src={{ kb_src }} dest={{ kb_dest }} mode=0755
      - name: decompression the msu file
        raw: "{{ decompression_command }}"
      - name: install KB
        raw: "{{ install_command }}"
      - name: Check KB
        raw: "{{ check_command }}"
        register: command2_result
        failed_when: "'KB{{ kb_no }}' not in command2_result.stdout"
      - debug: msg="Block END ------------------------"
    when: "'KB{{ kb_no }}' not in command1_result.stdout"

    rescue:
      - debug: msg="Rescue START ---------------------"
      - debug: msg="install {{ kb_no }} is error"
      - name: uninstall KB
        raw: "{{ uninstall_command }}"
      - debug: msg="Rescue END -----------------------"

    always:
      - debug: msg="Always START ---------------------"
      - debug: msg="before '{{ check_command }}' {{ command1_result.stdout_lines }}"
        when: command1_result is defined
      - debug: msg="after  '{{ check_command }}' {{ command2_result.stdout_lines }}"
        when: command2_result is defined
      - debug: msg="Always END -----------------------"

  - debug: msg="Because KB{{ kb_no }} had been already installed, I skipped installation.
                This is result of the check command '{{ check_command }}'
                {{ command1_result.stdout_lines }}"
    when: "'KB{{ kb_no }}' in command1_result.stdout"

インベントリファイル hosts

[win]
win0[1:2]

[win:vars]
ansible_ssh_user=ansible
ansible_ssh_pass=ansibleansible
ansible_ssh_port=5985
ansible_connection=winrm

3.その他

patchディレクトリ配下

patch/
- Windows8.1-KB3079904-x64.msu
- Windows8.1-KB3140735-x64.msu
- openssl-1.0.1e-48.el6_8.1.x86_64.rpm

ansible --version

# ansible --version
ansible 2.2.0 (devel 394430a61e) last updated 2016/06/28 13:25:07 (GMT +900)
  lib/ansible/modules/core: (detached HEAD 3c6f2c2db1) last updated 2016/06/28 13:25:30 (GMT +900)
  lib/ansible/modules/extras: (detached HEAD 1c36665545) last updated 2016/06/28 13:25:37 (GMT +900)
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
5
4
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
5
4