Python
Ansible
Python3
AnsibleTower

Ansible TowerのAPI経由からテンプレートに変数を渡して実行してみた

Ansible TowerのAPI経由からテンプレート実行で変数(extra_vars)を渡すやり方で少しハマったのでメモっておきます。

環境

項目 バージョン
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

検証ストーリー

  • Playbookはローカルの /var/lib/aws/projects に直接作成したものを使います
  • REST APIから変数をセットした情報を渡してテンプレートを実行します
  • APIはpythonスクリプトから実行します

Ansible Tower設定

プロジェクト設定

スクリーンショット 2018-03-20 22.08.40.png

テンプレート設定

注意点として 追加変数起動プロンプト にチェックを入れてください。

チェックが入っていない場合は、変数をAPI経由で渡しても無視されます。(デフォルトは無視になっています)

スクリーンショット 2018-03-20 22.09.39.png

テスト用Playbook

テスト用Playbookは以下の2つを使ってみます。

msgで変数値を出力

test.yml
---
- name: TEST Playbook
  hosts: localhost
  tasks:
    - debug: msg="{{ MSG }}"

ループで変数値を出力

test.yml
---
- name: TEST Playbook
  hosts: localhost
  tasks:
    - debug:
        msg: "{{ item }}"
      with_items: "{{ str_list }}"

APIを実行するツール

ソース

検証ツールとして以下のものを使用します。

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

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)
    print(r.status_code)

使い方

$ ./ansible-tower-api-tool.py --host AnsibleTowerのIP -t テンプレート名 -d key,valueをセットしたdict

検証

MSGの変数に値を入れてみる

MSGTEST Message を入れてAPIを実行してみます。

$ ./ansible-tower-api-tool.py --host 192.168.0.234 -t TEST -d '{"extra_vars": {"MSG":"TEST Message"}}'
Ansible Tower Password:
201

スクリーンショット 2018-03-20 22.30.13.png

ループで実行してみる

str_list に配列で Mes1 Mes2 Mes3 を入れてAPIを実行してみます。

$ ./ansible-tower-api-tool.py --host 192.168.0.234 -t TEST -d '{"extra_vars": {"str_list":["Mes1","Mes2","Mes3"]}}'
Ansible Tower Password:
201

スクリーンショット 2018-03-20 22.34.52.png

まとめ

Ansible TowerのAPI経由から変数を渡す場合は 追加変数起動プロンプト にチェックが入っていることが必要です。

これは、API経由(以下URL)からでも確認が可能です。

URL
https://$ansible_tower_ip/api/v1/job_templates/$TemplateID/launch/

以下が、GETした時の結果例です。

ask_variables_on_launchtrue になっている必要性があります。

{
  "can_start_without_user_input": false,
  "passwords_needed_to_start": [],
  "ask_variables_on_launch": true,
  "ask_tags_on_launch": false,
  "ask_diff_mode_on_launch": false,
  "ask_skip_tags_on_launch": false,
  "ask_job_type_on_launch": false,
  "ask_limit_on_launch": false,
  "ask_verbosity_on_launch": false,
  "ask_inventory_on_launch": false,
  "ask_credential_on_launch": false,
  "survey_enabled": false,
  "variables_needed_to_start": [],
  "credential_needed_to_start": false,
  "inventory_needed_to_start": false,
  "job_template_data": {
    "id": 13,
    "description": "",
    "name": "TEST"
  },
  "defaults": {
    "credential": {
      "id": 2,
      "name": "root"
    },
    "job_tags": "",
    "extra_vars": "",
    "verbosity": 0,
    "job_type": "run",
    "diff_mode": false,
    "skip_tags": "",
    "limit": "",
    "inventory": {
      "id": 2,
      "name": "TEST Host List"
    },
    "vault_credential": {
      "id": null,
      "name": null
    }
  }
}