AWX(Ansible Tower)の実行ログをバックアップする

# 概要

まず、この記事は「[ワークフロー内の一連のジョブの実行ログをファイルで保存するPlaybook](https://tekunabe.hatenablog.jp/entry/2020/04/18/ansible_awx_wf_log_dowload)」を参考にしました。いつもながらありがとうございます！
上記をベースに実行時のパラメータ（外部変数）履歴取得、DLした実行ログを圧縮し、S3に転送する機能を追加しました。

AWXのバージョンアップや作り直しでジョブの実行ログを監査目的で保存したいケースも多々あると思いますので、そのような時にお使いください。[ログアグリゲーター](https://docs.ansible.com/ansible-tower/latest/html/administration/logging.html)で常時転送する場合はこちらは不要になります。

ちなみに実行ログをバックアップする方法としてCLIでまとめてできないようです。どうしてもAPI経由で1件ずつ取得する必要があるようです。awx-cliも同じです。なので、ジョブ数が多い場合は**かなり時間がかかります**。

※AWXで実装しましたが、AnsibleTowerも同様のコードで動作するはず。

# 仕様

1. APIで1件ずつ実行ログと実行パラメータを取得し、ローカルにファイルとして出力します。
2. すべてのログを取得後に、Zipに圧縮し、S3に転送します。

# コード

以下のplaybookのvarsの各種変数の値を入力してから実行してください。
[REST APIのリファレンスはこちら](https://docs.ansible.com/ansible-tower/3.5.2/html_ja/towerapi/api_ref.html)を参照ください。

```yaml:playbook.yml
---
####################
# AWX の実行ログをすべてバックアップし、S3に保存
#
#
- name: Backup all AWX job stdouts and Upload to S3
  hosts: localhost
  connection: local
  gather_facts: False
  vars_files:
    - "../vars/env/all_{{ env_all.stage }}.yml"
  vars:
    awx_username: ""
    awx_password: ""
    awx_host: ""
    job_log_dir: "/tmp/awx_job_log"
    s3_bucket_name: ""
    s3_prefix: ""
    # ファイル名が重複しないように実行時間(unix)を保持する
    execute_time: "{{ lookup('pipe', 'date +%s' ) }}"
  roles:
    - role: ../roles/aws_auth_setup
  tasks:
    - name: Get job count
      uri:
        url: "{{ awx_host }}/api/v2/jobs/?page_size=1"
        method: GET
        url_username: "{{ awx_username }}"
        url_password: "{{ awx_password }}"
        force_basic_auth: true
        validate_certs: false
      register: _result_job_list

    - set_fact:
        _job_count: "{{ _result_job_list.json.count }}"

    - name: Make save logs directory
      file:
        path: "{{ job_log_dir }}"
        state: directory

    # 実行結果をバックアップする。
    # １からジョブ総数までループして出力します。
    - include_tasks: ./awx_backup_job_log.yml
      with_sequence: start=1 end="{{ _job_count }}"
      loop_control:
        loop_var: _job_id

    # 実行ログを圧縮
    - name: Archive awx log
      archive:
        path: "{{ job_log_dir }}/*"
        dest: "/tmp/awx_job_log_{{ execute_time }}.zip"
        format: zip

    # S3に転送
    - name: Upload to s3
      aws_s3:
        bucket: "{{ s3_bucket_name }}"
        object: "{{ s3_prefix }}/awx_job_log_{{ execute_time }}.zip"
        src: "/tmp/awx_job_log_{{ execute_time }}.zip"
        mode: put
```

```yaml:awx_backup_job_log.yml
---
# ジョブを１から順に取得するため、削除済みのジョブで404エラーになるが、無視します
- name: Get job stdout
  uri:
    url: "{{ awx_host }}/api/v2/jobs/{{ _job_id }}/stdout/?format=txt"
    method: GET
    return_content: true
    url_username: "{{ awx_username}}"
    url_password: "{{ awx_password }}"
    force_basic_auth: true
    validate_certs: false
  failed_when: _result_job.status != 404 and _result_job.status != 200
  register: _result_job
  until: not _result_job.failed
  retries: 3
  delay: 2

- name: Make save job log directory
  file:
    path: "{{ job_log_dir }}/job_{{ _job_id }}"
    state: directory

# ジョブIDごとにフォルダ分けて保存
- name: Make log file
  file:
    path: "{{ job_log_dir }}/job_{{ _job_id }}/stdout.txt"
    state: touch

# 404の時はスキップ
- block:
    # 結果をファイルに出力(上書き)
    - name: Save job log to file
      copy:
        content: "{{ _result_job.content }}"
        dest: "{{ job_log_dir }}/job_{{ _job_id }}/stdout.txt"
        force: yes

    # ジョブの実行時パラメータを取得
    - name: Get job activity stream
      uri:
        url: "{{ awx_host }}/api/v2/jobs/{{ _job_id }}/activity_stream/"
        method: GET
        return_content: true
        url_username: "{{ awx_username }}"
        url_password: "{{ awx_password }}"
        force_basic_auth: true
        validate_certs: false
      register: _result_job_stream
      until: not _result_job_stream.failed
      retries: 3
      delay: 2

    # 結果をファイルに出力(上書き)
    - name: Save job log to file
      copy:
        content: "{{ _result_job_stream.content }}"
        dest: "{{ job_log_dir }}/job_{{ _job_id }}/activity_stream.txt"
        force: yes

  when: _result_job.status == 200
```