mirror of
https://github.com/CloudNebulaProject/vm-manager.git
synced 2026-04-10 13:20:41 +00:00
Remove docs build output and gitignore docs/book/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b37beea0f5
commit
2265fca023
102 changed files with 1 additions and 25670 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
/target
|
/target
|
||||||
other-codes/
|
other-codes/
|
||||||
scripts/forger-src.tar.gz
|
scripts/forger-src.tar.gz
|
||||||
|
docs/book/
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
This file makes sure that Github Pages doesn't process mdBook's output.
|
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Page not found - vmctl Documentation</title>
|
|
||||||
<base href="/">
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="favicon.png">
|
|
||||||
<link rel="stylesheet" href="css/variables.css">
|
|
||||||
<link rel="stylesheet" href="css/general.css">
|
|
||||||
<link rel="stylesheet" href="css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="document-not-found-404"><a class="header" href="#document-not-found-404">Document not found (404)</a></h1>
|
|
||||||
<p>This URL is invalid, sorry. Please use the navigation bar or search to continue.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js"></script>
|
|
||||||
<script src="mark.min.js"></script>
|
|
||||||
<script src="searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="clipboard.min.js"></script>
|
|
||||||
<script src="highlight.js"></script>
|
|
||||||
<script src="book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
4
docs/book/FontAwesome/css/font-awesome.css
vendored
4
docs/book/FontAwesome/css/font-awesome.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,286 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Running in Docker/Podman - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="running-in-dockerpodman"><a class="header" href="#running-in-dockerpodman">Running in Docker/Podman</a></h1>
|
|
||||||
<p>vmctl can run inside a container for CI/CD pipelines or isolated environments. The key requirement is access to <code>/dev/kvm</code>.</p>
|
|
||||||
<h2 id="dockerfile"><a class="header" href="#dockerfile">Dockerfile</a></h2>
|
|
||||||
<pre><code class="language-dockerfile">FROM rust:1.85-bookworm AS builder
|
|
||||||
|
|
||||||
WORKDIR /build
|
|
||||||
COPY . .
|
|
||||||
RUN cargo build --release -p vmctl --features vm-manager/pure-iso
|
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
qemu-system-x86 \
|
|
||||||
qemu-utils \
|
|
||||||
openssh-client \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY --from=builder /build/target/release/vmctl /usr/local/bin/vmctl
|
|
||||||
|
|
||||||
ENV XDG_DATA_HOME=/data
|
|
||||||
ENTRYPOINT ["vmctl"]
|
|
||||||
</code></pre>
|
|
||||||
<p>The <code>pure-iso</code> feature eliminates the need for <code>genisoimage</code> in the container.</p>
|
|
||||||
<h2 id="docker"><a class="header" href="#docker">Docker</a></h2>
|
|
||||||
<pre><code class="language-bash">docker build -t vmctl .
|
|
||||||
|
|
||||||
docker run --rm \
|
|
||||||
--device /dev/kvm \
|
|
||||||
-v vmctl-data:/data \
|
|
||||||
vmctl list
|
|
||||||
</code></pre>
|
|
||||||
<p>The <code>--device /dev/kvm</code> flag passes through KVM access. No <code>--privileged</code> or special capabilities are needed for user-mode networking.</p>
|
|
||||||
<p>For TAP networking, you'll need <code>--cap-add NET_ADMIN</code> and appropriate bridge configuration.</p>
|
|
||||||
<h2 id="podman"><a class="header" href="#podman">Podman</a></h2>
|
|
||||||
<pre><code class="language-bash">podman build -t vmctl .
|
|
||||||
|
|
||||||
podman run --rm \
|
|
||||||
--device /dev/kvm \
|
|
||||||
-v vmctl-data:/data \
|
|
||||||
vmctl list
|
|
||||||
</code></pre>
|
|
||||||
<p>Podman works identically for user-mode networking.</p>
|
|
||||||
<h2 id="persistent-data"><a class="header" href="#persistent-data">Persistent Data</a></h2>
|
|
||||||
<p>Mount a volume at the <code>XDG_DATA_HOME</code> path (<code>/data</code> in the Dockerfile above) to persist VM state and cached images across container runs.</p>
|
|
||||||
<h2 id="using-vmfiles"><a class="header" href="#using-vmfiles">Using VMFiles</a></h2>
|
|
||||||
<p>Mount your project directory to use VMFile.kdl:</p>
|
|
||||||
<pre><code class="language-bash">docker run --rm \
|
|
||||||
--device /dev/kvm \
|
|
||||||
-v vmctl-data:/data \
|
|
||||||
-v $(pwd):/workspace \
|
|
||||||
-w /workspace \
|
|
||||||
vmctl up
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/vmfile-api.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/tap-networking.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/vmfile-api.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/tap-networking.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,294 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Custom Cloud-Init User Data - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="custom-cloud-init-user-data"><a class="header" href="#custom-cloud-init-user-data">Custom Cloud-Init User Data</a></h1>
|
|
||||||
<p>For advanced guest configuration, you can provide a complete cloud-config YAML file instead of using vmctl's built-in cloud-init generation.</p>
|
|
||||||
<h2 id="raw-user-data"><a class="header" href="#raw-user-data">Raw User-Data</a></h2>
|
|
||||||
<pre><code class="language-kdl">vm "custom" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
user-data "cloud-config.yaml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="example-cloud-configyaml"><a class="header" href="#example-cloud-configyaml">Example cloud-config.yaml</a></h2>
|
|
||||||
<pre><code class="language-yaml">#cloud-config
|
|
||||||
users:
|
|
||||||
- name: deploy
|
|
||||||
groups: sudo
|
|
||||||
shell: /bin/bash
|
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
|
||||||
ssh_authorized_keys:
|
|
||||||
- ssh-ed25519 AAAA... your-key
|
|
||||||
|
|
||||||
package_update: true
|
|
||||||
packages:
|
|
||||||
- nginx
|
|
||||||
- certbot
|
|
||||||
- python3-certbot-nginx
|
|
||||||
|
|
||||||
write_files:
|
|
||||||
- path: /etc/nginx/sites-available/default
|
|
||||||
content: |
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
root /var/www/html;
|
|
||||||
}
|
|
||||||
|
|
||||||
runcmd:
|
|
||||||
- systemctl enable nginx
|
|
||||||
- systemctl start nginx
|
|
||||||
|
|
||||||
growpart:
|
|
||||||
mode: auto
|
|
||||||
devices: ["/"]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="the-pure-iso-feature"><a class="header" href="#the-pure-iso-feature">The pure-iso Feature</a></h2>
|
|
||||||
<p>By default, vmctl generates the NoCloud seed ISO by shelling out to <code>genisoimage</code> or <code>mkisofs</code>. If neither is available, you can build with the <code>pure-iso</code> feature:</p>
|
|
||||||
<pre><code class="language-bash">cargo build --release -p vmctl --features vm-manager/pure-iso
|
|
||||||
</code></pre>
|
|
||||||
<p>This uses the <code>isobemak</code> crate to generate ISO 9660 images entirely in Rust.</p>
|
|
||||||
<h2 id="what-vmctl-generates"><a class="header" href="#what-vmctl-generates">What vmctl Generates</a></h2>
|
|
||||||
<p>When you don't provide raw user-data, vmctl generates a cloud-config that:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Creates a user with the specified name.</li>
|
|
||||||
<li>Grants passwordless sudo.</li>
|
|
||||||
<li>Sets bash as the default shell.</li>
|
|
||||||
<li>Injects the SSH public key into <code>authorized_keys</code>.</li>
|
|
||||||
<li>Disables root login.</li>
|
|
||||||
<li>Sets the hostname (from <code>hostname</code> field or VM name).</li>
|
|
||||||
<li>Sets a unique <code>instance-id</code> in the metadata.</li>
|
|
||||||
</ol>
|
|
||||||
<p>If you need more control than this, use raw user-data.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../advanced/propolis-illumos.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/debugging.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../advanced/propolis-illumos.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/debugging.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,311 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Debugging and Logs - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="debugging-and-logs"><a class="header" href="#debugging-and-logs">Debugging and Logs</a></h1>
|
|
||||||
<h2 id="log-verbosity"><a class="header" href="#log-verbosity">Log Verbosity</a></h2>
|
|
||||||
<p>vmctl uses the <code>tracing</code> crate with <code>RUST_LOG</code> environment variable support:</p>
|
|
||||||
<pre><code class="language-bash"># Default (info level)
|
|
||||||
vmctl up
|
|
||||||
|
|
||||||
# Debug logging
|
|
||||||
RUST_LOG=debug vmctl up
|
|
||||||
|
|
||||||
# Trace logging (very verbose)
|
|
||||||
RUST_LOG=trace vmctl up
|
|
||||||
|
|
||||||
# Target specific modules
|
|
||||||
RUST_LOG=vm_manager::ssh=debug vmctl ssh myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="vm-logs"><a class="header" href="#vm-logs">VM Logs</a></h2>
|
|
||||||
<h3 id="console-log"><a class="header" href="#console-log">Console Log</a></h3>
|
|
||||||
<p>The serial console output is captured to <code>console.log</code> in the VM's work directory. This includes boot messages and cloud-init output:</p>
|
|
||||||
<pre><code class="language-bash">vmctl log myvm --console
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="provision-log"><a class="header" href="#provision-log">Provision Log</a></h3>
|
|
||||||
<p>Provisioner stdout/stderr is captured to <code>provision.log</code>:</p>
|
|
||||||
<pre><code class="language-bash">vmctl log myvm --provision
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="tail-recent-output"><a class="header" href="#tail-recent-output">Tail Recent Output</a></h3>
|
|
||||||
<pre><code class="language-bash">vmctl log myvm --console --tail 50
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="work-directory"><a class="header" href="#work-directory">Work Directory</a></h2>
|
|
||||||
<p>Each VM's files are in <code>~/.local/share/vmctl/vms/<name>/</code>:</p>
|
|
||||||
<pre><code class="language-bash">ls ~/.local/share/vmctl/vms/myvm/
|
|
||||||
</code></pre>
|
|
||||||
<p>Contents:</p>
|
|
||||||
<ul>
|
|
||||||
<li><code>overlay.qcow2</code> - Disk overlay</li>
|
|
||||||
<li><code>seed.iso</code> - Cloud-init ISO</li>
|
|
||||||
<li><code>console.log</code> - Serial output</li>
|
|
||||||
<li><code>provision.log</code> - Provisioner output</li>
|
|
||||||
<li><code>qmp.sock</code> - QMP control socket</li>
|
|
||||||
<li><code>console.sock</code> - Console socket</li>
|
|
||||||
<li><code>pidfile</code> - QEMU PID</li>
|
|
||||||
<li><code>id_ed25519_generated</code> - Auto-generated SSH key</li>
|
|
||||||
<li><code>id_ed25519_generated.pub</code> - Public key</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="qmp-socket"><a class="header" href="#qmp-socket">QMP Socket</a></h2>
|
|
||||||
<p>You can interact with the QEMU Machine Protocol directly for advanced debugging:</p>
|
|
||||||
<pre><code class="language-bash"># Using socat
|
|
||||||
socat - UNIX-CONNECT:~/.local/share/vmctl/vms/myvm/qmp.sock
|
|
||||||
</code></pre>
|
|
||||||
<p>After connecting, send <code>{"execute": "qmp_capabilities"}</code> to initialize, then commands like:</p>
|
|
||||||
<pre><code class="language-json">{"execute": "query-status"}
|
|
||||||
{"execute": "query-vnc"}
|
|
||||||
{"execute": "human-monitor-command", "arguments": {"command-line": "info network"}}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="common-issues"><a class="header" href="#common-issues">Common Issues</a></h2>
|
|
||||||
<h3 id="qemu-spawn-failed"><a class="header" href="#qemu-spawn-failed">"QEMU spawn failed"</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>Verify <code>qemu-system-x86_64</code> is in your PATH.</li>
|
|
||||||
<li>Check <code>/dev/kvm</code> exists and is accessible.</li>
|
|
||||||
<li>Ensure your user is in the <code>kvm</code> group.</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="cloud-init-iso-failed"><a class="header" href="#cloud-init-iso-failed">"Cloud-init ISO failed"</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>Install <code>genisoimage</code> or <code>mkisofs</code>.</li>
|
|
||||||
<li>Or rebuild with <code>--features vm-manager/pure-iso</code>.</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="ssh-failed"><a class="header" href="#ssh-failed">"SSH failed"</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>Check the console log for cloud-init errors: <code>vmctl log myvm --console</code></li>
|
|
||||||
<li>Verify the guest is reachable (check <code>vmctl status myvm</code> for SSH port).</li>
|
|
||||||
<li>Ensure sshd is running in the guest.</li>
|
|
||||||
<li>Try connecting manually: <code>ssh -p <port> -i <key> user@127.0.0.1</code></li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="ip-discovery-timeout-tap-networking"><a class="header" href="#ip-discovery-timeout-tap-networking">"IP discovery timeout" (TAP networking)</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>Verify the bridge exists and has DHCP.</li>
|
|
||||||
<li>Check <code>ip neigh show</code> for the guest's MAC address.</li>
|
|
||||||
<li>Ensure the guest has obtained a DHCP lease (check console log).</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="vm-stuck-in-stopped-state-but-qemu-still-running"><a class="header" href="#vm-stuck-in-stopped-state-but-qemu-still-running">VM stuck in "Stopped" state but QEMU still running</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>Check <code>vmctl status myvm</code> for the PID.</li>
|
|
||||||
<li>Verify: <code>kill -0 <pid></code> - if the process is alive, the QMP socket may be stale.</li>
|
|
||||||
<li>Destroy and recreate: <code>vmctl destroy myvm</code>.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../advanced/custom-cloud-init.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../advanced/custom-cloud-init.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,265 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>illumos / Propolis Backend - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="illumos--propolis-backend"><a class="header" href="#illumos--propolis-backend">illumos / Propolis Backend</a></h1>
|
|
||||||
<p>vmctl includes experimental support for running VMs on illumos using the Propolis hypervisor (bhyve-based).</p>
|
|
||||||
<h2 id="requirements"><a class="header" href="#requirements">Requirements</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>illumos-based OS (OmniOS, SmartOS, etc.)</li>
|
|
||||||
<li><code>propolis-server</code> installed and runnable</li>
|
|
||||||
<li>ZFS pool (default: <code>rpool</code>)</li>
|
|
||||||
<li><code>nebula-vm</code> zone brand installed</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="how-it-works"><a class="header" href="#how-it-works">How It Works</a></h2>
|
|
||||||
<p>The Propolis backend manages VMs as illumos zones:</p>
|
|
||||||
<ol>
|
|
||||||
<li><strong>Prepare</strong>: Creates a ZFS clone from <code>{pool}/images/{vm}@latest</code> to <code>{pool}/vms/{vm}</code>.</li>
|
|
||||||
<li><strong>Start</strong>: Boots the zone with <code>zoneadm -z {vm} boot</code>, waits for propolis-server on <code>127.0.0.1:12400</code>, then sends the instance spec and run command via REST API.</li>
|
|
||||||
<li><strong>Stop</strong>: Sends a stop command to propolis-server, then halts the zone.</li>
|
|
||||||
<li><strong>Destroy</strong>: Stops the VM, uninstalls the zone (<code>zoneadm uninstall -F</code>), deletes the zone config (<code>zonecfg delete -F</code>), and destroys the ZFS dataset.</li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="networking"><a class="header" href="#networking">Networking</a></h2>
|
|
||||||
<p>Uses illumos VNICs for exclusive-IP zone networking:</p>
|
|
||||||
<pre><code class="language-kdl">network "vnic" {
|
|
||||||
name "vnic0"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="limitations"><a class="header" href="#limitations">Limitations</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Suspend/resume not yet implemented.</li>
|
|
||||||
<li>Console endpoint (WebSocket) is defined but not fully integrated.</li>
|
|
||||||
<li>VNC address not yet exposed.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="building-for-illumos"><a class="header" href="#building-for-illumos">Building for illumos</a></h2>
|
|
||||||
<pre><code class="language-bash">cargo build --release -p vmctl --target x86_64-unknown-illumos
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../advanced/tap-networking.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/custom-cloud-init.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../advanced/tap-networking.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/custom-cloud-init.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,293 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>TAP Networking and Bridges - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="tap-networking-and-bridges"><a class="header" href="#tap-networking-and-bridges">TAP Networking and Bridges</a></h1>
|
|
||||||
<p>TAP networking gives VMs a real presence on a host network, with full Layer 2 connectivity.</p>
|
|
||||||
<h2 id="creating-a-bridge"><a class="header" href="#creating-a-bridge">Creating a Bridge</a></h2>
|
|
||||||
<pre><code class="language-bash"># Create bridge
|
|
||||||
sudo ip link add br0 type bridge
|
|
||||||
sudo ip link set br0 up
|
|
||||||
|
|
||||||
# Assign an IP to the bridge (optional, for host-to-guest communication)
|
|
||||||
sudo ip addr add 10.0.0.1/24 dev br0
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="dhcp-with-dnsmasq"><a class="header" href="#dhcp-with-dnsmasq">DHCP with dnsmasq</a></h2>
|
|
||||||
<p>Provide IP addresses to guests:</p>
|
|
||||||
<pre><code class="language-bash">sudo dnsmasq \
|
|
||||||
--interface=br0 \
|
|
||||||
--bind-interfaces \
|
|
||||||
--dhcp-range=10.0.0.100,10.0.0.200,12h \
|
|
||||||
--no-daemon
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="ip-forwarding-and-nat"><a class="header" href="#ip-forwarding-and-nat">IP Forwarding and NAT</a></h2>
|
|
||||||
<p>If you want guests to reach the internet:</p>
|
|
||||||
<pre><code class="language-bash"># Enable forwarding
|
|
||||||
sudo sysctl -w net.ipv4.ip_forward=1
|
|
||||||
|
|
||||||
# NAT outbound traffic
|
|
||||||
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -o br0 -j MASQUERADE
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="using-with-vmctl"><a class="header" href="#using-with-vmctl">Using with vmctl</a></h2>
|
|
||||||
<h3 id="imperative"><a class="header" href="#imperative">Imperative</a></h3>
|
|
||||||
<pre><code class="language-bash">vmctl create --name myvm --image ./image.qcow2 --bridge br0
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="declarative"><a class="header" href="#declarative">Declarative</a></h3>
|
|
||||||
<pre><code class="language-kdl">vm "myvm" {
|
|
||||||
image "image.qcow2"
|
|
||||||
|
|
||||||
network "tap" {
|
|
||||||
bridge "br0"
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "myvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="ip-discovery"><a class="header" href="#ip-discovery">IP Discovery</a></h2>
|
|
||||||
<p>vmctl discovers TAP-networked guest IPs by:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Checking the ARP table (<code>ip neigh show</code>) for the guest's MAC address on the bridge.</li>
|
|
||||||
<li>Falling back to dnsmasq lease files.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This happens automatically when you run <code>vmctl ssh</code> or provisioners.</p>
|
|
||||||
<h2 id="security-considerations"><a class="header" href="#security-considerations">Security Considerations</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>TAP interfaces may bypass host firewall rules.</li>
|
|
||||||
<li>Guests on the bridge can see other devices on the network.</li>
|
|
||||||
<li>Use iptables rules on the bridge to restrict traffic if needed.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../advanced/containerization.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/propolis-illumos.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../advanced/containerization.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/propolis-illumos.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,305 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Hypervisor Backends - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="hypervisor-backends"><a class="header" href="#hypervisor-backends">Hypervisor Backends</a></h1>
|
|
||||||
<h2 id="the-hypervisor-trait"><a class="header" href="#the-hypervisor-trait">The Hypervisor Trait</a></h2>
|
|
||||||
<p>All backends implement the <code>Hypervisor</code> trait defined in <code>crates/vm-manager/src/traits.rs</code>:</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub trait Hypervisor: Send + Sync {
|
|
||||||
fn prepare(&self, spec: &VmSpec) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn start(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn stop(&self, vm: &VmHandle, timeout: Duration) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn suspend(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn resume(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn destroy(&self, vm: VmHandle) -> impl Future<Output = Result<()>>;
|
|
||||||
fn state(&self, vm: &VmHandle) -> impl Future<Output = Result<VmState>>;
|
|
||||||
fn guest_ip(&self, vm: &VmHandle) -> impl Future<Output = Result<String>>;
|
|
||||||
fn console_endpoint(&self, vm: &VmHandle) -> Result<ConsoleEndpoint>;
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="qemu-backend-linux"><a class="header" href="#qemu-backend-linux">QEMU Backend (Linux)</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/backends/qemu.rs</code>.</p>
|
|
||||||
<p><strong>Prepare:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li>Creates work directory under <code>~/.local/share/vmctl/vms/<name>/</code>.</li>
|
|
||||||
<li>Creates QCOW2 overlay on top of the base image.</li>
|
|
||||||
<li>Generates cloud-init seed ISO (if configured).</li>
|
|
||||||
<li>Allocates a deterministic SSH port (10022-10122 range, hash-based).</li>
|
|
||||||
<li>Generates a locally-administered MAC address.</li>
|
|
||||||
</ul>
|
|
||||||
<p><strong>Start:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li>Launches <code>qemu-system-x86_64</code> with KVM acceleration.</li>
|
|
||||||
<li>CPU type: <code>host</code> (passthrough).</li>
|
|
||||||
<li>Machine type: <code>q35,accel=kvm</code>.</li>
|
|
||||||
<li>Devices: virtio-blk for disk, virtio-rng for entropy.</li>
|
|
||||||
<li>Console: Unix socket + log file.</li>
|
|
||||||
<li>VNC: localhost, auto-port.</li>
|
|
||||||
<li>Networking: User-mode (SLIRP with port forwarding) or TAP (bridged).</li>
|
|
||||||
<li>Daemonizes with PID file.</li>
|
|
||||||
<li>Connects via QMP to verify startup and retrieve VNC address.</li>
|
|
||||||
</ul>
|
|
||||||
<p><strong>Stop:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>ACPI power-down via QMP (<code>system_powerdown</code>).</li>
|
|
||||||
<li>Poll for process exit (500ms intervals) up to timeout.</li>
|
|
||||||
<li>SIGTERM if timeout exceeded.</li>
|
|
||||||
<li>SIGKILL as last resort.</li>
|
|
||||||
</ol>
|
|
||||||
<p><strong>IP Discovery:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li>User-mode: returns <code>127.0.0.1</code> (SSH via forwarded port).</li>
|
|
||||||
<li>TAP: parses ARP table (<code>ip neigh show</code>), falls back to dnsmasq lease files by MAC address.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="qmp-client"><a class="header" href="#qmp-client">QMP Client</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/backends/qmp.rs</code>. Async JSON-over-Unix-socket client implementing the QEMU Machine Protocol.</p>
|
|
||||||
<p>Commands: <code>system_powerdown</code>, <code>quit</code>, <code>stop</code>, <code>cont</code>, <code>query_status</code>, <code>query_vnc</code>.</p>
|
|
||||||
<h2 id="propolis-backend-illumos"><a class="header" href="#propolis-backend-illumos">Propolis Backend (illumos)</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/backends/propolis.rs</code>.</p>
|
|
||||||
<ul>
|
|
||||||
<li>Uses ZFS clones for VM disks.</li>
|
|
||||||
<li>Manages zones with the <code>nebula-vm</code> brand.</li>
|
|
||||||
<li>Communicates with <code>propolis-server</code> via REST API.</li>
|
|
||||||
<li>Networking via illumos VNICs.</li>
|
|
||||||
<li>Suspend/resume not yet implemented.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="noop-backend"><a class="header" href="#noop-backend">Noop Backend</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/backends/noop.rs</code>. All operations succeed immediately. Used for testing.</p>
|
|
||||||
<h2 id="routerhypervisor"><a class="header" href="#routerhypervisor">RouterHypervisor</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/backends/mod.rs</code>. Dispatches <code>Hypervisor</code> trait calls to the correct backend based on the <code>VmHandle</code>'s <code>BackendTag</code>.</p>
|
|
||||||
<p>Construction:</p>
|
|
||||||
<ul>
|
|
||||||
<li><code>RouterHypervisor::new(bridge, zfs_pool)</code> - Platform-aware, creates the appropriate backend.</li>
|
|
||||||
<li><code>RouterHypervisor::noop_only()</code> - Testing mode.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/crate-structure.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/state-management.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/crate-structure.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/state-management.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,293 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Crate Structure - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="crate-structure"><a class="header" href="#crate-structure">Crate Structure</a></h1>
|
|
||||||
<h2 id="workspace-layout"><a class="header" href="#workspace-layout">Workspace Layout</a></h2>
|
|
||||||
<pre><code class="language-text">vm-manager/
|
|
||||||
Cargo.toml # Workspace root
|
|
||||||
crates/
|
|
||||||
vm-manager/ # Library crate
|
|
||||||
Cargo.toml
|
|
||||||
src/
|
|
||||||
lib.rs # Re-exports
|
|
||||||
traits.rs # Hypervisor trait, ConsoleEndpoint
|
|
||||||
types.rs # VmSpec, VmHandle, VmState, NetworkConfig, etc.
|
|
||||||
error.rs # VmError with miette diagnostics
|
|
||||||
vmfile.rs # VMFile.kdl parser and resolver
|
|
||||||
image.rs # ImageManager (download, cache, overlay)
|
|
||||||
ssh.rs # SSH connect, exec, streaming, upload
|
|
||||||
provision.rs # Provisioner runner
|
|
||||||
cloudinit.rs # NoCloud seed ISO generation
|
|
||||||
backends/
|
|
||||||
mod.rs # RouterHypervisor
|
|
||||||
qemu.rs # QEMU/KVM backend (Linux)
|
|
||||||
qmp.rs # QMP client
|
|
||||||
propolis.rs # Propolis/bhyve backend (illumos)
|
|
||||||
noop.rs # No-op backend (testing)
|
|
||||||
vmctl/ # CLI binary crate
|
|
||||||
Cargo.toml
|
|
||||||
src/
|
|
||||||
main.rs # CLI entry point, clap App
|
|
||||||
commands/
|
|
||||||
create.rs # vmctl create
|
|
||||||
start.rs # vmctl start, suspend, resume
|
|
||||||
stop.rs # vmctl stop
|
|
||||||
destroy.rs # vmctl destroy
|
|
||||||
list.rs # vmctl list
|
|
||||||
status.rs # vmctl status
|
|
||||||
console.rs # vmctl console
|
|
||||||
ssh.rs # vmctl ssh
|
|
||||||
image.rs # vmctl image (pull, list, inspect)
|
|
||||||
up.rs # vmctl up
|
|
||||||
down.rs # vmctl down
|
|
||||||
reload.rs # vmctl reload
|
|
||||||
provision_cmd.rs # vmctl provision
|
|
||||||
log.rs # vmctl log
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="vm-manager-crate"><a class="header" href="#vm-manager-crate">vm-manager Crate</a></h2>
|
|
||||||
<p>The library crate. Contains all business logic and can be used as a dependency by other Rust projects.</p>
|
|
||||||
<p><strong>Public re-exports from <code>lib.rs</code>:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li><code>RouterHypervisor</code> (from <code>backends</code>)</li>
|
|
||||||
<li><code>Hypervisor</code>, <code>ConsoleEndpoint</code> (from <code>traits</code>)</li>
|
|
||||||
<li><code>VmError</code>, <code>Result</code> (from <code>error</code>)</li>
|
|
||||||
<li>All types from <code>types</code>: <code>BackendTag</code>, <code>VmSpec</code>, <code>VmHandle</code>, <code>VmState</code>, <code>NetworkConfig</code>, <code>CloudInitConfig</code>, <code>SshConfig</code></li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="vmctl-crate"><a class="header" href="#vmctl-crate">vmctl Crate</a></h2>
|
|
||||||
<p>The CLI binary. Depends on <code>vm-manager</code> and adds:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Clap-based argument parsing</li>
|
|
||||||
<li>Store persistence (<code>vms.json</code>)</li>
|
|
||||||
<li>Terminal I/O (console bridging, log display)</li>
|
|
||||||
<li>VMFile discovery and command dispatch</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/overview.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/backends.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/overview.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/backends.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Error Handling - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="error-handling"><a class="header" href="#error-handling">Error Handling</a></h1>
|
|
||||||
<h2 id="approach"><a class="header" href="#approach">Approach</a></h2>
|
|
||||||
<p>vm-manager uses <a href="https://docs.rs/miette">miette</a> for rich diagnostic error reporting. Every error variant includes:</p>
|
|
||||||
<ul>
|
|
||||||
<li>A human-readable message.</li>
|
|
||||||
<li>A diagnostic code (e.g., <code>vm_manager::qemu::spawn_failed</code>).</li>
|
|
||||||
<li>A <code>help</code> message telling the user what to do.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Errors are defined with <code>#[derive(thiserror::Error, miette::Diagnostic)]</code>.</p>
|
|
||||||
<h2 id="error-variants"><a class="header" href="#error-variants">Error Variants</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Code</th><th>Trigger</th><th>Help</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>vm_manager::qemu::spawn_failed</code></td><td>QEMU process failed to start</td><td>Ensure <code>qemu-system-x86_64</code> is installed, in PATH, and KVM is available (<code>/dev/kvm</code>)</td></tr>
|
|
||||||
<tr><td><code>vm_manager::qemu::qmp_connect_failed</code></td><td>Can't connect to QMP socket</td><td>QEMU may have crashed before QMP socket ready; check work directory logs</td></tr>
|
|
||||||
<tr><td><code>vm_manager::qemu::qmp_command_failed</code></td><td>QMP command returned an error</td><td>(varies)</td></tr>
|
|
||||||
<tr><td><code>vm_manager::image::overlay_creation_failed</code></td><td>QCOW2 overlay creation failed</td><td>Ensure <code>qemu-img</code> is installed and base image exists and is readable</td></tr>
|
|
||||||
<tr><td><code>vm_manager::network::ip_discovery_timeout</code></td><td>Guest IP not found</td><td>Guest may not have DHCP lease; check network config and cloud-init</td></tr>
|
|
||||||
<tr><td><code>vm_manager::propolis::unreachable</code></td><td>Can't reach propolis-server</td><td>Ensure propolis-server is running and listening on expected address</td></tr>
|
|
||||||
<tr><td><code>vm_manager::cloudinit::iso_failed</code></td><td>Seed ISO generation failed</td><td>Ensure <code>genisoimage</code> or <code>mkisofs</code> installed, or enable <code>pure-iso</code> feature</td></tr>
|
|
||||||
<tr><td><code>vm_manager::ssh::failed</code></td><td>SSH connection or command failed</td><td>Check SSH key, guest reachability, and sshd running</td></tr>
|
|
||||||
<tr><td><code>vm_manager::ssh::keygen_failed</code></td><td>Ed25519 key generation failed</td><td>Internal error; please report it</td></tr>
|
|
||||||
<tr><td><code>vm_manager::image::download_failed</code></td><td>Image download failed</td><td>Check network connectivity and URL correctness</td></tr>
|
|
||||||
<tr><td><code>vm_manager::image::format_detection_failed</code></td><td>Can't detect image format</td><td>Ensure <code>qemu-img</code> installed and file is valid disk image</td></tr>
|
|
||||||
<tr><td><code>vm_manager::image::conversion_failed</code></td><td>Image format conversion failed</td><td>Ensure <code>qemu-img</code> installed and sufficient disk space</td></tr>
|
|
||||||
<tr><td><code>vm_manager::vm::not_found</code></td><td>VM not in store</td><td>Run <code>vmctl list</code> to see available VMs</td></tr>
|
|
||||||
<tr><td><code>vm_manager::vm::invalid_state</code></td><td>Operation invalid for current state</td><td>(varies)</td></tr>
|
|
||||||
<tr><td><code>vm_manager::backend::not_available</code></td><td>Backend not supported on platform</td><td>Backend not supported on current platform</td></tr>
|
|
||||||
<tr><td><code>vm_manager::vmfile::not_found</code></td><td>VMFile.kdl not found</td><td>Create VMFile.kdl in current directory or specify path with <code>--file</code></td></tr>
|
|
||||||
<tr><td><code>vm_manager::vmfile::parse_failed</code></td><td>KDL syntax error</td><td>Check VMFile.kdl syntax; see https://kdl.dev</td></tr>
|
|
||||||
<tr><td><code>vm_manager::vmfile::validation</code></td><td>VMFile validation error</td><td>(custom hint per error)</td></tr>
|
|
||||||
<tr><td><code>vm_manager::provision::failed</code></td><td>Provisioner step failed</td><td>Check provisioner config and VM SSH reachability</td></tr>
|
|
||||||
<tr><td><code>vm_manager::io</code></td><td>General I/O error</td><td>(transparent)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="type-alias"><a class="header" href="#type-alias">Type Alias</a></h2>
|
|
||||||
<p>The library defines <code>pub type Result<T> = std::result::Result<T, VmError></code> for convenience. CLI commands return <code>miette::Result<()></code> for rich terminal output.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/ssh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/using-as-crate.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/ssh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/using-as-crate.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Overview - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="architecture-overview"><a class="header" href="#architecture-overview">Architecture Overview</a></h1>
|
|
||||||
<p>vm-manager is structured as a two-crate Cargo workspace.</p>
|
|
||||||
<h2 id="high-level-design"><a class="header" href="#high-level-design">High-Level Design</a></h2>
|
|
||||||
<pre><code class="language-text">┌─────────────────────────────────────────┐
|
|
||||||
│ vmctl CLI │
|
|
||||||
│ (crates/vmctl) │
|
|
||||||
│ │
|
|
||||||
│ Commands → VMFile parser → Hypervisor │
|
|
||||||
└──────────────────┬──────────────────────┘
|
|
||||||
│
|
|
||||||
┌──────────────────┴──────────────────────┐
|
|
||||||
│ vm-manager library │
|
|
||||||
│ (crates/vm-manager) │
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────┐ ┌──────────────────┐ │
|
|
||||||
│ │ Hypervisor │ │ Image Manager │ │
|
|
||||||
│ │ Trait │ │ │ │
|
|
||||||
│ └──────┬──────┘ └──────────────────┘ │
|
|
||||||
│ │ │
|
|
||||||
│ ┌──────┴──────────────────────┐ │
|
|
||||||
│ │ RouterHypervisor │ │
|
|
||||||
│ │ ┌──────┐ ┌────────┐ ┌────┐│ │
|
|
||||||
│ │ │ QEMU │ │Propolis│ │Noop││ │
|
|
||||||
│ │ └──────┘ └────────┘ └────┘│ │
|
|
||||||
│ └─────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌───────────┐ ┌──────────────────┐ │
|
|
||||||
│ │ SSH │ │ Cloud-Init │ │
|
|
||||||
│ │ Module │ │ Generator │ │
|
|
||||||
│ └───────────┘ └──────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌───────────┐ ┌──────────────────┐ │
|
|
||||||
│ │ Provision │ │ VMFile │ │
|
|
||||||
│ │ Runner │ │ Parser │ │
|
|
||||||
│ └───────────┘ └──────────────────┘ │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="async-runtime"><a class="header" href="#async-runtime">Async Runtime</a></h2>
|
|
||||||
<p>vmctl uses Tokio with the multi-threaded runtime. Most operations are async, with one exception: SSH operations use <code>ssh2</code> (libssh2 bindings), which is blocking. These are wrapped in <code>tokio::task::spawn_blocking</code> to avoid blocking the async executor.</p>
|
|
||||||
<h2 id="platform-abstraction"><a class="header" href="#platform-abstraction">Platform Abstraction</a></h2>
|
|
||||||
<p>The <code>Hypervisor</code> trait defines a platform-agnostic interface. The <code>RouterHypervisor</code> dispatches calls to the correct backend based on the <code>BackendTag</code> stored in each <code>VmHandle</code>:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Linux</strong> builds include <code>QemuBackend</code>.</li>
|
|
||||||
<li><strong>illumos</strong> builds include <code>PropolisBackend</code>.</li>
|
|
||||||
<li><strong>All platforms</strong> include <code>NoopBackend</code> for testing.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Conditional compilation (<code>#[cfg(target_os = ...)]</code>) ensures only the relevant backend is compiled.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/log.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/crate-structure.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/log.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/crate-structure.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,263 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>SSH Subsystem - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="ssh-subsystem"><a class="header" href="#ssh-subsystem">SSH Subsystem</a></h1>
|
|
||||||
<h2 id="library"><a class="header" href="#library">Library</a></h2>
|
|
||||||
<p>vmctl uses the <code>ssh2</code> crate (Rust bindings to libssh2) for SSH operations. The SSH module is at <code>crates/vm-manager/src/ssh.rs</code>.</p>
|
|
||||||
<h2 id="core-functions"><a class="header" href="#core-functions">Core Functions</a></h2>
|
|
||||||
<h3 id="connect"><a class="header" href="#connect">connect</a></h3>
|
|
||||||
<p>Establishes a TCP connection and authenticates via public key.</p>
|
|
||||||
<p>Supports two authentication modes:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>In-memory PEM</strong>: Private key stored as a string (used for auto-generated keys).</li>
|
|
||||||
<li><strong>File path</strong>: Reads key from disk.</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="exec"><a class="header" href="#exec">exec</a></h3>
|
|
||||||
<p>Executes a command and collects the full stdout/stderr output. Blocking.</p>
|
|
||||||
<h3 id="exec_streaming"><a class="header" href="#exec_streaming">exec_streaming</a></h3>
|
|
||||||
<p>Executes a command and streams stdout/stderr in real-time to provided writers. Uses non-blocking I/O:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Opens a channel and calls <code>exec()</code>.</li>
|
|
||||||
<li>Switches the session to non-blocking mode.</li>
|
|
||||||
<li>Polls stdout and stderr in a loop with 8KB buffers.</li>
|
|
||||||
<li>Flushes output after each read.</li>
|
|
||||||
<li>Sleeps 50ms when no data is available.</li>
|
|
||||||
<li>Switches back to blocking mode to read the exit status.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This is used by the provisioner to show build output live.</p>
|
|
||||||
<h3 id="upload"><a class="header" href="#upload">upload</a></h3>
|
|
||||||
<p>Transfers a file to the guest via SFTP. Creates the SFTP subsystem, opens a remote file, and writes the local file contents.</p>
|
|
||||||
<h3 id="connect_with_retry"><a class="header" href="#connect_with_retry">connect_with_retry</a></h3>
|
|
||||||
<p>Attempts to connect repeatedly until a timeout (typically 120 seconds for provisioning, 30 seconds for <code>vmctl ssh</code>). Uses exponential backoff starting at 1 second, capped at 5 seconds. Runs the blocking connect on <code>tokio::task::spawn_blocking</code>.</p>
|
|
||||||
<h2 id="why-not-native-ssh"><a class="header" href="#why-not-native-ssh">Why Not Native SSH?</a></h2>
|
|
||||||
<p>libssh2 is used for programmatic operations (provisioning, connectivity checks) because it can be controlled from Rust code. For interactive sessions (<code>vmctl ssh</code>), vmctl hands off to the system <code>ssh</code> binary for proper terminal handling (PTY allocation, signal forwarding, etc.).</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/state-management.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/error-handling.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/state-management.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/error-handling.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>State Management - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="state-management"><a class="header" href="#state-management">State Management</a></h1>
|
|
||||||
<h2 id="vm-store"><a class="header" href="#vm-store">VM Store</a></h2>
|
|
||||||
<p>vmctl persists VM state in a JSON file at <code>$XDG_DATA_HOME/vmctl/vms.json</code> (typically <code>~/.local/share/vmctl/vms.json</code>). Falls back to <code>/tmp</code> if <code>XDG_DATA_HOME</code> is not set.</p>
|
|
||||||
<p>The store is a simple mapping from VM name to <code>VmHandle</code>.</p>
|
|
||||||
<h2 id="vmhandle-serialization"><a class="header" href="#vmhandle-serialization">VmHandle Serialization</a></h2>
|
|
||||||
<p><code>VmHandle</code> is serialized to JSON with all fields. Fields added in later versions have <code>#[serde(default)]</code> annotations, so older JSON files are deserialized without errors (missing fields get defaults).</p>
|
|
||||||
<p>Example stored handle:</p>
|
|
||||||
<pre><code class="language-json">{
|
|
||||||
"id": "abc123",
|
|
||||||
"name": "myvm",
|
|
||||||
"backend": "qemu",
|
|
||||||
"work_dir": "/home/user/.local/share/vmctl/vms/myvm",
|
|
||||||
"overlay_path": "/home/user/.local/share/vmctl/vms/myvm/overlay.qcow2",
|
|
||||||
"seed_iso_path": "/home/user/.local/share/vmctl/vms/myvm/seed.iso",
|
|
||||||
"pid": 12345,
|
|
||||||
"qmp_socket": "/home/user/.local/share/vmctl/vms/myvm/qmp.sock",
|
|
||||||
"console_socket": "/home/user/.local/share/vmctl/vms/myvm/console.sock",
|
|
||||||
"vnc_addr": "127.0.0.1:5900",
|
|
||||||
"vcpus": 2,
|
|
||||||
"memory_mb": 2048,
|
|
||||||
"disk_gb": 20,
|
|
||||||
"network": {"type": "User"},
|
|
||||||
"ssh_host_port": 10042,
|
|
||||||
"mac_addr": "52:54:00:ab:cd:ef"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="write-safety"><a class="header" href="#write-safety">Write Safety</a></h2>
|
|
||||||
<p>The store uses an atomic write pattern:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Write to a <code>.tmp</code> file.</li>
|
|
||||||
<li>Rename (atomic on most filesystems) to the final path.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This prevents corruption if the process is interrupted during a write.</p>
|
|
||||||
<h2 id="state-vs-process-state"><a class="header" href="#state-vs-process-state">State vs Process State</a></h2>
|
|
||||||
<p>The store records the <em>last known</em> state but doesn't actively monitor QEMU processes. When vmctl queries a VM's state, it:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Checks if the PID file exists.</li>
|
|
||||||
<li>Sends <code>kill(pid, 0)</code> to verify the process is alive.</li>
|
|
||||||
<li>If alive, queries QMP for detailed status (<code>running</code>, <code>paused</code>, etc.).</li>
|
|
||||||
<li>If dead, reports <code>Stopped</code>.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/backends.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/ssh.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/backends.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/ssh.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
Based off of the Ayu theme
|
|
||||||
Original by Dempfi (https://github.com/dempfi/ayu)
|
|
||||||
*/
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
overflow-x: auto;
|
|
||||||
background: #191f26;
|
|
||||||
color: #e6e1cf;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-quote {
|
|
||||||
color: #5c6773;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-template-variable,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-attr,
|
|
||||||
.hljs-regexp,
|
|
||||||
.hljs-link,
|
|
||||||
.hljs-selector-id,
|
|
||||||
.hljs-selector-class {
|
|
||||||
color: #ff7733;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-number,
|
|
||||||
.hljs-meta,
|
|
||||||
.hljs-builtin-name,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-type,
|
|
||||||
.hljs-params {
|
|
||||||
color: #ffee99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-bullet {
|
|
||||||
color: #b8cc52;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-section {
|
|
||||||
color: #ffb454;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-keyword,
|
|
||||||
.hljs-selector-tag,
|
|
||||||
.hljs-symbol {
|
|
||||||
color: #ff7733;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-name {
|
|
||||||
color: #36a3d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-tag {
|
|
||||||
color: #00568d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-emphasis {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-addition {
|
|
||||||
color: #91b362;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
color: #d96c75;
|
|
||||||
}
|
|
||||||
|
|
@ -1,839 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS */
|
|
||||||
|
|
||||||
// Fix back button cache problem
|
|
||||||
window.onunload = function() { };
|
|
||||||
|
|
||||||
// Global variable, shared between modules
|
|
||||||
function playground_text(playground, hidden = true) {
|
|
||||||
const code_block = playground.querySelector('code');
|
|
||||||
|
|
||||||
if (window.ace && code_block.classList.contains('editable')) {
|
|
||||||
const editor = window.ace.edit(code_block);
|
|
||||||
return editor.getValue();
|
|
||||||
} else if (hidden) {
|
|
||||||
return code_block.textContent;
|
|
||||||
} else {
|
|
||||||
return code_block.innerText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(function codeSnippets() {
|
|
||||||
function fetch_with_timeout(url, options, timeout = 6000) {
|
|
||||||
return Promise.race([
|
|
||||||
fetch(url, options),
|
|
||||||
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const playgrounds = Array.from(document.querySelectorAll('.playground'));
|
|
||||||
if (playgrounds.length > 0) {
|
|
||||||
fetch_with_timeout('https://play.rust-lang.org/meta/crates', {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'POST',
|
|
||||||
mode: 'cors',
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(response => {
|
|
||||||
// get list of crates available in the rust playground
|
|
||||||
const playground_crates = response.crates.map(item => item['id']);
|
|
||||||
playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle_crate_list_update(playground_block, playground_crates) {
|
|
||||||
// update the play buttons after receiving the response
|
|
||||||
update_play_button(playground_block, playground_crates);
|
|
||||||
|
|
||||||
// and install on change listener to dynamically update ACE editors
|
|
||||||
if (window.ace) {
|
|
||||||
const code_block = playground_block.querySelector('code');
|
|
||||||
if (code_block.classList.contains('editable')) {
|
|
||||||
const editor = window.ace.edit(code_block);
|
|
||||||
editor.addEventListener('change', () => {
|
|
||||||
update_play_button(playground_block, playground_crates);
|
|
||||||
});
|
|
||||||
// add Ctrl-Enter command to execute rust code
|
|
||||||
editor.commands.addCommand({
|
|
||||||
name: 'run',
|
|
||||||
bindKey: {
|
|
||||||
win: 'Ctrl-Enter',
|
|
||||||
mac: 'Ctrl-Enter',
|
|
||||||
},
|
|
||||||
exec: _editor => run_rust_code(playground_block),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updates the visibility of play button based on `no_run` class and
|
|
||||||
// used crates vs ones available on https://play.rust-lang.org
|
|
||||||
function update_play_button(pre_block, playground_crates) {
|
|
||||||
const play_button = pre_block.querySelector('.play-button');
|
|
||||||
|
|
||||||
// skip if code is `no_run`
|
|
||||||
if (pre_block.querySelector('code').classList.contains('no_run')) {
|
|
||||||
play_button.classList.add('hidden');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get list of `extern crate`'s from snippet
|
|
||||||
const txt = playground_text(pre_block);
|
|
||||||
const re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
|
|
||||||
const snippet_crates = [];
|
|
||||||
let item;
|
|
||||||
// eslint-disable-next-line no-cond-assign
|
|
||||||
while (item = re.exec(txt)) {
|
|
||||||
snippet_crates.push(item[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if all used crates are available on play.rust-lang.org
|
|
||||||
const all_available = snippet_crates.every(function(elem) {
|
|
||||||
return playground_crates.indexOf(elem) > -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (all_available) {
|
|
||||||
play_button.classList.remove('hidden');
|
|
||||||
} else {
|
|
||||||
play_button.classList.add('hidden');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_rust_code(code_block) {
|
|
||||||
let result_block = code_block.querySelector('.result');
|
|
||||||
if (!result_block) {
|
|
||||||
result_block = document.createElement('code');
|
|
||||||
result_block.className = 'result hljs language-bash';
|
|
||||||
|
|
||||||
code_block.append(result_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = playground_text(code_block);
|
|
||||||
const classes = code_block.querySelector('code').classList;
|
|
||||||
let edition = '2015';
|
|
||||||
classes.forEach(className => {
|
|
||||||
if (className.startsWith('edition')) {
|
|
||||||
edition = className.slice(7);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const params = {
|
|
||||||
version: 'stable',
|
|
||||||
optimize: '0',
|
|
||||||
code: text,
|
|
||||||
edition: edition,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (text.indexOf('#![feature') !== -1) {
|
|
||||||
params.version = 'nightly';
|
|
||||||
}
|
|
||||||
|
|
||||||
result_block.innerText = 'Running...';
|
|
||||||
|
|
||||||
fetch_with_timeout('https://play.rust-lang.org/evaluate.json', {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'POST',
|
|
||||||
mode: 'cors',
|
|
||||||
body: JSON.stringify(params),
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(response => {
|
|
||||||
if (response.result.trim() === '') {
|
|
||||||
result_block.innerText = 'No output';
|
|
||||||
result_block.classList.add('result-no-output');
|
|
||||||
} else {
|
|
||||||
result_block.innerText = response.result;
|
|
||||||
result_block.classList.remove('result-no-output');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => result_block.innerText = 'Playground Communication: ' + error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Syntax highlighting Configuration
|
|
||||||
hljs.configure({
|
|
||||||
tabReplace: ' ', // 4 spaces
|
|
||||||
languages: [], // Languages used for auto-detection
|
|
||||||
});
|
|
||||||
|
|
||||||
const code_nodes = Array
|
|
||||||
.from(document.querySelectorAll('code'))
|
|
||||||
// Don't highlight `inline code` blocks in headers.
|
|
||||||
.filter(function(node) {
|
|
||||||
return !node.parentElement.classList.contains('header');
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.ace) {
|
|
||||||
// language-rust class needs to be removed for editable
|
|
||||||
// blocks or highlightjs will capture events
|
|
||||||
code_nodes
|
|
||||||
.filter(function(node) {
|
|
||||||
return node.classList.contains('editable');
|
|
||||||
})
|
|
||||||
.forEach(function(block) {
|
|
||||||
block.classList.remove('language-rust');
|
|
||||||
});
|
|
||||||
|
|
||||||
code_nodes
|
|
||||||
.filter(function(node) {
|
|
||||||
return !node.classList.contains('editable');
|
|
||||||
})
|
|
||||||
.forEach(function(block) {
|
|
||||||
hljs.highlightBlock(block);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
code_nodes.forEach(function(block) {
|
|
||||||
hljs.highlightBlock(block);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adding the hljs class gives code blocks the color css
|
|
||||||
// even if highlighting doesn't apply
|
|
||||||
code_nodes.forEach(function(block) {
|
|
||||||
block.classList.add('hljs');
|
|
||||||
});
|
|
||||||
|
|
||||||
Array.from(document.querySelectorAll('code.hljs')).forEach(function(block) {
|
|
||||||
|
|
||||||
const lines = Array.from(block.querySelectorAll('.boring'));
|
|
||||||
// If no lines were hidden, return
|
|
||||||
if (!lines.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
block.classList.add('hide-boring');
|
|
||||||
|
|
||||||
const buttons = document.createElement('div');
|
|
||||||
buttons.className = 'buttons';
|
|
||||||
buttons.innerHTML = '<button class="fa fa-eye" title="Show hidden lines" \
|
|
||||||
aria-label="Show hidden lines"></button>';
|
|
||||||
|
|
||||||
// add expand button
|
|
||||||
const pre_block = block.parentNode;
|
|
||||||
pre_block.insertBefore(buttons, pre_block.firstChild);
|
|
||||||
|
|
||||||
pre_block.querySelector('.buttons').addEventListener('click', function(e) {
|
|
||||||
if (e.target.classList.contains('fa-eye')) {
|
|
||||||
e.target.classList.remove('fa-eye');
|
|
||||||
e.target.classList.add('fa-eye-slash');
|
|
||||||
e.target.title = 'Hide lines';
|
|
||||||
e.target.setAttribute('aria-label', e.target.title);
|
|
||||||
|
|
||||||
block.classList.remove('hide-boring');
|
|
||||||
} else if (e.target.classList.contains('fa-eye-slash')) {
|
|
||||||
e.target.classList.remove('fa-eye-slash');
|
|
||||||
e.target.classList.add('fa-eye');
|
|
||||||
e.target.title = 'Show hidden lines';
|
|
||||||
e.target.setAttribute('aria-label', e.target.title);
|
|
||||||
|
|
||||||
block.classList.add('hide-boring');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.playground_copyable) {
|
|
||||||
Array.from(document.querySelectorAll('pre code')).forEach(function(block) {
|
|
||||||
const pre_block = block.parentNode;
|
|
||||||
if (!pre_block.classList.contains('playground')) {
|
|
||||||
let buttons = pre_block.querySelector('.buttons');
|
|
||||||
if (!buttons) {
|
|
||||||
buttons = document.createElement('div');
|
|
||||||
buttons.className = 'buttons';
|
|
||||||
pre_block.insertBefore(buttons, pre_block.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
const clipButton = document.createElement('button');
|
|
||||||
clipButton.className = 'clip-button';
|
|
||||||
clipButton.title = 'Copy to clipboard';
|
|
||||||
clipButton.setAttribute('aria-label', clipButton.title);
|
|
||||||
clipButton.innerHTML = '<i class="tooltiptext"></i>';
|
|
||||||
|
|
||||||
buttons.insertBefore(clipButton, buttons.firstChild);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process playground code blocks
|
|
||||||
Array.from(document.querySelectorAll('.playground')).forEach(function(pre_block) {
|
|
||||||
// Add play button
|
|
||||||
let buttons = pre_block.querySelector('.buttons');
|
|
||||||
if (!buttons) {
|
|
||||||
buttons = document.createElement('div');
|
|
||||||
buttons.className = 'buttons';
|
|
||||||
pre_block.insertBefore(buttons, pre_block.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
const runCodeButton = document.createElement('button');
|
|
||||||
runCodeButton.className = 'fa fa-play play-button';
|
|
||||||
runCodeButton.hidden = true;
|
|
||||||
runCodeButton.title = 'Run this code';
|
|
||||||
runCodeButton.setAttribute('aria-label', runCodeButton.title);
|
|
||||||
|
|
||||||
buttons.insertBefore(runCodeButton, buttons.firstChild);
|
|
||||||
runCodeButton.addEventListener('click', () => {
|
|
||||||
run_rust_code(pre_block);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (window.playground_copyable) {
|
|
||||||
const copyCodeClipboardButton = document.createElement('button');
|
|
||||||
copyCodeClipboardButton.className = 'clip-button';
|
|
||||||
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
|
|
||||||
copyCodeClipboardButton.title = 'Copy to clipboard';
|
|
||||||
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
|
|
||||||
|
|
||||||
buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
const code_block = pre_block.querySelector('code');
|
|
||||||
if (window.ace && code_block.classList.contains('editable')) {
|
|
||||||
const undoChangesButton = document.createElement('button');
|
|
||||||
undoChangesButton.className = 'fa fa-history reset-button';
|
|
||||||
undoChangesButton.title = 'Undo changes';
|
|
||||||
undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
|
|
||||||
|
|
||||||
buttons.insertBefore(undoChangesButton, buttons.firstChild);
|
|
||||||
|
|
||||||
undoChangesButton.addEventListener('click', function() {
|
|
||||||
const editor = window.ace.edit(code_block);
|
|
||||||
editor.setValue(editor.originalCode);
|
|
||||||
editor.clearSelection();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function themes() {
|
|
||||||
const html = document.querySelector('html');
|
|
||||||
const themeToggleButton = document.getElementById('theme-toggle');
|
|
||||||
const themePopup = document.getElementById('theme-list');
|
|
||||||
const themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
|
|
||||||
const themeIds = [];
|
|
||||||
themePopup.querySelectorAll('button.theme').forEach(function(el) {
|
|
||||||
themeIds.push(el.id);
|
|
||||||
});
|
|
||||||
const stylesheets = {
|
|
||||||
ayuHighlight: document.querySelector('#ayu-highlight-css'),
|
|
||||||
tomorrowNight: document.querySelector('#tomorrow-night-css'),
|
|
||||||
highlight: document.querySelector('#highlight-css'),
|
|
||||||
};
|
|
||||||
|
|
||||||
function showThemes() {
|
|
||||||
themePopup.style.display = 'block';
|
|
||||||
themeToggleButton.setAttribute('aria-expanded', true);
|
|
||||||
themePopup.querySelector('button#' + get_theme()).focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateThemeSelected() {
|
|
||||||
themePopup.querySelectorAll('.theme-selected').forEach(function(el) {
|
|
||||||
el.classList.remove('theme-selected');
|
|
||||||
});
|
|
||||||
const selected = get_saved_theme() ?? 'default_theme';
|
|
||||||
let element = themePopup.querySelector('button#' + selected);
|
|
||||||
if (element === null) {
|
|
||||||
// Fall back in case there is no "Default" item.
|
|
||||||
element = themePopup.querySelector('button#' + get_theme());
|
|
||||||
}
|
|
||||||
element.classList.add('theme-selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideThemes() {
|
|
||||||
themePopup.style.display = 'none';
|
|
||||||
themeToggleButton.setAttribute('aria-expanded', false);
|
|
||||||
themeToggleButton.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_saved_theme() {
|
|
||||||
let theme = null;
|
|
||||||
try {
|
|
||||||
theme = localStorage.getItem('mdbook-theme');
|
|
||||||
} catch (e) {
|
|
||||||
// ignore error.
|
|
||||||
}
|
|
||||||
return theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
function delete_saved_theme() {
|
|
||||||
localStorage.removeItem('mdbook-theme');
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_theme() {
|
|
||||||
const theme = get_saved_theme();
|
|
||||||
if (theme === null || theme === undefined || !themeIds.includes(theme)) {
|
|
||||||
if (typeof default_dark_theme === 'undefined') {
|
|
||||||
// A customized index.hbs might not define this, so fall back to
|
|
||||||
// old behavior of determining the default on page load.
|
|
||||||
return default_theme;
|
|
||||||
}
|
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
? default_dark_theme
|
|
||||||
: default_light_theme;
|
|
||||||
} else {
|
|
||||||
return theme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let previousTheme = default_theme;
|
|
||||||
function set_theme(theme, store = true) {
|
|
||||||
let ace_theme;
|
|
||||||
|
|
||||||
if (theme === 'coal' || theme === 'navy') {
|
|
||||||
stylesheets.ayuHighlight.disabled = true;
|
|
||||||
stylesheets.tomorrowNight.disabled = false;
|
|
||||||
stylesheets.highlight.disabled = true;
|
|
||||||
|
|
||||||
ace_theme = 'ace/theme/tomorrow_night';
|
|
||||||
} else if (theme === 'ayu') {
|
|
||||||
stylesheets.ayuHighlight.disabled = false;
|
|
||||||
stylesheets.tomorrowNight.disabled = true;
|
|
||||||
stylesheets.highlight.disabled = true;
|
|
||||||
ace_theme = 'ace/theme/tomorrow_night';
|
|
||||||
} else {
|
|
||||||
stylesheets.ayuHighlight.disabled = true;
|
|
||||||
stylesheets.tomorrowNight.disabled = true;
|
|
||||||
stylesheets.highlight.disabled = false;
|
|
||||||
ace_theme = 'ace/theme/dawn';
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor;
|
|
||||||
}, 1);
|
|
||||||
|
|
||||||
if (window.ace && window.editors) {
|
|
||||||
window.editors.forEach(function(editor) {
|
|
||||||
editor.setTheme(ace_theme);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (store) {
|
|
||||||
try {
|
|
||||||
localStorage.setItem('mdbook-theme', theme);
|
|
||||||
} catch (e) {
|
|
||||||
// ignore error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html.classList.remove(previousTheme);
|
|
||||||
html.classList.add(theme);
|
|
||||||
previousTheme = theme;
|
|
||||||
updateThemeSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = window.matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
query.onchange = function() {
|
|
||||||
set_theme(get_theme(), false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set theme.
|
|
||||||
set_theme(get_theme(), false);
|
|
||||||
|
|
||||||
themeToggleButton.addEventListener('click', function() {
|
|
||||||
if (themePopup.style.display === 'block') {
|
|
||||||
hideThemes();
|
|
||||||
} else {
|
|
||||||
showThemes();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
themePopup.addEventListener('click', function(e) {
|
|
||||||
let theme;
|
|
||||||
if (e.target.className === 'theme') {
|
|
||||||
theme = e.target.id;
|
|
||||||
} else if (e.target.parentElement.className === 'theme') {
|
|
||||||
theme = e.target.parentElement.id;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (theme === 'default_theme' || theme === null) {
|
|
||||||
delete_saved_theme();
|
|
||||||
set_theme(get_theme(), false);
|
|
||||||
} else {
|
|
||||||
set_theme(theme);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
themePopup.addEventListener('focusout', function(e) {
|
|
||||||
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
|
|
||||||
if (!!e.relatedTarget &&
|
|
||||||
!themeToggleButton.contains(e.relatedTarget) &&
|
|
||||||
!themePopup.contains(e.relatedTarget)
|
|
||||||
) {
|
|
||||||
hideThemes();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Should not be needed, but it works around an issue on macOS & iOS:
|
|
||||||
// https://github.com/rust-lang/mdBook/issues/628
|
|
||||||
document.addEventListener('click', function(e) {
|
|
||||||
if (themePopup.style.display === 'block' &&
|
|
||||||
!themeToggleButton.contains(e.target) &&
|
|
||||||
!themePopup.contains(e.target)
|
|
||||||
) {
|
|
||||||
hideThemes();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('keydown', function(e) {
|
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!themePopup.contains(e.target)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let li;
|
|
||||||
switch (e.key) {
|
|
||||||
case 'Escape':
|
|
||||||
e.preventDefault();
|
|
||||||
hideThemes();
|
|
||||||
break;
|
|
||||||
case 'ArrowUp':
|
|
||||||
e.preventDefault();
|
|
||||||
li = document.activeElement.parentElement;
|
|
||||||
if (li && li.previousElementSibling) {
|
|
||||||
li.previousElementSibling.querySelector('button').focus();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'ArrowDown':
|
|
||||||
e.preventDefault();
|
|
||||||
li = document.activeElement.parentElement;
|
|
||||||
if (li && li.nextElementSibling) {
|
|
||||||
li.nextElementSibling.querySelector('button').focus();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Home':
|
|
||||||
e.preventDefault();
|
|
||||||
themePopup.querySelector('li:first-child button').focus();
|
|
||||||
break;
|
|
||||||
case 'End':
|
|
||||||
e.preventDefault();
|
|
||||||
themePopup.querySelector('li:last-child button').focus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function sidebar() {
|
|
||||||
const sidebar = document.getElementById('sidebar');
|
|
||||||
const sidebarLinks = document.querySelectorAll('#sidebar a');
|
|
||||||
const sidebarToggleButton = document.getElementById('sidebar-toggle');
|
|
||||||
const sidebarResizeHandle = document.getElementById('sidebar-resize-handle');
|
|
||||||
const sidebarCheckbox = document.getElementById('sidebar-toggle-anchor');
|
|
||||||
let firstContact = null;
|
|
||||||
|
|
||||||
|
|
||||||
/* Because we cannot change the `display` using only CSS after/before the transition, we
|
|
||||||
need JS to do it. We change the display to prevent the browsers search to find text inside
|
|
||||||
the collapsed sidebar. */
|
|
||||||
if (!document.documentElement.classList.contains('sidebar-visible')) {
|
|
||||||
sidebar.style.display = 'none';
|
|
||||||
}
|
|
||||||
sidebar.addEventListener('transitionend', () => {
|
|
||||||
/* We only change the display to "none" if we're collapsing the sidebar. */
|
|
||||||
if (!sidebarCheckbox.checked) {
|
|
||||||
sidebar.style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sidebarToggleButton.addEventListener('click', () => {
|
|
||||||
/* To allow the sidebar expansion animation, we first need to put back the display. */
|
|
||||||
if (!sidebarCheckbox.checked) {
|
|
||||||
sidebar.style.display = '';
|
|
||||||
// Workaround for Safari skipping the animation when changing
|
|
||||||
// `display` and a transform in the same event loop. This forces a
|
|
||||||
// reflow after updating the display.
|
|
||||||
sidebar.offsetHeight;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function showSidebar() {
|
|
||||||
document.documentElement.classList.add('sidebar-visible');
|
|
||||||
Array.from(sidebarLinks).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', 0);
|
|
||||||
});
|
|
||||||
sidebarToggleButton.setAttribute('aria-expanded', true);
|
|
||||||
sidebar.setAttribute('aria-hidden', false);
|
|
||||||
try {
|
|
||||||
localStorage.setItem('mdbook-sidebar', 'visible');
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideSidebar() {
|
|
||||||
document.documentElement.classList.remove('sidebar-visible');
|
|
||||||
Array.from(sidebarLinks).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', -1);
|
|
||||||
});
|
|
||||||
sidebarToggleButton.setAttribute('aria-expanded', false);
|
|
||||||
sidebar.setAttribute('aria-hidden', true);
|
|
||||||
try {
|
|
||||||
localStorage.setItem('mdbook-sidebar', 'hidden');
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle sidebar
|
|
||||||
sidebarCheckbox.addEventListener('change', function sidebarToggle() {
|
|
||||||
if (sidebarCheckbox.checked) {
|
|
||||||
const current_width = parseInt(
|
|
||||||
document.documentElement.style.getPropertyValue('--sidebar-target-width'), 10);
|
|
||||||
if (current_width < 150) {
|
|
||||||
document.documentElement.style.setProperty('--sidebar-target-width', '150px');
|
|
||||||
}
|
|
||||||
showSidebar();
|
|
||||||
} else {
|
|
||||||
hideSidebar();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sidebarResizeHandle.addEventListener('mousedown', initResize, false);
|
|
||||||
|
|
||||||
function initResize() {
|
|
||||||
window.addEventListener('mousemove', resize, false);
|
|
||||||
window.addEventListener('mouseup', stopResize, false);
|
|
||||||
document.documentElement.classList.add('sidebar-resizing');
|
|
||||||
}
|
|
||||||
function resize(e) {
|
|
||||||
let pos = e.clientX - sidebar.offsetLeft;
|
|
||||||
if (pos < 20) {
|
|
||||||
hideSidebar();
|
|
||||||
} else {
|
|
||||||
if (!document.documentElement.classList.contains('sidebar-visible')) {
|
|
||||||
showSidebar();
|
|
||||||
}
|
|
||||||
pos = Math.min(pos, window.innerWidth - 100);
|
|
||||||
document.documentElement.style.setProperty('--sidebar-target-width', pos + 'px');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//on mouseup remove windows functions mousemove & mouseup
|
|
||||||
function stopResize() {
|
|
||||||
document.documentElement.classList.remove('sidebar-resizing');
|
|
||||||
window.removeEventListener('mousemove', resize, false);
|
|
||||||
window.removeEventListener('mouseup', stopResize, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('touchstart', function(e) {
|
|
||||||
firstContact = {
|
|
||||||
x: e.touches[0].clientX,
|
|
||||||
time: Date.now(),
|
|
||||||
};
|
|
||||||
}, { passive: true });
|
|
||||||
|
|
||||||
document.addEventListener('touchmove', function(e) {
|
|
||||||
if (!firstContact) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const curX = e.touches[0].clientX;
|
|
||||||
const xDiff = curX - firstContact.x,
|
|
||||||
tDiff = Date.now() - firstContact.time;
|
|
||||||
|
|
||||||
if (tDiff < 250 && Math.abs(xDiff) >= 150) {
|
|
||||||
if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) {
|
|
||||||
showSidebar();
|
|
||||||
} else if (xDiff < 0 && curX < 300) {
|
|
||||||
hideSidebar();
|
|
||||||
}
|
|
||||||
|
|
||||||
firstContact = null;
|
|
||||||
}
|
|
||||||
}, { passive: true });
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function chapterNavigation() {
|
|
||||||
document.addEventListener('keydown', function(e) {
|
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (window.search && window.search.hasFocus()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const html = document.querySelector('html');
|
|
||||||
|
|
||||||
function next() {
|
|
||||||
const nextButton = document.querySelector('.nav-chapters.next');
|
|
||||||
if (nextButton) {
|
|
||||||
window.location.href = nextButton.href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function prev() {
|
|
||||||
const previousButton = document.querySelector('.nav-chapters.previous');
|
|
||||||
if (previousButton) {
|
|
||||||
window.location.href = previousButton.href;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function showHelp() {
|
|
||||||
const container = document.getElementById('mdbook-help-container');
|
|
||||||
const overlay = document.getElementById('mdbook-help-popup');
|
|
||||||
container.style.display = 'flex';
|
|
||||||
|
|
||||||
// Clicking outside the popup will dismiss it.
|
|
||||||
const mouseHandler = event => {
|
|
||||||
if (overlay.contains(event.target)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.button !== 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
document.removeEventListener('mousedown', mouseHandler);
|
|
||||||
hideHelp();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pressing esc will dismiss the popup.
|
|
||||||
const escapeKeyHandler = event => {
|
|
||||||
if (event.key === 'Escape') {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
document.removeEventListener('keydown', escapeKeyHandler, true);
|
|
||||||
hideHelp();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener('keydown', escapeKeyHandler, true);
|
|
||||||
document.getElementById('mdbook-help-container')
|
|
||||||
.addEventListener('mousedown', mouseHandler);
|
|
||||||
}
|
|
||||||
function hideHelp() {
|
|
||||||
document.getElementById('mdbook-help-container').style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usually needs the Shift key to be pressed
|
|
||||||
switch (e.key) {
|
|
||||||
case '?':
|
|
||||||
e.preventDefault();
|
|
||||||
showHelp();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rest of the keys are only active when the Shift key is not pressed
|
|
||||||
if (e.shiftKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (e.key) {
|
|
||||||
case 'ArrowRight':
|
|
||||||
e.preventDefault();
|
|
||||||
if (html.dir === 'rtl') {
|
|
||||||
prev();
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'ArrowLeft':
|
|
||||||
e.preventDefault();
|
|
||||||
if (html.dir === 'rtl') {
|
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
prev();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function clipboard() {
|
|
||||||
const clipButtons = document.querySelectorAll('.clip-button');
|
|
||||||
|
|
||||||
function hideTooltip(elem) {
|
|
||||||
elem.firstChild.innerText = '';
|
|
||||||
elem.className = 'clip-button';
|
|
||||||
}
|
|
||||||
|
|
||||||
function showTooltip(elem, msg) {
|
|
||||||
elem.firstChild.innerText = msg;
|
|
||||||
elem.className = 'clip-button tooltipped';
|
|
||||||
}
|
|
||||||
|
|
||||||
const clipboardSnippets = new ClipboardJS('.clip-button', {
|
|
||||||
text: function(trigger) {
|
|
||||||
hideTooltip(trigger);
|
|
||||||
const playground = trigger.closest('pre');
|
|
||||||
return playground_text(playground, false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Array.from(clipButtons).forEach(function(clipButton) {
|
|
||||||
clipButton.addEventListener('mouseout', function(e) {
|
|
||||||
hideTooltip(e.currentTarget);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
clipboardSnippets.on('success', function(e) {
|
|
||||||
e.clearSelection();
|
|
||||||
showTooltip(e.trigger, 'Copied!');
|
|
||||||
});
|
|
||||||
|
|
||||||
clipboardSnippets.on('error', function(e) {
|
|
||||||
showTooltip(e.trigger, 'Clipboard error!');
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function scrollToTop() {
|
|
||||||
const menuTitle = document.querySelector('.menu-title');
|
|
||||||
|
|
||||||
menuTitle.addEventListener('click', function() {
|
|
||||||
document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
(function controllMenu() {
|
|
||||||
const menu = document.getElementById('menu-bar');
|
|
||||||
|
|
||||||
(function controllPosition() {
|
|
||||||
let scrollTop = document.scrollingElement.scrollTop;
|
|
||||||
let prevScrollTop = scrollTop;
|
|
||||||
const minMenuY = -menu.clientHeight - 50;
|
|
||||||
// When the script loads, the page can be at any scroll (e.g. if you refresh it).
|
|
||||||
menu.style.top = scrollTop + 'px';
|
|
||||||
// Same as parseInt(menu.style.top.slice(0, -2), but faster
|
|
||||||
let topCache = menu.style.top.slice(0, -2);
|
|
||||||
menu.classList.remove('sticky');
|
|
||||||
let stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
|
|
||||||
document.addEventListener('scroll', function() {
|
|
||||||
scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
|
|
||||||
// `null` means that it doesn't need to be updated
|
|
||||||
let nextSticky = null;
|
|
||||||
let nextTop = null;
|
|
||||||
const scrollDown = scrollTop > prevScrollTop;
|
|
||||||
const menuPosAbsoluteY = topCache - scrollTop;
|
|
||||||
if (scrollDown) {
|
|
||||||
nextSticky = false;
|
|
||||||
if (menuPosAbsoluteY > 0) {
|
|
||||||
nextTop = prevScrollTop;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (menuPosAbsoluteY > 0) {
|
|
||||||
nextSticky = true;
|
|
||||||
} else if (menuPosAbsoluteY < minMenuY) {
|
|
||||||
nextTop = prevScrollTop + minMenuY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nextSticky === true && stickyCache === false) {
|
|
||||||
menu.classList.add('sticky');
|
|
||||||
stickyCache = true;
|
|
||||||
} else if (nextSticky === false && stickyCache === true) {
|
|
||||||
menu.classList.remove('sticky');
|
|
||||||
stickyCache = false;
|
|
||||||
}
|
|
||||||
if (nextTop !== null) {
|
|
||||||
menu.style.top = nextTop + 'px';
|
|
||||||
topCache = nextTop;
|
|
||||||
}
|
|
||||||
prevScrollTop = scrollTop;
|
|
||||||
}, { passive: true });
|
|
||||||
})();
|
|
||||||
(function controllBorder() {
|
|
||||||
function updateBorder() {
|
|
||||||
if (menu.offsetTop === 0) {
|
|
||||||
menu.classList.remove('bordered');
|
|
||||||
} else {
|
|
||||||
menu.classList.add('bordered');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateBorder();
|
|
||||||
document.addEventListener('scroll', updateBorder, { passive: true });
|
|
||||||
})();
|
|
||||||
})();
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl console - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-console"><a class="header" href="#vmctl-console">vmctl console</a></h1>
|
|
||||||
<p>Attach to a VM's serial console.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl console <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Connects to the VM's serial console via a Unix socket (QEMU) or WebSocket (Propolis). You'll see the same output as a physical serial port: boot messages, kernel output, and a login prompt.</p>
|
|
||||||
<p>Press <strong>Ctrl+]</strong> (0x1d) to detach from the console.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl console myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./ssh.html">vmctl ssh</a>, <a href="./log.html">vmctl log</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/status.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/ssh.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/status.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/ssh.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,272 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl create - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-create"><a class="header" href="#vmctl-create">vmctl create</a></h1>
|
|
||||||
<p>Create a new VM and optionally start it.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl create [OPTIONS] --name <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td><em>required</em></td><td>VM name</td></tr>
|
|
||||||
<tr><td><code>--image</code></td><td>path</td><td></td><td>Path to a local disk image</td></tr>
|
|
||||||
<tr><td><code>--image-url</code></td><td>string</td><td></td><td>URL to download an image from</td></tr>
|
|
||||||
<tr><td><code>--vcpus</code></td><td>integer</td><td><code>1</code></td><td>Number of virtual CPUs</td></tr>
|
|
||||||
<tr><td><code>--memory</code></td><td>integer</td><td><code>1024</code></td><td>Memory in MB</td></tr>
|
|
||||||
<tr><td><code>--disk</code></td><td>integer</td><td></td><td>Disk size in GB (overlay resize)</td></tr>
|
|
||||||
<tr><td><code>--bridge</code></td><td>string</td><td></td><td>Bridge name for TAP networking</td></tr>
|
|
||||||
<tr><td><code>--cloud-init</code></td><td>path</td><td></td><td>Path to cloud-init user-data file</td></tr>
|
|
||||||
<tr><td><code>--ssh-key</code></td><td>path</td><td></td><td>Path to SSH public key file</td></tr>
|
|
||||||
<tr><td><code>--start</code></td><td>flag</td><td><code>false</code></td><td>Start the VM after creation</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>One of <code>--image</code> or <code>--image-url</code> must be provided. If <code>--image-url</code> is given, the image is downloaded and cached.</p>
|
|
||||||
<p>When <code>--bridge</code> is specified, TAP networking is used. Otherwise, user-mode (SLIRP) networking is used.</p>
|
|
||||||
<p>When <code>--ssh-key</code> is provided, a cloud-init ISO is generated that injects the public key. The SSH user defaults to <code>"vm"</code>.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Create from a URL with defaults
|
|
||||||
vmctl create --name myvm --image-url https://example.com/image.img
|
|
||||||
|
|
||||||
# Create with custom resources and start immediately
|
|
||||||
vmctl create --name myvm \
|
|
||||||
--image-url https://example.com/image.img \
|
|
||||||
--vcpus 4 --memory 4096 --disk 40 \
|
|
||||||
--ssh-key ~/.ssh/id_ed25519.pub \
|
|
||||||
--start
|
|
||||||
|
|
||||||
# Create from local image with TAP networking
|
|
||||||
vmctl create --name myvm --image ./ubuntu.qcow2 --bridge br0
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./start.html">vmctl start</a>, <a href="./up.html">vmctl up</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/vmctl.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/start.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/vmctl.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/start.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl destroy - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-destroy"><a class="header" href="#vmctl-destroy">vmctl destroy</a></h1>
|
|
||||||
<p>Destroy a VM and clean up all associated resources.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl destroy <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Stops the VM if it's running, then removes all associated files: QCOW2 overlay, cloud-init ISO, log files, SSH keys, sockets, and the work directory. Unregisters the VM from the store.</p>
|
|
||||||
<p>This action is irreversible.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl destroy myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./down.html">vmctl down</a> (declarative equivalent)</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/stop.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/list.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/stop.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/list.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl down - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-down"><a class="header" href="#vmctl-down">vmctl down</a></h1>
|
|
||||||
<p>Bring down VMs defined in VMFile.kdl.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl down [OPTIONS]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--file</code></td><td>path</td><td></td><td>Path to VMFile.kdl (auto-discovered if omitted)</td></tr>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td></td><td>Only bring down a specific VM</td></tr>
|
|
||||||
<tr><td><code>--destroy</code></td><td>flag</td><td><code>false</code></td><td>Destroy VMs instead of just stopping</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Without <code>--destroy</code>, VMs are stopped gracefully (30-second timeout). They can be restarted with <code>vmctl up</code> or <code>vmctl start</code>.</p>
|
|
||||||
<p>With <code>--destroy</code>, VMs are fully destroyed: all files removed, unregistered from the store. This is irreversible.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Stop all VMs in VMFile.kdl
|
|
||||||
vmctl down
|
|
||||||
|
|
||||||
# Stop a specific VM
|
|
||||||
vmctl down --name webserver
|
|
||||||
|
|
||||||
# Destroy all VMs
|
|
||||||
vmctl down --destroy
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./up.html">vmctl up</a>, <a href="./destroy.html">vmctl destroy</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/up.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/reload.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/up.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/reload.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl image - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-image"><a class="header" href="#vmctl-image">vmctl image</a></h1>
|
|
||||||
<p>Manage VM disk images.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl image <SUBCOMMAND>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="subcommands"><a class="header" href="#subcommands">Subcommands</a></h2>
|
|
||||||
<h3 id="vmctl-image-pull"><a class="header" href="#vmctl-image-pull">vmctl image pull</a></h3>
|
|
||||||
<p>Download an image to the local cache.</p>
|
|
||||||
<pre><code>vmctl image pull [OPTIONS] <URL>
|
|
||||||
</code></pre>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument/Option</th><th>Type</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>URL</code></td><td>string</td><td>URL to download (positional)</td></tr>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td>Name to save as in the cache</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h3 id="vmctl-image-list"><a class="header" href="#vmctl-image-list">vmctl image list</a></h3>
|
|
||||||
<p>List cached images.</p>
|
|
||||||
<pre><code>vmctl image list
|
|
||||||
</code></pre>
|
|
||||||
<p>Output:</p>
|
|
||||||
<pre><code class="language-text">NAME SIZE PATH
|
|
||||||
noble-server-cloudimg-amd64.img 0.62 GB /home/user/.local/share/vmctl/images/noble-server-cloudimg-amd64.img
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="vmctl-image-inspect"><a class="header" href="#vmctl-image-inspect">vmctl image inspect</a></h3>
|
|
||||||
<p>Show image format and details.</p>
|
|
||||||
<pre><code>vmctl image inspect <PATH>
|
|
||||||
</code></pre>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>PATH</code></td><td>Path to image file (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Download and cache an image
|
|
||||||
vmctl image pull https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
|
|
||||||
|
|
||||||
# List what's cached
|
|
||||||
vmctl image list
|
|
||||||
|
|
||||||
# Check format of a local image
|
|
||||||
vmctl image inspect ./my-image.qcow2
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/resume.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/up.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/resume.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/up.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,256 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl list - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-list"><a class="header" href="#vmctl-list">vmctl list</a></h1>
|
|
||||||
<p>List all registered VMs.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl list
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="output"><a class="header" href="#output">Output</a></h2>
|
|
||||||
<pre><code class="language-text">NAME BACKEND VCPUS MEM NETWORK PID SSH
|
|
||||||
webserver qemu 2 2048 user 12345 10042
|
|
||||||
database qemu 4 4096 tap 12346 -
|
|
||||||
</code></pre>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Column</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name</td></tr>
|
|
||||||
<tr><td><code>BACKEND</code></td><td>Hypervisor backend (qemu, propolis, noop)</td></tr>
|
|
||||||
<tr><td><code>VCPUS</code></td><td>Number of virtual CPUs</td></tr>
|
|
||||||
<tr><td><code>MEM</code></td><td>Memory in MB</td></tr>
|
|
||||||
<tr><td><code>NETWORK</code></td><td>Networking mode (user, tap, vnic, none)</td></tr>
|
|
||||||
<tr><td><code>PID</code></td><td>QEMU process PID (or <code>-</code> if not running)</td></tr>
|
|
||||||
<tr><td><code>SSH</code></td><td>SSH host port (or <code>-</code> if not available)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl list
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/destroy.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/status.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/destroy.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/status.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,269 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl log - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-log"><a class="header" href="#vmctl-log">vmctl log</a></h1>
|
|
||||||
<p>Show VM console and provision logs.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl log [OPTIONS] <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--console</code></td><td>flag</td><td><code>false</code></td><td>Show only console log (boot / cloud-init output)</td></tr>
|
|
||||||
<tr><td><code>--provision</code></td><td>flag</td><td><code>false</code></td><td>Show only provision log</td></tr>
|
|
||||||
<tr><td><code>--tail</code>, <code>-n</code></td><td>integer</td><td><code>0</code></td><td>Show the last N lines (0 = all)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>By default (no flags), both console and provision logs are shown. The console log captures serial output (boot messages, cloud-init output). The provision log captures stdout/stderr from provisioner runs.</p>
|
|
||||||
<p>Log files are located in the VM's work directory:</p>
|
|
||||||
<ul>
|
|
||||||
<li><code>console.log</code> - Serial console output</li>
|
|
||||||
<li><code>provision.log</code> - Provisioning output</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Show all logs
|
|
||||||
vmctl log myvm
|
|
||||||
|
|
||||||
# Show only provision output
|
|
||||||
vmctl log myvm --provision
|
|
||||||
|
|
||||||
# Show last 50 lines of console log
|
|
||||||
vmctl log myvm --console --tail 50
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./console.html">vmctl console</a>, <a href="./status.html">vmctl status</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/provision.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/overview.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/provision.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../architecture/overview.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,257 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl provision - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-provision"><a class="header" href="#vmctl-provision">vmctl provision</a></h1>
|
|
||||||
<p>Re-run provisioners on running VMs from VMFile.kdl.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl provision [OPTIONS]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--file</code></td><td>path</td><td></td><td>Path to VMFile.kdl (auto-discovered if omitted)</td></tr>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td></td><td>Only provision a specific VM</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Re-runs all provision steps defined in the VMFile on already-running VMs. The VM must be running and have an <code>ssh</code> block in the VMFile.</p>
|
|
||||||
<p>vmctl waits up to 120 seconds for SSH to become available, then runs each provisioner in sequence, streaming output to the terminal and logging to <code>provision.log</code>.</p>
|
|
||||||
<p>Useful for iterating on provision scripts without recreating the VM.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Re-provision all VMs
|
|
||||||
vmctl provision
|
|
||||||
|
|
||||||
# Re-provision a specific VM
|
|
||||||
vmctl provision --name builder
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./up.html">vmctl up</a>, <a href="./reload.html">vmctl reload</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/reload.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/log.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/reload.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/log.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl reload - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-reload"><a class="header" href="#vmctl-reload">vmctl reload</a></h1>
|
|
||||||
<p>Destroy and recreate VMs from VMFile.kdl.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl reload [OPTIONS]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--file</code></td><td>path</td><td></td><td>Path to VMFile.kdl (auto-discovered if omitted)</td></tr>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td></td><td>Only reload a specific VM</td></tr>
|
|
||||||
<tr><td><code>--no-provision</code></td><td>flag</td><td><code>false</code></td><td>Skip provisioning after reload</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>For each VM: destroys the existing instance (if any), then creates, starts, and provisions a fresh VM from the current VMFile definition. Useful when you've changed the VMFile and want a clean slate.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Reload all VMs
|
|
||||||
vmctl reload
|
|
||||||
|
|
||||||
# Reload a specific VM
|
|
||||||
vmctl reload --name webserver
|
|
||||||
|
|
||||||
# Reload without provisioning
|
|
||||||
vmctl reload --no-provision
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./up.html">vmctl up</a>, <a href="./down.html">vmctl down</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/down.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/provision.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/down.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/provision.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl resume - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-resume"><a class="header" href="#vmctl-resume">vmctl resume</a></h1>
|
|
||||||
<p>Resume a suspended VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl resume <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Resumes a VM that was paused with <code>vmctl suspend</code>. The VM continues from exactly where it left off.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl resume myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./suspend.html">vmctl suspend</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/suspend.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/image.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/suspend.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/image.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl ssh - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-ssh"><a class="header" href="#vmctl-ssh">vmctl ssh</a></h1>
|
|
||||||
<p>SSH into a VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl ssh [OPTIONS] [NAME]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (optional; inferred from VMFile.kdl if only one VM is defined)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--user</code></td><td>string</td><td>SSH username (overrides VMFile)</td></tr>
|
|
||||||
<tr><td><code>--key</code></td><td>path</td><td>Path to SSH private key</td></tr>
|
|
||||||
<tr><td><code>--file</code></td><td>path</td><td>Path to VMFile.kdl (for reading ssh user)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="key-resolution"><a class="header" href="#key-resolution">Key Resolution</a></h2>
|
|
||||||
<p>vmctl searches for a private key in this order:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Auto-generated key in VM's work directory (<code>id_ed25519_generated</code>)</li>
|
|
||||||
<li>Key specified with <code>--key</code></li>
|
|
||||||
<li><code>~/.ssh/id_ed25519</code></li>
|
|
||||||
<li><code>~/.ssh/id_ecdsa</code></li>
|
|
||||||
<li><code>~/.ssh/id_rsa</code></li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="user-resolution"><a class="header" href="#user-resolution">User Resolution</a></h2>
|
|
||||||
<ol>
|
|
||||||
<li><code>--user</code> CLI flag</li>
|
|
||||||
<li><code>user</code> field in VMFile's <code>ssh</code> block</li>
|
|
||||||
<li>Default: <code>"vm"</code></li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>vmctl first verifies SSH connectivity using libssh2 (with a 30-second retry timeout), then hands off to the system <code>ssh</code> binary for full interactive terminal support. SSH options <code>StrictHostKeyChecking=no</code> and <code>UserKnownHostsFile=/dev/null</code> are set automatically.</p>
|
|
||||||
<p>For user-mode networking, vmctl connects to <code>127.0.0.1</code> on the forwarded host port. For TAP networking, it discovers the guest IP via ARP.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># SSH into the only VM in VMFile.kdl
|
|
||||||
vmctl ssh
|
|
||||||
|
|
||||||
# SSH into a specific VM
|
|
||||||
vmctl ssh myvm
|
|
||||||
|
|
||||||
# Override user and key
|
|
||||||
vmctl ssh myvm --user root --key ~/.ssh/special_key
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./console.html">vmctl console</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/console.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/suspend.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/console.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/suspend.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl start - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-start"><a class="header" href="#vmctl-start">vmctl start</a></h1>
|
|
||||||
<p>Start an existing VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl start <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Starts a VM that is in the <code>Prepared</code> or <code>Stopped</code> state. The VM must have been previously created with <code>vmctl create</code> or <code>vmctl up</code>.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl start myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./stop.html">vmctl stop</a>, <a href="./create.html">vmctl create</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/create.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/stop.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/create.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/stop.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl status - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-status"><a class="header" href="#vmctl-status">vmctl status</a></h1>
|
|
||||||
<p>Show detailed status of a VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl status <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="output"><a class="header" href="#output">Output</a></h2>
|
|
||||||
<p>Displays all known information about the VM:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Name, ID, Backend, State</li>
|
|
||||||
<li>vCPUs, Memory, Disk</li>
|
|
||||||
<li>Network configuration (mode, bridge name)</li>
|
|
||||||
<li>Work directory path</li>
|
|
||||||
<li>Overlay path, Seed ISO path</li>
|
|
||||||
<li>PID, VNC address</li>
|
|
||||||
<li>SSH port, MAC address</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl status myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./list.html">vmctl list</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/list.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/console.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/list.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/console.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl stop - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-stop"><a class="header" href="#vmctl-stop">vmctl stop</a></h1>
|
|
||||||
<p>Stop a running VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl stop [OPTIONS] <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--timeout</code></td><td>integer</td><td><code>30</code></td><td>Graceful shutdown timeout in seconds</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Sends an ACPI power-down signal via QMP. If the guest doesn't shut down within the timeout, vmctl sends SIGTERM to the QEMU process, then SIGKILL as a last resort.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Stop with default 30-second timeout
|
|
||||||
vmctl stop myvm
|
|
||||||
|
|
||||||
# Give it more time to shut down gracefully
|
|
||||||
vmctl stop myvm --timeout 120
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./start.html">vmctl start</a>, <a href="./destroy.html">vmctl destroy</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/start.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/destroy.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/start.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/destroy.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl suspend - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-suspend"><a class="header" href="#vmctl-suspend">vmctl suspend</a></h1>
|
|
||||||
<p>Suspend (pause) a running VM.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl suspend <NAME>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="arguments"><a class="header" href="#arguments">Arguments</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Argument</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>NAME</code></td><td>VM name (positional)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>Pauses the VM's vCPUs via QMP. The VM remains in memory but stops executing. Use <code>vmctl resume</code> to continue.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl suspend myvm
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./resume.html">vmctl resume</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/ssh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/resume.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/ssh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/resume.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl up - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl-up"><a class="header" href="#vmctl-up">vmctl up</a></h1>
|
|
||||||
<p>Bring up VMs defined in VMFile.kdl.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl up [OPTIONS]
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="options"><a class="header" href="#options">Options</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>--file</code></td><td>path</td><td></td><td>Path to VMFile.kdl (auto-discovered if omitted)</td></tr>
|
|
||||||
<tr><td><code>--name</code></td><td>string</td><td></td><td>Only bring up a specific VM</td></tr>
|
|
||||||
<tr><td><code>--no-provision</code></td><td>flag</td><td><code>false</code></td><td>Skip provisioning steps</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="details"><a class="header" href="#details">Details</a></h2>
|
|
||||||
<p>For each VM in the VMFile:</p>
|
|
||||||
<ol>
|
|
||||||
<li>If the VM is <strong>already running</strong>, it is skipped.</li>
|
|
||||||
<li>If the VM exists but is <strong>stopped</strong>, it is restarted and re-provisioned.</li>
|
|
||||||
<li>If the VM <strong>doesn't exist</strong>, it is created, started, and provisioned.</li>
|
|
||||||
</ol>
|
|
||||||
<p>Images are downloaded and cached as needed. SSH keys are auto-generated when cloud-init is configured without an explicit key.</p>
|
|
||||||
<h2 id="examples"><a class="header" href="#examples">Examples</a></h2>
|
|
||||||
<pre><code class="language-bash"># Bring up all VMs in ./VMFile.kdl
|
|
||||||
vmctl up
|
|
||||||
|
|
||||||
# Bring up a specific VM
|
|
||||||
vmctl up --name webserver
|
|
||||||
|
|
||||||
# Bring up without provisioning
|
|
||||||
vmctl up --no-provision
|
|
||||||
|
|
||||||
# Use a specific VMFile
|
|
||||||
vmctl up --file path/to/VMFile.kdl
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
|
|
||||||
<p><a href="./down.html">vmctl down</a>, <a href="./reload.html">vmctl reload</a></p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../cli/image.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/down.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../cli/image.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/down.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,263 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>vmctl - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmctl"><a class="header" href="#vmctl">vmctl</a></h1>
|
|
||||||
<p>The main entry point for the vmctl CLI.</p>
|
|
||||||
<h2 id="synopsis"><a class="header" href="#synopsis">Synopsis</a></h2>
|
|
||||||
<pre><code>vmctl <COMMAND>
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="commands"><a class="header" href="#commands">Commands</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Command</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>create</code></td><td>Create a new VM</td></tr>
|
|
||||||
<tr><td><code>start</code></td><td>Start an existing VM</td></tr>
|
|
||||||
<tr><td><code>stop</code></td><td>Stop a running VM</td></tr>
|
|
||||||
<tr><td><code>destroy</code></td><td>Destroy a VM and clean up resources</td></tr>
|
|
||||||
<tr><td><code>list</code></td><td>List all VMs</td></tr>
|
|
||||||
<tr><td><code>status</code></td><td>Show detailed VM status</td></tr>
|
|
||||||
<tr><td><code>console</code></td><td>Attach to serial console</td></tr>
|
|
||||||
<tr><td><code>ssh</code></td><td>SSH into a VM</td></tr>
|
|
||||||
<tr><td><code>suspend</code></td><td>Suspend (pause) a running VM</td></tr>
|
|
||||||
<tr><td><code>resume</code></td><td>Resume a suspended VM</td></tr>
|
|
||||||
<tr><td><code>image</code></td><td>Manage VM images</td></tr>
|
|
||||||
<tr><td><code>up</code></td><td>Bring up VMs from VMFile.kdl</td></tr>
|
|
||||||
<tr><td><code>down</code></td><td>Bring down VMs from VMFile.kdl</td></tr>
|
|
||||||
<tr><td><code>reload</code></td><td>Destroy and recreate VMs from VMFile.kdl</td></tr>
|
|
||||||
<tr><td><code>provision</code></td><td>Re-run provisioners from VMFile.kdl</td></tr>
|
|
||||||
<tr><td><code>log</code></td><td>Show VM logs</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="environment-variables"><a class="header" href="#environment-variables">Environment Variables</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Variable</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>RUST_LOG</code></td><td>Control log verbosity (e.g., <code>RUST_LOG=debug vmctl up</code>)</td></tr>
|
|
||||||
<tr><td><code>XDG_DATA_HOME</code></td><td>Override data directory (default: <code>~/.local/share</code>)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/full-example.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/create.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/full-example.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/create.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
7
docs/book/clipboard.min.js
vendored
7
docs/book/clipboard.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,293 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Cloud-Init and SSH Keys - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="cloud-init-and-ssh-keys"><a class="header" href="#cloud-init-and-ssh-keys">Cloud-Init and SSH Keys</a></h1>
|
|
||||||
<p>vmctl uses <a href="https://cloud-init.io/">cloud-init</a> to configure guests on first boot. It generates a NoCloud seed ISO containing user-data and meta-data, which the guest's cloud-init agent picks up automatically.</p>
|
|
||||||
<h2 id="ssh-key-modes"><a class="header" href="#ssh-key-modes">SSH Key Modes</a></h2>
|
|
||||||
<p>There are three ways to get SSH access to a VM:</p>
|
|
||||||
<h3 id="1-auto-generated-keypair-recommended"><a class="header" href="#1-auto-generated-keypair-recommended">1. Auto-Generated Keypair (Recommended)</a></h3>
|
|
||||||
<p>When you define a <code>cloud-init</code> block without an explicit <code>ssh-key</code>, vmctl generates a per-VM Ed25519 keypair:</p>
|
|
||||||
<pre><code class="language-kdl">cloud-init {
|
|
||||||
hostname "myvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>The keys are stored in the VM's work directory:</p>
|
|
||||||
<ul>
|
|
||||||
<li><code>~/.local/share/vmctl/vms/<name>/id_ed25519_generated</code> (private)</li>
|
|
||||||
<li><code>~/.local/share/vmctl/vms/<name>/id_ed25519_generated.pub</code> (public)</li>
|
|
||||||
</ul>
|
|
||||||
<p>This is the simplest option. No key management required.</p>
|
|
||||||
<h3 id="2-explicit-ssh-key"><a class="header" href="#2-explicit-ssh-key">2. Explicit SSH Key</a></h3>
|
|
||||||
<p>Point to your own public key file:</p>
|
|
||||||
<pre><code class="language-kdl">cloud-init {
|
|
||||||
ssh-key "~/.ssh/id_ed25519.pub"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
private-key "~/.ssh/id_ed25519"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="3-raw-user-data"><a class="header" href="#3-raw-user-data">3. Raw User-Data</a></h3>
|
|
||||||
<p>Provide a complete cloud-config YAML file for full control:</p>
|
|
||||||
<pre><code class="language-kdl">cloud-init {
|
|
||||||
user-data "./my-cloud-config.yaml"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>In this mode, you're responsible for setting up SSH access yourself in the user-data.</p>
|
|
||||||
<h2 id="ssh-key-resolution"><a class="header" href="#ssh-key-resolution">SSH Key Resolution</a></h2>
|
|
||||||
<p>When vmctl needs to SSH into a VM (for <code>vmctl ssh</code> or provisioning), it searches for a private key in this order:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Generated key in the VM's work directory (<code>id_ed25519_generated</code>)</li>
|
|
||||||
<li>Key specified with <code>--key</code> flag or <code>private-key</code> in VMFile ssh block</li>
|
|
||||||
<li>Standard keys in <code>~/.ssh/</code>: <code>id_ed25519</code>, <code>id_ecdsa</code>, <code>id_rsa</code></li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="ssh-user-resolution"><a class="header" href="#ssh-user-resolution">SSH User Resolution</a></h2>
|
|
||||||
<ol>
|
|
||||||
<li><code>--user</code> CLI flag</li>
|
|
||||||
<li><code>user</code> in VMFile <code>ssh</code> block</li>
|
|
||||||
<li>Default: <code>"vm"</code></li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="cloud-init-user-setup"><a class="header" href="#cloud-init-user-setup">Cloud-Init User Setup</a></h2>
|
|
||||||
<p>When vmctl generates the cloud-config, it creates a user with:</p>
|
|
||||||
<ul>
|
|
||||||
<li>The specified username</li>
|
|
||||||
<li>Passwordless <code>sudo</code> access</li>
|
|
||||||
<li>The SSH public key in <code>authorized_keys</code></li>
|
|
||||||
<li>Bash as the default shell</li>
|
|
||||||
<li>Root login disabled</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/image-management.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/imperative-vm.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/image-management.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/imperative-vm.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>How vmctl Works - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="how-vmctl-works"><a class="header" href="#how-vmctl-works">How vmctl Works</a></h1>
|
|
||||||
<h2 id="state-directory"><a class="header" href="#state-directory">State Directory</a></h2>
|
|
||||||
<p>vmctl stores all VM state under <code>$XDG_DATA_HOME/vmctl/</code> (typically <code>~/.local/share/vmctl/</code>):</p>
|
|
||||||
<pre><code>~/.local/share/vmctl/
|
|
||||||
vms.json # VM registry (name -> handle mapping)
|
|
||||||
images/ # Downloaded image cache
|
|
||||||
vms/
|
|
||||||
<vm-name>/ # Per-VM working directory
|
|
||||||
overlay.qcow2 # Copy-on-write disk overlay
|
|
||||||
seed.iso # Cloud-init NoCloud ISO
|
|
||||||
qmp.sock # QEMU Machine Protocol socket
|
|
||||||
console.sock # Serial console socket
|
|
||||||
console.log # Boot/cloud-init log
|
|
||||||
provision.log # Provisioning output log
|
|
||||||
id_ed25519_generated # Auto-generated SSH private key
|
|
||||||
id_ed25519_generated.pub # Auto-generated SSH public key
|
|
||||||
pidfile # QEMU process PID
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="qcow2-overlays"><a class="header" href="#qcow2-overlays">QCOW2 Overlays</a></h2>
|
|
||||||
<p>vmctl never modifies the base image directly. Instead, it creates a QCOW2 copy-on-write overlay on top of the original. This means:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Multiple VMs can share the same base image.</li>
|
|
||||||
<li>The base image stays clean in the cache.</li>
|
|
||||||
<li>Destroying a VM just deletes the overlay.</li>
|
|
||||||
</ul>
|
|
||||||
<p>If you specify <code>disk</code> in your VMFile, the overlay is resized to that size and the guest filesystem can be grown.</p>
|
|
||||||
<h2 id="routerhypervisor"><a class="header" href="#routerhypervisor">RouterHypervisor</a></h2>
|
|
||||||
<p>All hypervisor operations go through a <code>RouterHypervisor</code> that dispatches to the appropriate backend based on the platform:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Linux</strong> -> <code>QemuBackend</code></li>
|
|
||||||
<li><strong>illumos</strong> -> <code>PropolisBackend</code></li>
|
|
||||||
<li><strong>Testing</strong> -> <code>NoopBackend</code></li>
|
|
||||||
</ul>
|
|
||||||
<p>Each backend implements the same <code>Hypervisor</code> trait, so the CLI code is platform-agnostic.</p>
|
|
||||||
<h2 id="the-up-flow"><a class="header" href="#the-up-flow">The Up Flow</a></h2>
|
|
||||||
<p>When you run <code>vmctl up</code>, the following happens for each VM defined in <code>VMFile.kdl</code>:</p>
|
|
||||||
<ol>
|
|
||||||
<li><strong>Parse</strong> - Read and validate the VMFile.</li>
|
|
||||||
<li><strong>Resolve</strong> - Download images (if URL), generate SSH keys (if cloud-init enabled), resolve paths.</li>
|
|
||||||
<li><strong>Prepare</strong> - Create work directory, QCOW2 overlay, cloud-init seed ISO, allocate MAC address and SSH port.</li>
|
|
||||||
<li><strong>Start</strong> - Launch QEMU with the correct arguments, wait for QMP socket.</li>
|
|
||||||
<li><strong>Provision</strong> - Wait for SSH to become available (up to 120 seconds), then run each provisioner in order.</li>
|
|
||||||
</ol>
|
|
||||||
<p>If a VM is already running, <code>vmctl up</code> skips it. If it's stopped, it restarts and re-provisions.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../getting-started/quick-start.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/imperative-vs-declarative.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../getting-started/quick-start.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/imperative-vs-declarative.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Image Management - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="image-management"><a class="header" href="#image-management">Image Management</a></h1>
|
|
||||||
<p>vmctl can work with local disk images or download them from URLs. Downloaded images are cached for reuse.</p>
|
|
||||||
<h2 id="image-cache"><a class="header" href="#image-cache">Image Cache</a></h2>
|
|
||||||
<p>Downloaded images are stored in <code>~/.local/share/vmctl/images/</code>. If an image already exists in the cache, it won't be re-downloaded.</p>
|
|
||||||
<h2 id="supported-formats"><a class="header" href="#supported-formats">Supported Formats</a></h2>
|
|
||||||
<p>vmctl uses <code>qemu-img</code> to detect and convert image formats. Common formats:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>qcow2</strong> - QEMU's native format, supports snapshots and compression.</li>
|
|
||||||
<li><strong>raw</strong> - Plain disk image.</li>
|
|
||||||
</ul>
|
|
||||||
<p>The format is auto-detected from the file header.</p>
|
|
||||||
<h2 id="zstd-decompression"><a class="header" href="#zstd-decompression">Zstd Decompression</a></h2>
|
|
||||||
<p>If a URL ends in <code>.zst</code> or <code>.zstd</code>, vmctl automatically decompresses the image after downloading. This is common for distribution cloud images.</p>
|
|
||||||
<h2 id="overlay-system"><a class="header" href="#overlay-system">Overlay System</a></h2>
|
|
||||||
<p>vmctl never boots from the base image directly. Instead:</p>
|
|
||||||
<ol>
|
|
||||||
<li>The base image is stored in the cache (or at a local path you provide).</li>
|
|
||||||
<li>A QCOW2 overlay is created on top, pointing to the base as a backing file.</li>
|
|
||||||
<li>All writes go to the overlay. The base stays untouched.</li>
|
|
||||||
<li>Destroying a VM just removes the overlay.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This means multiple VMs can share the same base image efficiently.</p>
|
|
||||||
<h2 id="disk-resizing"><a class="header" href="#disk-resizing">Disk Resizing</a></h2>
|
|
||||||
<p>If you specify <code>disk</code> (in GB) in your VMFile or <code>--disk</code> on the CLI, the overlay is created with that size. The guest OS can then grow its filesystem to fill the available space (most cloud images do this automatically via cloud-init's <code>growpart</code> module).</p>
|
|
||||||
<h2 id="managing-images-with-the-cli"><a class="header" href="#managing-images-with-the-cli">Managing Images with the CLI</a></h2>
|
|
||||||
<pre><code class="language-bash"># Download an image to the cache
|
|
||||||
vmctl image pull https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
|
|
||||||
|
|
||||||
# List cached images
|
|
||||||
vmctl image list
|
|
||||||
|
|
||||||
# Inspect a local image
|
|
||||||
vmctl image inspect ./my-image.qcow2
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/networking.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/cloud-init-ssh.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/networking.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/cloud-init-ssh.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,287 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Imperative vs Declarative - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="imperative-vs-declarative"><a class="header" href="#imperative-vs-declarative">Imperative vs Declarative</a></h1>
|
|
||||||
<p>vmctl supports two workflows for managing VMs.</p>
|
|
||||||
<h2 id="imperative"><a class="header" href="#imperative">Imperative</a></h2>
|
|
||||||
<p>Use individual commands to create, configure, and manage VMs step by step:</p>
|
|
||||||
<pre><code class="language-bash">vmctl create --name myvm --image-url https://example.com/image.img --vcpus 2 --memory 2048 --start
|
|
||||||
vmctl ssh myvm
|
|
||||||
vmctl stop myvm
|
|
||||||
vmctl destroy myvm
|
|
||||||
</code></pre>
|
|
||||||
<p>This is useful for:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Quick one-off VMs</li>
|
|
||||||
<li>Experimenting with different images</li>
|
|
||||||
<li>Scripting custom workflows</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="declarative"><a class="header" href="#declarative">Declarative</a></h2>
|
|
||||||
<p>Define your VMs in a <code>VMFile.kdl</code> and let vmctl converge to the desired state:</p>
|
|
||||||
<pre><code class="language-kdl">vm "myvm" {
|
|
||||||
image-url "https://example.com/image.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "myvm"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "echo hello"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<pre><code class="language-bash">vmctl up # create + start + provision
|
|
||||||
vmctl down # stop
|
|
||||||
vmctl reload # destroy + recreate + provision
|
|
||||||
vmctl provision # re-run provisioners only
|
|
||||||
</code></pre>
|
|
||||||
<p>This is useful for:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Reproducible development environments</li>
|
|
||||||
<li>Multi-VM setups</li>
|
|
||||||
<li>Checked-in VM definitions alongside your project</li>
|
|
||||||
<li>Complex provisioning workflows</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="when-to-use-which"><a class="header" href="#when-to-use-which">When to Use Which</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Scenario</th><th>Approach</th></tr></thead><tbody>
|
|
||||||
<tr><td>"I need a quick VM to test something"</td><td>Imperative</td></tr>
|
|
||||||
<tr><td>"My project needs a build VM with specific packages"</td><td>Declarative</td></tr>
|
|
||||||
<tr><td>"I want to script VM lifecycle in CI"</td><td>Either, depending on complexity</td></tr>
|
|
||||||
<tr><td>"Multiple VMs that work together"</td><td>Declarative</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/how-it-works.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/vm-lifecycle.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/how-it-works.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/vm-lifecycle.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,281 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Networking Modes - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="networking-modes"><a class="header" href="#networking-modes">Networking Modes</a></h1>
|
|
||||||
<p>vmctl supports several networking modes depending on your needs and permissions.</p>
|
|
||||||
<h2 id="user-mode-slirp---default"><a class="header" href="#user-mode-slirp---default">User Mode (SLIRP) - Default</a></h2>
|
|
||||||
<pre><code class="language-kdl">network "user"
|
|
||||||
</code></pre>
|
|
||||||
<p>QEMU's built-in user-mode networking. No root or special permissions required.</p>
|
|
||||||
<p><strong>How it works:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li>QEMU emulates a full TCP/IP stack in userspace.</li>
|
|
||||||
<li>The guest gets a private IP (typically <code>10.0.2.x</code>).</li>
|
|
||||||
<li>Outbound connections from the guest are NAT'd through the host.</li>
|
|
||||||
<li>SSH access is provided via host port forwarding (ports 10022-10122, deterministically assigned per VM name).</li>
|
|
||||||
</ul>
|
|
||||||
<p><strong>Pros:</strong> Zero setup, no root needed.
|
|
||||||
<strong>Cons:</strong> No inbound connections (except forwarded ports), lower performance than TAP.</p>
|
|
||||||
<h2 id="tap-mode"><a class="header" href="#tap-mode">TAP Mode</a></h2>
|
|
||||||
<pre><code class="language-kdl">network "tap" {
|
|
||||||
bridge "br0"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Creates a TAP device and attaches it to a host bridge. The guest appears as a real machine on the bridge's network.</p>
|
|
||||||
<p><strong>How it works:</strong></p>
|
|
||||||
<ul>
|
|
||||||
<li>vmctl creates a TAP interface and bridges it.</li>
|
|
||||||
<li>The guest gets an IP via DHCP from whatever serves the bridge network.</li>
|
|
||||||
<li>Full Layer 2 connectivity.</li>
|
|
||||||
</ul>
|
|
||||||
<p><strong>Pros:</strong> Real network presence, full inbound/outbound, better performance.
|
|
||||||
<strong>Cons:</strong> Requires bridge setup, may need root or appropriate capabilities.</p>
|
|
||||||
<p>If no bridge name is specified, it defaults to <code>br0</code>.</p>
|
|
||||||
<h2 id="vnic-mode-illumos-only"><a class="header" href="#vnic-mode-illumos-only">VNIC Mode (illumos only)</a></h2>
|
|
||||||
<pre><code class="language-kdl">network "vnic" {
|
|
||||||
name "vnic0"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Uses an illumos VNIC for exclusive-IP zone networking. Only available on the Propolis backend.</p>
|
|
||||||
<h2 id="none"><a class="header" href="#none">None</a></h2>
|
|
||||||
<pre><code class="language-kdl">network "none"
|
|
||||||
</code></pre>
|
|
||||||
<p>No networking at all. Useful for isolated compute tasks or testing.</p>
|
|
||||||
<h2 id="ip-discovery"><a class="header" href="#ip-discovery">IP Discovery</a></h2>
|
|
||||||
<p>vmctl discovers the guest IP differently depending on the network mode:</p>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Mode</th><th>IP Discovery Method</th></tr></thead><tbody>
|
|
||||||
<tr><td>User</td><td>Returns <code>127.0.0.1</code> (SSH via forwarded port)</td></tr>
|
|
||||||
<tr><td>TAP</td><td>Parses ARP table (<code>ip neigh show</code>), falls back to dnsmasq lease files by MAC address</td></tr>
|
|
||||||
<tr><td>VNIC</td><td>Zone-based discovery</td></tr>
|
|
||||||
<tr><td>None</td><td>Not available</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/vm-lifecycle.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/image-management.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/vm-lifecycle.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/image-management.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>VM Lifecycle - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vm-lifecycle"><a class="header" href="#vm-lifecycle">VM Lifecycle</a></h1>
|
|
||||||
<p>Every VM in vmctl moves through a set of well-defined states.</p>
|
|
||||||
<h2 id="states"><a class="header" href="#states">States</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>State</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>Preparing</code></td><td>Backend is allocating resources (overlay, ISO, sockets)</td></tr>
|
|
||||||
<tr><td><code>Prepared</code></td><td>Resources allocated, ready to boot</td></tr>
|
|
||||||
<tr><td><code>Running</code></td><td>VM is booted and executing</td></tr>
|
|
||||||
<tr><td><code>Stopped</code></td><td>VM has been shut down (gracefully or forcibly)</td></tr>
|
|
||||||
<tr><td><code>Failed</code></td><td>An error occurred during a lifecycle operation</td></tr>
|
|
||||||
<tr><td><code>Destroyed</code></td><td>VM and all its resources have been cleaned up</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="transitions"><a class="header" href="#transitions">Transitions</a></h2>
|
|
||||||
<pre><code class="language-text"> prepare() start()
|
|
||||||
[new] ──────────> Prepared ──────────> Running
|
|
||||||
│ │
|
|
||||||
suspend() │ │ stop(timeout)
|
|
||||||
┌────────────┘ └──────────────┐
|
|
||||||
v v
|
|
||||||
Suspended ─── resume() ──> Stopped
|
|
||||||
│
|
|
||||||
start() │
|
|
||||||
Running <──────────┘
|
|
||||||
|
|
||||||
Any state ── destroy() ──> Destroyed
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="commands-and-transitions"><a class="header" href="#commands-and-transitions">Commands and Transitions</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Command</th><th>From State</th><th>To State</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>vmctl create</code></td><td>(none)</td><td>Prepared</td></tr>
|
|
||||||
<tr><td><code>vmctl start</code></td><td>Prepared, Stopped</td><td>Running</td></tr>
|
|
||||||
<tr><td><code>vmctl stop</code></td><td>Running</td><td>Stopped</td></tr>
|
|
||||||
<tr><td><code>vmctl suspend</code></td><td>Running</td><td>Suspended (paused vCPUs)</td></tr>
|
|
||||||
<tr><td><code>vmctl resume</code></td><td>Suspended</td><td>Running</td></tr>
|
|
||||||
<tr><td><code>vmctl destroy</code></td><td>Any</td><td>Destroyed</td></tr>
|
|
||||||
<tr><td><code>vmctl up</code></td><td>(none), Stopped</td><td>Running (auto-creates if needed)</td></tr>
|
|
||||||
<tr><td><code>vmctl down</code></td><td>Running</td><td>Stopped</td></tr>
|
|
||||||
<tr><td><code>vmctl reload</code></td><td>Any</td><td>Running (destroys + recreates)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="graceful-shutdown"><a class="header" href="#graceful-shutdown">Graceful Shutdown</a></h2>
|
|
||||||
<p><code>vmctl stop</code> sends an ACPI power-down signal via QMP. If the guest doesn't shut down within the timeout (default 30 seconds), vmctl sends SIGTERM, and finally SIGKILL as a last resort.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/imperative-vs-declarative.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/networking.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/imperative-vs-declarative.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/networking.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,725 +0,0 @@
|
||||||
/* CSS for UI elements (a.k.a. chrome) */
|
|
||||||
|
|
||||||
html {
|
|
||||||
scrollbar-color: var(--scrollbar) var(--bg);
|
|
||||||
}
|
|
||||||
#searchresults a,
|
|
||||||
.content a:link,
|
|
||||||
a:visited,
|
|
||||||
a > .hljs {
|
|
||||||
color: var(--links);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
body-container is necessary because mobile browsers don't seem to like
|
|
||||||
overflow-x on the body tag when there is a <meta name="viewport"> tag.
|
|
||||||
*/
|
|
||||||
#body-container {
|
|
||||||
/*
|
|
||||||
This is used when the sidebar pushes the body content off the side of
|
|
||||||
the screen on small screens. Without it, dragging on mobile Safari
|
|
||||||
will want to reposition the viewport in a weird way.
|
|
||||||
*/
|
|
||||||
overflow-x: clip;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Menu Bar */
|
|
||||||
|
|
||||||
#menu-bar,
|
|
||||||
#menu-bar-hover-placeholder {
|
|
||||||
z-index: 101;
|
|
||||||
margin: auto calc(0px - var(--page-padding));
|
|
||||||
}
|
|
||||||
#menu-bar {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
background-color: var(--bg);
|
|
||||||
border-block-end-color: var(--bg);
|
|
||||||
border-block-end-width: 1px;
|
|
||||||
border-block-end-style: solid;
|
|
||||||
}
|
|
||||||
#menu-bar.sticky,
|
|
||||||
#menu-bar-hover-placeholder:hover + #menu-bar,
|
|
||||||
#menu-bar:hover,
|
|
||||||
html.sidebar-visible #menu-bar {
|
|
||||||
position: -webkit-sticky;
|
|
||||||
position: sticky;
|
|
||||||
top: 0 !important;
|
|
||||||
}
|
|
||||||
#menu-bar-hover-placeholder {
|
|
||||||
position: sticky;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
top: 0;
|
|
||||||
height: var(--menu-bar-height);
|
|
||||||
}
|
|
||||||
#menu-bar.bordered {
|
|
||||||
border-block-end-color: var(--table-border-color);
|
|
||||||
}
|
|
||||||
#menu-bar i, #menu-bar .icon-button {
|
|
||||||
position: relative;
|
|
||||||
padding: 0 8px;
|
|
||||||
z-index: 10;
|
|
||||||
line-height: var(--menu-bar-height);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.5s;
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 420px) {
|
|
||||||
#menu-bar i, #menu-bar .icon-button {
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
.icon-button i {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-buttons {
|
|
||||||
margin: 0 15px;
|
|
||||||
}
|
|
||||||
.right-buttons a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left-buttons {
|
|
||||||
display: flex;
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
html:not(.js) .left-buttons button {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-title {
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: 200;
|
|
||||||
font-size: 2.4rem;
|
|
||||||
line-height: var(--menu-bar-height);
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
flex: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.menu-title {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-bar,
|
|
||||||
.menu-bar:visited,
|
|
||||||
.nav-chapters,
|
|
||||||
.nav-chapters:visited,
|
|
||||||
.mobile-nav-chapters,
|
|
||||||
.mobile-nav-chapters:visited,
|
|
||||||
.menu-bar .icon-button,
|
|
||||||
.menu-bar a i {
|
|
||||||
color: var(--icons);
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-bar i:hover,
|
|
||||||
.menu-bar .icon-button:hover,
|
|
||||||
.nav-chapters:hover,
|
|
||||||
.mobile-nav-chapters i:hover {
|
|
||||||
color: var(--icons-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nav Icons */
|
|
||||||
|
|
||||||
.nav-chapters {
|
|
||||||
font-size: 2.5em;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: 0;
|
|
||||||
max-width: 150px;
|
|
||||||
min-width: 90px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
transition: color 0.5s, background-color 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-chapters:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: var(--theme-hover);
|
|
||||||
transition: background-color 0.15s, color 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-wrapper {
|
|
||||||
margin-block-start: 50px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-nav-chapters {
|
|
||||||
font-size: 2.5em;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
width: 90px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: var(--sidebar-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only Firefox supports flow-relative values */
|
|
||||||
.previous { float: left; }
|
|
||||||
[dir=rtl] .previous { float: right; }
|
|
||||||
|
|
||||||
/* Only Firefox supports flow-relative values */
|
|
||||||
.next {
|
|
||||||
float: right;
|
|
||||||
right: var(--page-padding);
|
|
||||||
}
|
|
||||||
[dir=rtl] .next {
|
|
||||||
float: left;
|
|
||||||
right: unset;
|
|
||||||
left: var(--page-padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use the correct buttons for RTL layouts*/
|
|
||||||
[dir=rtl] .previous i.fa-angle-left:before {content:"\f105";}
|
|
||||||
[dir=rtl] .next i.fa-angle-right:before { content:"\f104"; }
|
|
||||||
|
|
||||||
@media only screen and (max-width: 1080px) {
|
|
||||||
.nav-wide-wrapper { display: none; }
|
|
||||||
.nav-wrapper { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sidebar-visible */
|
|
||||||
@media only screen and (max-width: 1380px) {
|
|
||||||
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; }
|
|
||||||
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inline code */
|
|
||||||
|
|
||||||
:not(pre) > .hljs {
|
|
||||||
display: inline;
|
|
||||||
padding: 0.1em 0.3em;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:not(pre):not(a) > .hljs {
|
|
||||||
color: var(--inline-code-color);
|
|
||||||
overflow-x: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover > .hljs {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
pre > .buttons {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 100;
|
|
||||||
right: 0px;
|
|
||||||
top: 2px;
|
|
||||||
margin: 0px;
|
|
||||||
padding: 2px 0px;
|
|
||||||
|
|
||||||
color: var(--sidebar-fg);
|
|
||||||
cursor: pointer;
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: visibility 0.1s linear, opacity 0.1s linear;
|
|
||||||
}
|
|
||||||
pre:hover > .buttons {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
pre > .buttons :hover {
|
|
||||||
color: var(--sidebar-active);
|
|
||||||
border-color: var(--icons-hover);
|
|
||||||
background-color: var(--theme-hover);
|
|
||||||
}
|
|
||||||
pre > .buttons i {
|
|
||||||
margin-inline-start: 8px;
|
|
||||||
}
|
|
||||||
pre > .buttons button {
|
|
||||||
cursor: inherit;
|
|
||||||
margin: 0px 5px;
|
|
||||||
padding: 4px 4px 3px 5px;
|
|
||||||
font-size: 23px;
|
|
||||||
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border-color: var(--icons);
|
|
||||||
background-color: var(--theme-popup-bg);
|
|
||||||
transition: 100ms;
|
|
||||||
transition-property: color,border-color,background-color;
|
|
||||||
color: var(--icons);
|
|
||||||
}
|
|
||||||
|
|
||||||
pre > .buttons button.clip-button {
|
|
||||||
padding: 2px 4px 0px 6px;
|
|
||||||
}
|
|
||||||
pre > .buttons button.clip-button::before {
|
|
||||||
/* clipboard image from octicons (https://github.com/primer/octicons/tree/v2.0.0) MIT license
|
|
||||||
*/
|
|
||||||
content: url('data:image/svg+xml,<svg width="21" height="20" viewBox="0 0 24 25" \
|
|
||||||
xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard">\
|
|
||||||
<path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 \
|
|
||||||
0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 \
|
|
||||||
7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 \
|
|
||||||
2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/>\
|
|
||||||
<path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/>\
|
|
||||||
</svg>');
|
|
||||||
filter: var(--copy-button-filter);
|
|
||||||
}
|
|
||||||
pre > .buttons button.clip-button:hover::before {
|
|
||||||
filter: var(--copy-button-filter-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (pointer: coarse) {
|
|
||||||
pre > .buttons button {
|
|
||||||
/* On mobile, make it easier to tap buttons. */
|
|
||||||
padding: 0.3rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-resize-indicator {
|
|
||||||
/* Hide resize indicator on devices with limited accuracy */
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pre > code {
|
|
||||||
display: block;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: ACE editors overlap their buttons because ACE does absolute
|
|
||||||
positioning within the code block which breaks padding. The only solution I
|
|
||||||
can think of is to move the padding to the outer pre tag (or insert a div
|
|
||||||
wrapper), but that would require fixing a whole bunch of CSS rules.
|
|
||||||
*/
|
|
||||||
.hljs.ace_editor {
|
|
||||||
padding: 0rem 0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre > .result {
|
|
||||||
margin-block-start: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Search */
|
|
||||||
|
|
||||||
#searchresults a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
mark {
|
|
||||||
border-radius: 2px;
|
|
||||||
padding-block-start: 0;
|
|
||||||
padding-block-end: 1px;
|
|
||||||
padding-inline-start: 3px;
|
|
||||||
padding-inline-end: 3px;
|
|
||||||
margin-block-start: 0;
|
|
||||||
margin-block-end: -1px;
|
|
||||||
margin-inline-start: -3px;
|
|
||||||
margin-inline-end: -3px;
|
|
||||||
background-color: var(--search-mark-bg);
|
|
||||||
transition: background-color 300ms linear;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
mark.fade-out {
|
|
||||||
background-color: rgba(0,0,0,0) !important;
|
|
||||||
cursor: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchbar-outer {
|
|
||||||
margin-inline-start: auto;
|
|
||||||
margin-inline-end: auto;
|
|
||||||
max-width: var(--content-max-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchbar-outer.searching #searchbar {
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
#searchbar-outer .spinner-wrapper {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#searchbar-outer.searching .spinner-wrapper {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-wrapper {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner-wrapper {
|
|
||||||
--spinner-margin: 2px;
|
|
||||||
position: absolute;
|
|
||||||
margin-block-start: calc(var(--searchbar-margin-block-start) + var(--spinner-margin));
|
|
||||||
right: var(--spinner-margin);
|
|
||||||
top: 0;
|
|
||||||
bottom: var(--spinner-margin);
|
|
||||||
padding: 6px;
|
|
||||||
background-color: var(--bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchbar {
|
|
||||||
width: 100%;
|
|
||||||
margin-block-start: var(--searchbar-margin-block-start);
|
|
||||||
margin-block-end: 0;
|
|
||||||
margin-inline-start: auto;
|
|
||||||
margin-inline-end: auto;
|
|
||||||
padding: 10px 16px;
|
|
||||||
transition: box-shadow 300ms ease-in-out;
|
|
||||||
border: 1px solid var(--searchbar-border-color);
|
|
||||||
border-radius: 3px;
|
|
||||||
background-color: var(--searchbar-bg);
|
|
||||||
color: var(--searchbar-fg);
|
|
||||||
}
|
|
||||||
#searchbar:focus,
|
|
||||||
#searchbar.active {
|
|
||||||
box-shadow: 0 0 3px var(--searchbar-shadow-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchresults-header {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1em;
|
|
||||||
padding-block-start: 18px;
|
|
||||||
padding-block-end: 0;
|
|
||||||
padding-inline-start: 5px;
|
|
||||||
padding-inline-end: 0;
|
|
||||||
color: var(--searchresults-header-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.searchresults-outer {
|
|
||||||
margin-inline-start: auto;
|
|
||||||
margin-inline-end: auto;
|
|
||||||
max-width: var(--content-max-width);
|
|
||||||
border-block-end: 1px dashed var(--searchresults-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul#searchresults {
|
|
||||||
list-style: none;
|
|
||||||
padding-inline-start: 20px;
|
|
||||||
}
|
|
||||||
ul#searchresults li {
|
|
||||||
margin: 10px 0px;
|
|
||||||
padding: 2px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
ul#searchresults li.focus {
|
|
||||||
background-color: var(--searchresults-li-bg);
|
|
||||||
}
|
|
||||||
ul#searchresults span.teaser {
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
margin-block-start: 5px;
|
|
||||||
margin-block-end: 0;
|
|
||||||
margin-inline-start: 20px;
|
|
||||||
margin-inline-end: 0;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
ul#searchresults span.teaser em {
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar */
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: var(--sidebar-width);
|
|
||||||
font-size: 0.875em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
overscroll-behavior-y: contain;
|
|
||||||
background-color: var(--sidebar-bg);
|
|
||||||
color: var(--sidebar-fg);
|
|
||||||
}
|
|
||||||
.sidebar-iframe-inner {
|
|
||||||
--padding: 10px;
|
|
||||||
|
|
||||||
background-color: var(--sidebar-bg);
|
|
||||||
padding: var(--padding);
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
color: var(--sidebar-fg);
|
|
||||||
min-height: calc(100vh - var(--padding) * 2);
|
|
||||||
}
|
|
||||||
.sidebar-iframe-outer {
|
|
||||||
border: none;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
[dir=rtl] .sidebar { left: unset; right: 0; }
|
|
||||||
.sidebar-resizing {
|
|
||||||
-moz-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
html:not(.sidebar-resizing) .sidebar {
|
|
||||||
transition: transform 0.3s; /* Animation: slide away */
|
|
||||||
}
|
|
||||||
.sidebar code {
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
.sidebar .sidebar-scrollbox {
|
|
||||||
overflow-y: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 10px 10px;
|
|
||||||
}
|
|
||||||
.sidebar .sidebar-resize-handle {
|
|
||||||
position: absolute;
|
|
||||||
cursor: col-resize;
|
|
||||||
width: 0;
|
|
||||||
right: calc(var(--sidebar-resize-indicator-width) * -1);
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-resize-handle .sidebar-resize-indicator {
|
|
||||||
width: 100%;
|
|
||||||
height: 16px;
|
|
||||||
color: var(--icons);
|
|
||||||
margin-inline-start: var(--sidebar-resize-indicator-space);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
.sidebar-resize-handle .sidebar-resize-indicator::before {
|
|
||||||
content: "";
|
|
||||||
width: 2px;
|
|
||||||
height: 12px;
|
|
||||||
border-left: dotted 2px currentColor;
|
|
||||||
}
|
|
||||||
.sidebar-resize-handle .sidebar-resize-indicator::after {
|
|
||||||
content: "";
|
|
||||||
width: 2px;
|
|
||||||
height: 16px;
|
|
||||||
border-left: dotted 2px currentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
[dir=rtl] .sidebar .sidebar-resize-handle {
|
|
||||||
left: calc(var(--sidebar-resize-indicator-width) * -1);
|
|
||||||
right: unset;
|
|
||||||
}
|
|
||||||
.js .sidebar .sidebar-resize-handle {
|
|
||||||
cursor: col-resize;
|
|
||||||
width: calc(var(--sidebar-resize-indicator-width) - var(--sidebar-resize-indicator-space));
|
|
||||||
}
|
|
||||||
/* sidebar-hidden */
|
|
||||||
#sidebar-toggle-anchor:not(:checked) ~ .sidebar {
|
|
||||||
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
|
|
||||||
}
|
|
||||||
[dir=rtl] #sidebar-toggle-anchor:not(:checked) ~ .sidebar {
|
|
||||||
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
|
|
||||||
}
|
|
||||||
.sidebar::-webkit-scrollbar {
|
|
||||||
background: var(--sidebar-bg);
|
|
||||||
}
|
|
||||||
.sidebar::-webkit-scrollbar-thumb {
|
|
||||||
background: var(--scrollbar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sidebar-visible */
|
|
||||||
#sidebar-toggle-anchor:checked ~ .page-wrapper {
|
|
||||||
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
|
|
||||||
}
|
|
||||||
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
|
|
||||||
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
|
|
||||||
}
|
|
||||||
@media only screen and (min-width: 620px) {
|
|
||||||
#sidebar-toggle-anchor:checked ~ .page-wrapper {
|
|
||||||
transform: none;
|
|
||||||
margin-inline-start: calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width));
|
|
||||||
}
|
|
||||||
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter {
|
|
||||||
list-style: none outside none;
|
|
||||||
padding-inline-start: 0;
|
|
||||||
line-height: 2.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter ol {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li {
|
|
||||||
display: flex;
|
|
||||||
color: var(--sidebar-non-existant);
|
|
||||||
}
|
|
||||||
.chapter li a {
|
|
||||||
display: block;
|
|
||||||
padding: 0;
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--sidebar-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li a:hover {
|
|
||||||
color: var(--sidebar-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li a.active {
|
|
||||||
color: var(--sidebar-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li > a.toggle {
|
|
||||||
cursor: pointer;
|
|
||||||
display: block;
|
|
||||||
margin-inline-start: auto;
|
|
||||||
padding: 0 10px;
|
|
||||||
user-select: none;
|
|
||||||
opacity: 0.68;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li > a.toggle div {
|
|
||||||
transition: transform 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* collapse the section */
|
|
||||||
.chapter li:not(.expanded) + li > ol {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li.chapter-item {
|
|
||||||
line-height: 1.5em;
|
|
||||||
margin-block-start: 0.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li.expanded > a.toggle div {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.spacer {
|
|
||||||
width: 100%;
|
|
||||||
height: 3px;
|
|
||||||
margin: 5px 0px;
|
|
||||||
}
|
|
||||||
.chapter .spacer {
|
|
||||||
background-color: var(--sidebar-spacer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (-moz-touch-enabled: 1), (pointer: coarse) {
|
|
||||||
.chapter li a { padding: 5px 0; }
|
|
||||||
.spacer { margin: 10px 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
list-style: none outside none;
|
|
||||||
padding-inline-start: 20px;
|
|
||||||
line-height: 1.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Theme Menu Popup */
|
|
||||||
|
|
||||||
.theme-popup {
|
|
||||||
position: absolute;
|
|
||||||
left: 10px;
|
|
||||||
top: var(--menu-bar-height);
|
|
||||||
z-index: 1000;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.7em;
|
|
||||||
color: var(--fg);
|
|
||||||
background: var(--theme-popup-bg);
|
|
||||||
border: 1px solid var(--theme-popup-border);
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
display: none;
|
|
||||||
/* Don't let the children's background extend past the rounded corners. */
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
[dir=rtl] .theme-popup { left: unset; right: 10px; }
|
|
||||||
.theme-popup .default {
|
|
||||||
color: var(--icons);
|
|
||||||
}
|
|
||||||
.theme-popup .theme {
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 2px 20px;
|
|
||||||
line-height: 25px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-align: start;
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
background: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
.theme-popup .theme:hover {
|
|
||||||
background-color: var(--theme-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-selected::before {
|
|
||||||
display: inline-block;
|
|
||||||
content: "✓";
|
|
||||||
margin-inline-start: -14px;
|
|
||||||
width: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The container for the help popup that covers the whole window. */
|
|
||||||
#mdbook-help-container {
|
|
||||||
/* Position and size for the whole window. */
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
/* This uses flex layout (which is set in book.js), and centers the popup
|
|
||||||
in the window.*/
|
|
||||||
display: none;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
z-index: 1000;
|
|
||||||
/* Dim out the book while the popup is visible. */
|
|
||||||
background: var(--overlay-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The popup help box. */
|
|
||||||
#mdbook-help-popup {
|
|
||||||
box-shadow: 0 4px 24px rgba(0,0,0,0.15);
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 500px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
background-color: var(--bg);
|
|
||||||
color: var(--fg);
|
|
||||||
border-width: 1px;
|
|
||||||
border-color: var(--theme-popup-border);
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdbook-help-title {
|
|
||||||
text-align: center;
|
|
||||||
/* mdbook's margin for h2 is way too large. */
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
/* Base styles and content styles */
|
|
||||||
|
|
||||||
:root {
|
|
||||||
/* Browser default font-size is 16px, this way 1 rem = 10px */
|
|
||||||
font-size: 62.5%;
|
|
||||||
color-scheme: var(--color-scheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: "Open Sans", sans-serif;
|
|
||||||
color: var(--fg);
|
|
||||||
background-color: var(--bg);
|
|
||||||
text-size-adjust: none;
|
|
||||||
-webkit-text-size-adjust: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.6rem;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: var(--mono-font) !important;
|
|
||||||
font-size: var(--code-font-size);
|
|
||||||
direction: ltr !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make long words/inline code not x overflow */
|
|
||||||
main {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make wide tables scroll if they overflow */
|
|
||||||
.table-wrapper {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't change font size in headers. */
|
|
||||||
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
|
|
||||||
font-size: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left { float: left; }
|
|
||||||
.right { float: right; }
|
|
||||||
.boring { opacity: 0.6; }
|
|
||||||
.hide-boring .boring { display: none; }
|
|
||||||
.hidden { display: none !important; }
|
|
||||||
|
|
||||||
h2, h3 { margin-block-start: 2.5em; }
|
|
||||||
h4, h5 { margin-block-start: 2em; }
|
|
||||||
|
|
||||||
.header + .header h3,
|
|
||||||
.header + .header h4,
|
|
||||||
.header + .header h5 {
|
|
||||||
margin-block-start: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1:target::before,
|
|
||||||
h2:target::before,
|
|
||||||
h3:target::before,
|
|
||||||
h4:target::before,
|
|
||||||
h5:target::before,
|
|
||||||
h6:target::before {
|
|
||||||
display: inline-block;
|
|
||||||
content: "»";
|
|
||||||
margin-inline-start: -30px;
|
|
||||||
width: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is broken on Safari as of version 14, but is fixed
|
|
||||||
in Safari Technology Preview 117 which I think will be Safari 14.2.
|
|
||||||
https://bugs.webkit.org/show_bug.cgi?id=218076
|
|
||||||
*/
|
|
||||||
:target {
|
|
||||||
/* Safari does not support logical properties */
|
|
||||||
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
outline: 0;
|
|
||||||
padding: 0 var(--page-padding);
|
|
||||||
margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
|
|
||||||
}
|
|
||||||
.page-wrapper {
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: var(--bg);
|
|
||||||
}
|
|
||||||
html:not(.js) .page-wrapper,
|
|
||||||
.js:not(.sidebar-resizing) .page-wrapper {
|
|
||||||
transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
|
|
||||||
}
|
|
||||||
[dir=rtl]:not(.js) .page-wrapper,
|
|
||||||
[dir=rtl].js:not(.sidebar-resizing) .page-wrapper {
|
|
||||||
transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 0 5px 50px 5px;
|
|
||||||
}
|
|
||||||
.content main {
|
|
||||||
margin-inline-start: auto;
|
|
||||||
margin-inline-end: auto;
|
|
||||||
max-width: var(--content-max-width);
|
|
||||||
}
|
|
||||||
.content p { line-height: 1.45em; }
|
|
||||||
.content ol { line-height: 1.45em; }
|
|
||||||
.content ul { line-height: 1.45em; }
|
|
||||||
.content a { text-decoration: none; }
|
|
||||||
.content a:hover { text-decoration: underline; }
|
|
||||||
.content img, .content video { max-width: 100%; }
|
|
||||||
.content .header:link,
|
|
||||||
.content .header:visited {
|
|
||||||
color: var(--fg);
|
|
||||||
}
|
|
||||||
.content .header:link,
|
|
||||||
.content .header:visited:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin: 0 auto;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
table td {
|
|
||||||
padding: 3px 20px;
|
|
||||||
border: 1px var(--table-border-color) solid;
|
|
||||||
}
|
|
||||||
table thead {
|
|
||||||
background: var(--table-header-bg);
|
|
||||||
}
|
|
||||||
table thead td {
|
|
||||||
font-weight: 700;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
table thead th {
|
|
||||||
padding: 3px 20px;
|
|
||||||
}
|
|
||||||
table thead tr {
|
|
||||||
border: 1px var(--table-header-bg) solid;
|
|
||||||
}
|
|
||||||
/* Alternate background colors for rows */
|
|
||||||
table tbody tr:nth-child(2n) {
|
|
||||||
background: var(--table-alternate-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 20px 0;
|
|
||||||
padding: 0 20px;
|
|
||||||
color: var(--fg);
|
|
||||||
background-color: var(--quote-bg);
|
|
||||||
border-block-start: .1em solid var(--quote-border);
|
|
||||||
border-block-end: .1em solid var(--quote-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning {
|
|
||||||
margin: 20px;
|
|
||||||
padding: 0 20px;
|
|
||||||
border-inline-start: 2px solid var(--warning-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning:before {
|
|
||||||
position: absolute;
|
|
||||||
width: 3rem;
|
|
||||||
height: 3rem;
|
|
||||||
margin-inline-start: calc(-1.5rem - 21px);
|
|
||||||
content: "ⓘ";
|
|
||||||
text-align: center;
|
|
||||||
background-color: var(--bg);
|
|
||||||
color: var(--warning-border);
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote .warning:before {
|
|
||||||
background-color: var(--quote-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
kbd {
|
|
||||||
background-color: var(--table-border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
border: solid 1px var(--theme-popup-border);
|
|
||||||
box-shadow: inset 0 -1px 0 var(--theme-hover);
|
|
||||||
display: inline-block;
|
|
||||||
font-size: var(--code-font-size);
|
|
||||||
font-family: var(--mono-font);
|
|
||||||
line-height: 10px;
|
|
||||||
padding: 4px 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
/* Set the line-height for superscript and footnote references so that there
|
|
||||||
isn't an awkward space appearing above lines that contain the footnote.
|
|
||||||
|
|
||||||
See https://github.com/rust-lang/mdBook/pull/2443#discussion_r1813773583
|
|
||||||
for an explanation.
|
|
||||||
*/
|
|
||||||
line-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footnote-definition {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
/* The default spacing for a list is a little too large. */
|
|
||||||
.footnote-definition ul,
|
|
||||||
.footnote-definition ol {
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
.footnote-definition > li {
|
|
||||||
/* Required to position the ::before target */
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.footnote-definition > li:target {
|
|
||||||
scroll-margin-top: 50vh;
|
|
||||||
}
|
|
||||||
.footnote-reference:target {
|
|
||||||
scroll-margin-top: 50vh;
|
|
||||||
}
|
|
||||||
/* Draws a border around the footnote (including the marker) when it is selected.
|
|
||||||
TODO: If there are multiple linkbacks, highlight which one you just came
|
|
||||||
from so you know which one to click.
|
|
||||||
*/
|
|
||||||
.footnote-definition > li:target::before {
|
|
||||||
border: 2px solid var(--footnote-highlight);
|
|
||||||
border-radius: 6px;
|
|
||||||
position: absolute;
|
|
||||||
top: -8px;
|
|
||||||
right: -8px;
|
|
||||||
bottom: -8px;
|
|
||||||
left: -32px;
|
|
||||||
pointer-events: none;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
/* Pulses the footnote reference so you can quickly see where you left off reading.
|
|
||||||
This could use some improvement.
|
|
||||||
*/
|
|
||||||
@media not (prefers-reduced-motion) {
|
|
||||||
.footnote-reference:target {
|
|
||||||
animation: fn-highlight 0.8s;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fn-highlight {
|
|
||||||
from {
|
|
||||||
background-color: var(--footnote-highlight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltiptext {
|
|
||||||
position: absolute;
|
|
||||||
visibility: hidden;
|
|
||||||
color: #fff;
|
|
||||||
background-color: #333;
|
|
||||||
transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
|
|
||||||
left: -8px; /* Half of the width of the icon */
|
|
||||||
top: -35px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 5px 8px;
|
|
||||||
margin: 5px;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.tooltipped .tooltiptext {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chapter li.part-title {
|
|
||||||
color: var(--sidebar-fg);
|
|
||||||
margin: 5px 0px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-no-output {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
|
|
||||||
#sidebar,
|
|
||||||
#menu-bar,
|
|
||||||
.nav-chapters,
|
|
||||||
.mobile-nav-chapters {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#page-wrapper.page-wrapper {
|
|
||||||
transform: none !important;
|
|
||||||
margin-inline-start: 0px;
|
|
||||||
overflow-y: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
max-width: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page {
|
|
||||||
overflow-y: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
direction: ltr !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre > .buttons {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
a, a:visited, a:active, a:hover {
|
|
||||||
color: #4183c4;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
page-break-inside: avoid;
|
|
||||||
page-break-after: avoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre, code {
|
|
||||||
page-break-inside: avoid;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
@ -1,331 +0,0 @@
|
||||||
|
|
||||||
/* Globals */
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--sidebar-target-width: 300px;
|
|
||||||
--sidebar-width: min(var(--sidebar-target-width), 80vw);
|
|
||||||
--sidebar-resize-indicator-width: 8px;
|
|
||||||
--sidebar-resize-indicator-space: 2px;
|
|
||||||
--page-padding: 15px;
|
|
||||||
--content-max-width: 750px;
|
|
||||||
--menu-bar-height: 50px;
|
|
||||||
--mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
|
|
||||||
--code-font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */
|
|
||||||
--searchbar-margin-block-start: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Themes */
|
|
||||||
|
|
||||||
.ayu {
|
|
||||||
--bg: hsl(210, 25%, 8%);
|
|
||||||
--fg: #c5c5c5;
|
|
||||||
|
|
||||||
--sidebar-bg: #14191f;
|
|
||||||
--sidebar-fg: #c8c9db;
|
|
||||||
--sidebar-non-existant: #5c6773;
|
|
||||||
--sidebar-active: #ffb454;
|
|
||||||
--sidebar-spacer: #2d334f;
|
|
||||||
|
|
||||||
--scrollbar: var(--sidebar-fg);
|
|
||||||
|
|
||||||
--icons: #737480;
|
|
||||||
--icons-hover: #b7b9cc;
|
|
||||||
|
|
||||||
--links: #0096cf;
|
|
||||||
|
|
||||||
--inline-code-color: #ffb454;
|
|
||||||
|
|
||||||
--theme-popup-bg: #14191f;
|
|
||||||
--theme-popup-border: #5c6773;
|
|
||||||
--theme-hover: #191f26;
|
|
||||||
|
|
||||||
--quote-bg: hsl(226, 15%, 17%);
|
|
||||||
--quote-border: hsl(226, 15%, 22%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(210, 25%, 13%);
|
|
||||||
--table-header-bg: hsl(210, 25%, 28%);
|
|
||||||
--table-alternate-bg: hsl(210, 25%, 11%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #848484;
|
|
||||||
--searchbar-bg: #424242;
|
|
||||||
--searchbar-fg: #fff;
|
|
||||||
--searchbar-shadow-color: #d4c89f;
|
|
||||||
--searchresults-header-fg: #666;
|
|
||||||
--searchresults-border-color: #888;
|
|
||||||
--searchresults-li-bg: #252932;
|
|
||||||
--search-mark-bg: #e3b171;
|
|
||||||
|
|
||||||
--color-scheme: dark;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(45%) sepia(6%) saturate(621%) hue-rotate(198deg) brightness(99%) contrast(85%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(68%) sepia(55%) saturate(531%) hue-rotate(341deg) brightness(104%) contrast(101%);
|
|
||||||
|
|
||||||
--footnote-highlight: #2668a6;
|
|
||||||
|
|
||||||
--overlay-bg: rgba(33, 40, 48, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.coal {
|
|
||||||
--bg: hsl(200, 7%, 8%);
|
|
||||||
--fg: #98a3ad;
|
|
||||||
|
|
||||||
--sidebar-bg: #292c2f;
|
|
||||||
--sidebar-fg: #a1adb8;
|
|
||||||
--sidebar-non-existant: #505254;
|
|
||||||
--sidebar-active: #3473ad;
|
|
||||||
--sidebar-spacer: #393939;
|
|
||||||
|
|
||||||
--scrollbar: var(--sidebar-fg);
|
|
||||||
|
|
||||||
--icons: #43484d;
|
|
||||||
--icons-hover: #b3c0cc;
|
|
||||||
|
|
||||||
--links: #2b79a2;
|
|
||||||
|
|
||||||
--inline-code-color: #c5c8c6;
|
|
||||||
|
|
||||||
--theme-popup-bg: #141617;
|
|
||||||
--theme-popup-border: #43484d;
|
|
||||||
--theme-hover: #1f2124;
|
|
||||||
|
|
||||||
--quote-bg: hsl(234, 21%, 18%);
|
|
||||||
--quote-border: hsl(234, 21%, 23%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(200, 7%, 13%);
|
|
||||||
--table-header-bg: hsl(200, 7%, 28%);
|
|
||||||
--table-alternate-bg: hsl(200, 7%, 11%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #aaa;
|
|
||||||
--searchbar-bg: #b7b7b7;
|
|
||||||
--searchbar-fg: #000;
|
|
||||||
--searchbar-shadow-color: #aaa;
|
|
||||||
--searchresults-header-fg: #666;
|
|
||||||
--searchresults-border-color: #98a3ad;
|
|
||||||
--searchresults-li-bg: #2b2b2f;
|
|
||||||
--search-mark-bg: #355c7d;
|
|
||||||
|
|
||||||
--color-scheme: dark;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%);
|
|
||||||
|
|
||||||
--footnote-highlight: #4079ae;
|
|
||||||
|
|
||||||
--overlay-bg: rgba(33, 40, 48, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.light, html:not(.js) {
|
|
||||||
--bg: hsl(0, 0%, 100%);
|
|
||||||
--fg: hsl(0, 0%, 0%);
|
|
||||||
|
|
||||||
--sidebar-bg: #fafafa;
|
|
||||||
--sidebar-fg: hsl(0, 0%, 0%);
|
|
||||||
--sidebar-non-existant: #aaaaaa;
|
|
||||||
--sidebar-active: #1f1fff;
|
|
||||||
--sidebar-spacer: #f4f4f4;
|
|
||||||
|
|
||||||
--scrollbar: #8F8F8F;
|
|
||||||
|
|
||||||
--icons: #747474;
|
|
||||||
--icons-hover: #000000;
|
|
||||||
|
|
||||||
--links: #20609f;
|
|
||||||
|
|
||||||
--inline-code-color: #301900;
|
|
||||||
|
|
||||||
--theme-popup-bg: #fafafa;
|
|
||||||
--theme-popup-border: #cccccc;
|
|
||||||
--theme-hover: #e6e6e6;
|
|
||||||
|
|
||||||
--quote-bg: hsl(197, 37%, 96%);
|
|
||||||
--quote-border: hsl(197, 37%, 91%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(0, 0%, 95%);
|
|
||||||
--table-header-bg: hsl(0, 0%, 80%);
|
|
||||||
--table-alternate-bg: hsl(0, 0%, 97%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #aaa;
|
|
||||||
--searchbar-bg: #fafafa;
|
|
||||||
--searchbar-fg: #000;
|
|
||||||
--searchbar-shadow-color: #aaa;
|
|
||||||
--searchresults-header-fg: #666;
|
|
||||||
--searchresults-border-color: #888;
|
|
||||||
--searchresults-li-bg: #e4f2fe;
|
|
||||||
--search-mark-bg: #a2cff5;
|
|
||||||
|
|
||||||
--color-scheme: light;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(45.49%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(14%) sepia(93%) saturate(4250%) hue-rotate(243deg) brightness(99%) contrast(130%);
|
|
||||||
|
|
||||||
--footnote-highlight: #7e7eff;
|
|
||||||
|
|
||||||
--overlay-bg: rgba(200, 200, 205, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.navy {
|
|
||||||
--bg: hsl(226, 23%, 11%);
|
|
||||||
--fg: #bcbdd0;
|
|
||||||
|
|
||||||
--sidebar-bg: #282d3f;
|
|
||||||
--sidebar-fg: #c8c9db;
|
|
||||||
--sidebar-non-existant: #505274;
|
|
||||||
--sidebar-active: #2b79a2;
|
|
||||||
--sidebar-spacer: #2d334f;
|
|
||||||
|
|
||||||
--scrollbar: var(--sidebar-fg);
|
|
||||||
|
|
||||||
--icons: #737480;
|
|
||||||
--icons-hover: #b7b9cc;
|
|
||||||
|
|
||||||
--links: #2b79a2;
|
|
||||||
|
|
||||||
--inline-code-color: #c5c8c6;
|
|
||||||
|
|
||||||
--theme-popup-bg: #161923;
|
|
||||||
--theme-popup-border: #737480;
|
|
||||||
--theme-hover: #282e40;
|
|
||||||
|
|
||||||
--quote-bg: hsl(226, 15%, 17%);
|
|
||||||
--quote-border: hsl(226, 15%, 22%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(226, 23%, 16%);
|
|
||||||
--table-header-bg: hsl(226, 23%, 31%);
|
|
||||||
--table-alternate-bg: hsl(226, 23%, 14%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #aaa;
|
|
||||||
--searchbar-bg: #aeaec6;
|
|
||||||
--searchbar-fg: #000;
|
|
||||||
--searchbar-shadow-color: #aaa;
|
|
||||||
--searchresults-header-fg: #5f5f71;
|
|
||||||
--searchresults-border-color: #5c5c68;
|
|
||||||
--searchresults-li-bg: #242430;
|
|
||||||
--search-mark-bg: #a2cff5;
|
|
||||||
|
|
||||||
--color-scheme: dark;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(46%) sepia(20%) saturate(1537%) hue-rotate(156deg) brightness(85%) contrast(90%);
|
|
||||||
|
|
||||||
--footnote-highlight: #4079ae;
|
|
||||||
|
|
||||||
--overlay-bg: rgba(33, 40, 48, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rust {
|
|
||||||
--bg: hsl(60, 9%, 87%);
|
|
||||||
--fg: #262625;
|
|
||||||
|
|
||||||
--sidebar-bg: #3b2e2a;
|
|
||||||
--sidebar-fg: #c8c9db;
|
|
||||||
--sidebar-non-existant: #505254;
|
|
||||||
--sidebar-active: #e69f67;
|
|
||||||
--sidebar-spacer: #45373a;
|
|
||||||
|
|
||||||
--scrollbar: var(--sidebar-fg);
|
|
||||||
|
|
||||||
--icons: #737480;
|
|
||||||
--icons-hover: #262625;
|
|
||||||
|
|
||||||
--links: #2b79a2;
|
|
||||||
|
|
||||||
--inline-code-color: #6e6b5e;
|
|
||||||
|
|
||||||
--theme-popup-bg: #e1e1db;
|
|
||||||
--theme-popup-border: #b38f6b;
|
|
||||||
--theme-hover: #99908a;
|
|
||||||
|
|
||||||
--quote-bg: hsl(60, 5%, 75%);
|
|
||||||
--quote-border: hsl(60, 5%, 70%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(60, 9%, 82%);
|
|
||||||
--table-header-bg: #b3a497;
|
|
||||||
--table-alternate-bg: hsl(60, 9%, 84%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #aaa;
|
|
||||||
--searchbar-bg: #fafafa;
|
|
||||||
--searchbar-fg: #000;
|
|
||||||
--searchbar-shadow-color: #aaa;
|
|
||||||
--searchresults-header-fg: #666;
|
|
||||||
--searchresults-border-color: #888;
|
|
||||||
--searchresults-li-bg: #dec2a2;
|
|
||||||
--search-mark-bg: #e69f67;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(77%) sepia(16%) saturate(1798%) hue-rotate(328deg) brightness(98%) contrast(83%);
|
|
||||||
|
|
||||||
--footnote-highlight: #d3a17a;
|
|
||||||
|
|
||||||
--overlay-bg: rgba(150, 150, 150, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
html:not(.js) {
|
|
||||||
--bg: hsl(200, 7%, 8%);
|
|
||||||
--fg: #98a3ad;
|
|
||||||
|
|
||||||
--sidebar-bg: #292c2f;
|
|
||||||
--sidebar-fg: #a1adb8;
|
|
||||||
--sidebar-non-existant: #505254;
|
|
||||||
--sidebar-active: #3473ad;
|
|
||||||
--sidebar-spacer: #393939;
|
|
||||||
|
|
||||||
--scrollbar: var(--sidebar-fg);
|
|
||||||
|
|
||||||
--icons: #43484d;
|
|
||||||
--icons-hover: #b3c0cc;
|
|
||||||
|
|
||||||
--links: #2b79a2;
|
|
||||||
|
|
||||||
--inline-code-color: #c5c8c6;
|
|
||||||
|
|
||||||
--theme-popup-bg: #141617;
|
|
||||||
--theme-popup-border: #43484d;
|
|
||||||
--theme-hover: #1f2124;
|
|
||||||
|
|
||||||
--quote-bg: hsl(234, 21%, 18%);
|
|
||||||
--quote-border: hsl(234, 21%, 23%);
|
|
||||||
|
|
||||||
--warning-border: #ff8e00;
|
|
||||||
|
|
||||||
--table-border-color: hsl(200, 7%, 13%);
|
|
||||||
--table-header-bg: hsl(200, 7%, 28%);
|
|
||||||
--table-alternate-bg: hsl(200, 7%, 11%);
|
|
||||||
|
|
||||||
--searchbar-border-color: #aaa;
|
|
||||||
--searchbar-bg: #b7b7b7;
|
|
||||||
--searchbar-fg: #000;
|
|
||||||
--searchbar-shadow-color: #aaa;
|
|
||||||
--searchresults-header-fg: #666;
|
|
||||||
--searchresults-border-color: #98a3ad;
|
|
||||||
--searchresults-li-bg: #2b2b2f;
|
|
||||||
--search-mark-bg: #355c7d;
|
|
||||||
|
|
||||||
--color-scheme: dark;
|
|
||||||
|
|
||||||
/* Same as `--icons` */
|
|
||||||
--copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%);
|
|
||||||
/* Same as `--sidebar-active` */
|
|
||||||
--copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
docs/book/elasticlunr.min.js
vendored
10
docs/book/elasticlunr.min.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
|
|
@ -1,22 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 199.7 184.2">
|
|
||||||
<style>
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
svg { fill: white; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<path d="M189.5,36.8c0.2,2.8,0,5.1-0.6,6.8L153,162c-0.6,2.1-2,3.7-4.2,5c-2.2,1.2-4.4,1.9-6.7,1.9H31.4c-9.6,0-15.3-2.8-17.3-8.4
|
|
||||||
c-0.8-2.2-0.8-3.9,0.1-5.2c0.9-1.2,2.4-1.8,4.6-1.8H123c7.4,0,12.6-1.4,15.4-4.1s5.7-8.9,8.6-18.4l32.9-108.6
|
|
||||||
c1.8-5.9,1-11.1-2.2-15.6S169.9,0,164,0H72.7c-1,0-3.1,0.4-6.1,1.1l0.1-0.4C64.5,0.2,62.6,0,61,0.1s-3,0.5-4.3,1.4
|
|
||||||
c-1.3,0.9-2.4,1.8-3.2,2.8S52,6.5,51.2,8.1c-0.8,1.6-1.4,3-1.9,4.3s-1.1,2.7-1.8,4.2c-0.7,1.5-1.3,2.7-2,3.7c-0.5,0.6-1.2,1.5-2,2.5
|
|
||||||
s-1.6,2-2.2,2.8s-0.9,1.5-1.1,2.2c-0.2,0.7-0.1,1.8,0.2,3.2c0.3,1.4,0.4,2.4,0.4,3.1c-0.3,3-1.4,6.9-3.3,11.6
|
|
||||||
c-1.9,4.7-3.6,8.1-5.1,10.1c-0.3,0.4-1.2,1.3-2.6,2.7c-1.4,1.4-2.3,2.6-2.6,3.7c-0.3,0.4-0.3,1.5-0.1,3.4c0.3,1.8,0.4,3.1,0.3,3.8
|
|
||||||
c-0.3,2.7-1.3,6.3-3,10.8c-1.7,4.5-3.4,8.2-5,11c-0.2,0.5-0.9,1.4-2,2.8c-1.1,1.4-1.8,2.5-2,3.4c-0.2,0.6-0.1,1.8,0.1,3.4
|
|
||||||
c0.2,1.6,0.2,2.8-0.1,3.6c-0.6,3-1.8,6.7-3.6,11c-1.8,4.3-3.6,7.9-5.4,11c-0.5,0.8-1.1,1.7-2,2.8c-0.8,1.1-1.5,2-2,2.8
|
|
||||||
s-0.8,1.6-1,2.5c-0.1,0.5,0,1.3,0.4,2.3c0.3,1.1,0.4,1.9,0.4,2.6c-0.1,1.1-0.2,2.6-0.5,4.4c-0.2,1.8-0.4,2.9-0.4,3.2
|
|
||||||
c-1.8,4.8-1.7,9.9,0.2,15.2c2.2,6.2,6.2,11.5,11.9,15.8c5.7,4.3,11.7,6.4,17.8,6.4h110.7c5.2,0,10.1-1.7,14.7-5.2s7.7-7.8,9.2-12.9
|
|
||||||
l33-108.6c1.8-5.8,1-10.9-2.2-15.5C194.9,39.7,192.6,38,189.5,36.8z M59.6,122.8L73.8,80c0,0,7,0,10.8,0s28.8-1.7,25.4,17.5
|
|
||||||
c-3.4,19.2-18.8,25.2-36.8,25.4S59.6,122.8,59.6,122.8z M78.6,116.8c4.7-0.1,18.9-2.9,22.1-17.1S89.2,86.3,89.2,86.3l-8.9,0
|
|
||||||
l-10.2,30.5C70.2,116.9,74,116.9,78.6,116.8z M75.3,68.7L89,26.2h9.8l0.8,34l23.6-34h9.9l-13.6,42.5h-7.1l12.5-35.4l-24.5,35.4h-6.8
|
|
||||||
l-0.8-35L82,68.7H75.3z"/>
|
|
||||||
</svg>
|
|
||||||
<!-- Original image Copyright Dave Gandy — CC BY 4.0 License -->
|
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB |
|
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
|
||||||
|
|
||||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
||||||
This license is copied below, and is also available with a FAQ at:
|
|
||||||
http://scripts.sil.org/OFL
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------
|
|
||||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
PREAMBLE
|
|
||||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
||||||
development of collaborative font projects, to support the font creation
|
|
||||||
efforts of academic and linguistic communities, and to provide a free and
|
|
||||||
open framework in which fonts may be shared and improved in partnership
|
|
||||||
with others.
|
|
||||||
|
|
||||||
The OFL allows the licensed fonts to be used, studied, modified and
|
|
||||||
redistributed freely as long as they are not sold by themselves. The
|
|
||||||
fonts, including any derivative works, can be bundled, embedded,
|
|
||||||
redistributed and/or sold with any software provided that any reserved
|
|
||||||
names are not used by derivative works. The fonts and derivatives,
|
|
||||||
however, cannot be released under any other type of license. The
|
|
||||||
requirement for fonts to remain under this license does not apply
|
|
||||||
to any document created using the fonts or their derivatives.
|
|
||||||
|
|
||||||
DEFINITIONS
|
|
||||||
"Font Software" refers to the set of files released by the Copyright
|
|
||||||
Holder(s) under this license and clearly marked as such. This may
|
|
||||||
include source files, build scripts and documentation.
|
|
||||||
|
|
||||||
"Reserved Font Name" refers to any names specified as such after the
|
|
||||||
copyright statement(s).
|
|
||||||
|
|
||||||
"Original Version" refers to the collection of Font Software components as
|
|
||||||
distributed by the Copyright Holder(s).
|
|
||||||
|
|
||||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
||||||
or substituting -- in part or in whole -- any of the components of the
|
|
||||||
Original Version, by changing formats or by porting the Font Software to a
|
|
||||||
new environment.
|
|
||||||
|
|
||||||
"Author" refers to any designer, engineer, programmer, technical
|
|
||||||
writer or other person who contributed to the Font Software.
|
|
||||||
|
|
||||||
PERMISSION & CONDITIONS
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
||||||
redistribute, and sell modified and unmodified copies of the Font
|
|
||||||
Software, subject to the following conditions:
|
|
||||||
|
|
||||||
1) Neither the Font Software nor any of its individual components,
|
|
||||||
in Original or Modified Versions, may be sold by itself.
|
|
||||||
|
|
||||||
2) Original or Modified Versions of the Font Software may be bundled,
|
|
||||||
redistributed and/or sold with any software, provided that each copy
|
|
||||||
contains the above copyright notice and this license. These can be
|
|
||||||
included either as stand-alone text files, human-readable headers or
|
|
||||||
in the appropriate machine-readable metadata fields within text or
|
|
||||||
binary files as long as those fields can be easily viewed by the user.
|
|
||||||
|
|
||||||
3) No Modified Version of the Font Software may use the Reserved Font
|
|
||||||
Name(s) unless explicit written permission is granted by the corresponding
|
|
||||||
Copyright Holder. This restriction only applies to the primary font name as
|
|
||||||
presented to the users.
|
|
||||||
|
|
||||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
||||||
Software shall not be used to promote, endorse or advertise any
|
|
||||||
Modified Version, except to acknowledge the contribution(s) of the
|
|
||||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
5) The Font Software, modified or unmodified, in part or in whole,
|
|
||||||
must be distributed entirely under this license, and must not be
|
|
||||||
distributed under any other license. The requirement for fonts to
|
|
||||||
remain under this license does not apply to any document created
|
|
||||||
using the Font Software.
|
|
||||||
|
|
||||||
TERMINATION
|
|
||||||
This license becomes null and void if any of the above conditions are
|
|
||||||
not met.
|
|
||||||
|
|
||||||
DISCLAIMER
|
|
||||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
||||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
||||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
||||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */
|
|
||||||
/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */
|
|
||||||
|
|
||||||
/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Open Sans Light'), local('OpenSans-Light'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-300.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-300italic.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Open Sans Regular'), local('OpenSans-Regular'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-regular.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Open Sans Italic'), local('OpenSans-Italic'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-italic.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-600.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-600italic.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Open Sans Bold'), local('OpenSans-Bold'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-700.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-700italic.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-800.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Open Sans';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 800;
|
|
||||||
src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'),
|
|
||||||
url('../fonts/open-sans-v17-all-charsets-800italic.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Source Code Pro';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
src: url('../fonts/source-code-pro-v11-all-charsets-500.woff2') format('woff2');
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,262 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Installation - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="installation"><a class="header" href="#installation">Installation</a></h1>
|
|
||||||
<p>vmctl is built from source using Rust's Cargo build system.</p>
|
|
||||||
<h2 id="requirements"><a class="header" href="#requirements">Requirements</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Rust 1.85 or later (edition 2024)</li>
|
|
||||||
<li>A working C compiler (for native dependencies like libssh2)</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="building-from-source"><a class="header" href="#building-from-source">Building from Source</a></h2>
|
|
||||||
<p>Clone the repository and build the release binary:</p>
|
|
||||||
<pre><code class="language-bash">git clone https://github.com/user/vm-manager.git
|
|
||||||
cd vm-manager
|
|
||||||
cargo build --release -p vmctl
|
|
||||||
</code></pre>
|
|
||||||
<p>The binary will be at <code>target/release/vmctl</code>. Copy it somewhere in your <code>$PATH</code>:</p>
|
|
||||||
<pre><code class="language-bash">sudo cp target/release/vmctl /usr/local/bin/
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="feature-flags"><a class="header" href="#feature-flags">Feature Flags</a></h2>
|
|
||||||
<p>The <code>vm-manager</code> library crate has one optional feature:</p>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>pure-iso</code></td><td>Use a pure-Rust ISO 9660 generator (<code>isobemak</code>) instead of shelling out to <code>genisoimage</code>/<code>mkisofs</code>. Useful in minimal or containerized environments.</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<p>To build with it:</p>
|
|
||||||
<pre><code class="language-bash">cargo build --release -p vmctl --features vm-manager/pure-iso
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="verify-installation"><a class="header" href="#verify-installation">Verify Installation</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl --help
|
|
||||||
</code></pre>
|
|
||||||
<p>You should see the list of available subcommands.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../introduction.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../getting-started/prerequisites.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../introduction.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../getting-started/prerequisites.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,278 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Prerequisites - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h1>
|
|
||||||
<p>vmctl requires several system tools depending on the backend and features you use.</p>
|
|
||||||
<h2 id="linux-qemukvm"><a class="header" href="#linux-qemukvm">Linux (QEMU/KVM)</a></h2>
|
|
||||||
<h3 id="required"><a class="header" href="#required">Required</a></h3>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Tool</th><th>Purpose</th><th>Install (Debian/Ubuntu)</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>qemu-system-x86_64</code></td><td>VM hypervisor</td><td><code>sudo apt install qemu-system-x86</code></td></tr>
|
|
||||||
<tr><td><code>qemu-img</code></td><td>Disk image operations</td><td><code>sudo apt install qemu-utils</code></td></tr>
|
|
||||||
<tr><td><code>/dev/kvm</code></td><td>Hardware virtualization</td><td>Kernel module (usually built-in)</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h3 id="cloud-init-iso-generation-one-of"><a class="header" href="#cloud-init-iso-generation-one-of">Cloud-Init ISO Generation (one of)</a></h3>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Tool</th><th>Purpose</th><th>Install</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>genisoimage</code></td><td>ISO 9660 image creation</td><td><code>sudo apt install genisoimage</code></td></tr>
|
|
||||||
<tr><td><code>mkisofs</code></td><td>Alternative ISO tool</td><td><code>sudo apt install mkisofs</code></td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<p>Or build with the <code>pure-iso</code> feature to avoid needing either.</p>
|
|
||||||
<h2 id="verify-everything"><a class="header" href="#verify-everything">Verify Everything</a></h2>
|
|
||||||
<pre><code class="language-bash"># QEMU
|
|
||||||
qemu-system-x86_64 --version
|
|
||||||
|
|
||||||
# qemu-img
|
|
||||||
qemu-img --version
|
|
||||||
|
|
||||||
# KVM access
|
|
||||||
ls -la /dev/kvm
|
|
||||||
|
|
||||||
# ISO tools (one of these)
|
|
||||||
genisoimage --version 2>/dev/null || mkisofs --version 2>/dev/null
|
|
||||||
|
|
||||||
# Your user should be in the kvm group
|
|
||||||
groups | grep -q kvm && echo "kvm: OK" || echo "kvm: add yourself to the kvm group"
|
|
||||||
</code></pre>
|
|
||||||
<p>If <code>/dev/kvm</code> is not present, enable KVM in your BIOS/UEFI settings (look for "VT-x" or "AMD-V") and ensure the <code>kvm</code> kernel module is loaded:</p>
|
|
||||||
<pre><code class="language-bash">sudo modprobe kvm
|
|
||||||
sudo modprobe kvm_intel # or kvm_amd
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="illumos-propolis"><a class="header" href="#illumos-propolis">illumos (Propolis)</a></h2>
|
|
||||||
<p>For the experimental Propolis backend:</p>
|
|
||||||
<ul>
|
|
||||||
<li>A running <code>propolis-server</code> instance</li>
|
|
||||||
<li>ZFS pool (default: <code>rpool</code>)</li>
|
|
||||||
<li><code>nebula-vm</code> zone brand installed</li>
|
|
||||||
<li>VNIC networking configured</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../getting-started/installation.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../getting-started/quick-start.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../getting-started/installation.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../getting-started/quick-start.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,285 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Quick Start - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="quick-start"><a class="header" href="#quick-start">Quick Start</a></h1>
|
|
||||||
<p>This guide walks you through creating your first VM in under a minute.</p>
|
|
||||||
<h2 id="imperative-one-off"><a class="header" href="#imperative-one-off">Imperative (One-Off)</a></h2>
|
|
||||||
<p>Create and start a VM from an Ubuntu cloud image:</p>
|
|
||||||
<pre><code class="language-bash">vmctl create \
|
|
||||||
--name demo \
|
|
||||||
--image-url https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img \
|
|
||||||
--vcpus 2 \
|
|
||||||
--memory 2048 \
|
|
||||||
--start
|
|
||||||
</code></pre>
|
|
||||||
<p>Wait a moment for the image to download and the VM to boot, then connect:</p>
|
|
||||||
<pre><code class="language-bash">vmctl ssh demo
|
|
||||||
</code></pre>
|
|
||||||
<p>When you're done:</p>
|
|
||||||
<pre><code class="language-bash">vmctl destroy demo
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="declarative-reproducible"><a class="header" href="#declarative-reproducible">Declarative (Reproducible)</a></h2>
|
|
||||||
<p>Create a <code>VMFile.kdl</code> in your project directory:</p>
|
|
||||||
<pre><code class="language-kdl">vm "demo" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "demo"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Bring it up:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up
|
|
||||||
</code></pre>
|
|
||||||
<p>vmctl will download the image (cached for future use), create a QCOW2 overlay, generate an Ed25519 SSH keypair, build a cloud-init ISO, and boot the VM.</p>
|
|
||||||
<p>Connect:</p>
|
|
||||||
<pre><code class="language-bash">vmctl ssh
|
|
||||||
</code></pre>
|
|
||||||
<p>Tear it down:</p>
|
|
||||||
<pre><code class="language-bash">vmctl down
|
|
||||||
</code></pre>
|
|
||||||
<p>Or destroy it completely (removes all VM files):</p>
|
|
||||||
<pre><code class="language-bash">vmctl down --destroy
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="next-steps"><a class="header" href="#next-steps">Next Steps</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../concepts/how-it-works.html">Concepts: How vmctl Works</a> for an understanding of what happens under the hood.</li>
|
|
||||||
<li><a href="../tutorials/declarative-workflow.html">Tutorials: Declarative Workflow</a> for a complete walkthrough with provisioning.</li>
|
|
||||||
<li><a href="../vmfile/overview.html">VMFile.kdl Reference</a> for the full configuration format.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../getting-started/prerequisites.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/how-it-works.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../getting-started/prerequisites.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../concepts/how-it-works.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* An increased contrast highlighting scheme loosely based on the
|
|
||||||
* "Base16 Atelier Dune Light" theme by Bram de Haan
|
|
||||||
* (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune)
|
|
||||||
* Original Base16 color scheme by Chris Kempson
|
|
||||||
* (https://github.com/chriskempson/base16)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Comment */
|
|
||||||
.hljs-comment,
|
|
||||||
.hljs-quote {
|
|
||||||
color: #575757;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Red */
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-template-variable,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-attr,
|
|
||||||
.hljs-tag,
|
|
||||||
.hljs-name,
|
|
||||||
.hljs-regexp,
|
|
||||||
.hljs-link,
|
|
||||||
.hljs-name,
|
|
||||||
.hljs-selector-id,
|
|
||||||
.hljs-selector-class {
|
|
||||||
color: #d70025;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Orange */
|
|
||||||
.hljs-number,
|
|
||||||
.hljs-meta,
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-builtin-name,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-type,
|
|
||||||
.hljs-params {
|
|
||||||
color: #b21e00;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Green */
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-symbol,
|
|
||||||
.hljs-bullet {
|
|
||||||
color: #008200;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Blue */
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-section {
|
|
||||||
color: #0030f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Purple */
|
|
||||||
.hljs-keyword,
|
|
||||||
.hljs-selector-tag {
|
|
||||||
color: #9d00ec;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
overflow-x: auto;
|
|
||||||
background: #f6f7f6;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-emphasis {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-addition {
|
|
||||||
color: #22863a;
|
|
||||||
background-color: #f0fff4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
color: #b31d28;
|
|
||||||
background-color: #ffeef0;
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,277 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Introduction - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="favicon.png">
|
|
||||||
<link rel="stylesheet" href="css/variables.css">
|
|
||||||
<link rel="stylesheet" href="css/general.css">
|
|
||||||
<link rel="stylesheet" href="css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
|
|
||||||
<p><strong>vmctl</strong> is a command-line tool for creating, managing, and provisioning virtual machines on Linux (QEMU/KVM) and illumos (Propolis/bhyve). It offers both imperative commands for one-off tasks and a declarative configuration format (<code>VMFile.kdl</code>) for reproducible VM environments.</p>
|
|
||||||
<h2 id="why-vmctl"><a class="header" href="#why-vmctl">Why vmctl?</a></h2>
|
|
||||||
<p>Managing VMs with raw QEMU commands is tedious and error-prone. vmctl handles the plumbing: disk overlays, cloud-init ISOs, SSH key generation, network configuration, and process lifecycle. You describe <em>what</em> you want; vmctl figures out <em>how</em>.</p>
|
|
||||||
<p>Think of it like this:</p>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Docker world</th><th>vmctl world</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>docker run</code></td><td><code>vmctl create --start</code></td></tr>
|
|
||||||
<tr><td><code>docker-compose.yml</code></td><td><code>VMFile.kdl</code></td></tr>
|
|
||||||
<tr><td><code>docker compose up</code></td><td><code>vmctl up</code></td></tr>
|
|
||||||
<tr><td><code>docker compose down</code></td><td><code>vmctl down</code></td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="a-taste"><a class="header" href="#a-taste">A Taste</a></h2>
|
|
||||||
<p>Create a <code>VMFile.kdl</code>:</p>
|
|
||||||
<pre><code class="language-kdl">vm "dev" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "dev"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y build-essential"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Then:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up # download image, create VM, boot, provision
|
|
||||||
vmctl ssh # connect over SSH
|
|
||||||
vmctl down # shut it down
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="platform-support"><a class="header" href="#platform-support">Platform Support</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Platform</th><th>Backend</th><th>Status</th></tr></thead><tbody>
|
|
||||||
<tr><td>Linux</td><td>QEMU/KVM</td><td>Fully supported</td></tr>
|
|
||||||
<tr><td>illumos</td><td>Propolis/bhyve</td><td>Experimental</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="project-structure"><a class="header" href="#project-structure">Project Structure</a></h2>
|
|
||||||
<p>vmctl is split into two crates:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>vm-manager</strong> - Library crate with the hypervisor abstraction, image management, SSH, provisioning, and VMFile parsing.</li>
|
|
||||||
<li><strong>vmctl</strong> - CLI binary built on top of vm-manager.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Both live in a Cargo workspace under <code>crates/</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="getting-started/installation.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="getting-started/installation.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js"></script>
|
|
||||||
<script src="mark.min.js"></script>
|
|
||||||
<script src="searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="clipboard.min.js"></script>
|
|
||||||
<script src="highlight.js"></script>
|
|
||||||
<script src="book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Introduction - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="favicon.png">
|
|
||||||
<link rel="stylesheet" href="css/variables.css">
|
|
||||||
<link rel="stylesheet" href="css/general.css">
|
|
||||||
<link rel="stylesheet" href="css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
|
|
||||||
<p><strong>vmctl</strong> is a command-line tool for creating, managing, and provisioning virtual machines on Linux (QEMU/KVM) and illumos (Propolis/bhyve). It offers both imperative commands for one-off tasks and a declarative configuration format (<code>VMFile.kdl</code>) for reproducible VM environments.</p>
|
|
||||||
<h2 id="why-vmctl"><a class="header" href="#why-vmctl">Why vmctl?</a></h2>
|
|
||||||
<p>Managing VMs with raw QEMU commands is tedious and error-prone. vmctl handles the plumbing: disk overlays, cloud-init ISOs, SSH key generation, network configuration, and process lifecycle. You describe <em>what</em> you want; vmctl figures out <em>how</em>.</p>
|
|
||||||
<p>Think of it like this:</p>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Docker world</th><th>vmctl world</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>docker run</code></td><td><code>vmctl create --start</code></td></tr>
|
|
||||||
<tr><td><code>docker-compose.yml</code></td><td><code>VMFile.kdl</code></td></tr>
|
|
||||||
<tr><td><code>docker compose up</code></td><td><code>vmctl up</code></td></tr>
|
|
||||||
<tr><td><code>docker compose down</code></td><td><code>vmctl down</code></td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="a-taste"><a class="header" href="#a-taste">A Taste</a></h2>
|
|
||||||
<p>Create a <code>VMFile.kdl</code>:</p>
|
|
||||||
<pre><code class="language-kdl">vm "dev" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "dev"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y build-essential"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Then:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up # download image, create VM, boot, provision
|
|
||||||
vmctl ssh # connect over SSH
|
|
||||||
vmctl down # shut it down
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="platform-support"><a class="header" href="#platform-support">Platform Support</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Platform</th><th>Backend</th><th>Status</th></tr></thead><tbody>
|
|
||||||
<tr><td>Linux</td><td>QEMU/KVM</td><td>Fully supported</td></tr>
|
|
||||||
<tr><td>illumos</td><td>Propolis/bhyve</td><td>Experimental</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="project-structure"><a class="header" href="#project-structure">Project Structure</a></h2>
|
|
||||||
<p>vmctl is split into two crates:</p>
|
|
||||||
<ul>
|
|
||||||
<li><strong>vm-manager</strong> - Library crate with the hypervisor abstraction, image management, SSH, provisioning, and VMFile parsing.</li>
|
|
||||||
<li><strong>vmctl</strong> - CLI binary built on top of vm-manager.</li>
|
|
||||||
</ul>
|
|
||||||
<p>Both live in a Cargo workspace under <code>crates/</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="getting-started/installation.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="getting-started/installation.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="elasticlunr.min.js"></script>
|
|
||||||
<script src="mark.min.js"></script>
|
|
||||||
<script src="searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="clipboard.min.js"></script>
|
|
||||||
<script src="highlight.js"></script>
|
|
||||||
<script src="book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,329 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Core Types - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="core-types"><a class="header" href="#core-types">Core Types</a></h1>
|
|
||||||
<p>All types are defined in <code>crates/vm-manager/src/types.rs</code> and re-exported from the crate root.</p>
|
|
||||||
<h2 id="vmspec"><a class="header" href="#vmspec">VmSpec</a></h2>
|
|
||||||
<p>The input specification for creating a VM.</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct VmSpec {
|
|
||||||
pub name: String,
|
|
||||||
pub image_path: PathBuf,
|
|
||||||
pub vcpus: u16,
|
|
||||||
pub memory_mb: u64,
|
|
||||||
pub disk_gb: Option<u32>,
|
|
||||||
pub network: NetworkConfig,
|
|
||||||
pub cloud_init: Option<CloudInitConfig>,
|
|
||||||
pub ssh: Option<SshConfig>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="vmhandle"><a class="header" href="#vmhandle">VmHandle</a></h2>
|
|
||||||
<p>A runtime handle to a managed VM. Serializable to JSON for persistence.</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct VmHandle {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub backend: BackendTag,
|
|
||||||
pub work_dir: PathBuf,
|
|
||||||
pub overlay_path: Option<PathBuf>,
|
|
||||||
pub seed_iso_path: Option<PathBuf>,
|
|
||||||
pub pid: Option<u32>,
|
|
||||||
pub qmp_socket: Option<PathBuf>,
|
|
||||||
pub console_socket: Option<PathBuf>,
|
|
||||||
pub vnc_addr: Option<String>,
|
|
||||||
pub vcpus: u16, // default: 1
|
|
||||||
pub memory_mb: u64, // default: 1024
|
|
||||||
pub disk_gb: Option<u32>,
|
|
||||||
pub network: NetworkConfig,
|
|
||||||
pub ssh_host_port: Option<u16>,
|
|
||||||
pub mac_addr: Option<String>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>All optional fields default to <code>None</code> and numeric fields have sensible defaults for backward-compatible deserialization.</p>
|
|
||||||
<h2 id="vmstate"><a class="header" href="#vmstate">VmState</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum VmState {
|
|
||||||
Preparing,
|
|
||||||
Prepared,
|
|
||||||
Running,
|
|
||||||
Stopped,
|
|
||||||
Failed,
|
|
||||||
Destroyed,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Implements <code>Display</code> with lowercase names.</p>
|
|
||||||
<h2 id="networkconfig"><a class="header" href="#networkconfig">NetworkConfig</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum NetworkConfig {
|
|
||||||
Tap { bridge: String },
|
|
||||||
User, // default
|
|
||||||
Vnic { name: String },
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Serialized with <code>#[serde(tag = "type")]</code> for clean JSON representation.</p>
|
|
||||||
<h2 id="cloudinitconfig"><a class="header" href="#cloudinitconfig">CloudInitConfig</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct CloudInitConfig {
|
|
||||||
pub user_data: Vec<u8>,
|
|
||||||
pub instance_id: Option<String>,
|
|
||||||
pub hostname: Option<String>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p><code>user_data</code> is the raw cloud-config YAML content.</p>
|
|
||||||
<h2 id="sshconfig"><a class="header" href="#sshconfig">SshConfig</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct SshConfig {
|
|
||||||
pub user: String,
|
|
||||||
pub public_key: Option<String>,
|
|
||||||
pub private_key_path: Option<PathBuf>,
|
|
||||||
pub private_key_pem: Option<String>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Supports both file-based keys (<code>private_key_path</code>) and in-memory keys (<code>private_key_pem</code>).</p>
|
|
||||||
<h2 id="backendtag"><a class="header" href="#backendtag">BackendTag</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum BackendTag {
|
|
||||||
Noop,
|
|
||||||
Qemu,
|
|
||||||
Propolis,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Serialized as lowercase strings. Implements <code>Display</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/hypervisor-trait.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/image-api.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/hypervisor-trait.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/image-api.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,284 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Hypervisor Trait - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="hypervisor-trait"><a class="header" href="#hypervisor-trait">Hypervisor Trait</a></h1>
|
|
||||||
<p>The <code>Hypervisor</code> trait is the core abstraction for VM lifecycle management. All backends implement it.</p>
|
|
||||||
<h2 id="definition"><a class="header" href="#definition">Definition</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub trait Hypervisor: Send + Sync {
|
|
||||||
fn prepare(&self, spec: &VmSpec) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn start(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn stop(&self, vm: &VmHandle, timeout: Duration) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn suspend(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn resume(&self, vm: &VmHandle) -> impl Future<Output = Result<VmHandle>>;
|
|
||||||
fn destroy(&self, vm: VmHandle) -> impl Future<Output = Result<()>>;
|
|
||||||
fn state(&self, vm: &VmHandle) -> impl Future<Output = Result<VmState>>;
|
|
||||||
fn guest_ip(&self, vm: &VmHandle) -> impl Future<Output = Result<String>>;
|
|
||||||
fn console_endpoint(&self, vm: &VmHandle) -> Result<ConsoleEndpoint>;
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="methods"><a class="header" href="#methods">Methods</a></h2>
|
|
||||||
<h3 id="prepare"><a class="header" href="#prepare">prepare</a></h3>
|
|
||||||
<p>Allocates resources for a VM based on the provided <code>VmSpec</code>. Creates the work directory, QCOW2 overlay, cloud-init ISO, and networking configuration. Returns a <code>VmHandle</code> in the <code>Prepared</code> state.</p>
|
|
||||||
<h3 id="start"><a class="header" href="#start">start</a></h3>
|
|
||||||
<p>Boots the VM. Returns an updated <code>VmHandle</code> with runtime information (PID, VNC address, etc.).</p>
|
|
||||||
<h3 id="stop"><a class="header" href="#stop">stop</a></h3>
|
|
||||||
<p>Gracefully shuts down the VM. Tries ACPI power-down first, then force-kills after the timeout. Returns the handle in <code>Stopped</code> state.</p>
|
|
||||||
<h3 id="suspend--resume"><a class="header" href="#suspend--resume">suspend / resume</a></h3>
|
|
||||||
<p>Pauses and unpauses VM vCPUs without shutting down.</p>
|
|
||||||
<h3 id="destroy"><a class="header" href="#destroy">destroy</a></h3>
|
|
||||||
<p>Stops the VM (if running) and removes all associated resources. Takes ownership of the handle.</p>
|
|
||||||
<h3 id="state"><a class="header" href="#state">state</a></h3>
|
|
||||||
<p>Queries the current VM state by checking the process and QMP status.</p>
|
|
||||||
<h3 id="guest_ip"><a class="header" href="#guest_ip">guest_ip</a></h3>
|
|
||||||
<p>Discovers the guest's IP address. Method varies by network mode and backend.</p>
|
|
||||||
<h3 id="console_endpoint"><a class="header" href="#console_endpoint">console_endpoint</a></h3>
|
|
||||||
<p>Returns the console connection details. Synchronous (not async).</p>
|
|
||||||
<h2 id="consoleendpoint"><a class="header" href="#consoleendpoint">ConsoleEndpoint</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum ConsoleEndpoint {
|
|
||||||
UnixSocket(PathBuf), // QEMU serial console
|
|
||||||
WebSocket(String), // Propolis console
|
|
||||||
None, // Noop backend
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="implementing-a-custom-backend"><a class="header" href="#implementing-a-custom-backend">Implementing a Custom Backend</a></h2>
|
|
||||||
<p>To add a new hypervisor backend:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Create a struct implementing <code>Hypervisor</code>.</li>
|
|
||||||
<li>Add it to <code>RouterHypervisor</code> with appropriate <code>#[cfg]</code> gates.</li>
|
|
||||||
<li>Add a new variant to <code>BackendTag</code>.</li>
|
|
||||||
<li>Implement dispatch in <code>RouterHypervisor</code>'s <code>Hypervisor</code> impl.</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/using-as-crate.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/core-types.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/using-as-crate.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/core-types.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,285 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Image Management API - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="image-management-api"><a class="header" href="#image-management-api">Image Management API</a></h1>
|
|
||||||
<p>The image module handles downloading, caching, format detection, and overlay creation. Located in <code>crates/vm-manager/src/image.rs</code>.</p>
|
|
||||||
<h2 id="imagemanager"><a class="header" href="#imagemanager">ImageManager</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct ImageManager {
|
|
||||||
client: reqwest::Client,
|
|
||||||
cache: PathBuf, // default: ~/.local/share/vmctl/images/
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h3 id="new"><a class="header" href="#new">new</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>ImageManager::new() -> Self
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Creates an ImageManager with the default cache directory.</p>
|
|
||||||
<h3 id="download"><a class="header" href="#download">download</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>async fn download(&self, url: &str, destination: &Path) -> Result<()>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Downloads an image from a URL to a local path. Skips if the destination already exists. Auto-decompresses <code>.zst</code>/<code>.zstd</code> files. Logs progress every 5%.</p>
|
|
||||||
<h3 id="pull"><a class="header" href="#pull">pull</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>async fn pull(&self, url: &str, name: Option<&str>) -> Result<PathBuf>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Downloads an image to the cache directory and returns the cached path. If <code>name</code> is None, extracts the filename from the URL.</p>
|
|
||||||
<h3 id="list"><a class="header" href="#list">list</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>fn list(&self) -> Result<Vec<CachedImage>>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Lists all images in the cache with their names, sizes, and paths.</p>
|
|
||||||
<h3 id="detect_format"><a class="header" href="#detect_format">detect_format</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>async fn detect_format(path: &Path) -> Result<String>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Runs <code>qemu-img info --output=json</code> and returns the format string (e.g., <code>"qcow2"</code>, <code>"raw"</code>).</p>
|
|
||||||
<h3 id="create_overlay"><a class="header" href="#create_overlay">create_overlay</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>async fn create_overlay(base: &Path, overlay: &Path, size_gb: Option<u32>) -> Result<()>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Creates a QCOW2 overlay with the given base image as a backing file. Optionally resizes to <code>size_gb</code>.</p>
|
|
||||||
<h3 id="convert"><a class="header" href="#convert">convert</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>async fn convert(src: &Path, dst: &Path, format: &str) -> Result<()>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Converts an image between formats using <code>qemu-img convert</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/core-types.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/ssh-provisioning-api.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/core-types.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/ssh-provisioning-api.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,297 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>SSH and Provisioning API - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="ssh-and-provisioning-api"><a class="header" href="#ssh-and-provisioning-api">SSH and Provisioning API</a></h1>
|
|
||||||
<h2 id="ssh-module"><a class="header" href="#ssh-module">SSH Module</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/ssh.rs</code>.</p>
|
|
||||||
<h3 id="connect"><a class="header" href="#connect">connect</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn connect(ip: &str, port: u16, config: &SshConfig) -> Result<Session>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Establishes an SSH connection and authenticates. Supports in-memory PEM keys and file-based keys.</p>
|
|
||||||
<h3 id="exec"><a class="header" href="#exec">exec</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn exec(sess: &Session, cmd: &str) -> Result<(String, String, i32)>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Executes a command and returns <code>(stdout, stderr, exit_code)</code>.</p>
|
|
||||||
<h3 id="exec_streaming"><a class="header" href="#exec_streaming">exec_streaming</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn exec_streaming<W1: Write, W2: Write>(
|
|
||||||
sess: &Session,
|
|
||||||
cmd: &str,
|
|
||||||
stdout_writer: &mut W1,
|
|
||||||
stderr_writer: &mut W2,
|
|
||||||
) -> Result<(String, String, i32)>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Executes a command with real-time output streaming. Uses non-blocking I/O with 8KB buffers and 50ms polling interval. Both writes to the provided writers and collects the full output.</p>
|
|
||||||
<h3 id="upload"><a class="header" href="#upload">upload</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn upload(sess: &Session, local: &Path, remote: &str) -> Result<()>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Uploads a file via SFTP.</p>
|
|
||||||
<h3 id="connect_with_retry"><a class="header" href="#connect_with_retry">connect_with_retry</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub async fn connect_with_retry(
|
|
||||||
ip: &str,
|
|
||||||
port: u16,
|
|
||||||
config: &SshConfig,
|
|
||||||
timeout: Duration,
|
|
||||||
) -> Result<Session>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Retries connection with exponential backoff (1s to 5s). Runs blocking SSH on <code>tokio::task::spawn_blocking</code>.</p>
|
|
||||||
<h2 id="provisioning-module"><a class="header" href="#provisioning-module">Provisioning Module</a></h2>
|
|
||||||
<p>Located in <code>crates/vm-manager/src/provision.rs</code>.</p>
|
|
||||||
<h3 id="run_provisions"><a class="header" href="#run_provisions">run_provisions</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn run_provisions(
|
|
||||||
sess: &Session,
|
|
||||||
provisions: &[ProvisionDef],
|
|
||||||
base_dir: &Path,
|
|
||||||
vm_name: &str,
|
|
||||||
log_dir: Option<&Path>,
|
|
||||||
) -> Result<()>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Runs all provisioners in sequence:</p>
|
|
||||||
<ol>
|
|
||||||
<li><strong>Shell (inline)</strong>: Executes the command via <code>exec_streaming</code>.</li>
|
|
||||||
<li><strong>Shell (script)</strong>: Uploads the script to <code>/tmp/vmctl-provision-<step>.sh</code>, makes it executable, runs it.</li>
|
|
||||||
<li><strong>File</strong>: Uploads via SFTP.</li>
|
|
||||||
</ol>
|
|
||||||
<p>Output is streamed to the terminal and appended to <code>provision.log</code> if <code>log_dir</code> is provided.</p>
|
|
||||||
<p>Aborts on the first non-zero exit code with <code>VmError::ProvisionFailed</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/image-api.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/vmfile-api.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/image-api.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/vmfile-api.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,291 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Using vm-manager as a Crate - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="using-vm-manager-as-a-crate"><a class="header" href="#using-vm-manager-as-a-crate">Using vm-manager as a Crate</a></h1>
|
|
||||||
<p>The <code>vm-manager</code> library can be used as a Rust dependency for building custom VM management tools.</p>
|
|
||||||
<h2 id="add-the-dependency"><a class="header" href="#add-the-dependency">Add the Dependency</a></h2>
|
|
||||||
<pre><code class="language-toml">[dependencies]
|
|
||||||
vm-manager = { path = "crates/vm-manager" }
|
|
||||||
# or from a git repository:
|
|
||||||
# vm-manager = { git = "https://github.com/user/vm-manager.git" }
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="re-exports"><a class="header" href="#re-exports">Re-Exports</a></h2>
|
|
||||||
<p>The crate root re-exports the most commonly used types:</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>use vm_manager::{
|
|
||||||
// Hypervisor abstraction
|
|
||||||
Hypervisor, ConsoleEndpoint, RouterHypervisor,
|
|
||||||
// Error handling
|
|
||||||
VmError, Result,
|
|
||||||
// Core types
|
|
||||||
BackendTag, VmSpec, VmHandle, VmState,
|
|
||||||
NetworkConfig, CloudInitConfig, SshConfig,
|
|
||||||
};
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="minimal-example"><a class="header" href="#minimal-example">Minimal Example</a></h2>
|
|
||||||
<pre><pre class="playground"><code class="language-rust">use vm_manager::{RouterHypervisor, Hypervisor, VmSpec, NetworkConfig};
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() -> vm_manager::Result<()> {
|
|
||||||
// Create a hypervisor (platform-detected)
|
|
||||||
let hyp = RouterHypervisor::new(None, "rpool".into());
|
|
||||||
|
|
||||||
// Define a VM
|
|
||||||
let spec = VmSpec {
|
|
||||||
name: "example".into(),
|
|
||||||
image_path: "/path/to/image.qcow2".into(),
|
|
||||||
vcpus: 2,
|
|
||||||
memory_mb: 2048,
|
|
||||||
disk_gb: Some(20),
|
|
||||||
network: NetworkConfig::User,
|
|
||||||
cloud_init: None,
|
|
||||||
ssh: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Lifecycle
|
|
||||||
let handle = hyp.prepare(&spec).await?;
|
|
||||||
let handle = hyp.start(&handle).await?;
|
|
||||||
|
|
||||||
// ... use the VM ...
|
|
||||||
|
|
||||||
hyp.stop(&handle, Duration::from_secs(30)).await?;
|
|
||||||
hyp.destroy(handle).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}</code></pre></pre>
|
|
||||||
<h2 id="feature-flags"><a class="header" href="#feature-flags">Feature Flags</a></h2>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Effect</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>pure-iso</code></td><td>Use pure-Rust ISO generation instead of <code>genisoimage</code>/<code>mkisofs</code></td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../architecture/error-handling.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/hypervisor-trait.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../architecture/error-handling.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../library/hypervisor-trait.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,333 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>VMFile Parsing API - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmfile-parsing-api"><a class="header" href="#vmfile-parsing-api">VMFile Parsing API</a></h1>
|
|
||||||
<p>The VMFile module parses and resolves <code>VMFile.kdl</code> configuration files. Located in <code>crates/vm-manager/src/vmfile.rs</code>.</p>
|
|
||||||
<h2 id="types"><a class="header" href="#types">Types</a></h2>
|
|
||||||
<h3 id="vmfile"><a class="header" href="#vmfile">VmFile</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct VmFile {
|
|
||||||
pub base_dir: PathBuf,
|
|
||||||
pub vms: Vec<VmDef>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h3 id="vmdef"><a class="header" href="#vmdef">VmDef</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub struct VmDef {
|
|
||||||
pub name: String,
|
|
||||||
pub image: ImageSource,
|
|
||||||
pub vcpus: u16,
|
|
||||||
pub memory_mb: u64,
|
|
||||||
pub disk_gb: Option<u32>,
|
|
||||||
pub network: NetworkDef,
|
|
||||||
pub cloud_init: Option<CloudInitDef>,
|
|
||||||
pub ssh: Option<SshDef>,
|
|
||||||
pub provisions: Vec<ProvisionDef>,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h3 id="imagesource"><a class="header" href="#imagesource">ImageSource</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum ImageSource {
|
|
||||||
Local(String),
|
|
||||||
Url(String),
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h3 id="provisiondef"><a class="header" href="#provisiondef">ProvisionDef</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub enum ProvisionDef {
|
|
||||||
Shell(ShellProvision),
|
|
||||||
File(FileProvision),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ShellProvision {
|
|
||||||
pub inline: Option<String>,
|
|
||||||
pub script: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FileProvision {
|
|
||||||
pub source: String,
|
|
||||||
pub destination: String,
|
|
||||||
}
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<h2 id="functions"><a class="header" href="#functions">Functions</a></h2>
|
|
||||||
<h3 id="discover"><a class="header" href="#discover">discover</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn discover(explicit: Option<&Path>) -> Result<PathBuf>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Finds the VMFile. If <code>explicit</code> is provided, uses that path. Otherwise, looks for <code>VMFile.kdl</code> in the current directory.</p>
|
|
||||||
<h3 id="parse"><a class="header" href="#parse">parse</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn parse(path: &Path) -> Result<VmFile>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Parses a VMFile.kdl into a <code>VmFile</code> struct. Validates:</p>
|
|
||||||
<ul>
|
|
||||||
<li>At least one <code>vm</code> block.</li>
|
|
||||||
<li>No duplicate VM names.</li>
|
|
||||||
<li>Each VM has a valid image source.</li>
|
|
||||||
<li>Provisioner blocks are well-formed.</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="resolve"><a class="header" href="#resolve">resolve</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub async fn resolve(def: &VmDef, base_dir: &Path) -> Result<VmSpec>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Converts a <code>VmDef</code> into a <code>VmSpec</code> ready for the hypervisor:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Downloads images from URLs.</li>
|
|
||||||
<li>Resolves local image paths.</li>
|
|
||||||
<li>Generates Ed25519 SSH keypairs if needed.</li>
|
|
||||||
<li>Reads cloud-init user-data files.</li>
|
|
||||||
<li>Resolves all relative paths against <code>base_dir</code>.</li>
|
|
||||||
</ul>
|
|
||||||
<h3 id="utility-functions"><a class="header" href="#utility-functions">Utility Functions</a></h3>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn expand_tilde(s: &str) -> PathBuf
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Expands <code>~</code> to the user's home directory.</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn resolve_path(raw: &str, base_dir: &Path) -> PathBuf
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Expands tilde and makes relative paths absolute against <code>base_dir</code>.</p>
|
|
||||||
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
||||||
</span><span class="boring">fn main() {
|
|
||||||
</span>pub fn generate_ssh_keypair(vm_name: &str) -> Result<(String, String)>
|
|
||||||
<span class="boring">}</span></code></pre></pre>
|
|
||||||
<p>Generates an Ed25519 keypair. Returns <code>(public_key_openssh, private_key_pem)</code>.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../library/ssh-provisioning-api.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/containerization.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../library/ssh-provisioning-api.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../advanced/containerization.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
7
docs/book/mark.min.js
vendored
7
docs/book/mark.min.js
vendored
File diff suppressed because one or more lines are too long
2788
docs/book/print.html
2788
docs/book/print.html
File diff suppressed because it is too large
Load diff
|
|
@ -1,554 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/* global Mark, elasticlunr, path_to_root */
|
|
||||||
|
|
||||||
window.search = window.search || {};
|
|
||||||
(function search() {
|
|
||||||
// Search functionality
|
|
||||||
//
|
|
||||||
// You can use !hasFocus() to prevent keyhandling in your key
|
|
||||||
// event handlers while the user is typing their search.
|
|
||||||
|
|
||||||
if (!Mark || !elasticlunr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
// IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
|
||||||
if (!String.prototype.startsWith) {
|
|
||||||
String.prototype.startsWith = function(search, pos) {
|
|
||||||
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const search_wrap = document.getElementById('search-wrapper'),
|
|
||||||
searchbar_outer = document.getElementById('searchbar-outer'),
|
|
||||||
searchbar = document.getElementById('searchbar'),
|
|
||||||
searchresults = document.getElementById('searchresults'),
|
|
||||||
searchresults_outer = document.getElementById('searchresults-outer'),
|
|
||||||
searchresults_header = document.getElementById('searchresults-header'),
|
|
||||||
searchicon = document.getElementById('search-toggle'),
|
|
||||||
content = document.getElementById('content'),
|
|
||||||
|
|
||||||
// SVG text elements don't render if inside a <mark> tag.
|
|
||||||
mark_exclude = ['text'],
|
|
||||||
marker = new Mark(content),
|
|
||||||
URL_SEARCH_PARAM = 'search',
|
|
||||||
URL_MARK_PARAM = 'highlight';
|
|
||||||
|
|
||||||
let current_searchterm = '',
|
|
||||||
doc_urls = [],
|
|
||||||
search_options = {
|
|
||||||
bool: 'AND',
|
|
||||||
expand: true,
|
|
||||||
fields: {
|
|
||||||
title: {boost: 1},
|
|
||||||
body: {boost: 1},
|
|
||||||
breadcrumbs: {boost: 0},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
searchindex = null,
|
|
||||||
results_options = {
|
|
||||||
teaser_word_count: 30,
|
|
||||||
limit_results: 30,
|
|
||||||
},
|
|
||||||
teaser_count = 0;
|
|
||||||
|
|
||||||
function hasFocus() {
|
|
||||||
return searchbar === document.activeElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeChildren(elem) {
|
|
||||||
while (elem.firstChild) {
|
|
||||||
elem.removeChild(elem.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to parse a url into its building blocks.
|
|
||||||
function parseURL(url) {
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = url;
|
|
||||||
return {
|
|
||||||
source: url,
|
|
||||||
protocol: a.protocol.replace(':', ''),
|
|
||||||
host: a.hostname,
|
|
||||||
port: a.port,
|
|
||||||
params: (function() {
|
|
||||||
const ret = {};
|
|
||||||
const seg = a.search.replace(/^\?/, '').split('&');
|
|
||||||
for (const part of seg) {
|
|
||||||
if (!part) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const s = part.split('=');
|
|
||||||
ret[s[0]] = s[1];
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
})(),
|
|
||||||
file: (a.pathname.match(/\/([^/?#]+)$/i) || ['', ''])[1],
|
|
||||||
hash: a.hash.replace('#', ''),
|
|
||||||
path: a.pathname.replace(/^([^/])/, '/$1'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to recreate a url string from its building blocks.
|
|
||||||
function renderURL(urlobject) {
|
|
||||||
let url = urlobject.protocol + '://' + urlobject.host;
|
|
||||||
if (urlobject.port !== '') {
|
|
||||||
url += ':' + urlobject.port;
|
|
||||||
}
|
|
||||||
url += urlobject.path;
|
|
||||||
let joiner = '?';
|
|
||||||
for (const prop in urlobject.params) {
|
|
||||||
if (Object.prototype.hasOwnProperty.call(urlobject.params, prop)) {
|
|
||||||
url += joiner + prop + '=' + urlobject.params[prop];
|
|
||||||
joiner = '&';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (urlobject.hash !== '') {
|
|
||||||
url += '#' + urlobject.hash;
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to escape html special chars for displaying the teasers
|
|
||||||
const escapeHTML = (function() {
|
|
||||||
const MAP = {
|
|
||||||
'&': '&',
|
|
||||||
'<': '<',
|
|
||||||
'>': '>',
|
|
||||||
'"': '"',
|
|
||||||
'\'': ''',
|
|
||||||
};
|
|
||||||
const repl = function(c) {
|
|
||||||
return MAP[c];
|
|
||||||
};
|
|
||||||
return function(s) {
|
|
||||||
return s.replace(/[&<>'"]/g, repl);
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
function formatSearchMetric(count, searchterm) {
|
|
||||||
if (count === 1) {
|
|
||||||
return count + ' search result for \'' + searchterm + '\':';
|
|
||||||
} else if (count === 0) {
|
|
||||||
return 'No search results for \'' + searchterm + '\'.';
|
|
||||||
} else {
|
|
||||||
return count + ' search results for \'' + searchterm + '\':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSearchResult(result, searchterms) {
|
|
||||||
const teaser = makeTeaser(escapeHTML(result.doc.body), searchterms);
|
|
||||||
teaser_count++;
|
|
||||||
|
|
||||||
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
|
|
||||||
const url = doc_urls[result.ref].split('#');
|
|
||||||
if (url.length === 1) { // no anchor found
|
|
||||||
url.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
// encodeURIComponent escapes all chars that could allow an XSS except
|
|
||||||
// for '. Due to that we also manually replace ' with its url-encoded
|
|
||||||
// representation (%27).
|
|
||||||
const encoded_search = encodeURIComponent(searchterms.join(' ')).replace(/'/g, '%27');
|
|
||||||
|
|
||||||
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + encoded_search
|
|
||||||
+ '#' + url[1] + '" aria-details="teaser_' + teaser_count + '">'
|
|
||||||
+ result.doc.breadcrumbs + '</a>' + '<span class="teaser" id="teaser_' + teaser_count
|
|
||||||
+ '" aria-label="Search Result Teaser">' + teaser + '</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeTeaser(body, searchterms) {
|
|
||||||
// The strategy is as follows:
|
|
||||||
// First, assign a value to each word in the document:
|
|
||||||
// Words that correspond to search terms (stemmer aware): 40
|
|
||||||
// Normal words: 2
|
|
||||||
// First word in a sentence: 8
|
|
||||||
// Then use a sliding window with a constant number of words and count the
|
|
||||||
// sum of the values of the words within the window. Then use the window that got the
|
|
||||||
// maximum sum. If there are multiple maximas, then get the last one.
|
|
||||||
// Enclose the terms in <em>.
|
|
||||||
const stemmed_searchterms = searchterms.map(function(w) {
|
|
||||||
return elasticlunr.stemmer(w.toLowerCase());
|
|
||||||
});
|
|
||||||
const searchterm_weight = 40;
|
|
||||||
const weighted = []; // contains elements of ["word", weight, index_in_document]
|
|
||||||
// split in sentences, then words
|
|
||||||
const sentences = body.toLowerCase().split('. ');
|
|
||||||
let index = 0;
|
|
||||||
let value = 0;
|
|
||||||
let searchterm_found = false;
|
|
||||||
for (const sentenceindex in sentences) {
|
|
||||||
const words = sentences[sentenceindex].split(' ');
|
|
||||||
value = 8;
|
|
||||||
for (const wordindex in words) {
|
|
||||||
const word = words[wordindex];
|
|
||||||
if (word.length > 0) {
|
|
||||||
for (const searchtermindex in stemmed_searchterms) {
|
|
||||||
if (elasticlunr.stemmer(word).startsWith(
|
|
||||||
stemmed_searchterms[searchtermindex])
|
|
||||||
) {
|
|
||||||
value = searchterm_weight;
|
|
||||||
searchterm_found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
weighted.push([word, value, index]);
|
|
||||||
value = 2;
|
|
||||||
}
|
|
||||||
index += word.length;
|
|
||||||
index += 1; // ' ' or '.' if last word in sentence
|
|
||||||
}
|
|
||||||
index += 1; // because we split at a two-char boundary '. '
|
|
||||||
}
|
|
||||||
|
|
||||||
if (weighted.length === 0) {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
const window_weight = [];
|
|
||||||
const window_size = Math.min(weighted.length, results_options.teaser_word_count);
|
|
||||||
|
|
||||||
let cur_sum = 0;
|
|
||||||
for (let wordindex = 0; wordindex < window_size; wordindex++) {
|
|
||||||
cur_sum += weighted[wordindex][1];
|
|
||||||
}
|
|
||||||
window_weight.push(cur_sum);
|
|
||||||
for (let wordindex = 0; wordindex < weighted.length - window_size; wordindex++) {
|
|
||||||
cur_sum -= weighted[wordindex][1];
|
|
||||||
cur_sum += weighted[wordindex + window_size][1];
|
|
||||||
window_weight.push(cur_sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
let max_sum_window_index = 0;
|
|
||||||
if (searchterm_found) {
|
|
||||||
let max_sum = 0;
|
|
||||||
// backwards
|
|
||||||
for (let i = window_weight.length - 1; i >= 0; i--) {
|
|
||||||
if (window_weight[i] > max_sum) {
|
|
||||||
max_sum = window_weight[i];
|
|
||||||
max_sum_window_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
max_sum_window_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add <em/> around searchterms
|
|
||||||
const teaser_split = [];
|
|
||||||
index = weighted[max_sum_window_index][2];
|
|
||||||
for (let i = max_sum_window_index; i < max_sum_window_index + window_size; i++) {
|
|
||||||
const word = weighted[i];
|
|
||||||
if (index < word[2]) {
|
|
||||||
// missing text from index to start of `word`
|
|
||||||
teaser_split.push(body.substring(index, word[2]));
|
|
||||||
index = word[2];
|
|
||||||
}
|
|
||||||
if (word[1] === searchterm_weight) {
|
|
||||||
teaser_split.push('<em>');
|
|
||||||
}
|
|
||||||
index = word[2] + word[0].length;
|
|
||||||
teaser_split.push(body.substring(word[2], index));
|
|
||||||
if (word[1] === searchterm_weight) {
|
|
||||||
teaser_split.push('</em>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return teaser_split.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(config) {
|
|
||||||
results_options = config.results_options;
|
|
||||||
search_options = config.search_options;
|
|
||||||
doc_urls = config.doc_urls;
|
|
||||||
searchindex = elasticlunr.Index.load(config.index);
|
|
||||||
|
|
||||||
searchbar_outer.classList.remove('searching');
|
|
||||||
|
|
||||||
searchbar.focus();
|
|
||||||
|
|
||||||
const searchterm = searchbar.value.trim();
|
|
||||||
if (searchterm !== '') {
|
|
||||||
searchbar.classList.add('active');
|
|
||||||
doSearch(searchterm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initSearchInteractions(config) {
|
|
||||||
// Set up events
|
|
||||||
searchicon.addEventListener('click', () => {
|
|
||||||
searchIconClickHandler();
|
|
||||||
}, false);
|
|
||||||
searchbar.addEventListener('keyup', () => {
|
|
||||||
searchbarKeyUpHandler();
|
|
||||||
}, false);
|
|
||||||
document.addEventListener('keydown', e => {
|
|
||||||
globalKeyHandler(e);
|
|
||||||
}, false);
|
|
||||||
// If the user uses the browser buttons, do the same as if a reload happened
|
|
||||||
window.onpopstate = () => {
|
|
||||||
doSearchOrMarkFromUrl();
|
|
||||||
};
|
|
||||||
// Suppress "submit" events so the page doesn't reload when the user presses Enter
|
|
||||||
document.addEventListener('submit', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
// If reloaded, do the search or mark again, depending on the current url parameters
|
|
||||||
doSearchOrMarkFromUrl();
|
|
||||||
|
|
||||||
// Exported functions
|
|
||||||
config.hasFocus = hasFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
initSearchInteractions(window.search);
|
|
||||||
|
|
||||||
function unfocusSearchbar() {
|
|
||||||
// hacky, but just focusing a div only works once
|
|
||||||
const tmp = document.createElement('input');
|
|
||||||
tmp.setAttribute('style', 'position: absolute; opacity: 0;');
|
|
||||||
searchicon.appendChild(tmp);
|
|
||||||
tmp.focus();
|
|
||||||
tmp.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// On reload or browser history backwards/forwards events, parse the url and do search or mark
|
|
||||||
function doSearchOrMarkFromUrl() {
|
|
||||||
// Check current URL for search request
|
|
||||||
const url = parseURL(window.location.href);
|
|
||||||
if (Object.prototype.hasOwnProperty.call(url.params, URL_SEARCH_PARAM)
|
|
||||||
&& url.params[URL_SEARCH_PARAM] !== '') {
|
|
||||||
showSearch(true);
|
|
||||||
searchbar.value = decodeURIComponent(
|
|
||||||
(url.params[URL_SEARCH_PARAM] + '').replace(/\+/g, '%20'));
|
|
||||||
searchbarKeyUpHandler(); // -> doSearch()
|
|
||||||
} else {
|
|
||||||
showSearch(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.prototype.hasOwnProperty.call(url.params, URL_MARK_PARAM)) {
|
|
||||||
const words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' ');
|
|
||||||
marker.mark(words, {
|
|
||||||
exclude: mark_exclude,
|
|
||||||
});
|
|
||||||
|
|
||||||
const markers = document.querySelectorAll('mark');
|
|
||||||
const hide = () => {
|
|
||||||
for (let i = 0; i < markers.length; i++) {
|
|
||||||
markers[i].classList.add('fade-out');
|
|
||||||
window.setTimeout(() => {
|
|
||||||
marker.unmark();
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let i = 0; i < markers.length; i++) {
|
|
||||||
markers[i].addEventListener('click', hide);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eventhandler for keyevents on `document`
|
|
||||||
function globalKeyHandler(e) {
|
|
||||||
if (e.altKey ||
|
|
||||||
e.ctrlKey ||
|
|
||||||
e.metaKey ||
|
|
||||||
e.shiftKey ||
|
|
||||||
e.target.type === 'textarea' ||
|
|
||||||
e.target.type === 'text' ||
|
|
||||||
!hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.key === 'Escape') {
|
|
||||||
e.preventDefault();
|
|
||||||
searchbar.classList.remove('active');
|
|
||||||
setSearchUrlParameters('',
|
|
||||||
searchbar.value.trim() !== '' ? 'push' : 'replace');
|
|
||||||
if (hasFocus()) {
|
|
||||||
unfocusSearchbar();
|
|
||||||
}
|
|
||||||
showSearch(false);
|
|
||||||
marker.unmark();
|
|
||||||
} else if (!hasFocus() && (e.key === 's' || e.key === '/')) {
|
|
||||||
e.preventDefault();
|
|
||||||
showSearch(true);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
searchbar.select();
|
|
||||||
} else if (hasFocus() && (e.key === 'ArrowDown'
|
|
||||||
|| e.key === 'Enter')) {
|
|
||||||
e.preventDefault();
|
|
||||||
const first = searchresults.firstElementChild;
|
|
||||||
if (first !== null) {
|
|
||||||
unfocusSearchbar();
|
|
||||||
first.classList.add('focus');
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
window.location.assign(first.querySelector('a'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!hasFocus() && (e.key === 'ArrowDown'
|
|
||||||
|| e.key === 'ArrowUp'
|
|
||||||
|| e.key === 'Enter')) {
|
|
||||||
// not `:focus` because browser does annoying scrolling
|
|
||||||
const focused = searchresults.querySelector('li.focus');
|
|
||||||
if (!focused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.key === 'ArrowDown') {
|
|
||||||
const next = focused.nextElementSibling;
|
|
||||||
if (next) {
|
|
||||||
focused.classList.remove('focus');
|
|
||||||
next.classList.add('focus');
|
|
||||||
}
|
|
||||||
} else if (e.key === 'ArrowUp') {
|
|
||||||
focused.classList.remove('focus');
|
|
||||||
const prev = focused.previousElementSibling;
|
|
||||||
if (prev) {
|
|
||||||
prev.classList.add('focus');
|
|
||||||
} else {
|
|
||||||
searchbar.select();
|
|
||||||
}
|
|
||||||
} else { // Enter
|
|
||||||
window.location.assign(focused.querySelector('a'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadSearchScript(url, id) {
|
|
||||||
if (document.getElementById(id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
searchbar_outer.classList.add('searching');
|
|
||||||
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = url;
|
|
||||||
script.id = id;
|
|
||||||
script.onload = () => init(window.search);
|
|
||||||
script.onerror = error => {
|
|
||||||
console.error(`Failed to load \`${url}\`: ${error}`);
|
|
||||||
};
|
|
||||||
document.head.append(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSearch(yes) {
|
|
||||||
if (yes) {
|
|
||||||
loadSearchScript(
|
|
||||||
window.path_to_searchindex_js ||
|
|
||||||
path_to_root + 'searchindex.js',
|
|
||||||
'search-index');
|
|
||||||
search_wrap.classList.remove('hidden');
|
|
||||||
searchicon.setAttribute('aria-expanded', 'true');
|
|
||||||
} else {
|
|
||||||
search_wrap.classList.add('hidden');
|
|
||||||
searchicon.setAttribute('aria-expanded', 'false');
|
|
||||||
const results = searchresults.children;
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
|
||||||
results[i].classList.remove('focus');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showResults(yes) {
|
|
||||||
if (yes) {
|
|
||||||
searchresults_outer.classList.remove('hidden');
|
|
||||||
} else {
|
|
||||||
searchresults_outer.classList.add('hidden');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eventhandler for search icon
|
|
||||||
function searchIconClickHandler() {
|
|
||||||
if (search_wrap.classList.contains('hidden')) {
|
|
||||||
showSearch(true);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
searchbar.select();
|
|
||||||
} else {
|
|
||||||
showSearch(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eventhandler for keyevents while the searchbar is focused
|
|
||||||
function searchbarKeyUpHandler() {
|
|
||||||
const searchterm = searchbar.value.trim();
|
|
||||||
if (searchterm !== '') {
|
|
||||||
searchbar.classList.add('active');
|
|
||||||
doSearch(searchterm);
|
|
||||||
} else {
|
|
||||||
searchbar.classList.remove('active');
|
|
||||||
showResults(false);
|
|
||||||
removeChildren(searchresults);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSearchUrlParameters(searchterm, 'push_if_new_search_else_replace');
|
|
||||||
|
|
||||||
// Remove marks
|
|
||||||
marker.unmark();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and
|
|
||||||
// `#heading-anchor`. `action` can be one of "push", "replace",
|
|
||||||
// "push_if_new_search_else_replace" and replaces or pushes a new browser history item.
|
|
||||||
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
|
|
||||||
function setSearchUrlParameters(searchterm, action) {
|
|
||||||
const url = parseURL(window.location.href);
|
|
||||||
const first_search = !Object.prototype.hasOwnProperty.call(url.params, URL_SEARCH_PARAM);
|
|
||||||
|
|
||||||
if (searchterm !== '' || action === 'push_if_new_search_else_replace') {
|
|
||||||
url.params[URL_SEARCH_PARAM] = searchterm;
|
|
||||||
delete url.params[URL_MARK_PARAM];
|
|
||||||
url.hash = '';
|
|
||||||
} else {
|
|
||||||
delete url.params[URL_MARK_PARAM];
|
|
||||||
delete url.params[URL_SEARCH_PARAM];
|
|
||||||
}
|
|
||||||
// A new search will also add a new history item, so the user can go back
|
|
||||||
// to the page prior to searching. A updated search term will only replace
|
|
||||||
// the url.
|
|
||||||
if (action === 'push' || action === 'push_if_new_search_else_replace' && first_search ) {
|
|
||||||
history.pushState({}, document.title, renderURL(url));
|
|
||||||
} else if (action === 'replace' ||
|
|
||||||
action === 'push_if_new_search_else_replace' &&
|
|
||||||
!first_search
|
|
||||||
) {
|
|
||||||
history.replaceState({}, document.title, renderURL(url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doSearch(searchterm) {
|
|
||||||
// Don't search the same twice
|
|
||||||
if (current_searchterm === searchterm) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
searchbar_outer.classList.add('searching');
|
|
||||||
if (searchindex === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_searchterm = searchterm;
|
|
||||||
|
|
||||||
// Do the actual search
|
|
||||||
const results = searchindex.search(searchterm, search_options);
|
|
||||||
const resultcount = Math.min(results.length, results_options.limit_results);
|
|
||||||
|
|
||||||
// Display search metrics
|
|
||||||
searchresults_header.innerText = formatSearchMetric(resultcount, searchterm);
|
|
||||||
|
|
||||||
// Clear and insert results
|
|
||||||
const searchterms = searchterm.split(' ');
|
|
||||||
removeChildren(searchresults);
|
|
||||||
for (let i = 0; i < resultcount ; i++) {
|
|
||||||
const resultElem = document.createElement('li');
|
|
||||||
resultElem.innerHTML = formatSearchResult(results[i], searchterms);
|
|
||||||
searchresults.appendChild(resultElem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display results
|
|
||||||
showResults(true);
|
|
||||||
searchbar_outer.classList.remove('searching');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exported functions
|
|
||||||
search.hasFocus = hasFocus;
|
|
||||||
})(window.search);
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,104 +0,0 @@
|
||||||
/* Tomorrow Night Theme */
|
|
||||||
/* https://github.com/jmblog/color-themes-for-highlightjs */
|
|
||||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
|
||||||
/* https://github.com/jmblog/color-themes-for-highlightjs */
|
|
||||||
|
|
||||||
/* Tomorrow Comment */
|
|
||||||
.hljs-comment {
|
|
||||||
color: #969896;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Red */
|
|
||||||
.hljs-variable,
|
|
||||||
.hljs-attribute,
|
|
||||||
.hljs-attr,
|
|
||||||
.hljs-tag,
|
|
||||||
.hljs-regexp,
|
|
||||||
.ruby .hljs-constant,
|
|
||||||
.xml .hljs-tag .hljs-title,
|
|
||||||
.xml .hljs-pi,
|
|
||||||
.xml .hljs-doctype,
|
|
||||||
.html .hljs-doctype,
|
|
||||||
.css .hljs-id,
|
|
||||||
.css .hljs-class,
|
|
||||||
.css .hljs-pseudo {
|
|
||||||
color: #cc6666;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Orange */
|
|
||||||
.hljs-number,
|
|
||||||
.hljs-preprocessor,
|
|
||||||
.hljs-pragma,
|
|
||||||
.hljs-built_in,
|
|
||||||
.hljs-literal,
|
|
||||||
.hljs-params,
|
|
||||||
.hljs-constant {
|
|
||||||
color: #de935f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Yellow */
|
|
||||||
.ruby .hljs-class .hljs-title,
|
|
||||||
.css .hljs-rule .hljs-attribute {
|
|
||||||
color: #f0c674;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Green */
|
|
||||||
.hljs-string,
|
|
||||||
.hljs-value,
|
|
||||||
.hljs-inheritance,
|
|
||||||
.hljs-header,
|
|
||||||
.hljs-name,
|
|
||||||
.ruby .hljs-symbol,
|
|
||||||
.xml .hljs-cdata {
|
|
||||||
color: #b5bd68;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Aqua */
|
|
||||||
.hljs-title,
|
|
||||||
.hljs-section,
|
|
||||||
.css .hljs-hexcolor {
|
|
||||||
color: #8abeb7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Blue */
|
|
||||||
.hljs-function,
|
|
||||||
.python .hljs-decorator,
|
|
||||||
.python .hljs-title,
|
|
||||||
.ruby .hljs-function .hljs-title,
|
|
||||||
.ruby .hljs-title .hljs-keyword,
|
|
||||||
.perl .hljs-sub,
|
|
||||||
.javascript .hljs-title,
|
|
||||||
.coffeescript .hljs-title {
|
|
||||||
color: #81a2be;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tomorrow Purple */
|
|
||||||
.hljs-keyword,
|
|
||||||
.javascript .hljs-function {
|
|
||||||
color: #b294bb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
display: block;
|
|
||||||
overflow-x: auto;
|
|
||||||
background: #1d1f21;
|
|
||||||
color: #c5c8c6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coffeescript .javascript,
|
|
||||||
.javascript .xml,
|
|
||||||
.tex .hljs-formula,
|
|
||||||
.xml .javascript,
|
|
||||||
.xml .vbscript,
|
|
||||||
.xml .css,
|
|
||||||
.xml .hljs-cdata {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-addition {
|
|
||||||
color: #718c00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-deletion {
|
|
||||||
color: #c82829;
|
|
||||||
}
|
|
||||||
|
|
@ -1,299 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Declarative Workflow with VMFile.kdl - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="declarative-workflow-with-vmfilekdl"><a class="header" href="#declarative-workflow-with-vmfilekdl">Declarative Workflow with VMFile.kdl</a></h1>
|
|
||||||
<p>This tutorial shows how to define VMs in a configuration file and manage them with <code>vmctl up</code>/<code>down</code>.</p>
|
|
||||||
<h2 id="write-a-vmfile"><a class="header" href="#write-a-vmfile">Write a VMFile</a></h2>
|
|
||||||
<p>Create <code>VMFile.kdl</code> in your project directory:</p>
|
|
||||||
<pre><code class="language-kdl">vm "webserver" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
disk 20
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "webserver"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y nginx"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "echo 'Hello from vmctl!' | sudo tee /var/www/html/index.html"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="bring-it-up"><a class="header" href="#bring-it-up">Bring It Up</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl up
|
|
||||||
</code></pre>
|
|
||||||
<p>vmctl will:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Discover <code>VMFile.kdl</code> in the current directory.</li>
|
|
||||||
<li>Download the Ubuntu image (or use the cached copy).</li>
|
|
||||||
<li>Generate an Ed25519 SSH keypair for this VM.</li>
|
|
||||||
<li>Create a QCOW2 overlay with 20GB disk.</li>
|
|
||||||
<li>Build a cloud-init ISO with the hostname and generated SSH key.</li>
|
|
||||||
<li>Boot the VM.</li>
|
|
||||||
<li>Wait for SSH to become available.</li>
|
|
||||||
<li>Run the provision steps in order, streaming output to your terminal.</li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="connect"><a class="header" href="#connect">Connect</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl ssh
|
|
||||||
</code></pre>
|
|
||||||
<p>When there's only one VM in the VMFile, you don't need to specify the name.</p>
|
|
||||||
<h2 id="make-changes"><a class="header" href="#make-changes">Make Changes</a></h2>
|
|
||||||
<p>Edit <code>VMFile.kdl</code> to add another provisioner, then reload:</p>
|
|
||||||
<pre><code class="language-bash">vmctl reload
|
|
||||||
</code></pre>
|
|
||||||
<p>This destroys the existing VM and recreates it from scratch with the updated definition.</p>
|
|
||||||
<p>To re-run just the provisioners without recreating:</p>
|
|
||||||
<pre><code class="language-bash">vmctl provision
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="bring-it-down"><a class="header" href="#bring-it-down">Bring It Down</a></h2>
|
|
||||||
<p>Stop the VM:</p>
|
|
||||||
<pre><code class="language-bash">vmctl down
|
|
||||||
</code></pre>
|
|
||||||
<p>Or stop and destroy:</p>
|
|
||||||
<pre><code class="language-bash">vmctl down --destroy
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="filtering-by-name"><a class="header" href="#filtering-by-name">Filtering by Name</a></h2>
|
|
||||||
<p>If your VMFile defines multiple VMs, use <code>--name</code> to target a specific one:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up --name webserver
|
|
||||||
vmctl ssh --name webserver
|
|
||||||
vmctl down --name webserver
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../tutorials/imperative-vm.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/provisioning.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../tutorials/imperative-vm.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/provisioning.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,284 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Creating a VM Imperatively - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="creating-a-vm-imperatively"><a class="header" href="#creating-a-vm-imperatively">Creating a VM Imperatively</a></h1>
|
|
||||||
<p>This tutorial walks through the full lifecycle of a VM using individual vmctl commands.</p>
|
|
||||||
<h2 id="create-a-vm"><a class="header" href="#create-a-vm">Create a VM</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl create \
|
|
||||||
--name tutorial \
|
|
||||||
--image-url https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img \
|
|
||||||
--vcpus 2 \
|
|
||||||
--memory 2048 \
|
|
||||||
--ssh-key ~/.ssh/id_ed25519.pub
|
|
||||||
</code></pre>
|
|
||||||
<p>This downloads the image (cached for future use), creates a QCOW2 overlay, generates a cloud-init ISO with your SSH key, and registers the VM.</p>
|
|
||||||
<h2 id="start-it"><a class="header" href="#start-it">Start It</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl start tutorial
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="check-status"><a class="header" href="#check-status">Check Status</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl list
|
|
||||||
</code></pre>
|
|
||||||
<pre><code class="language-text">NAME BACKEND VCPUS MEM NETWORK PID SSH
|
|
||||||
tutorial qemu 2 2048 user 12345 10042
|
|
||||||
</code></pre>
|
|
||||||
<p>For detailed info:</p>
|
|
||||||
<pre><code class="language-bash">vmctl status tutorial
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="connect-via-ssh"><a class="header" href="#connect-via-ssh">Connect via SSH</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl ssh tutorial
|
|
||||||
</code></pre>
|
|
||||||
<p>vmctl waits for SSH to become available (cloud-init needs a moment to set up the user), then drops you into a shell.</p>
|
|
||||||
<h2 id="suspend-and-resume"><a class="header" href="#suspend-and-resume">Suspend and Resume</a></h2>
|
|
||||||
<p>Pause the VM without shutting it down:</p>
|
|
||||||
<pre><code class="language-bash">vmctl suspend tutorial
|
|
||||||
</code></pre>
|
|
||||||
<p>Resume it:</p>
|
|
||||||
<pre><code class="language-bash">vmctl resume tutorial
|
|
||||||
</code></pre>
|
|
||||||
<p>The VM continues from exactly where it was, no reboot needed.</p>
|
|
||||||
<h2 id="stop-the-vm"><a class="header" href="#stop-the-vm">Stop the VM</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl stop tutorial
|
|
||||||
</code></pre>
|
|
||||||
<p>This sends an ACPI power-down signal. If the guest doesn't shut down within 30 seconds, vmctl sends SIGTERM.</p>
|
|
||||||
<p>To change the timeout:</p>
|
|
||||||
<pre><code class="language-bash">vmctl stop tutorial --timeout 60
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="restart"><a class="header" href="#restart">Restart</a></h2>
|
|
||||||
<p>A stopped VM can be started again:</p>
|
|
||||||
<pre><code class="language-bash">vmctl start tutorial
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="destroy"><a class="header" href="#destroy">Destroy</a></h2>
|
|
||||||
<p>When you're done, clean up everything:</p>
|
|
||||||
<pre><code class="language-bash">vmctl destroy tutorial
|
|
||||||
</code></pre>
|
|
||||||
<p>This stops the VM (if running), removes the overlay, cloud-init ISO, and all work directory files, and unregisters the VM from the store.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../concepts/cloud-init-ssh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/declarative-workflow.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../concepts/cloud-init-ssh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/declarative-workflow.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,317 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Real-World: OmniOS Builder VM - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="real-world-omnios-builder-vm"><a class="header" href="#real-world-omnios-builder-vm">Real-World: OmniOS Builder VM</a></h1>
|
|
||||||
<p>This tutorial walks through the real-world VMFile.kdl used in the vm-manager project itself to build software on OmniOS (an illumos distribution).</p>
|
|
||||||
<h2 id="the-goal"><a class="header" href="#the-goal">The Goal</a></h2>
|
|
||||||
<p>Build a Rust binary (<code>forger</code>) on OmniOS. This requires:</p>
|
|
||||||
<ol>
|
|
||||||
<li>An OmniOS cloud VM with development tools.</li>
|
|
||||||
<li>Uploading the source code.</li>
|
|
||||||
<li>Compiling on the guest.</li>
|
|
||||||
</ol>
|
|
||||||
<h2 id="the-vmfile"><a class="header" href="#the-vmfile">The VMFile</a></h2>
|
|
||||||
<pre><code class="language-kdl">vm "omnios-builder" {
|
|
||||||
image-url "https://downloads.omnios.org/media/stable/omnios-r151056.cloud.qcow2"
|
|
||||||
vcpus 4
|
|
||||||
memory 4096
|
|
||||||
disk 20
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "omnios-builder"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "smithy"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
script "scripts/bootstrap-omnios.sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "file" {
|
|
||||||
source "scripts/forger-src.tar.gz"
|
|
||||||
destination "/tmp/forger-src.tar.gz"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
script "scripts/install-forger.sh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="stage-1-bootstrap-bootstrap-omniossh"><a class="header" href="#stage-1-bootstrap-bootstrap-omniossh">Stage 1: Bootstrap (<code>bootstrap-omnios.sh</code>)</a></h2>
|
|
||||||
<p>This script installs system packages and the Rust toolchain:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Sets up PATH for GNU tools (OmniOS ships BSD-style tools by default).</li>
|
|
||||||
<li>Installs <code>gcc14</code>, <code>gnu-make</code>, <code>pkg-config</code>, <code>openssl</code>, <code>curl</code>, <code>git</code>, and other build dependencies via IPS (<code>pkg install</code>).</li>
|
|
||||||
<li>Installs Rust via <code>rustup</code>.</li>
|
|
||||||
<li>Verifies all tools are available.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="stage-2-upload-source"><a class="header" href="#stage-2-upload-source">Stage 2: Upload Source</a></h2>
|
|
||||||
<p>The <code>file</code> provisioner uploads a pre-packed tarball of the forger source code. This tarball is created beforehand with:</p>
|
|
||||||
<pre><code class="language-bash">./scripts/pack-forger.sh
|
|
||||||
</code></pre>
|
|
||||||
<p>The pack script:</p>
|
|
||||||
<ul>
|
|
||||||
<li>Copies <code>crates/forger</code>, <code>crates/spec-parser</code>, and <code>images/</code> into a staging directory.</li>
|
|
||||||
<li>Generates a minimal workspace <code>Cargo.toml</code>.</li>
|
|
||||||
<li>Includes <code>Cargo.lock</code> for reproducible builds.</li>
|
|
||||||
<li>Creates <code>scripts/forger-src.tar.gz</code>.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="stage-3-build-and-install-install-forgersh"><a class="header" href="#stage-3-build-and-install-install-forgersh">Stage 3: Build and Install (<code>install-forger.sh</code>)</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Extracts the tarball to <code>$HOME/forger</code>.</li>
|
|
||||||
<li>Runs <code>cargo build -p forger --release</code>.</li>
|
|
||||||
<li>Copies the binary to <code>/usr/local/bin/forger</code>.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="the-full-workflow"><a class="header" href="#the-full-workflow">The Full Workflow</a></h2>
|
|
||||||
<pre><code class="language-bash"># Pack the source on the host
|
|
||||||
./scripts/pack-forger.sh
|
|
||||||
|
|
||||||
# Bring up the VM, provision, and build
|
|
||||||
vmctl up
|
|
||||||
|
|
||||||
# SSH in to test the binary
|
|
||||||
vmctl ssh
|
|
||||||
forger --help
|
|
||||||
|
|
||||||
# Tear it down when done
|
|
||||||
vmctl down --destroy
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="key-takeaways"><a class="header" href="#key-takeaways">Key Takeaways</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Multi-stage provisioning</strong> separates concerns: system setup, source upload, build.</li>
|
|
||||||
<li><strong>File provisioners</strong> transfer artifacts to the guest.</li>
|
|
||||||
<li><strong>Script provisioners</strong> are easier to iterate on than inline commands for complex logic.</li>
|
|
||||||
<li><strong>Streaming output</strong> lets you watch the build progress in real-time.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../tutorials/provisioning.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/overview.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../tutorials/provisioning.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/overview.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,305 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Provisioning - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="provisioning"><a class="header" href="#provisioning">Provisioning</a></h1>
|
|
||||||
<p>Provisioners run commands and upload files to a VM after it boots. They execute in order and stop on the first failure.</p>
|
|
||||||
<h2 id="provision-types"><a class="header" href="#provision-types">Provision Types</a></h2>
|
|
||||||
<h3 id="shell-with-inline-command"><a class="header" href="#shell-with-inline-command">Shell with Inline Command</a></h3>
|
|
||||||
<p>Execute a command directly on the guest:</p>
|
|
||||||
<pre><code class="language-kdl">provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y curl"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h3 id="shell-with-script-file"><a class="header" href="#shell-with-script-file">Shell with Script File</a></h3>
|
|
||||||
<p>Upload and execute a local script:</p>
|
|
||||||
<pre><code class="language-kdl">provision "shell" {
|
|
||||||
script "scripts/setup.sh"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>The script is uploaded to <code>/tmp/vmctl-provision-<step>.sh</code> on the guest, made executable, and run. Paths are relative to the directory containing <code>VMFile.kdl</code>.</p>
|
|
||||||
<h3 id="file-upload"><a class="header" href="#file-upload">File Upload</a></h3>
|
|
||||||
<p>Upload a file to the guest via SFTP:</p>
|
|
||||||
<pre><code class="language-kdl">provision "file" {
|
|
||||||
source "config/nginx.conf"
|
|
||||||
destination "/tmp/nginx.conf"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="execution-details"><a class="header" href="#execution-details">Execution Details</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Shell provisioners stream stdout/stderr to your terminal in real-time.</li>
|
|
||||||
<li>A non-zero exit code aborts the entire provisioning sequence.</li>
|
|
||||||
<li>Output is logged to <code>provision.log</code> in the VM's work directory.</li>
|
|
||||||
<li>vmctl waits up to 120 seconds for SSH to become available before provisioning starts.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="multi-stage-example"><a class="header" href="#multi-stage-example">Multi-Stage Example</a></h2>
|
|
||||||
<p>A common pattern is to combine file uploads with shell commands:</p>
|
|
||||||
<pre><code class="language-kdl">vm "builder" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 4
|
|
||||||
memory 4096
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "builder"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage 1: Install dependencies
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y build-essential"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage 2: Upload source code
|
|
||||||
provision "file" {
|
|
||||||
source "src.tar.gz"
|
|
||||||
destination "/tmp/src.tar.gz"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stage 3: Build
|
|
||||||
provision "shell" {
|
|
||||||
inline "cd /tmp && tar xzf src.tar.gz && cd src && make"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="re-running-provisioners"><a class="header" href="#re-running-provisioners">Re-Running Provisioners</a></h2>
|
|
||||||
<p>To re-run provisioners on an already-running VM:</p>
|
|
||||||
<pre><code class="language-bash">vmctl provision
|
|
||||||
</code></pre>
|
|
||||||
<p>Or for a specific VM:</p>
|
|
||||||
<pre><code class="language-bash">vmctl provision --name builder
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="viewing-provision-logs"><a class="header" href="#viewing-provision-logs">Viewing Provision Logs</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl log builder --provision
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../tutorials/declarative-workflow.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/omnios-builder.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../tutorials/declarative-workflow.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../tutorials/omnios-builder.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,265 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Cloud-Init Block - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="cloud-init-block"><a class="header" href="#cloud-init-block">Cloud-Init Block</a></h1>
|
|
||||||
<p>The <code>cloud-init</code> block configures guest initialization via cloud-init's NoCloud datasource.</p>
|
|
||||||
<h2 id="syntax"><a class="header" href="#syntax">Syntax</a></h2>
|
|
||||||
<pre><code class="language-kdl">cloud-init {
|
|
||||||
hostname "myvm"
|
|
||||||
ssh-key "~/.ssh/id_ed25519.pub"
|
|
||||||
user-data "path/to/cloud-config.yaml"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>All fields are optional.</p>
|
|
||||||
<h2 id="fields"><a class="header" href="#fields">Fields</a></h2>
|
|
||||||
<h3 id="hostname"><a class="header" href="#hostname">hostname</a></h3>
|
|
||||||
<pre><code class="language-kdl">hostname "myvm"
|
|
||||||
</code></pre>
|
|
||||||
<p>Sets the guest hostname via cloud-init metadata.</p>
|
|
||||||
<h3 id="ssh-key"><a class="header" href="#ssh-key">ssh-key</a></h3>
|
|
||||||
<pre><code class="language-kdl">ssh-key "~/.ssh/id_ed25519.pub"
|
|
||||||
</code></pre>
|
|
||||||
<p>Path to an SSH public key file. The key is injected into the cloud-config's <code>authorized_keys</code> for the SSH user. Path is resolved relative to the VMFile directory.</p>
|
|
||||||
<h3 id="user-data"><a class="header" href="#user-data">user-data</a></h3>
|
|
||||||
<pre><code class="language-kdl">user-data "cloud-config.yaml"
|
|
||||||
</code></pre>
|
|
||||||
<p>Path to a raw cloud-config YAML file. When this is set, vmctl passes the file contents directly as user-data without generating its own cloud-config. You are responsible for user creation and SSH setup.</p>
|
|
||||||
<p><strong>Mutually exclusive with <code>ssh-key</code></strong> in practice - if you provide raw user-data, vmctl won't inject any SSH keys.</p>
|
|
||||||
<h2 id="auto-generated-ssh-keys"><a class="header" href="#auto-generated-ssh-keys">Auto-Generated SSH Keys</a></h2>
|
|
||||||
<p>When a <code>cloud-init</code> block is present but neither <code>ssh-key</code> nor <code>user-data</code> is specified, vmctl automatically:</p>
|
|
||||||
<ol>
|
|
||||||
<li>Generates a per-VM Ed25519 keypair.</li>
|
|
||||||
<li>Injects the public key into the cloud-config.</li>
|
|
||||||
<li>Stores both keys in the VM's work directory.</li>
|
|
||||||
</ol>
|
|
||||||
<p>This is the recommended approach for most use cases.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/network.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/ssh.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/network.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/ssh.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,314 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Full Example - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="full-example"><a class="header" href="#full-example">Full Example</a></h1>
|
|
||||||
<p>A complete VMFile.kdl demonstrating every available feature:</p>
|
|
||||||
<pre><code class="language-kdl">// Development VM with all options specified
|
|
||||||
vm "full-example" {
|
|
||||||
// Image source: URL (auto-cached)
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
|
|
||||||
// Resources
|
|
||||||
vcpus 4
|
|
||||||
memory 4096
|
|
||||||
disk 40
|
|
||||||
|
|
||||||
// Networking: user-mode (default, no root needed)
|
|
||||||
network "user"
|
|
||||||
|
|
||||||
// Cloud-init guest configuration
|
|
||||||
cloud-init {
|
|
||||||
hostname "full-example"
|
|
||||||
// ssh-key and user-data are omitted, so vmctl auto-generates an Ed25519 keypair
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSH connection settings
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
// private-key is omitted, so vmctl uses the auto-generated key
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provisioners run in order after boot
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y build-essential curl git"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "file" {
|
|
||||||
source "config/bashrc"
|
|
||||||
destination "/home/ubuntu/.bashrc"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
script "scripts/setup-dev-tools.sh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second VM demonstrating TAP networking and explicit keys
|
|
||||||
vm "tap-example" {
|
|
||||||
image "~/images/debian-12-generic-amd64.qcow2"
|
|
||||||
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
network "tap" {
|
|
||||||
bridge "br0"
|
|
||||||
}
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "tap-vm"
|
|
||||||
ssh-key "~/.ssh/id_ed25519.pub"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "debian"
|
|
||||||
private-key "~/.ssh/id_ed25519"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Minimal VM: just an image and defaults
|
|
||||||
vm "minimal" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="what-happens"><a class="header" href="#what-happens">What Happens</a></h2>
|
|
||||||
<p>Running <code>vmctl up</code> with this VMFile:</p>
|
|
||||||
<ol>
|
|
||||||
<li><strong>full-example</strong>: Downloads the Ubuntu image, creates a 40GB overlay, auto-generates SSH keys, boots with 4 vCPUs / 4GB RAM, runs three provisioners.</li>
|
|
||||||
<li><strong>tap-example</strong>: Uses a local Debian image, sets up TAP networking on <code>br0</code>, injects your existing SSH key.</li>
|
|
||||||
<li><strong>minimal</strong>: Downloads the same Ubuntu image (cache hit), boots with defaults (1 vCPU, 1GB RAM, user networking), no cloud-init, no provisioning.</li>
|
|
||||||
</ol>
|
|
||||||
<p>Use <code>--name</code> to target specific VMs:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up --name full-example
|
|
||||||
vmctl ssh --name tap-example
|
|
||||||
vmctl down --name minimal
|
|
||||||
</code></pre>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/multi-vm.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/vmctl.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/multi-vm.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../cli/vmctl.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Image Sources - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="image-sources"><a class="header" href="#image-sources">Image Sources</a></h1>
|
|
||||||
<p>Every VM must specify exactly one image source. The two options are mutually exclusive.</p>
|
|
||||||
<h2 id="local-image"><a class="header" href="#local-image">Local Image</a></h2>
|
|
||||||
<pre><code class="language-kdl">image "path/to/image.qcow2"
|
|
||||||
</code></pre>
|
|
||||||
<p>Points to a disk image on the host filesystem. The path is resolved relative to the VMFile directory, with tilde expansion.</p>
|
|
||||||
<p>The file must exist at parse time. Supported formats are auto-detected by <code>qemu-img</code> (qcow2, raw, etc.).</p>
|
|
||||||
<h2 id="remote-image"><a class="header" href="#remote-image">Remote Image</a></h2>
|
|
||||||
<pre><code class="language-kdl">image-url "https://example.com/image.qcow2"
|
|
||||||
</code></pre>
|
|
||||||
<p>Downloads the image and caches it in <code>~/.local/share/vmctl/images/</code>. If the image is already cached, it won't be re-downloaded.</p>
|
|
||||||
<p>URLs ending in <code>.zst</code> or <code>.zstd</code> are automatically decompressed after download.</p>
|
|
||||||
<h2 id="validation"><a class="header" href="#validation">Validation</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Exactly one of <code>image</code> or <code>image-url</code> must be specified.</li>
|
|
||||||
<li>Specifying both is an error.</li>
|
|
||||||
<li>Specifying neither is an error.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/vm-block.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/resources.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/vm-block.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/resources.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,290 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Multi-VM Definitions - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="multi-vm-definitions"><a class="header" href="#multi-vm-definitions">Multi-VM Definitions</a></h1>
|
|
||||||
<p>A VMFile can define multiple VMs. Each <code>vm</code> block is independent.</p>
|
|
||||||
<h2 id="example"><a class="header" href="#example">Example</a></h2>
|
|
||||||
<pre><code class="language-kdl">vm "web" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 2048
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "web"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y nginx"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm "db" {
|
|
||||||
image-url "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
|
||||||
vcpus 2
|
|
||||||
memory 4096
|
|
||||||
disk 50
|
|
||||||
|
|
||||||
cloud-init {
|
|
||||||
hostname "db"
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh {
|
|
||||||
user "ubuntu"
|
|
||||||
}
|
|
||||||
|
|
||||||
provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y postgresql"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="behavior-with-multi-vm"><a class="header" href="#behavior-with-multi-vm">Behavior with Multi-VM</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li><code>vmctl up</code> brings up all VMs in order.</li>
|
|
||||||
<li><code>vmctl down</code> stops all VMs.</li>
|
|
||||||
<li><code>vmctl ssh</code> requires <code>--name</code> when multiple VMs are defined (or it will error).</li>
|
|
||||||
<li>Use <code>--name</code> with any command to target a specific VM.</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="filtering"><a class="header" href="#filtering">Filtering</a></h2>
|
|
||||||
<pre><code class="language-bash">vmctl up --name web # only bring up "web"
|
|
||||||
vmctl provision --name db # re-provision only "db"
|
|
||||||
vmctl down --name web # stop only "web"
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="constraints"><a class="header" href="#constraints">Constraints</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>VM names must be unique within the file.</li>
|
|
||||||
<li>Each VM is fully independent (no shared networking or cross-references).</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/provision.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/full-example.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/provision.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/full-example.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Network Block - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="network-block"><a class="header" href="#network-block">Network Block</a></h1>
|
|
||||||
<p>The <code>network</code> node configures VM networking.</p>
|
|
||||||
<h2 id="syntax"><a class="header" href="#syntax">Syntax</a></h2>
|
|
||||||
<pre><code class="language-kdl">network "mode"
|
|
||||||
// or
|
|
||||||
network "mode" {
|
|
||||||
// mode-specific attributes
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="modes"><a class="header" href="#modes">Modes</a></h2>
|
|
||||||
<h3 id="user-default"><a class="header" href="#user-default">User (Default)</a></h3>
|
|
||||||
<pre><code class="language-kdl">network "user"
|
|
||||||
</code></pre>
|
|
||||||
<p>QEMU's SLIRP user-mode networking. No root required. SSH access is via a forwarded host port.</p>
|
|
||||||
<h3 id="tap"><a class="header" href="#tap">TAP</a></h3>
|
|
||||||
<pre><code class="language-kdl">network "tap"
|
|
||||||
// or with explicit bridge:
|
|
||||||
network "tap" {
|
|
||||||
bridge "br0"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>TAP device attached to a Linux bridge. The guest appears on the bridge's network with a real IP.</p>
|
|
||||||
<p><strong>Default bridge:</strong> <code>"br0"</code></p>
|
|
||||||
<h3 id="none"><a class="header" href="#none">None</a></h3>
|
|
||||||
<pre><code class="language-kdl">network "none"
|
|
||||||
</code></pre>
|
|
||||||
<p>No networking.</p>
|
|
||||||
<h2 id="default"><a class="header" href="#default">Default</a></h2>
|
|
||||||
<p>If no <code>network</code> node is specified, user-mode networking is used.</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/resources.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/cloud-init.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/resources.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/cloud-init.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,272 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Overview - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="vmfilekdl-overview"><a class="header" href="#vmfilekdl-overview">VMFile.kdl Overview</a></h1>
|
|
||||||
<p><code>VMFile.kdl</code> is the declarative configuration format for vmctl. It uses <a href="https://kdl.dev">KDL</a> (KDL Document Language), a human-friendly configuration language.</p>
|
|
||||||
<h2 id="discovery"><a class="header" href="#discovery">Discovery</a></h2>
|
|
||||||
<p>vmctl looks for <code>VMFile.kdl</code> in the current directory by default. You can override this with <code>--file</code>:</p>
|
|
||||||
<pre><code class="language-bash">vmctl up --file path/to/MyVMFile.kdl
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="basic-structure"><a class="header" href="#basic-structure">Basic Structure</a></h2>
|
|
||||||
<p>A VMFile contains one or more <code>vm</code> blocks, each defining a virtual machine:</p>
|
|
||||||
<pre><code class="language-kdl">vm "name" {
|
|
||||||
// image source (required)
|
|
||||||
// resources
|
|
||||||
// networking
|
|
||||||
// cloud-init
|
|
||||||
// ssh config
|
|
||||||
// provisioners
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="path-resolution"><a class="header" href="#path-resolution">Path Resolution</a></h2>
|
|
||||||
<p>All paths in a VMFile are resolved relative to the directory containing the VMFile. Tilde (<code>~</code>) is expanded to the user's home directory.</p>
|
|
||||||
<pre><code class="language-kdl">// Relative to VMFile directory
|
|
||||||
image "images/ubuntu.qcow2"
|
|
||||||
|
|
||||||
// Absolute path
|
|
||||||
image "/opt/images/ubuntu.qcow2"
|
|
||||||
|
|
||||||
// Home directory expansion
|
|
||||||
cloud-init {
|
|
||||||
ssh-key "~/.ssh/id_ed25519.pub"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<h2 id="validation"><a class="header" href="#validation">Validation</a></h2>
|
|
||||||
<p>vmctl validates the VMFile on parse and provides detailed error messages with hints:</p>
|
|
||||||
<ul>
|
|
||||||
<li>VM names must be unique.</li>
|
|
||||||
<li>Each VM must have exactly one image source (<code>image</code> or <code>image-url</code>, not both).</li>
|
|
||||||
<li>Shell provisioners must have exactly one of <code>inline</code> or <code>script</code>.</li>
|
|
||||||
<li>File provisioners must have both <code>source</code> and <code>destination</code>.</li>
|
|
||||||
<li>Network type must be <code>"user"</code>, <code>"tap"</code>, or <code>"none"</code>.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../tutorials/omnios-builder.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/vm-block.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../tutorials/omnios-builder.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/vm-block.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,271 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Provision Blocks - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="provision-blocks"><a class="header" href="#provision-blocks">Provision Blocks</a></h1>
|
|
||||||
<p>Provision blocks define steps to run on the guest after boot. They execute in order and abort on the first failure.</p>
|
|
||||||
<h2 id="shell-provisioner"><a class="header" href="#shell-provisioner">Shell Provisioner</a></h2>
|
|
||||||
<h3 id="inline-command"><a class="header" href="#inline-command">Inline Command</a></h3>
|
|
||||||
<pre><code class="language-kdl">provision "shell" {
|
|
||||||
inline "sudo apt-get update && sudo apt-get install -y nginx"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Executes the command directly on the guest via SSH.</p>
|
|
||||||
<h3 id="script-file"><a class="header" href="#script-file">Script File</a></h3>
|
|
||||||
<pre><code class="language-kdl">provision "shell" {
|
|
||||||
script "scripts/setup.sh"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>The script file is uploaded to <code>/tmp/vmctl-provision-<step>.sh</code> on the guest, made executable with <code>chmod +x</code>, and executed. The path is resolved relative to the VMFile directory.</p>
|
|
||||||
<h3 id="validation"><a class="header" href="#validation">Validation</a></h3>
|
|
||||||
<p>A shell provisioner must have exactly one of <code>inline</code> or <code>script</code>. Specifying both or neither is an error.</p>
|
|
||||||
<h2 id="file-provisioner"><a class="header" href="#file-provisioner">File Provisioner</a></h2>
|
|
||||||
<pre><code class="language-kdl">provision "file" {
|
|
||||||
source "config/app.conf"
|
|
||||||
destination "/etc/app/app.conf"
|
|
||||||
}
|
|
||||||
</code></pre>
|
|
||||||
<p>Uploads a local file to the guest via SFTP.</p>
|
|
||||||
<h3 id="required-fields"><a class="header" href="#required-fields">Required Fields</a></h3>
|
|
||||||
<div class="table-wrapper"><table><thead><tr><th>Field</th><th>Description</th></tr></thead><tbody>
|
|
||||||
<tr><td><code>source</code></td><td>Local file path (relative to VMFile directory)</td></tr>
|
|
||||||
<tr><td><code>destination</code></td><td>Absolute path on the guest</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
<h2 id="execution-behavior"><a class="header" href="#execution-behavior">Execution Behavior</a></h2>
|
|
||||||
<ul>
|
|
||||||
<li>Provisioners run sequentially in the order they appear.</li>
|
|
||||||
<li>Shell provisioners stream stdout and stderr to your terminal in real-time.</li>
|
|
||||||
<li>A non-zero exit code from any shell provisioner aborts the sequence.</li>
|
|
||||||
<li>All output is also logged to <code>provision.log</code> in the VM's work directory.</li>
|
|
||||||
<li>vmctl waits up to 120 seconds for SSH to become available before starting provisioners.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/ssh.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/multi-vm.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/ssh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/multi-vm.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en" class="navy sidebar-visible" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<!-- Book generated using mdBook -->
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Resources - vmctl Documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom HTML head -->
|
|
||||||
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="theme-color" content="#ffffff">
|
|
||||||
|
|
||||||
<link rel="icon" href="../favicon.svg">
|
|
||||||
<link rel="shortcut icon" href="../favicon.png">
|
|
||||||
<link rel="stylesheet" href="../css/variables.css">
|
|
||||||
<link rel="stylesheet" href="../css/general.css">
|
|
||||||
<link rel="stylesheet" href="../css/chrome.css">
|
|
||||||
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
||||||
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
||||||
|
|
||||||
<!-- Highlight.js Stylesheets -->
|
|
||||||
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
||||||
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
||||||
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
||||||
|
|
||||||
<!-- Custom theme stylesheets -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Provide site root and default themes to javascript -->
|
|
||||||
<script>
|
|
||||||
const path_to_root = "../";
|
|
||||||
const default_light_theme = "navy";
|
|
||||||
const default_dark_theme = "navy";
|
|
||||||
window.path_to_searchindex_js = "../searchindex.js";
|
|
||||||
</script>
|
|
||||||
<!-- Start loading toc.js asap -->
|
|
||||||
<script src="../toc.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="mdbook-help-container">
|
|
||||||
<div id="mdbook-help-popup">
|
|
||||||
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
||||||
<div>
|
|
||||||
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
||||||
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
||||||
<p>Press <kbd>?</kbd> to show this help</p>
|
|
||||||
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="body-container">
|
|
||||||
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
||||||
<script>
|
|
||||||
try {
|
|
||||||
let theme = localStorage.getItem('mdbook-theme');
|
|
||||||
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
||||||
|
|
||||||
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
||||||
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
||||||
<script>
|
|
||||||
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
||||||
let theme;
|
|
||||||
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
||||||
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
||||||
const html = document.documentElement;
|
|
||||||
html.classList.remove('navy')
|
|
||||||
html.classList.add(theme);
|
|
||||||
html.classList.add("js");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
||||||
|
|
||||||
<!-- Hide / unhide sidebar before it is displayed -->
|
|
||||||
<script>
|
|
||||||
let sidebar = null;
|
|
||||||
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
||||||
if (document.body.clientWidth >= 1080) {
|
|
||||||
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
||||||
sidebar = sidebar || 'visible';
|
|
||||||
} else {
|
|
||||||
sidebar = 'hidden';
|
|
||||||
sidebar_toggle.checked = false;
|
|
||||||
}
|
|
||||||
if (sidebar === 'visible') {
|
|
||||||
sidebar_toggle.checked = true;
|
|
||||||
} else {
|
|
||||||
html.classList.remove('sidebar-visible');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
||||||
<!-- populated by js -->
|
|
||||||
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
||||||
<noscript>
|
|
||||||
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
||||||
</noscript>
|
|
||||||
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
||||||
<div class="sidebar-resize-indicator"></div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div id="page-wrapper" class="page-wrapper">
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div id="menu-bar-hover-placeholder"></div>
|
|
||||||
<div id="menu-bar" class="menu-bar sticky">
|
|
||||||
<div class="left-buttons">
|
|
||||||
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</label>
|
|
||||||
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
||||||
<i class="fa fa-paint-brush"></i>
|
|
||||||
</button>
|
|
||||||
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
||||||
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
||||||
</ul>
|
|
||||||
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1 class="menu-title">vmctl Documentation</h1>
|
|
||||||
|
|
||||||
<div class="right-buttons">
|
|
||||||
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
||||||
<i id="print-button" class="fa fa-print"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/toasty/vm-manager" title="Git repository" aria-label="Git repository">
|
|
||||||
<i id="git-repository-button" class="fa fa-github"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="search-wrapper" class="hidden">
|
|
||||||
<form id="searchbar-outer" class="searchbar-outer">
|
|
||||||
<div class="search-wrapper">
|
|
||||||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
||||||
<div class="spinner-wrapper">
|
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
||||||
<div id="searchresults-header" class="searchresults-header"></div>
|
|
||||||
<ul id="searchresults">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
||||||
<script>
|
|
||||||
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
||||||
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
||||||
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
||||||
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div id="content" class="content">
|
|
||||||
<main>
|
|
||||||
<h1 id="resources"><a class="header" href="#resources">Resources</a></h1>
|
|
||||||
<p>Resource nodes control the VM's CPU, memory, and disk allocation.</p>
|
|
||||||
<h2 id="vcpus"><a class="header" href="#vcpus">vcpus</a></h2>
|
|
||||||
<pre><code class="language-kdl">vcpus 2
|
|
||||||
</code></pre>
|
|
||||||
<p>Number of virtual CPUs. Must be greater than 0.</p>
|
|
||||||
<p><strong>Default:</strong> <code>1</code></p>
|
|
||||||
<h2 id="memory"><a class="header" href="#memory">memory</a></h2>
|
|
||||||
<pre><code class="language-kdl">memory 2048
|
|
||||||
</code></pre>
|
|
||||||
<p>Memory in megabytes. Must be greater than 0.</p>
|
|
||||||
<p><strong>Default:</strong> <code>1024</code> (1 GB)</p>
|
|
||||||
<h2 id="disk"><a class="header" href="#disk">disk</a></h2>
|
|
||||||
<pre><code class="language-kdl">disk 20
|
|
||||||
</code></pre>
|
|
||||||
<p>Disk size in gigabytes. When specified, the QCOW2 overlay is created with this size, allowing the guest to use more space than the base image provides. Most cloud images auto-grow the filesystem via cloud-init.</p>
|
|
||||||
<p><strong>Default:</strong> not set (overlay matches base image size)</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
||||||
<!-- Mobile navigation buttons -->
|
|
||||||
<a rel="prev" href="../vmfile/image-sources.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/network.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div style="clear: both"></div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
||||||
<a rel="prev" href="../vmfile/image-sources.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
||||||
<i class="fa fa-angle-left"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a rel="next prefetch" href="../vmfile/network.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
||||||
<i class="fa fa-angle-right"></i>
|
|
||||||
</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.playground_copyable = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="../elasticlunr.min.js"></script>
|
|
||||||
<script src="../mark.min.js"></script>
|
|
||||||
<script src="../searcher.js"></script>
|
|
||||||
|
|
||||||
<script src="../clipboard.min.js"></script>
|
|
||||||
<script src="../highlight.js"></script>
|
|
||||||
<script src="../book.js"></script>
|
|
||||||
|
|
||||||
<!-- Custom JS scripts -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue