【问题标题】:Ansible Tasks reuse of HTTP Session from Python Requests moduleAnsible 任务重用来自 Python 请求模块的 HTTP 会话
【发布时间】:2021-09-06 09:46:46
【问题描述】:

Ansible 任务重用 Python 请求中的 HTTP 会话

场景:

  • 复杂的 Web 服务登录过程,包括多次重定向和表单抓取(通过 BeautifulSoup)
  • Python 脚本文件使用带有 Session 的 Requests 模块,用于存储登录成功的令牌和 cookie,以供后续 Web 服务 API 调用使用

目标:

  • Ansible 任务 1:执行 Python 脚本进行 Web Service 身份验证,将 HTTPS 会话返回给 Ansible
  • Ansible 任务 2..n:使用内置的 uri Ansible 模块执行 Web 服务 API,使用来自 HTTPS 会话

想法:

  • 老实说,我有点困惑如何在 Ansible 中有效地构建它。将用于身份验证的整个 Python 脚本视为一个 Ansible 模块可能是明智的?

Python 身份验证脚本示例(简化)

def main():
    import requests

    # Create Session for requests, store all cookies in this object
    https_session = requests.Session()

    if 'page_1' not in globals():
        page_1 = https_session.get(
            'https://login.test.com',
            allow_redirects=True
        )

    ...
    ...
    ...

    if 'redirect_8' not in globals():
        redirect_8 = https_session.post(
            'https://login.test.com/authenticate',
            allow_redirects=True,
        data = {
            "token": response_7['token']
            }
        )

    # Return the Cookie Jar
    return https_session.cookies


main()

ANSIBLE 调用示例:

- name: test1
  script: login.py
  args:
        executable: python3
  environment:
        username: "{{ input_user }}"
        password: "{{ input_pwd }}"
  ignore_errors: yes
  register: login_test

- debug:
    msg: "{{ login_test }}.stdout"

返回 ANSIBLE 的示例:

"
{
    "results": [
        {
            "changed": True,
            "rc": 0,
            "stdout": "<RequestsCookieJar[<Cookie TOKEN=wxyz-wxyz for .home.test.com/>, <Cookie USER_ID=123456789 for .home.test.com/>\\n",
            "stdout_lines": [
                "<RequestsCookieJar[<Cookie TOKEN=wxyz-wxyz for .home.test.com/>, <Cookie USER_ID=123456789 for .home.test.com/>, "
            ],
            "stderr": "",
            "stderr_lines": [],
            "failed": False,
            "ansible_loop_var": "item",
        }
    ],
    "skipped": False,
    "changed": True,
    "msg": "All items completed",
}
.stdout"

【问题讨论】:

  • 也许return json.dumps(https_session.cookies.get_dict()) 是要走的路?仍然对采取什么方向/此用例可用的选项感到困惑

标签: python ansible ansible-inventory


【解决方案1】:

这可以很好地包裹在lookup plugin

lookup_plugins/session_cookie.py:

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

DOCUMENTATION = """
  lookup: session_cookie
  author: Author
  options:
    username:
      type: string
      required: True
    password:
      type: string
      required: True
"""

from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
import requests

display = Display()

class LookupModule(LookupBase):
    def run(self, _terms, variables=None, **kwargs):
        self.set_options(var_options=variables, direct=kwargs)

        url_username=self.get_option('username')
        url_password=self.get_option('password')

        https_session = requests.Session()

        # do your custom sutff here
        https_session.get(
            'https://google.com',
            allow_redirects=True
        )

        # retrieve cookies from session an return them
        cookies = https_session.cookies.get_dict()

        return [cookies]


然后它可以像这样在剧本中使用:

playbook.yml

- name: Get session cookie
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    password: secret
    user: admin
    cookie: "{{ lookup('session_cookie', username=user, password=password) }}"
  tasks:
    - debug:
         msg: "{{ cookie['1P_JAR'] }}"

运行它会从会话中返回 cookie 值:

ansible-playbook -i',' playbook.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [Get session cookie] *****************************************************************************************************

TASK [debug] ******************************************************************************************************************
ok: [localhost] => {
    "msg": "2021-09-13-10"
}

我注意到 requests 有时不能很好地与 ansible 分叉配合使用,请参阅 ansible issue,所以我不得不添加这个环境 export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

【讨论】:

    最近更新 更多