Add options to LXC builder for influencing for how containers are built and started
via - create_options: a list of options passed to lxc-create - start_options: a list of options passed to lxc-start - attach_options: a list of options passed to lxc-attach Also extended existing LXC builder BATS tests to exercise the new builder options, and added website docs.
This commit is contained in:
parent
fe4d4648e6
commit
1f2135f65e
|
@ -16,6 +16,7 @@ import (
|
||||||
type LxcAttachCommunicator struct {
|
type LxcAttachCommunicator struct {
|
||||||
RootFs string
|
RootFs string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
|
AttachOptions []string
|
||||||
CmdWrapper CommandWrapper
|
CmdWrapper CommandWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +111,13 @@ func (c *LxcAttachCommunicator) DownloadDir(src string, dst string, exclude []st
|
||||||
|
|
||||||
func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) {
|
func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) {
|
||||||
log.Printf("Executing with lxc-attach in container: %s %s %s", c.ContainerName, c.RootFs, commandString)
|
log.Printf("Executing with lxc-attach in container: %s %s %s", c.ContainerName, c.RootFs, commandString)
|
||||||
|
|
||||||
|
attachCommand := []string{"sudo", "lxc-attach"}
|
||||||
|
attachCommand = append(attachCommand, c.AttachOptions...)
|
||||||
|
attachCommand = append(attachCommand, []string{"--name", "%s", "--", "/bin/sh -c \"%s\""}...)
|
||||||
|
|
||||||
command, err := c.CmdWrapper(
|
command, err := c.CmdWrapper(
|
||||||
fmt.Sprintf("sudo lxc-attach --name %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString))
|
fmt.Sprintf(strings.Join(attachCommand, " "), c.ContainerName, commandString))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@ type Config struct {
|
||||||
ContainerName string `mapstructure:"container_name"`
|
ContainerName string `mapstructure:"container_name"`
|
||||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||||
RawInitTimeout string `mapstructure:"init_timeout"`
|
RawInitTimeout string `mapstructure:"init_timeout"`
|
||||||
|
CreateOptions []string `mapstructure:"create_options"`
|
||||||
|
StartOptions []string `mapstructure:"start_options"`
|
||||||
|
AttachOptions []string `mapstructure:"attach_options"`
|
||||||
Name string `mapstructure:"template_name"`
|
Name string `mapstructure:"template_name"`
|
||||||
Parameters []string `mapstructure:"template_parameters"`
|
Parameters []string `mapstructure:"template_parameters"`
|
||||||
EnvVars []string `mapstructure:"template_environment_vars"`
|
EnvVars []string `mapstructure:"template_environment_vars"`
|
||||||
|
|
|
@ -28,12 +28,15 @@ func (s *stepLxcCreate) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
commands := make([][]string, 3)
|
commands := make([][]string, 3)
|
||||||
commands[0] = append(config.EnvVars, []string{"lxc-create", "-n", name, "-t", config.Name, "--"}...)
|
commands[0] = append(config.EnvVars, "lxc-create")
|
||||||
|
commands[0] = append(commands[0], config.CreateOptions...)
|
||||||
|
commands[0] = append(commands[0], []string{"-n", name, "-t", config.Name, "--"}...)
|
||||||
commands[0] = append(commands[0], config.Parameters...)
|
commands[0] = append(commands[0], config.Parameters...)
|
||||||
// prevent tmp from being cleaned on boot, we put provisioning scripts there
|
// prevent tmp from being cleaned on boot, we put provisioning scripts there
|
||||||
// todo: wait for init to finish before moving on to provisioning instead of this
|
// todo: wait for init to finish before moving on to provisioning instead of this
|
||||||
commands[1] = []string{"touch", filepath.Join(rootfs, "tmp", ".tmpfs")}
|
commands[1] = []string{"touch", filepath.Join(rootfs, "tmp", ".tmpfs")}
|
||||||
commands[2] = []string{"lxc-start", "-d", "--name", name}
|
commands[2] = append([]string{"lxc-start"}, config.StartOptions...)
|
||||||
|
commands[2] = append(commands[2], []string{"-d", "--name", name}...)
|
||||||
|
|
||||||
ui.Say("Creating container...")
|
ui.Say("Creating container...")
|
||||||
for _, command := range commands {
|
for _, command := range commands {
|
||||||
|
|
|
@ -19,6 +19,7 @@ func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
// Create our communicator
|
// Create our communicator
|
||||||
comm := &LxcAttachCommunicator{
|
comm := &LxcAttachCommunicator{
|
||||||
ContainerName: config.ContainerName,
|
ContainerName: config.ContainerName,
|
||||||
|
AttachOptions: config.AttachOptions,
|
||||||
RootFs: mountPath,
|
RootFs: mountPath,
|
||||||
CmdWrapper: wrappedCommand,
|
CmdWrapper: wrappedCommand,
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struc
|
||||||
|
|
||||||
comm := &LxcAttachCommunicator{
|
comm := &LxcAttachCommunicator{
|
||||||
ContainerName: config.ContainerName,
|
ContainerName: config.ContainerName,
|
||||||
|
AttachOptions: config.AttachOptions,
|
||||||
RootFs: mountPath,
|
RootFs: mountPath,
|
||||||
CmdWrapper: wrappedCommand,
|
CmdWrapper: wrappedCommand,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,106 @@
|
||||||
#!/usr/bin/env bats
|
#!/usr/bin/env bats
|
||||||
#
|
#
|
||||||
# This tests the lxc builder. The teardown function will
|
# This tests the lxc builder by creating minimal containers and checking that
|
||||||
# delete any images in the output-lxc-* folders.
|
# custom lxc container configuration files are successfully applied. The
|
||||||
|
# teardown function will delete any images in the output-lxc-* folders along
|
||||||
|
# with the auto-generated lxc container configuration files and hook scripts.
|
||||||
|
|
||||||
#load test_helper
|
#load test_helper
|
||||||
#fixtures builder-lxc
|
#fixtures builder-lxc
|
||||||
FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/builder-lxc"
|
FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/builder-lxc"
|
||||||
|
|
||||||
|
have_command() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
# Required parameters
|
# Required parameters
|
||||||
command -v lxc-create >/dev/null 2>&1 || {
|
have_command lxc-create || {
|
||||||
echo "'lxc-create' must be installed via the lxc (or lxc1 for ubuntu >=16.04) package" >&2
|
echo "'lxc-create' must be installed via the lxc (or lxc1 for ubuntu >=16.04) package" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DESTROY_HOOK_SCRIPT=$FIXTURE_ROOT/destroy-hook.sh
|
||||||
|
DESTROY_HOOK_LOG=$FIXTURE_ROOT/destroy-hook.log
|
||||||
|
printf > "$DESTROY_HOOK_SCRIPT" '
|
||||||
|
echo "$LXC_NAME" > "%s"
|
||||||
|
' "$DESTROY_HOOK_LOG"
|
||||||
|
chmod +x "$DESTROY_HOOK_SCRIPT"
|
||||||
|
|
||||||
|
INIT_CONFIG=$FIXTURE_ROOT/lxc.custom.conf
|
||||||
|
printf > "$INIT_CONFIG" '
|
||||||
|
lxc.hook.destroy = %s
|
||||||
|
' "$DESTROY_HOOK_SCRIPT"
|
||||||
|
|
||||||
teardown() {
|
teardown() {
|
||||||
|
for f in "$INIT_CONFIG" "$DESTROY_HOOK_SCRIPT" "$DESTROY_HOOK_LOG"; do
|
||||||
|
[ -e "$f" ] && rm -f "$f"
|
||||||
|
done
|
||||||
|
|
||||||
rm -rf output-lxc-*
|
rm -rf output-lxc-*
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "lxc: build centos minimal.json" {
|
assert_build() {
|
||||||
run packer build -var template_name=centos $FIXTURE_ROOT/minimal.json
|
local template_name="$1"
|
||||||
[ "$status" -eq 0 ]
|
shift
|
||||||
[ -f output-lxc-centos/rootfs.tar.gz ]
|
|
||||||
[ -f output-lxc-centos/lxc-config ]
|
local build_status=0
|
||||||
|
|
||||||
|
run packer build -var template_name="$template_name" "$@"
|
||||||
|
|
||||||
|
[ "$status" -eq 0 ] || {
|
||||||
|
echo "${template_name} build exited badly: $status" >&2
|
||||||
|
echo "$output" >&2
|
||||||
|
build_status="$status"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for expected in "output-lxc-${template_name}"/{rootfs.tar.gz,lxc-config}; do
|
||||||
|
[ -f "$expected" ] || {
|
||||||
|
echo "missing expected artifact '${expected}'" >&2
|
||||||
|
build_status=1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
return $build_status
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_container_name() {
|
||||||
|
local container_name="$1"
|
||||||
|
|
||||||
|
[ -f "$DESTROY_HOOK_LOG" ] || {
|
||||||
|
echo "missing expected lxc.hook.destroy logfile '$DESTROY_HOOK_LOG'"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
read -r lxc_name < "$DESTROY_HOOK_LOG"
|
||||||
|
|
||||||
|
[ "$lxc_name" = "$container_name" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "lxc: build centos minimal.json" {
|
||||||
|
have_command yum || skip "'yum' must be installed to build centos containers"
|
||||||
|
local container_name=packer-lxc-centos
|
||||||
|
assert_build centos -var init_config="$INIT_CONFIG" \
|
||||||
|
-var container_name="$container_name" \
|
||||||
|
$FIXTURE_ROOT/minimal.json
|
||||||
|
assert_container_name "$container_name"
|
||||||
|
}
|
||||||
|
|
||||||
@test "lxc: build trusty minimal.json" {
|
@test "lxc: build trusty minimal.json" {
|
||||||
run packer build -var template_name=ubuntu -var template_parameters="SUITE=trusty" $FIXTURE_ROOT/minimal.json
|
have_command debootstrap || skip "'debootstrap' must be installed to build ubuntu containers"
|
||||||
[ "$status" -eq 0 ]
|
local container_name=packer-lxc-ubuntu
|
||||||
[ -f output-lxc-ubuntu/rootfs.tar.gz ]
|
assert_build ubuntu -var init_config="$INIT_CONFIG" \
|
||||||
[ -f output-lxc-ubuntu/lxc-config ]
|
-var container_name="$container_name" \
|
||||||
|
-var template_parameters="SUITE=trusty" \
|
||||||
|
$FIXTURE_ROOT/minimal.json
|
||||||
|
assert_container_name "$container_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "lxc: build debian minimal.json" {
|
@test "lxc: build debian minimal.json" {
|
||||||
run packer build -var template_name=debian -var template_parameters="SUITE=jessie" $FIXTURE_ROOT/minimal.json
|
have_command debootstrap || skip "'debootstrap' must be installed to build debian containers"
|
||||||
[ "$status" -eq 0 ]
|
local container_name=packer-lxc-debian
|
||||||
[ -f output-lxc-debian/rootfs.tar.gz ]
|
assert_build debian -var init_config="$INIT_CONFIG" \
|
||||||
[ -f output-lxc-debian/lxc-config ]
|
-var container_name="$container_name" \
|
||||||
|
-var template_parameters="SUITE=jessie" \
|
||||||
|
$FIXTURE_ROOT/minimal.json
|
||||||
|
assert_container_name "$container_name"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,29 @@
|
||||||
{
|
{
|
||||||
"variables": {
|
"variables": {
|
||||||
"template_name": "debian",
|
"template_name": "debian",
|
||||||
"template_parameters": "SUITE=jessie"
|
"template_parameters": "SUITE=jessie",
|
||||||
|
"container_name": "packer-lxc",
|
||||||
|
"set_var": "hello"
|
||||||
},
|
},
|
||||||
|
"provisioners": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"inline": [
|
||||||
|
"if [ \"$SET_VAR\" != \"{{user `set_var`}}\" ]; then",
|
||||||
|
" echo \"Got unexpected value '$SET_VAR' for SET_VAR\" 1>&2",
|
||||||
|
" exit 1",
|
||||||
|
"fi"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"builders": [
|
"builders": [
|
||||||
{
|
{
|
||||||
"type": "lxc",
|
"type": "lxc",
|
||||||
"name": "lxc-{{user `template_name`}}",
|
"name": "lxc-{{user `template_name`}}",
|
||||||
"template_name": "{{user `template_name`}}",
|
"template_name": "{{user `template_name`}}",
|
||||||
|
"container_name": "{{user `container_name`}}",
|
||||||
|
"create_options": [ "-f", "{{user `init_config`}}" ],
|
||||||
|
"attach_options": [ "--clear-env", "--set-var", "SET_VAR={{user `set_var`}}" ],
|
||||||
"config_file": "/usr/share/lxc/config/{{user `template_name`}}.common.conf",
|
"config_file": "/usr/share/lxc/config/{{user `template_name`}}.common.conf",
|
||||||
"template_environment_vars": [ "{{user `template_parameters`}}" ]
|
"template_environment_vars": [ "{{user `template_parameters`}}" ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,3 +110,18 @@ Below is a fully functioning example.
|
||||||
`/usr/share/lxc/templates/lxc-<template_name>`. Note: This gets passed as
|
`/usr/share/lxc/templates/lxc-<template_name>`. Note: This gets passed as
|
||||||
ARGV to the template command. Ensure you have an array of strings, as
|
ARGV to the template command. Ensure you have an array of strings, as
|
||||||
a single string with spaces probably won't work. Defaults to `[]`.
|
a single string with spaces probably won't work. Defaults to `[]`.
|
||||||
|
|
||||||
|
- `create_options` (array of strings) - Options to pass to `lxc-create`. For
|
||||||
|
instance, you can specify a custom LXC container configuration file with
|
||||||
|
`["-f", "/path/to/lxc.conf"]`. Defaults to `[]`. See `man 1 lxc-create` for
|
||||||
|
available options.
|
||||||
|
|
||||||
|
- `start_options` (array of strings) - Options to pass to `lxc-start`. For
|
||||||
|
instance, you can override parameters from the LXC container configuration
|
||||||
|
file via `["--define", "KEY=VALUE"]`. Defaults to `[]`. See `man 1
|
||||||
|
lxc-start` for available options.
|
||||||
|
|
||||||
|
- `attach_options` (array of strings) - Options to pass to `lxc-attach`. For
|
||||||
|
instance, you can prevent the container from inheriting the host machine's
|
||||||
|
environment by specifying `["--clear-env"]`. Defaults to `[]`. See `man 1
|
||||||
|
lxc-attach` for available options.
|
||||||
|
|
Loading…
Reference in New Issue