关于基于Playwright Python实现Chrome浏览器下Swagger API自动化及Ansible Tower自动化Python框架的技术需求与建议征集
Got it, let's tackle your two requirements step by step—first building a Playwright Python script for Swagger API automation in Chrome, then creating a Python framework that plays nicely with Ansible Tower.
Swagger UI is a web interface, so we'll use Playwright's browser automation to interact with it just like a human would. Here's a practical implementation:
Prerequisites
First, set up your environment:
- Install Playwright and Chrome dependencies:
pip install playwright playwright install chrome
Core Automation Script
This script targets a sample Swagger UI, navigates to a specific API endpoint, fills in parameters, executes the request, and validates the response:
from playwright.sync_api import sync_playwright import logging import json # Configure logging for debugging (critical for Ansible Tower integration) logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) def automate_swagger_api(swagger_url: str, api_operation_id: str, request_body: dict): with sync_playwright() as p: # Launch Chrome in headless mode (ideal for server environments like Ansible Tower) browser = p.chromium.launch(headless=True, channel="chrome") page = browser.new_page() try: # Navigate to Swagger UI and wait for full load page.goto(swagger_url, wait_until="networkidle") logger.info(f"Successfully loaded Swagger UI at {swagger_url}") # Expand the target API operation using its unique operation ID (more stable than text) expand_button = page.locator(f'[data-operation-id="{api_operation_id}"]').locator('button') expand_button.click() logger.info(f"Expanded API operation: {api_operation_id}") # Click "Try it out" to enable parameter editing try_it_button = page.locator(f'[data-operation-id="{api_operation_id}"] button:has-text("Try it out")') try_it_button.click() logger.info("Enabled API parameter editing via 'Try it out'") # Fill in request body (adjust selector if your Swagger UI uses a different layout) body_textarea = page.locator(f'[data-operation-id="{api_operation_id}"] textarea[name="body"]') body_textarea.fill(json.dumps(request_body)) logger.info(f"Filled request body: {json.dumps(request_body)}") # Execute the API request execute_button = page.locator(f'[data-operation-id="{api_operation_id}"] button:has-text("Execute")') execute_button.click() # Wait for response and extract status code response_status = page.locator(f'[data-operation-id="{api_operation_id}"] .response-col_status') response_status.wait_for(timeout=10000) status_code = response_status.text_content().strip() logger.info(f"API executed successfully, status code: {status_code}") # Extract and return response details response_body = page.locator(f'[data-operation-id="{api_operation_id}"] .response-col_body pre').text_content() return {"status": "success", "status_code": status_code, "response_body": json.loads(response_body)} except Exception as e: logger.error(f"Automation failed: {str(e)}", exc_info=True) # Capture screenshot for debugging (saved to Tower's execution directory) page.screenshot(path=f"swagger_error_{api_operation_id}.png") raise # Re-raise to let Ansible Tower mark the job as failed finally: browser.close() # Example direct execution if __name__ == "__main__": automate_swagger_api( swagger_url="https://petstore.swagger.io/v2/swagger.json", api_operation_id="addPet", request_body={"id": 123, "name": "TestPet", "status": "available"} )
Key Reliability Tips
- Use operation IDs instead of text selectors: Swagger generates unique
data-operation-idattributes for each endpoint, making your script resistant to UI text changes. - Headless mode: Non-negotiable for Ansible Tower's server environment (no GUI required).
- Timeouts & retries: Add
wait_forcalls with reasonable timeouts to handle slow-loading Swagger UIs.
To make your automation work seamlessly with Ansible Tower, focus on configurability, compatibility with Tower's execution model, and clear error handling. Here's how to structure the framework:
Core Framework Components
a. Configurability (No Hardcoding!)
Use command-line arguments and environment variables to pass parameters—Tower can inject these via job templates:
import argparse import os import json def parse_args(): parser = argparse.ArgumentParser(description="Swagger API Automation for Ansible Tower") parser.add_argument("--swagger-url", default=os.getenv("SWAGGER_URL"), required=True, help="URL of Swagger UI") parser.add_argument("--api-operation-id", default=os.getenv("API_OPERATION_ID"), required=True, help="Target API operation ID") parser.add_argument("--request-body", default=os.getenv("REQUEST_BODY"), required=True, help="JSON request body") return parser.parse_args() # In your main execution flow args = parse_args() request_body = json.loads(args.request_body) automate_swagger_api(args.swagger_url, args.api_operation_id, request_body)
b. Ansible Tower Compatibility
- Proper exit codes: Tower uses exit codes to mark jobs as success/failure. Re-raising exceptions (like in the script above) ensures non-zero exit codes on failure.
- Log to stdout/stderr: Tower captures console logs, so use Python's
loggingmodule withStreamHandlerto send all logs directly to the console. - Dependency management: Create a
requirements.txtfile for your dependencies:
Add a pre-run step in your Tower job template to install them:playwright==1.40.0pip install -r requirements.txt && playwright install chrome --with-deps
c. Integration with Tower's Ecosystem
- Use Tower environment variables: If you need to interact with Tower's API post-execution, leverage built-in variables like
TOWER_HOSTandTOWER_OAUTH_TOKEN. - Idempotent operations: Ensure your API automation is idempotent (running it multiple times doesn't cause unintended side effects)—critical for repeatable Tower jobs.
Example Tower Job Setup
- Store code in Git: Push your framework and scripts to a Git repo (Tower can pull this directly via a project).
- Create a Job Template:
- Select "Python" as the execution environment.
- Set the command to:
python swagger_automation.py --swagger-url "{{ swagger_url }}" --api-operation-id "{{ api_operation_id }}" --request-body "{{ request_body }}" - Add Extra Variables for
swagger_url,api_operation_id, andrequest_body(set defaults or prompt users at runtime).
- Configure Environment Variables:
- Add
PLAYWRIGHT_BROWSERS_PATH=0to force Playwright to use the system-installed Chrome (avoids downloading browsers in Tower's temporary space).
- Add
Bonus Tips
- Isolated execution: Run your script in a Docker container pre-configured with Playwright and Chrome to avoid dependency conflicts in Tower.
- Notifications: Add logic to trigger Tower's built-in notifications (Slack, email, etc.) on success/failure.
- Result storage: Push automation results (like response data) to Tower's custom facts or a external datastore for auditing.
内容的提问来源于stack exchange,提问作者Ali Haider

