Add parent-child VM nesting support from infrastructure.conf
This commit is contained in:
43
app/app.py
43
app/app.py
@@ -42,6 +42,7 @@ class Server(db.Model):
|
||||
last_collected = db.Column(db.DateTime, nullable=True)
|
||||
details = db.Column(db.JSON, nullable=True)
|
||||
notes = db.Column(db.Text, default='')
|
||||
parent_hostname = db.Column(db.String(255), default='')
|
||||
__table_args__ = (db.UniqueConstraint('username', 'hostname', name='uq_user_host'),)
|
||||
|
||||
|
||||
@@ -50,6 +51,7 @@ class Server(db.Model):
|
||||
def parse_infrastructure_conf():
|
||||
servers = []
|
||||
current_group = None
|
||||
current_host = None # track the last top-level host for nesting
|
||||
try:
|
||||
with open(INFRA_CONF_PATH) as f:
|
||||
for line in f:
|
||||
@@ -58,7 +60,18 @@ def parse_infrastructure_conf():
|
||||
continue
|
||||
if line[0] not in (' ', '\t'):
|
||||
current_group = line.strip()
|
||||
current_host = None
|
||||
else:
|
||||
# Detect indent level: double indent = child VM
|
||||
stripped = line.lstrip('\t')
|
||||
tab_count = len(line) - len(stripped)
|
||||
if tab_count < 2:
|
||||
# Also check spaces: 8+ spaces = double indent
|
||||
space_indent = len(line) - len(line.lstrip(' '))
|
||||
is_child = space_indent >= 8
|
||||
else:
|
||||
is_child = tab_count >= 2
|
||||
|
||||
parts = line.strip().split(None, 1)
|
||||
entry = parts[0] if parts else ''
|
||||
url = parts[1] if len(parts) > 1 else ''
|
||||
@@ -67,11 +80,17 @@ def parse_infrastructure_conf():
|
||||
else:
|
||||
user, host = 'infmap', entry
|
||||
if host:
|
||||
parent = ''
|
||||
if is_child and current_host:
|
||||
parent = current_host
|
||||
else:
|
||||
current_host = host.strip()
|
||||
servers.append({
|
||||
'group': current_group or 'Default',
|
||||
'username': user.strip(),
|
||||
'hostname': host.strip(),
|
||||
'url': url.strip(),
|
||||
'parent_hostname': parent,
|
||||
})
|
||||
except FileNotFoundError:
|
||||
logger.error("infrastructure.conf not found at %s", INFRA_CONF_PATH)
|
||||
@@ -221,6 +240,7 @@ def collect_all():
|
||||
|
||||
server.group_name = entry['group']
|
||||
server.url = entry.get('url', '')
|
||||
server.parent_hostname = entry.get('parent_hostname', '')
|
||||
server.is_online = result.get('is_online', False)
|
||||
server.last_collected = datetime.now(timezone.utc)
|
||||
server.details = result
|
||||
@@ -269,9 +289,24 @@ def collector_loop():
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
servers = Server.query.order_by(Server.group_name, Server.primary_ip).all()
|
||||
all_servers = Server.query.order_by(Server.group_name, Server.primary_ip).all()
|
||||
|
||||
# Separate parents and children
|
||||
children_map = {} # parent_hostname -> [child_servers]
|
||||
parents = []
|
||||
for s in all_servers:
|
||||
if s.parent_hostname:
|
||||
children_map.setdefault(s.parent_hostname, []).append(s)
|
||||
else:
|
||||
parents.append(s)
|
||||
|
||||
# Sort children by IP
|
||||
for hostname in children_map:
|
||||
children_map[hostname].sort(key=lambda s: _ip_sort_key(s.primary_ip))
|
||||
|
||||
# Group parents
|
||||
groups = {}
|
||||
for s in servers:
|
||||
for s in parents:
|
||||
g = s.group_name or 'Default'
|
||||
if g not in groups:
|
||||
groups[g] = []
|
||||
@@ -281,7 +316,7 @@ def index():
|
||||
for g in groups:
|
||||
groups[g].sort(key=lambda s: _ip_sort_key(s.primary_ip))
|
||||
|
||||
return render_template('index.html', groups=groups, build_date=BUILD_DATE)
|
||||
return render_template('index.html', groups=groups, children_map=children_map, build_date=BUILD_DATE)
|
||||
|
||||
|
||||
@app.route('/api/servers')
|
||||
@@ -299,6 +334,7 @@ def api_servers():
|
||||
'is_online': s.is_online,
|
||||
'last_collected': s.last_collected.isoformat() if s.last_collected else None,
|
||||
'notes': s.notes,
|
||||
'parent_hostname': s.parent_hostname,
|
||||
'details': s.details,
|
||||
})
|
||||
return jsonify(result)
|
||||
@@ -510,6 +546,7 @@ def migrate_db():
|
||||
migrations = {
|
||||
'url': "ALTER TABLE servers ADD COLUMN url VARCHAR(1024) DEFAULT ''",
|
||||
'notes': "ALTER TABLE servers ADD COLUMN notes TEXT DEFAULT ''",
|
||||
'parent_hostname': "ALTER TABLE servers ADD COLUMN parent_hostname VARCHAR(255) DEFAULT ''",
|
||||
}
|
||||
for col, sql in migrations.items():
|
||||
if col not in existing:
|
||||
|
||||
Reference in New Issue
Block a user