Hard-cut banger away from source-checkout runtime bundles as an implicit source of\nimage and host defaults. Managed images now own their full boot set,\nimage build starts from an existing registered image, and daemon startup\nno longer synthesizes a default image from host paths.\n\nResolve Firecracker from PATH or firecracker_bin, make SSH keys config-owned\nwith an auto-managed XDG default, replace the external name generator and\npackage manifests with Go code, and keep the vsock helper as a companion\nbinary instead of a user-managed runtime asset.\n\nUpdate the manual scripts, web/CLI forms, config surface, and docs around\nthe new build/manual flow and explicit image registration semantics.\n\nValidation: GOCACHE=/tmp/banger-gocache go test ./..., bash -n scripts/*.sh,\nand make build.
168 lines
7.3 KiB
HTML
168 lines
7.3 KiB
HTML
{{define "image_list_content"}}
|
|
<div class="section-head">
|
|
<p class="muted">Manage registered rootfs/kernel stacks and promote unmanaged experiments into daemon-owned artifacts.</p>
|
|
<div class="stack-inline">
|
|
<a class="button secondary" href="/images/register">Register Image</a>
|
|
<a class="button" href="/images/build">Build Image</a>
|
|
</div>
|
|
</div>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Managed</th>
|
|
<th>Docker</th>
|
|
<th>Rootfs</th>
|
|
<th>Created</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Images}}
|
|
<tr>
|
|
<td><a class="table-link" href="/images/{{.ID}}">{{.Name}}</a></td>
|
|
<td>{{formatBool .Managed}}</td>
|
|
<td>{{formatBool .Docker}}</td>
|
|
<td><code>{{.RootfsPath}}</code></td>
|
|
<td>{{relativeTime .CreatedAt}}</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="5" class="muted">No images registered.</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{end}}
|
|
|
|
{{define "image_build_content"}}
|
|
<p class="muted">Build a managed image from an existing registered image, then redirect into the async build progress view.</p>
|
|
{{if .ErrorMessage}}
|
|
<div class="inline-error">{{.ErrorMessage}}</div>
|
|
{{end}}
|
|
<form method="post" action="/images/build" class="form-grid">
|
|
{{template "csrf_field" .}}
|
|
<label><span>Name</span><input type="text" name="name" value="{{.ImageBuildForm.Name}}" placeholder="generated when empty"></label>
|
|
<label><span>From Image</span><input type="text" name="from_image" value="{{.ImageBuildForm.FromImage}}" placeholder="image id or name"></label>
|
|
<label><span>Size Override</span><input type="text" name="size" value="{{.ImageBuildForm.Size}}" placeholder="optional"></label>
|
|
<label class="picker-field">
|
|
<span>Kernel Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="kernel_path" value="{{.ImageBuildForm.KernelPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="kernel_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Initrd Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="initrd_path" value="{{.ImageBuildForm.InitrdPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="initrd_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Modules Directory</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="modules_dir" value="{{.ImageBuildForm.ModulesDir}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="modules_dir" data-picker-kind="dir">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="checkbox">
|
|
<input type="checkbox" name="docker" {{if .ImageBuildForm.Docker}}checked{{end}}>
|
|
<span>Install Docker</span>
|
|
</label>
|
|
<div class="form-actions">
|
|
<a class="button secondary" href="/images">Cancel</a>
|
|
<button class="button" type="submit" {{if not .MutationAllowed}}disabled{{end}}>Build Image</button>
|
|
</div>
|
|
</form>
|
|
{{end}}
|
|
|
|
{{define "image_register_content"}}
|
|
<p class="muted">Register an existing host-side image stack. Paths stay on the host; nothing is uploaded through the browser.</p>
|
|
{{if .ErrorMessage}}
|
|
<div class="inline-error">{{.ErrorMessage}}</div>
|
|
{{end}}
|
|
<form method="post" action="/images/register" class="form-grid">
|
|
{{template "csrf_field" .}}
|
|
<label><span>Name</span><input type="text" name="name" value="{{.ImageRegisterForm.Name}}"></label>
|
|
<label class="picker-field">
|
|
<span>Rootfs Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="rootfs_path" value="{{.ImageRegisterForm.RootfsPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="rootfs_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Work Seed Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="work_seed_path" value="{{.ImageRegisterForm.WorkSeedPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="work_seed_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Kernel Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="kernel_path" value="{{.ImageRegisterForm.KernelPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="kernel_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Initrd Path</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="initrd_path" value="{{.ImageRegisterForm.InitrdPath}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="initrd_path" data-picker-kind="file">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="picker-field">
|
|
<span>Modules Directory</span>
|
|
<div class="picker-input">
|
|
<input type="text" name="modules_dir" value="{{.ImageRegisterForm.ModulesDir}}" data-picker-input>
|
|
<button type="button" class="button secondary" data-picker-target="modules_dir" data-picker-kind="dir">Browse</button>
|
|
</div>
|
|
</label>
|
|
<label class="checkbox">
|
|
<input type="checkbox" name="docker" {{if .ImageRegisterForm.Docker}}checked{{end}}>
|
|
<span>Mark image as Docker-ready</span>
|
|
</label>
|
|
<div class="form-actions">
|
|
<a class="button secondary" href="/images">Cancel</a>
|
|
<button class="button" type="submit" {{if not .MutationAllowed}}disabled{{end}}>Register Image</button>
|
|
</div>
|
|
</form>
|
|
{{end}}
|
|
|
|
{{define "image_show_content"}}
|
|
<section class="detail-grid">
|
|
<article class="detail-card">
|
|
<h2>{{.Image.Name}}</h2>
|
|
<dl>
|
|
<dt>ID</dt><dd><code>{{.Image.ID}}</code></dd>
|
|
<dt>Managed</dt><dd>{{formatBool .Image.Managed}}</dd>
|
|
<dt>Docker</dt><dd>{{formatBool .Image.Docker}}</dd>
|
|
<dt>Used By</dt><dd>{{.ImageUsers}} VM(s)</dd>
|
|
</dl>
|
|
</article>
|
|
<article class="detail-card">
|
|
<h2>Artifacts</h2>
|
|
<dl>
|
|
<dt>Rootfs</dt><dd><code>{{.Image.RootfsPath}}</code></dd>
|
|
<dt>Work Seed</dt><dd>{{if .Image.WorkSeedPath}}<code>{{.Image.WorkSeedPath}}</code>{{else}}-{{end}}</dd>
|
|
<dt>Kernel</dt><dd><code>{{.Image.KernelPath}}</code></dd>
|
|
<dt>Initrd</dt><dd>{{if .Image.InitrdPath}}<code>{{.Image.InitrdPath}}</code>{{else}}-{{end}}</dd>
|
|
<dt>Modules</dt><dd>{{if .Image.ModulesDir}}<code>{{.Image.ModulesDir}}</code>{{else}}-{{end}}</dd>
|
|
</dl>
|
|
</article>
|
|
<article class="detail-card">
|
|
<h2>Lifecycle</h2>
|
|
<dl>
|
|
<dt>Created</dt><dd>{{relativeTime .Image.CreatedAt}}</dd>
|
|
<dt>Updated</dt><dd>{{relativeTime .Image.UpdatedAt}}</dd>
|
|
<dt>Artifact Dir</dt><dd>{{if .Image.ArtifactDir}}<code>{{.Image.ArtifactDir}}</code>{{else}}-{{end}}</dd>
|
|
</dl>
|
|
</article>
|
|
</section>
|
|
|
|
<div class="stack-inline">
|
|
{{if not .Image.Managed}}
|
|
<form method="post" action="/images/{{.Image.ID}}/promote">{{template "csrf_field" .}}<button class="button" type="submit" {{if not .MutationAllowed}}disabled{{end}}>Promote to Managed</button></form>
|
|
{{end}}
|
|
<form method="post" action="/images/{{.Image.ID}}/delete" data-confirm="Delete image {{.Image.Name}}?">{{template "csrf_field" .}}<button class="button danger" type="submit" {{if not .MutationAllowed}}disabled{{end}}>Delete Image</button></form>
|
|
</div>
|
|
{{end}}
|