Initial commit of AthonetTools

This commit is contained in:
2025-08-21 12:59:43 +00:00
commit cd932b8fcb
2483 changed files with 433999 additions and 0 deletions

39
static/js/wizard/api.js Normal file
View File

@@ -0,0 +1,39 @@
// static/js/graph/wizard/api.js
export async function setTarget(ip) {
const r = await fetch('/api/host/target', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ ip })
});
const j = await r.json();
if (!r.ok || !j.ok) throw new Error(j.error || 'Failed to set target IP');
return j;
}
export async function getTarget() {
const r = await fetch('/api/host/target');
// returns { ip: "x.x.x.x" } or { ip: null }
return r.ok ? r.json() : { ip: null };
}
export async function bootstrapAccess() {
const r = await fetch('/api/host/bootstrap_access', { method: 'POST' });
const j = await r.json();
if (!r.ok || !j.ok) throw new Error(j.error || 'Failed to bootstrap access');
return j;
}
// static/js/wizard/api.js
export async function renderAnsible(payload) {
const r = await fetch('/api/ansible/render', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(payload)
});
const j = await r.json().catch(() => ({}));
if (!r.ok || !j.ok) {
const msg = j.error || `Render failed (HTTP ${r.status})`;
throw new Error(msg);
}
return j; // { ok: true, staging: "ansible_workspace/staging" }
}

View File

@@ -0,0 +1,60 @@
// static/js/graph/wizard/step0_target.js
import { setTarget, bootstrapAccess, getTarget } from './api.js';
export function mountTargetControls() {
const row = document.querySelector('#target-host-row');
if (!row) return;
// Use explicit IDs so we always hit the right elements
const ipInput = document.getElementById('target-ip-input');
const btn = document.getElementById('btn-enable-access');
const badge = document.getElementById('access-badge');
if (!ipInput || !btn || !badge) return;
// Prefill: localStorage first, then try backend GET /api/host/target
const saved = localStorage.getItem('targetHostIp');
if (saved) ipInput.value = saved;
getTarget()
.then(({ ip }) => { if (ip && !saved) ipInput.value = ip; })
.catch(() => { /* ignore if endpoint missing */ });
btn.addEventListener('click', async () => {
const ip = (ipInput.value || '').trim();
if (!ip) {
badge.className = 'badge bg-warning';
badge.textContent = 'Enter IP first';
return;
}
try {
btn.disabled = true;
const old = btn.textContent;
btn.textContent = 'Enabling…';
badge.className = 'badge bg-secondary';
badge.textContent = 'Working';
await setTarget(ip); // POST /api/host/target
await bootstrapAccess(); // POST /api/host/bootstrap_access (SSH+webconsole)
// Persist for Stage 2 (and page reloads)
localStorage.setItem('targetHostIp', ip);
badge.className = 'badge bg-success';
badge.textContent = 'SSH & Webconsole Ready';
btn.textContent = old;
btn.disabled = false;
} catch (e) {
console.error(e);
badge.className = 'badge bg-danger';
badge.textContent = 'Failed';
btn.disabled = false;
}
});
}
// Helper for other steps to read the latest target IP
export function getTargetHostData() {
const inputIp = (document.getElementById('target-ip-input')?.value || '').trim();
const stored = localStorage.getItem('targetHostIp') || '';
return { ip: inputIp || stored || '' };
}

View File

