mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-26 17:21:58 -06:00
Fix agent hash discovery and add lookup endpoint
This commit is contained in:
@@ -145,17 +145,43 @@ _AGENT_HASH_CACHE = {
|
||||
|
||||
|
||||
def _iter_hash_roots():
|
||||
seen = set()
|
||||
"""Yield candidate folders that may contain github_repo_hash.txt."""
|
||||
|
||||
root = _project_root()
|
||||
for _ in range(6):
|
||||
if not root or root in seen:
|
||||
break
|
||||
yield root
|
||||
seen.add(root)
|
||||
parent = os.path.dirname(root)
|
||||
if not parent or parent == root:
|
||||
break
|
||||
root = parent
|
||||
if not root:
|
||||
return
|
||||
|
||||
# Breadth-first walk up to a small, bounded set of parents/siblings.
|
||||
seen = set()
|
||||
queue = [root]
|
||||
|
||||
# Some deployments place the hash file directly under Agent/, while others
|
||||
# (including the scheduled updater) write to Agent/Borealis/. The previous
|
||||
# implementation only checked the parent chain which skipped Agent/Borealis,
|
||||
# so seed the queue with that sibling when available.
|
||||
borealis = os.path.join(root, "Borealis")
|
||||
if os.path.isdir(borealis):
|
||||
queue.append(borealis)
|
||||
|
||||
steps = 0
|
||||
while queue and steps < 12: # hard stop to avoid wandering too far
|
||||
steps += 1
|
||||
cur = queue.pop(0)
|
||||
if not cur or cur in seen:
|
||||
continue
|
||||
seen.add(cur)
|
||||
yield cur
|
||||
|
||||
parent = os.path.dirname(cur)
|
||||
if parent and parent != cur and parent not in seen:
|
||||
queue.append(parent)
|
||||
|
||||
# If we're currently at Agent/ or its parent, also check for an adjacent
|
||||
# Borealis/ folder in case the hash lives there.
|
||||
if cur != borealis:
|
||||
candidate = os.path.join(cur, "Borealis")
|
||||
if os.path.isdir(candidate) and candidate not in seen:
|
||||
queue.append(candidate)
|
||||
|
||||
|
||||
def _resolve_git_head_hash(root: str) -> Optional[str]:
|
||||
|
||||
@@ -3138,6 +3138,83 @@ def set_device_description(hostname: str):
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/agent/hash/<path:agent_id>", methods=["GET"])
|
||||
def get_agent_hash(agent_id: str):
|
||||
"""Return the last known github_repo_hash for a specific agent."""
|
||||
|
||||
agent_id = (agent_id or "").strip()
|
||||
if not agent_id:
|
||||
return jsonify({"error": "invalid agent id"}), 400
|
||||
|
||||
# Prefer the in-memory registry (updated on every heartbeat/details post).
|
||||
info = registered_agents.get(agent_id) or {}
|
||||
candidate = (info.get("agent_hash") or "").strip()
|
||||
hostname = (info.get("hostname") or "").strip()
|
||||
|
||||
if candidate:
|
||||
return jsonify({
|
||||
"agent_id": agent_id,
|
||||
"agent_hash": candidate,
|
||||
"source": "memory",
|
||||
})
|
||||
|
||||
# Fall back to the persisted device_details row, if any.
|
||||
try:
|
||||
conn = _db_conn()
|
||||
cur = conn.cursor()
|
||||
|
||||
row = None
|
||||
if hostname:
|
||||
cur.execute(
|
||||
"SELECT agent_hash, details FROM device_details WHERE hostname = ?",
|
||||
(hostname,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
else:
|
||||
# No hostname available; scan for a matching agent_id in the JSON payload.
|
||||
cur.execute("SELECT hostname, agent_hash, details FROM device_details")
|
||||
for host, db_hash, details_json in cur.fetchall():
|
||||
try:
|
||||
data = json.loads(details_json or "{}")
|
||||
except Exception:
|
||||
data = {}
|
||||
summary = data.get("summary") or {}
|
||||
if (summary.get("agent_id") or "").strip() == agent_id:
|
||||
row = (db_hash, details_json)
|
||||
hostname = host or hostname
|
||||
break
|
||||
|
||||
conn.close()
|
||||
|
||||
if row:
|
||||
db_hash = (row[0] or "").strip()
|
||||
if db_hash:
|
||||
return jsonify({
|
||||
"agent_id": agent_id,
|
||||
"agent_hash": db_hash,
|
||||
"hostname": hostname,
|
||||
"source": "database",
|
||||
})
|
||||
# Hash column may be empty if only stored inside details JSON.
|
||||
try:
|
||||
details = json.loads(row[1] or "{}")
|
||||
except Exception:
|
||||
details = {}
|
||||
summary = details.get("summary") or {}
|
||||
summary_hash = (summary.get("agent_hash") or "").strip()
|
||||
if summary_hash:
|
||||
return jsonify({
|
||||
"agent_id": agent_id,
|
||||
"agent_hash": summary_hash,
|
||||
"hostname": hostname,
|
||||
"source": "database",
|
||||
})
|
||||
|
||||
return jsonify({"error": "agent hash not found"}), 404
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
# ---------------------------------------------
|
||||
# Quick Job Execution + Activity History
|
||||
# ---------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user