### Full Workflow: Create and Start LXC Container Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/06-command.md A complete function to create and start an LXC container, including building the command arguments, executing creation, and starting the container. Handles errors at each step. ```go func createAndStartContainer(name, template string, envVars []string) error { // Build lxc-create command args := []string{"env"} args = append(args, envVars...) args = append(args, "lxc-create", "-n", name, "-t", template) // Execute if err := RunCommand(args...); err != nil { return fmt.Errorf("failed to create: %w", err) } // Start the container if err := RunCommand("lxc-start", "-d", "-n", name); err != nil { return fmt.Errorf("failed to start: %w", err) } return nil } ``` -------------------------------- ### Configure Shell Provisioner Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Example of configuring a shell provisioner to update package lists, install curl, and download a script. ```hcl provisioner "shell" { inline = [ "apt-get update", "apt-get install -y curl", "curl -fsSL https://example.com/install.sh | bash" ] } ``` -------------------------------- ### Command Wrapper Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/00-index.md Demonstrates how to wrap original commands for remote execution using a template. The example shows an `lxc-create` command being prefixed with `ssh remote`. ```template Original command: lxc-create -n ubuntu -t ubuntu Wrapper template: ssh remote {{.Command}} Result: ssh remote lxc-create -n ubuntu -t ubuntu ``` -------------------------------- ### LXC Attach Provisioning Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Illustrates how provisioners execute commands using `lxc-attach` and transfer files directly to the container's root filesystem. ```go // Provisioners run commands like: // lxc-attach -n packer-ubuntu -- /bin/sh -c "apt-get update" // and upload files to the container rootfs ``` -------------------------------- ### Basic LXC Packer Builder Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/docs/builders/lxc.mdx This example demonstrates how to configure multiple LXC builders for different Ubuntu and Debian releases, as well as a CentOS 7 image. It specifies the builder type, name, configuration file path, template name, and template environment variables or parameters. ```json { "builders": [ { "type": "lxc", "name": "lxc-trusty", "config_file": "/tmp/lxc/config", "template_name": "ubuntu", "template_environment_vars": ["SUITE=trusty"] }, { "type": "lxc", "name": "lxc-xenial", "config_file": "/tmp/lxc/config", "template_name": "ubuntu", "template_environment_vars": ["SUITE=xenial"] }, { "type": "lxc", "name": "lxc-jessie", "config_file": "/tmp/lxc/config", "template_name": "debian", "template_environment_vars": ["SUITE=jessie"] }, { "type": "lxc", "name": "lxc-centos-7-x64", "config_file": "/tmp/lxc/config", "template_name": "centos", "template_parameters": ["-R", "7", "-a", "x86_64"] } ] } ``` -------------------------------- ### LXC Export Step Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Illustrates the expected output files after the LXC export step, including the compressed root filesystem and configuration file. ```go // Container: /var/lib/lxc/packer-ubuntu// // Output directory: output-ubuntu/ // Creates: // output-ubuntu/rootfs.tar.gz (compressed filesystem) // output-ubuntu/lxc-config (configuration file) ``` -------------------------------- ### Install LXC Plugin using packer plugins install Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/docs/README.md Use the `packer plugins install` command to manage the installation of the LXC plugin. ```sh $ packer plugins install github.com/hashicorp/lxc ``` -------------------------------- ### Configure File Provisioner Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Example of configuring a file provisioner to upload local configuration files to the container. ```hcl provisioner "file" { source = "local/config/" destination = "/etc/myapp/" } ``` -------------------------------- ### External Setup Script for Provisioning Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/09-usage-examples.md An external bash script used as a shell provisioner in Packer. It installs development tools, creates a user, configures sudo, and sets up the SSH directory. ```bash #!/bin/bash set -e # Install development tools apt-get install -y vim nano git # Create application user useradd -m -s /bin/bash appuser # Configure sudo echo "appuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/appuser # Set up SSH directory mkdir -p /home/appuser/.ssh chmod 700 /home/appuser/.ssh chown -R appuser:appuser /home/appuser/.ssh echo "Setup completed" ``` -------------------------------- ### Start Command Execution in LXC Container Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/05-communicator.md Starts a command asynchronously in a running LXC container. Use this when the command needs to run in the background and its output is captured. ```go comm := &LxcAttachCommunicator{ ContainerName: "packer-ubuntu", RootFs: "/var/lib/lxc/packer-ubuntu/rootfs", AttachOptions: []string{}, CmdWrapper: func(cmd string) (string, error) { return cmd, nil }, } cmd := &packersdk.RemoteCmd{ Command: "apt-get update", Stdout: os.Stdout, Stderr: os.Stderr, } err := comm.Start(context.Background(), cmd) if err != nil { log.Fatalf("Failed to start command: %v", err) } // Command runs in background, check cmd.ExitStatus() later ``` -------------------------------- ### Extract Tar Archive Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Example command to extract the created rootfs.tar.gz archive to a specified directory. ```bash tar -xzf rootfs.tar.gz -C /target/ ``` -------------------------------- ### LXC Builder Run Method Example Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/03-builder.md Demonstrates how to instantiate and run the LXC builder. Ensure the builder is configured via `Prepare()` before calling `Run()`. The `artifact.Files()` will contain the generated `rootfs.tar.gz` and `lxc-config`. ```go builder := &Builder{} builder.Prepare(cfg) // Configure the builder artifact, err := builder.Run(context.Background(), ui, hook) if err != nil { log.Fatalf("Build failed: %v", err) } // artifact.Files() contains ["rootfs.tar.gz", "lxc-config"] // artifact.String() returns "VM files in directory: output-ubuntu" ``` -------------------------------- ### Start Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/05-communicator.md Starts execution of a command in the running container asynchronously. The command runs in the background, and the method returns immediately. Output is captured through pipes connected to the provided stdout/stderr. ```APIDOC ## Start ### Description Starts execution of a command in the running container asynchronously. The command runs in the background, and the method returns immediately. Output is captured through pipes connected to the provided stdout/stderr. ### Method `error` ### Parameters - `ctx` (context.Context) — Go context for cancellation (used in Packer) - `cmd` (*packersdk.RemoteCmd) — Remote command to execute - `cmd.Command` (string) — The command string to execute - `cmd.Stdin` (io.Reader) — Standard input stream (or nil) - `cmd.Stdout` (io.Writer) — Standard output stream - `cmd.Stderr` (io.Writer) — Standard error stream ### Return - `error` — Error if command execution cannot be started, nil on success ### Behavior - Constructs an `lxc-attach` command using the container name and attach options - Wraps the command using `CmdWrapper` for remote execution if configured - Starts the command in a goroutine to avoid blocking - Sets the exit status via `cmd.SetExited(exitStatus)` when the command completes ### Exit Code Handling: - On success: exit code 0 - On error: attempts to extract the real exit status using `syscall.WaitStatus` - Falls back to exit code 1 if the real exit code cannot be determined ### Example: ```go comm := &LxcAttachCommunicator{ ContainerName: "packer-ubuntu", RootFs: "/var/lib/lxc/packer-ubuntu/rootfs", AttachOptions: []string{}, CmdWrapper: func(cmd string) (string, error) { return cmd, nil }, } cmd := &packersdk.RemoteCmd{ Command: "apt-get update", Stdout: os.Stdout, Stderr: os.Stderr, } err := comm.Start(context.Background(), cmd) if err != nil { log.Fatalf("Failed to start command: %v", err) } // Command runs in background, check cmd.ExitStatus() later ``` ``` -------------------------------- ### Install Packer Plugin Lxc with packer init Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/README.md Use this snippet to declare the Lxc plugin in your Packer configuration. Run `packer init` to automatically install it. ```hcl packer { required_plugins { lxc = { version = ">= 1.0.0" source = "github.com/hashicorp/lxc" } } } ``` -------------------------------- ### Install LXC Plugin with Packer Configuration Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/docs/README.md Add this block to your Packer configuration to declare the LXC plugin as a requirement. Run `packer init` to install. ```hcl packer { required_plugins { lxc = { source = "github.com/hashicorp/lxc" version = "~> 1" } } } ``` -------------------------------- ### Configure Ansible-Local Provisioner Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md Example of configuring an ansible-local provisioner to run a playbook within the container. ```hcl provisioner "ansible-local" { playbook_file = "playbook.yml" } ``` -------------------------------- ### Creating and Using a Custom Artifact Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/04-artifact.md Provides a Go example of creating a custom Artifact struct, initializing it with output directory, files, and generated data, and then accessing its methods like String(), BuilderId(), Files(), and Destroy(). ```go func createArtifact(outputDir string, files []string, generatedData map[string]interface{}) *Artifact { return &Artifact{ dir: outputDir, f: files, StateData: map[string]interface{}{ "generated_data": generatedData, }, } } // Usage artifact := createArtifact( "output-ubuntu", []string{"output-ubuntu/rootfs.tar.gz", "output-ubuntu/lxc-config"}, map[string]interface{}{"provisioner": "ansible"}, ) fmt.Println(artifact.String()) // "VM files in directory: output-ubuntu" fmt.Println(artifact.BuilderId()) // "ustream.lxc" fmt.Println(artifact.Files()) // List of files // Cleanup when done artifact.Destroy() ``` -------------------------------- ### Container with File Provisioner (HCL2) Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/09-usage-examples.md Configure a container with file provisioners using HCL2. This example uploads a configuration file and a directory of scripts into the container. ```hcl source "lxc" "with_config" { config_file = "/etc/lxc/default.conf" template_name = "ubuntu" template_environment_vars = ["SUITE=focal"] container_name = "packer-ubuntu-config" output_directory = "output/ubuntu-config" } build { sources = ["source.lxc.with_config"] provisioner "file" { source = "config/app.conf" destination = "/etc/app/app.conf" } provisioner "file" { source = "scripts/" destination = "/opt/scripts" } provisioner "shell" { inline = [ "chmod +x /opt/scripts/*.sh", "chown -R root:root /opt/scripts" ] } } ``` -------------------------------- ### Alpine Linux Minimal Container (HCL2) Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/09-usage-examples.md Create a minimal Alpine Linux container using HCL2 configuration. This example includes shell provisioners for package installation. ```hcl source "lxc" "alpine" { config_file = "/etc/lxc/default.conf" template_name = "alpine" template_environment_vars = ["ARCH=x86_64"] container_name = "packer-alpine" output_directory = "output/alpine" init_timeout = "45s" } build { sources = ["source.lxc.alpine"] provisioner "shell" { inline = [ "apk update", "apk add curl wget", "apk add python3" ] } } ``` -------------------------------- ### Directory Structure for File Provisioner Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/09-usage-examples.md Illustrates the directory structure required for the file provisioner example, showing the location of the Packer template, configuration files, and scripts. ```text ├── packer.hcl ├── config/ │ └── app.conf └── scripts/ ├── setup.sh ├── install.sh └── configure.sh ``` -------------------------------- ### Get Artifact Files Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/04-artifact.md Retrieves the list of output files created by the build, including the container image and configuration. ```go artifact := &Artifact{ dir: "output-ubuntu", f: []string{"output-ubuntu/rootfs.tar.gz", "output-ubuntu/lxc-config"}, } files := artifact.Files() // files == []string{"output-ubuntu/rootfs.tar.gz", "output-ubuntu/lxc-config"} ``` -------------------------------- ### Execute Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/05-communicator.md Constructs an exec.Cmd that executes a command in the container using `lxc-attach`. The command is wrapped but not started. This is a lower-level method used internally by Start() and CheckInit(). ```APIDOC ## Execute ### Description Constructs an exec.Cmd that executes a command in the container using `lxc-attach`. The command is wrapped but not started. This is a lower-level method used internally by Start() and CheckInit(). ### Method `(*exec.Cmd, error)` ### Parameters - `commandString` (string) — The command to execute inside the container ### Return - `*exec.Cmd` — Go exec command object ready to run - `error` — Error if command construction fails ### Command Construction: - Builds: `lxc-attach [options] --name -- /bin/sh -c ""` - Applies `AttachOptions` to the lxc-attach invocation - Wraps the final command string using `CmdWrapper` ### Example: ```go localCmd, err := comm.Execute("dpkg -l") if err != nil { log.Fatalf("Failed to construct command: %v", err) } // Command is ready but not yet started pr, _ := localCmd.StdoutPipe() localCmd.Start() output, _ := ioutil.ReadAll(pr) ``` ``` -------------------------------- ### Prepare Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/03-builder.md Validates and prepares the builder configuration before the build starts. It internally calls `Config.Prepare()` to validate all configuration options and apply defaults. ```APIDOC ## Prepare(raws ...interface{}) ### Description Validates and prepares the builder configuration. This is called once by Packer before the build starts. Internally calls `Config.Prepare()` to validate all configuration options and apply defaults. ### Signature ```go func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) ``` ### Parameters - `raws` — Raw configuration data, typically a `map[string]interface{}` containing the decoded HCL2 block ### Return - First return value ([]string) — Provisioner names that this builder supports (currently empty) - Second return value ([]string) — User variable names (currently empty) - Error — Validation error, or nil on success ### Behavior - Creates or validates the internal `Config` object - Returns any errors from `Config.Prepare()` validation ### Example ```go builder := &Builder{} cfg := map[string]interface{}{ "config_file": "/tmp/lxc/config", "template_name": "ubuntu", "template_environment_vars": []interface{}{"SUITE=focal"}, } warnings, users, err := builder.Prepare(cfg) if err != nil { log.Fatalf("Build preparation failed: %v", err) } ``` ``` -------------------------------- ### Create LXC Container Step Source: https://github.com/hashicorp/packer-plugin-lxc/blob/main/_autodocs/07-build-steps.md This step creates and starts an LXC container using specified templates and configurations. It handles container cleanup if `packer_force` is true. ```go type stepLxcCreate struct{} ``` ```bash env lxc-create -n -t