Ansible技术问题:如何访问rescue区的refresh_token并消除代码重复?
解决Ansible中Token刷新后代码重复及Block访问Rescue变量的问题
首先修正你当前代码里的一个小错误:set_fact中引用的token_response应该是central_token_response,否则会触发未定义变量的错误。
下面是几种解决代码重复、实现token刷新后重试API请求的方案:
方案1:封装可复用的API请求任务(最推荐)
把API请求、401错误处理、token刷新的逻辑抽成单独的任务文件,所有API调用都复用这个文件,彻底消除重复代码。
步骤1:创建复用任务文件 tasks/api_request.yml
--- - block: - name: "{{ task_name }}" ansible.builtin.uri: url: "{{ api_url }}" method: "{{ api_method | default('GET') }}" headers: Authorization: Bearer {{ central_access_token }} Accept: application/json status_code: [200, 401] register: api_response rescue: # 只处理401(token过期)的情况,其他错误直接抛出 - name: 非401错误直接失败 ansible.builtin.fail: msg: "API请求出错,状态码: {{ api_response.status }}" when: api_response.status != 401 - name: 刷新Access Token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response - name: 更新token变量 ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" # 用新token重新执行API请求 - name: 重试 "{{ task_name }}" ansible.builtin.uri: url: "{{ api_url }}" method: "{{ api_method | default('GET') }}" headers: Authorization: Bearer {{ central_access_token }} Accept: application/json status_code: 200 register: api_response
步骤2:主任务中调用复用文件
--- # 先获取初始token(如果还没有的话) - name: 获取初始Access Token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response - name: 保存初始token ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" # 调用第一个API - name: 获取站点列表 ansible.builtin.include_tasks: tasks/api_request.yml vars: task_name: "获取站点列表" api_url: "{{ central_base_url }}/network-monitoring/v1/sites-health" register: central_sites_response # 调用第二个API - name: 获取站点下设备 ansible.builtin.include_tasks: tasks/api_request.yml vars: task_name: "获取站点下设备" api_url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}" register: central_devices_response - name: 调试设备信息 ansible.builtin.debug: var: central_devices_response.results[0].api_response
方案2:用循环重试机制处理token过期
利用Ansible的until循环,在API请求返回401时自动刷新token并重试,适合单个API的场景:
--- # 初始获取token - name: 获取初始Access Token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response - name: 保存初始token ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" token_已刷新: false - name: 获取站点列表 ansible.builtin.uri: url: "{{ central_base_url }}/network-monitoring/v1/sites-health" headers: Authorization: Bearer {{ central_access_token }} Accept: application/json method: GET status_code: 200 register: central_sites_response until: central_sites_response.status == 200 retries: 2 delay: 1 rescue: - name: 401时刷新token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response when: central_sites_response.status == 401 and not token_已刷新 - name: 更新token变量 ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" token_已刷新: true when: central_sites_response.status == 401 and not token_已刷新 - name: 非401错误直接失败 ansible.builtin.fail: msg: "API请求出错,状态码: {{ central_sites_response.status }}" when: central_sites_response.status != 401 # 同理处理第二个API请求 - name: 获取站点下设备 ansible.builtin.uri: url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}" headers: Authorization: Bearer {{ central_access_token }} Accept: application/json method: GET status_code: 200 register: central_devices_response until: central_devices_response.status == 200 retries: 2 delay: 1 rescue: - name: 401时刷新token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response when: central_devices_response.status == 401 and not token_已刷新 - name: 更新token变量 ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" token_已刷新: true when: central_devices_response.status == 401 and not token_已刷新 - name: 非401错误直接失败 ansible.builtin.fail: msg: "API请求出错,状态码: {{ central_devices_response.status }}" when: central_devices_response.status != 401 - name: 调试设备信息 ansible.builtin.debug: var: central_devices_response
方案3:Block-Rescue结合任务重入
把需要执行的API任务单独抽成文件,在rescue中刷新token后重新导入执行,适合批量API任务的场景:
步骤1:创建API任务文件 tasks/api_tasks.yml
--- - block: - name: 获取站点列表 ansible.builtin.uri: url: "{{ central_base_url }}/network-monitoring/v1/sites-health" headers: Authorization: Bearer {{ central_access_token }} Accept: application/json method: GET status_code: [200, 401] register: central_sites_response - name: 获取站点下设备 ansible.builtin.uri: url: "{{ central_base_url }}/network-monitoring/v1/aps?filter=siteId eq {{ siteId | urlencode}}" method: GET headers: Authorization: Bearer {{ central_access_token }} Accept: application/json status_code: [200, 401] register: central_devices_response - name: 调试设备信息 ansible.builtin.debug: var: central_devices_response rescue: - name: 已重试过则直接失败 ansible.builtin.fail: msg: "API任务在token刷新后仍失败" when: retry_on_token_expiry - name: 刷新Access Token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response - name: 更新token变量 ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" # 重新执行API任务,标记已重试 - name: 用新token重试API任务 ansible.builtin.include_tasks: tasks/api_tasks.yml vars: retry_on_token_expiry: true
步骤2:主任务中调用
--- # 初始获取token - name: 获取初始Access Token ansible.builtin.uri: method: POST status_code: 200 headers: Accept: application/json Content-Type: application/x-www-form-urlencoded payload: grant_type: client_credentials client_id: "{{ client_id }}" client_secret: "{{ client_secret }}" register: central_token_response - name: 保存初始token ansible.builtin.set_fact: central_access_token: "{{ central_token_response.json.access_token }}" # 执行API任务 - name: 执行站点及设备查询任务 ansible.builtin.include_tasks: tasks/api_tasks.yml vars: retry_on_token_expiry: false
内容的提问来源于stack exchange,提问作者Женя Медяник
相关产品推荐
相关产品推荐

