I am currently experimenting with an Ansible playbook executed from a Flask application, and I’m aiming to capture the output logs in real-time, then send them to my HTML using Socket.IO. Despite attempting options like setting quiet=False
and exploring runner.events
, I have not achieved the desired results as the logs are only sent after the playbook completes. I am relatively new to the Ansible Python integration. Any guidance or suggestions would be greatly appreciated. Thanks! Don’t mind the passwords ist for a local test machine
import ansible_runner
@app.route('/generate_ansible_inventory', methods=['GET'])
def generate_ansible_inventory():
# Load data from TinyDB
vm_data_list = load_vm_from_db()
# Create an empty inventory dictionary
inventory = {"all": {"hosts": {}, "vars": {}}}
# Loop through VMs in the TinyDB
for vm_data in vm_data_list:
# Add an inventory host
inventory["all"]["hosts"][vm_data["vm_name"]] = {
"ansible_host": vm_data["vm_ipv4_address"],
"ansible_user": "bart",
"ansible_ssh_pass": "bart",
"ansible_become_pass": "bart"
}
# Save the inventory dictionary to a json file in the Ansible directory
with open('ansible/inventory.json', 'w') as file:
json.dump(inventory, file, indent=4)
return jsonify(inventory)
# Run Ansible playbook asynchronously
def run_ansible_playbook_async(playbook_path, inventory_path):
try:
# Read the inventory from the JSON file
with open(inventory_path, 'r') as file:
inventory = json.load(file)
# Run the playbook
runner = ansible_runner.run(
playbook=playbook_path,
inventory=inventory,
quiet=False, # Set quiet to False to capture logs
stdout_callback=log_callback, # Set the callback for log messages
)
# Emit each log line to connected clients
for event in runner.events:
if event['event'] == 'runner_on_ok' and 'stdout' in event['stdout']:
socketio.emit('ansible_output', {'log_message': event['stdout']['stdout_lines'][0]})
elif event['event'] == 'runner_on_failed' and 'stderr' in event['stdout']:
socketio.emit('ansible_output', {'log_message': event['stdout']['stdout_lines'][0]})
# Print the output
print("Playbook run status:", runner.status)
print("Playbook run stats:", runner.stats)
except Exception as e:
print("Error running the Ansible playbook:", e)
# Route for running Ansible playbook
@app.route('/run_ansible_playbook', methods=['GET'])
def run_ansible_playbook():
try:
# Define playbook and inventory paths
playbook_path = os.path.join(os.getcwd(), 'ansible', 'playbook.yml')
inventory_path = os.path.join(os.getcwd(), 'ansible', 'inventory.json')
# Start a new thread for running Ansible playbook asynchronously
ansible_thread = Thread(target=run_ansible_playbook_async, args=(playbook_path, inventory_path))
ansible_thread.start()
return jsonify({"status": "Ansible playbook execution started in the background"})
except Exception as e:
return jsonify({"status": f"Error running Ansible playbook: {str(e)}"})
@app.route('/ansible_logs', methods=['GET'])
def ansible_logs():
return render_template('ansible_logs.html')
```