| modeline | vim: set ft=pandoc: |
|---|---|
| description | The sylve-iso builder creates a Bhyve virtual machine via the Sylve API, boots it from an ISO image, runs provisioners over SSH, and produces an artifact from the resulting VM state. |
| page_title | Sylve ISO - Builders |
| nav_title | ISO |
Type: sylve-iso
Artifact BuilderId: xoro.sylveiso
The sylve-iso builder creates a new Bhyve virtual machine through the
Sylve REST API, boots it from an ISO image that is fetched via
Sylve's built-in download manager, runs Packer provisioners over SSH, and
produces an artifact from the resulting VM state. The VM is deleted from
Sylve after a successful build by default (destroy = true).
| Platform | Artifact BuilderId |
|---|---|
| Sylve / Bhyve (FreeBSD) | xoro.sylveiso |
~> Note: This example is illustrative. Adjust sylve_url, switch_name,
and ISO URL to match your environment.
packer {
required_plugins {
sylve = {
version = ">= 0.1.0"
source = "github.com/xoro/sylve"
}
}
}
source "sylve-iso" "freebsd" {
sylve_url = "https://192.168.1.10:8181"
sylve_token = env("SYLVE_TOKEN")
iso_download_url = "https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/15.0/FreeBSD-15.0-RELEASE-amd64-dvd1.iso"
switch_name = "packer-switch"
vm_name = "freebsd-packer"
cpu_cores = 2
ram = 2048
storage_size_mb = 20480
boot_wait = "15s"
boot_command = [
"<enter>",
]
ssh_username = "root"
ssh_password = "sylve-example"
ssh_timeout = "30m"
shutdown_command = "/sbin/poweroff"
destroy = true
}
build {
sources = ["source.sylve-iso.freebsd"]
provisioner "shell" {
inline = ["pkg install -y curl"]
}
}The builder requires either a pre-issued Bearer token or a username and password pair. Exactly one authentication method must be provided.
Required (one of):
-
sylve_token(string) - A pre-issued Bearer token for the Sylve API. Falls back to theSYLVE_TOKENenvironment variable. When supplied,sylve_userandsylve_passwordare ignored. When absent, the builder performs a login at the start of the build and a logout when it finishes. -
sylve_user(string) - Sylve account username for login-based authentication. Falls back to theSYLVE_USERenvironment variable. Required whensylve_tokenis not set. -
sylve_password(string) - Sylve account password for login-based authentication. Falls back to theSYLVE_PASSWORDenvironment variable. Required whensylve_tokenis not set.
Required:
-
iso_download_url(string) - A URL passed to the Sylve download manager. The plugin triggers the download and polls until the download status becomes"done". Supports HTTP, HTTPS, and any scheme accepted by Sylve. -
switch_name(string) - Name of a DHCP-enabled Sylve virtual switch to attach the VM's network interface to. Falls back to theSYLVE_SWITCHenvironment variable.
Optional:
-
sylve_url(string) - Base URL of the Sylve instance including scheme and port. Defaults tohttps://localhost:8181. Alternatively set theSYLVE_HOSTenvironment variable to just the hostname (e.g.server.example.com) and the plugin constructshttps://<host>:8181automatically. -
sylve_auth_type(string) - Authentication type used in the login request. Valid values:"sylve"(native database account, default) or"pam"(PAM authentication). Falls back to theSYLVE_AUTH_TYPEenvironment variable. -
tls_skip_verify(bool) - Disables TLS certificate verification. Defaults totruebecause Sylve ships with a self-signed certificate. Set tofalsewhen using a trusted certificate. -
sylve_api_login_timeout(string) - How long to keep retrying the initial login when the Sylve API is unreachable (e.g. the service is still starting). Accepts Go duration strings, e.g."2m","5m". Ignored whensylve_tokenis set. Defaults to"2m". Falls back to theSYLVE_API_LOGIN_TIMEOUTenvironment variable.
Optional:
-
vm_name(string) - Name prefix for the temporary VM. A UUID suffix is appended automatically to avoid collisions. Defaults to a generated name. -
cpu_cores(int) - Number of vCPU cores per socket. Defaults to2. -
cpu_sockets(int) - Number of vCPU sockets. Defaults to1. -
cpu_threads(int) - Number of threads per core. Defaults to1. -
ram(int) - Amount of memory in MiB. Defaults to1024. -
loader(string) - VM firmware loader."uefi"(default) for UEFI boot or"bios"for legacy BIOS boot. -
time_offset(string) - Guest clock offset."utc"(default) or"localtime".
~> Note: ACPI and APIC are always enabled. Bhyve requires both for correct guest power management and interrupt routing.
Optional:
-
storage_pool(string) - ZFS pool name on the Sylve host to create the install disk in. Falls back to theSYLVE_POOLenvironment variable. When still empty, the plugin selects the first pool from Sylve's basic settings. -
storage_size_mb(int) - Install disk size in MiB. Defaults to65536(64 GiB). -
storage_type(string) - Zvol type. Defaults to"zvol". -
storage_emulation_type(string) - Disk emulation type for the install disk. Defaults to"virtio-blk".
Optional:
switch_emulation_type(string) - NIC emulation type for the virtual switch interface. Defaults to"e1000".
The builder uses a VNC connection through the Sylve WebSocket proxy to send boot commands to the guest console.
Optional:
-
vnc_port_min(int) - Lower bound of the VNC port range (inclusive). Defaults to5900. Must be >=5900. -
vnc_port_max(int) - Upper bound of the VNC port range (inclusive). Defaults to5999. -
vnc_host(string) - Hostname or IP address used for the VNC connection. Defaults to the host portion ofsylve_url, so that Packer running remotely (e.g. from macOS) connects to the correct Sylve server without additional configuration. -
vnc_password(string) - Optional VNC password. Leave empty when Sylve is not configured with a VNC password. -
vnc_resolution(string) - VNC display resolution passed to Sylve on VM creation. Defaults to"1024x768".
Optional:
-
boot_wait(string) - Duration to wait after the VM starts before sending VNC boot commands. Accepts Go duration strings (e.g."10s","2m"). Defaults to"10s". -
boot_key_interval(duration) - Delay between each key group inboot_command. Defaults to200ms. Increase this value if keystrokes are dropped on a high-latency connection. -
boot_command([]string) - List of VNC keyboard sequences to type at the guest console afterboot_wait. Supports the same key syntax as other Packer VNC builders (e.g."<enter>","<leftAltOn><F2><leftAltOff>").
The builder can serve a local directory over HTTP to the guest during provisioning (e.g. for preseed or kickstart files).
Optional:
-
http_directory(string) - Path to a local directory to serve over HTTP to the guest. The URL is available in boot commands via the{{ .HTTPIP }}and{{ .HTTPPort }}template variables. -
http_port_min(int) - Minimum port number for the HTTP server. Defaults to8000. -
http_port_max(int) - Maximum port number for the HTTP server. Defaults to9000. -
http_bind_address(string) - Address on which the HTTP server listens. Defaults to0.0.0.0.
Optional:
shutdown_command(string) - Command sent over SSH to shut down the provisioned VM gracefully. Defaults to"/sbin/poweroff".
Optional:
-
destroy(bool) - Whether to delete the VM from Sylve after a successful build. Defaults tofalse(VM is kept). Set totrueto delete the VM after a successful build. On error, deletion followskeep_on_error; on cancellation the VM is always deleted regardless of this setting. -
keep_on_error(bool) - Whether to keep the VM alive when the build fails. Defaults tofalse. Set totrueto keep the VM running for post-failure debugging (equivalent to-on-error=abort).
When Packer runs on a different machine than Sylve (e.g. from macOS against a
FreeBSD server), the provisioned VM's IP address (10.x.x.x on the Sylve
virtual switch) is not directly routable from the Packer host. The plugin can
automatically configure Packer's SSH communicator to use the Sylve host as an
SSH bastion/jump host, so no static routes or VPN are required.
This is always active when Packer is running on a different host than
Sylve. It is automatically skipped when the Sylve URL resolves to a local
interface address (i.e. Packer is running on the Sylve host itself), or when
an explicit ssh_bastion_host field is already set in HCL.
The plugin resolves bastion credentials in this order:
- Explicit
ssh_bastion_*fields already set in HCL — used as-is. SYLVE_SSH_PROXY_KEYenvironment variable — path to a private key file.~/.ssh/configIdentityFilematching the Sylve hostname — picked up automatically, no configuration required.- Default key paths —
~/.ssh/id_ed25519,id_ecdsa_sk,id_ecdsa,id_dsa,id_rsa(in that order). Each file is tested withssh.ParsePrivateKey; passphrase-protected and FIDO2/hardware keys are skipped. The first parseable key wins. - SSH agent (
ssh_bastion_agent_auth = true) — used when no key is found or parseable.
The bastion username is resolved in this order: explicit HCL
ssh_bastion_username > ~/.ssh/config User for the host > $USER.
~> Note: sylve_user and sylve_password are not used for the
bastion connection. They are Sylve API credentials and are unrelated to the
SSH system account on the Sylve host. Configure the bastion SSH credentials
via ~/.ssh/config, SYLVE_SSH_PROXY_KEY, or explicit ssh_bastion_*
HCL fields.
~> Note: If your ~/.ssh/config already has a Host entry for the Sylve
hostname with User and IdentityFile set, no additional configuration is
necessary — the plugin picks those values up automatically.
~> ProxyJump not supported: The plugin's built-in bastion implements a
single SSH hop (Packer → Sylve host → VM). ProxyJump directives found in
~/.ssh/config for the Sylve hostname are detected and logged as a warning,
but are not honoured — the pure-Go SSH client cannot chain jump hosts.
If the Sylve host is only reachable through another jump box, establish a
local port-forward first and then point the plugin at it:
# Forward local port 2222 → Sylve host port 22 through the jump box.
ssh -fNL 2222:<sylve-host>:22 <jump-user>@<jump-box>Then set SYLVE_HOST=localhost and, in your HCL source block, add:
ssh_bastion_host = "localhost"
ssh_bastion_port = 2222
ssh_bastion_username = "<your-user>"
ssh_bastion_private_key_file = "~/.ssh/id_ed25519"The builder uses the SSH communicator to run provisioners inside the guest.
Optional (common):
-
communicator(string) - Communicator type. Defaults to"ssh". -
pause_before_connecting(duration string | ex:"1h5m2s") - Wait this duration after a successful connection attempt before beginning provisioning. Useful when SSH becomes available before the guest is fully ready. Defaults to no pause.
Optional (SSH):
-
ssh_username(string) - The username to connect to SSH with. Defaults to"root". -
ssh_password(string) - A plaintext password to authenticate with SSH. Mutually exclusive withssh_private_key_file. -
ssh_private_key_file(string) - Path to a PEM-encoded private key for SSH authentication. The~can be used in path and will be expanded to the home directory of the current user. -
ssh_certificate_file(string) - Path to a user certificate used to authenticate with SSH. The~can be used in path and will be expanded to the home directory of the current user. -
ssh_timeout(duration string | ex:"1h5m2s") - Maximum time to wait for SSH to become available. Defaults to"5m". -
ssh_port(int) - The port to connect to SSH. Defaults to22. -
ssh_host(string) - Override the SSH host. When empty the IP address assigned by the Sylve DHCP virtual switch is used. -
ssh_handshake_attempts(int) - Number of SSH handshake attempts before failing. Defaults to10. -
ssh_pty(bool) - Allocate a pseudo-terminal for SSH sessions. Defaults tofalse. -
ssh_disable_agent_forwarding(bool) - Iftrue, SSH agent forwarding will be disabled. Defaults tofalse. -
ssh_keep_alive_interval(duration string | ex:"1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative value (-1s) to disable. Defaults to5s. -
ssh_read_write_timeout(duration string | ex:"1h5m2s") - The amount of time to wait for a remote command to end. Disabled by default.
Optional (SSH bastion):
-
ssh_bastion_host(string) - A bastion host to use for the actual SSH connection. When set, the plugin's automatic bastion configuration is skipped and these explicit fields are used instead. -
ssh_bastion_port(int) - The port of the bastion host. Defaults to22. -
ssh_bastion_agent_auth(bool) - Iftrue, the local SSH agent will be used to authenticate with the bastion host. Defaults tofalse. -
ssh_bastion_username(string) - The username to connect to the bastion host. -
ssh_bastion_password(string) - The password to use to authenticate with the bastion host. -
ssh_bastion_interactive(bool) - Iftrue, keyboard-interactive authentication is used with the bastion host. -
ssh_bastion_private_key_file(string) - Path to a PEM-encoded private key file to use to authenticate with the bastion host. The~can be used in path and will be expanded to the home directory of the current user. -
ssh_bastion_certificate_file(string) - Path to a user certificate used to authenticate with the bastion host. The~can be used in path and will be expanded to the home directory of the current user.
For additional SSH communicator options, refer to the Packer SSH communicator documentation.
All configuration fields that accept environment variable fallbacks are listed here for reference. HCL fields always take precedence over environment variables.
| Environment Variable | HCL Field / Purpose |
|---|---|
SYLVE_HOST |
Sets sylve_url as https://<SYLVE_HOST>:8181 when sylve_url is not set in HCL. |
SYLVE_TOKEN |
sylve_token — pre-issued Bearer token. |
SYLVE_USER |
sylve_user — login username. |
SYLVE_PASSWORD |
sylve_password — login password. |
SYLVE_AUTH_TYPE |
sylve_auth_type — "sylve" (default) or "pam". |
SYLVE_API_LOGIN_TIMEOUT |
sylve_api_login_timeout — retry window for initial login. Defaults to 2m. |
SYLVE_SWITCH |
switch_name — DHCP-enabled virtual switch name. |
SYLVE_POOL |
storage_pool — ZFS pool name. Plugin picks the first available pool when empty. |
SYLVE_SSH_PROXY_KEY |
Path to an SSH private key used for the automatic SSH bastion connection. |