LoginSignup
0
1

More than 5 years have passed since last update.

Ansible Towerで実行したテンプレートのジョブのステータスをAPIで確認する

Last updated at Posted at 2018-03-24

Ansible Towerで実行したテンプレートのジョブステータスをAPIで取得した時のメモです。

環境

項目 バージョン
OS RHEL7.4
Ansible Tower 3.2.3
python 3.4

Ansible Tower APIドキュメント

http://docs.ansible.com/ansible-tower/3.1.4/html/towerapi/index.html

ジョブ情報取得URL

テンプレートを実行した時に生成されるジョブIDを元に、そのジョブの情報が以下URLから取得できます。

URL
/api/v1/ジョブID

ジョブIDはテンプレート実行した時のレスポンスBodyに含まれています。
以下がレスポンスの例です。
レスポンスの url を元に実行したジョブのステータス情報が取得できます。

{
  "ignored_fields": {},
  "id": 142,
  "type": "job",
  "url": "/api/v1/jobs/142/",
(snip)
}

検証

検証Playbook

---
- name: TEST Playbook
  hosts: localhost
  tasks:
    - wait_for: timeout=5
    - debug: msg="Hello World"

検証テンプレート

検証ツール

ansible-tower-api-tool.py
#!/usr/bin/env python3
from getpass import getpass
import argparse
import sys
import json
import re
import time
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class colors:
    GREEN = '\033[32m'
    RED = '\033[91m'
    END = '\033[0m'

def options():
    parser = argparse.ArgumentParser(prog="ansible-tower-api-tool.py",
                                     add_help=True,
                                     description="Ansible Towerのテンプレートを実行するツール")
    parser.add_argument("--host",
                        type=str, required=True,
                        help="Ansible TowerサーバのIPまたはホスト名")
    parser.add_argument("--username", "-u",
                        type=str,default="admin",
                        help="Ansible Towerアカウント(default:admin)")
    parser.add_argument("--password", "-p",
                        type=str,
                        help="Ansible Towerアカウントのパスワード")
    parser.add_argument("--template", "-t",
                        type=str, required=True,
                        help="実行するテンプレート名")
    parser.add_argument("--data", "-d",
                        type=eval,
                        help="テンプレートのextra_vars")

    args = parser.parse_args()
    if(not(args.password)):
        args.password = getpass(prompt="Ansible Tower Password: ")

    return args

def get_header():
    headers = { "Content-Type": "application/json" }
    return headers

def get_cred(username, password):
    cred = {
        'username': username,
        'password': password
    }
    return cred

def create_url(host, path):
    url = "https://%s%s" % (host, path)
    return url

def get_token(host, cred):
    url = create_url(host, "/api/v2/authtoken/")
    r = post(url, get_header(), cred)

    if(r.status_code == 200):
        token = json.loads(r.text)['token']
        return token
    else:
        print('Token acquisition error.')
        sys.exit(1)

def get(url, headers):
    r = requests.get(url,
                     headers=headers,
                     verify=False)

    return r

def post(url, headers, data):
    r = requests.post(url,
                      headers=headers,
                      data=json.dumps(data),
                      verify=False)

    return r

if __name__ == '__main__':
    # オプションを取得
    args = options()

    # 認証Tokenを取得
    cred = get_cred(args.username, args.password)
    token = get_token(args.host, cred)

    # ヘッダー情報を生成
    headers = get_header()
    headers["Authorization"] = "Token " + token

    # テンプレードID取得
    url = create_url(args.host, "/api/v1/job_templates")
    r = get(url, headers)

    for i in json.loads(r.text)['results']:
        if(i["name"] == args.template):
            template_launch_url = i["related"]["launch"]
            break

    if(not("template_launch_url" in locals())):
        print("%s template not found" % args.template)
        sys.exit(1)

    # テンプレートを実行
    url = create_url(args.host, template_launch_url)
    r = post(url, headers, args.data)

    # ジョブIDとURLを取得
    job_id = json.loads(r.text)["job"]
    job_url = json.loads(r.text)["url"]

    # ジョブステータス確認
    Loop = True
    url = create_url(args.host, job_url)
    while Loop:
        r = get(url, headers)
        r = json.loads(r.text)
        if(r["id"] == job_id and re.match(r"new|pending|running", r["status"])):
            msg = "jobID: %s" % r["id"]
            sys.stdout.write(msg.ljust(20) + "[%s]" % r["status"] + "\r")
        elif(r["id"] == job_id and re.match(r"successful|failed|error|canceled", r["status"])):
            msg = "jobID: %s" % r["id"]
            if(r["status"] == "successful"):
                for i in range(1,30): sys.stdout.write(" ")
                sys.stdout.write("\r" + msg.ljust(20) + "[" + colors.GREEN + r["status"] + colors.END + "]" + "\n")
            else:
                for i in range(1,30): sys.stdout.write(" ")
                sys.stdout.write("\r" + msg.ljust(20) + "[" + colors.RED + r["status"] + colors.END + "]" + "\n")
            Loop = False
        time.sleep(1)

テンプレートを実行した後にレスポンスから job_url を取得してステータスが終了するまでループします。

実行例

こんな感じでステータスが確認できます。

ansible_tower_job_status_check.gif

最後に

ジョブ情報の中には result_stdout に実行結果が入るので以下のコードを上記ツールの最後に入れて実行すれば

(snip)
    # ジョブ実行結果出力
    r = get(url, headers)
    print(json.loads(r.text)["result_stdout"])

こんな感じで結果も見える。

[root@localhost ~]# ./ansible-tower-api-tool.py --host 192.168.0.234 -t TEST -d '{}'
Ansible Tower Password:
jobID: 149          [successful]
SSH password:

PLAY [TEST Playbook] ***********************************************************

TASK [Gathering Facts] *********************************************************
ok: [127.0.0.1]

TASK [wait_for] ****************************************************************
ok: [127.0.0.1]

TASK [debug] *******************************************************************
ok: [127.0.0.1] => {
    "msg": "Hello World"
}

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

追記

replace で文字の \n を改行に変更してあげればエラーが改行されて見やすくなる。

    # ジョブ実行結果出力
    r = get(url, headers)
    print(json.loads(r.text)["result_stdout"].replace("\\n","\n"))

結果

[root@localhost ~]# ./ansible-tower-api-tool.py --host 192.168.0.234 -t TEST -d '{}'
Ansible Tower Password:
jobID: 151          [failed]
SSH password:

PLAY [TEST Playbook] ***********************************************************

TASK [Gathering Facts] *********************************************************
ok: [127.0.0.1]

TASK [debug] *******************************************************************
fatal: [127.0.0.1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'MSG' is undefined

The error appears to have been in '/var/lib/awx/projects/test/test.yml': line 7, column 7, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

    #- debug: msg=\"Hello World\"
    - debug: msg=\"{{ MSG }}\"
      ^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes.  Always quote template expression brackets when they
start a value. For instance:

    with_items:
      - {{ foo }}

Should be written as:

    with_items:
      - \"{{ foo }}\"

exception type: <class 'ansible.errors.AnsibleUndefinedVariable'>
exception: 'MSG' is undefined"}

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=1    changed=0    unreachable=0    failed=1
0
1
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
0
1