Skip to content

Commit fc7b5e0

Browse files
authored
Add ansible play execution tracking to central log file (#1733)
Track all Ansible play executions (osism-ansible, kolla-ansible, ceph-ansible, osism-kubernetes) in /share/ansible-execution-history.json with timestamp, runtime version, hosts, and result status. - Add get_container_version() to read versions from /interface/versions/{worker}.yml - Add log_play_execution() to append execution records with file locking - Log play start and completion in run_ansible_in_environment() - Use "latest" as default when version parameter is empty - Use JSON Lines format for safe concurrent appends AI-assisted: Claude Code Signed-off-by: Christian Berendt <[email protected]>
1 parent 0a5626a commit fc7b5e0

File tree

2 files changed

+125
-3
lines changed

2 files changed

+125
-3
lines changed

osism/tasks/__init__.py

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3+
import fcntl
4+
import json
35
import os
46
import re
57
import subprocess
8+
import yaml
9+
from datetime import datetime, timezone
10+
from pathlib import Path
611

712
from loguru import logger
813

@@ -30,6 +35,103 @@ class Config:
3035
}
3136

3237

38+
def get_container_version(worker):
39+
"""Read container version from YAML version file.
40+
41+
Args:
42+
worker: The runtime container name (osism-ansible, kolla-ansible, ceph-ansible, osism-kubernetes)
43+
44+
Returns:
45+
str: The container version, "latest" if empty, or "unknown" if not found
46+
47+
Examples:
48+
>>> get_container_version("osism-ansible")
49+
"7.0.5a"
50+
>>> get_container_version("kolla-ansible")
51+
"18.1.0"
52+
>>> get_container_version("osism-kubernetes")
53+
"1.29.0"
54+
55+
Note:
56+
If the version parameter in the YAML file is an empty string (""),
57+
the function returns "latest" as the default value.
58+
"""
59+
version_file = Path(f"/interface/versions/{worker}.yml")
60+
61+
try:
62+
if not version_file.exists():
63+
logger.debug(f"Version file not found: {version_file}")
64+
return "unknown"
65+
66+
with open(version_file, "r") as f:
67+
version_data = yaml.safe_load(f)
68+
69+
# Convert worker name to version parameter name
70+
# osism-ansible -> osism_ansible_version
71+
# kolla-ansible -> kolla_ansible_version
72+
# ceph-ansible -> ceph_ansible_version
73+
version_key = f"{worker.replace('-', '_')}_version"
74+
75+
version = version_data.get(version_key, "unknown")
76+
77+
# If version is empty string, use "latest" as default
78+
if version == "":
79+
version = "latest"
80+
logger.debug(f"Version parameter empty for {worker}, using 'latest'")
81+
82+
logger.debug(f"Read version {version} for {worker} from {version_file}")
83+
return version
84+
85+
except Exception as e:
86+
logger.warning(f"Failed to read version from {version_file}: {e}")
87+
return "unknown"
88+
89+
90+
def log_play_execution(
91+
request_id, worker, environment, role, hosts=None, result="started"
92+
):
93+
"""Log Ansible play execution to central tracking file.
94+
95+
Args:
96+
request_id: The Celery task request ID for correlation
97+
worker: The runtime container (osism-ansible, kolla-ansible, ceph-ansible, osism-kubernetes)
98+
environment: The environment parameter
99+
role: The playbook/role that was executed
100+
hosts: List of hosts the play was executed against (default: empty list)
101+
result: Execution result - "started", "success", or "failure"
102+
"""
103+
log_file = Path("/share/ansible-execution-history.json")
104+
105+
# Get runtime version from YAML version file
106+
runtime_version = get_container_version(worker)
107+
108+
execution_record = {
109+
"timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
110+
"request_id": request_id,
111+
"worker": worker,
112+
"worker_version": runtime_version,
113+
"environment": environment,
114+
"role": role,
115+
"hosts": hosts if isinstance(hosts, list) else [],
116+
"result": result,
117+
}
118+
119+
try:
120+
# Create directory if it doesn't exist
121+
log_file.parent.mkdir(parents=True, exist_ok=True)
122+
123+
# Append with file locking for thread safety
124+
with open(log_file, "a") as f:
125+
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
126+
try:
127+
f.write(json.dumps(execution_record) + "\n")
128+
finally:
129+
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
130+
except Exception as e:
131+
# Log warning but don't fail the execution
132+
logger.warning(f"Failed to log play execution to {log_file}: {e}")
133+
134+
33135
def run_ansible_in_environment(
34136
request_id,
35137
worker,
@@ -73,6 +175,16 @@ def run_ansible_in_environment(
73175
if ansible_vault_password:
74176
env["VAULT"] = "/ansible-vault.py"
75177

178+
# Log play execution start
179+
log_play_execution(
180+
request_id=request_id,
181+
worker=worker,
182+
environment=environment,
183+
role=role,
184+
hosts=None, # Host extraction would require inventory parsing
185+
result="started",
186+
)
187+
76188
# NOTE: Consider arguments in the future
77189
if locking:
78190
lock = utils.create_redlock(
@@ -110,8 +222,8 @@ def run_ansible_in_environment(
110222
env=env,
111223
)
112224

113-
# execute roles from kubernetes
114-
elif worker == "kubernetes":
225+
# execute roles from osism-kubernetes
226+
elif worker == "osism-kubernetes":
115227
if locking:
116228
lock.acquire()
117229

@@ -163,6 +275,16 @@ def run_ansible_in_environment(
163275

164276
rc = p.wait(timeout=60)
165277

278+
# Log play execution result
279+
log_play_execution(
280+
request_id=request_id,
281+
worker=worker,
282+
environment=environment,
283+
role=role,
284+
hosts=None, # Host extraction would require inventory parsing
285+
result="success" if rc == 0 else "failure",
286+
)
287+
166288
if publish:
167289
utils.finish_task_output(request_id, rc=rc)
168290

osism/tasks/kubernetes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def run(self, environment, playbook, arguments, publish=True, auto_release_time=
2121

2222
return run_ansible_in_environment(
2323
self.request.id,
24-
"kubernetes",
24+
"osism-kubernetes",
2525
environment,
2626
playbook,
2727
arguments,

0 commit comments

Comments
 (0)