@@ -0,0 +1,77 @@
// static/js/graph/wizard/step2_render.js
import { renderAnsible } from './api.js';
import { getTargetHostData } from './step0_target.js';
export function mountStep2Render() {
const btn = document.getElementById('btn-create-yaml');
const badge = document.getElementById('yaml-badge');
if (!btn) return;
btn.onclick = null; // Remove any previous handler
btn.addEventListener('click', async () => {
const origText = btn.textContent;
btn.disabled = true;
btn.textContent = 'Creating…';
badge.className = 'badge bg-secondary';
badge.textContent = 'Running';
try {
const val = (id) => (document.getElementById(id)?.value || '').trim();
// Target IP priority: localStorage → helper → DOM
const lsIp = localStorage.getItem('targetHostIp') || '';
const target = (typeof getTargetHostData === 'function' ? getTargetHostData() : {}) || {};
const domIp = (document.querySelector('#target-host-row input')?.value || '').trim();
const ansibleHostIp = (lsIp || target.ip || domIp || '').trim();
// Get eth0 info from Stage 1 UI fields
const eth0Cidr = val('ip-core-mgmt');
const eth0Gw = val('ip-core-mgmt-gw');
const payload = {
hostname: val('network-name-input') || 'AIO-1',
network_name: val('network-name-input'),
plmn: val('plmn-input') || '315-010',
dns: (val('dns-input') || '8.8.8.8').split(',').map(s => s.trim()).filter(Boolean),
ntp: (val('ntp-input') || '0.pool.ntp.org, 1.pool.ntp.org').split(',').map(s => s.trim()).filter(Boolean),
ran: { cidr: val('ip-core-ran'), gw: val('ip-core-ran-gw') },
mgmt: { cidr: eth0Cidr, gw: eth0Gw },
dn: {
cidr: val('ip-core-dn'),
gw: val('ip-core-dn-gw'),
vlan: val('ip-core-dn-vlan') ? Number(val('ip-core-dn-vlan')) : undefined,
ue_pool: val('ip-core-dn-uepool'),
dnn: 'internet'
},
inventory_host: 'GBP08-AIO-1',
esxi_host: 'ESXI-1',
version: '25.1',
ova_file: '/home/mjensen/OVA/HPE_ANW_P5G_Core-1.25.1.1-qemux86-64.ova',
ansible_host_ip: ansibleHostIp
};
const res = await renderAnsible(payload);
badge.className = 'badge bg-success';
badge.textContent = 'Created';
btn.textContent = origText;
btn.disabled = false;
// Show YAML context in the UI for debug
let debugDiv = document.getElementById('yaml-debug-info');
if (!debugDiv) {
debugDiv = document.createElement('div');
debugDiv.id = 'yaml-debug-info';
debugDiv.className = 'mt-3 alert alert-info';
btn.parentNode.appendChild(debugDiv);
}
debugDiv.innerHTML = `<strong>YAML files created in:</strong> ${res.staging}<br><strong>Payload used:</strong><pre>${JSON.stringify(payload, null, 2)}</pre>`;
} catch (err) {
badge.className = 'badge bg-danger';
badge.textContent = 'Failed';
btn.textContent = origText;
btn.disabled = false;
alert(`Failed to create YAML files:\n${err.message || err}`);
}
});
}

View File

@@ -0,0 +1,24 @@
// static/js/wizard/step3_deploy.js
export function mountStep3Deploy() {
const btn = document.getElementById('btn-run-gaf');
const outputDiv = document.getElementById('gaf-output');
if (!btn || !outputDiv) return;
btn.onclick = null;
btn.addEventListener('click', async () => {
btn.disabled = true;
btn.textContent = 'Running…';
outputDiv.textContent = '';
try {
const res = await fetch('/api/ansible/deploy', { method: 'POST' });
const text = await res.text();
outputDiv.textContent = text;
btn.textContent = 'Run';
btn.disabled = false;
} catch (err) {
outputDiv.textContent = `Error: ${err.message || err}`;
btn.textContent = 'Run';
btn.disabled = false;
}
});
}

11
static/js/wizard/steps.js Normal file
View File

@@ -0,0 +1,11 @@
// static/js/graph/wizard/steps.js
import { mountTargetControls } from './step0_target.js';
import { mountStep2Render } from './step2_render.js';
import { mountStep3Deploy } from './step3_deploy.js';
export function mountWizard() {
mountTargetControls();
mountStep2Render();
mountStep3Deploy();
}