Skip to content

Commit

Permalink
fix: randomize lxc container names
Browse files Browse the repository at this point in the history
In situations where concurrent stacker runs are happening on a system,
and they are building containers with the same name,
and they are being done inside a mount namespace,
and the path name given as the roots dir is the same,
but the actual mounted volume is different,

then both stackers will be able to acquire the file lock at
$rootdir/.lock, and will go ahead and start containers named $name,
which will then race to set up the lxc control socket, which is named
after the container name and the rootfs path, which are both the same
here.

The fix is to add some randomness to the lxc container name, which
ensures that the socket won't clash. This should not affect other uses
of the image name, which will still use the un-randomized name.

Signed-off-by: Michael McCracken <[email protected]>
  • Loading branch information
mikemccracken committed Nov 7, 2024
1 parent ad9a694 commit 669c12a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
4 changes: 3 additions & 1 deletion pkg/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"syscall"

"github.com/google/uuid"
"github.com/lxc/go-lxc"
"github.com/pkg/errors"
embed_exec "stackerbuild.io/stacker/pkg/embed-exec"
Expand All @@ -36,7 +37,8 @@ func New(sc types.StackerConfig, name string) (*Container, error) {
return nil, errors.WithStack(err)
}

lxcC, err := lxc.NewContainer(name, sc.RootFSDir)
uniqname := fmt.Sprintf("%s-%s", name, uuid.NewString())
lxcC, err := lxc.NewContainer(uniqname, sc.RootFSDir)
if err != nil {
return nil, err
}
Expand Down
37 changes: 37 additions & 0 deletions test/concurrent.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
load helpers

function setup() {
stacker_setup
}

function teardown() {
cleanup
}

@test "concurrent w aliased rootdir" {
cat > stacker.yaml <<"EOF"
robertos:
from:
type: oci
url: ${{BUSYBOX_OCI}}
run: |
sleep ${{SNOOZ}} # make sure they have time to conflict
EOF

mkdir -p 1/roots 1/stacker 2/roots 2/stacker aliased-rootsdir
chmod -R 777 1 2

# simulate shared CI infra where name of sandbox dir is same despite backing store being different

mount --bind 1/roots aliased-rootsdir
${ROOT_DIR}/stacker --debug --roots-dir=aliased-rootsdir --stacker-dir=1/stacker --oci-dir=1/oci --log-file=1.log build --substitute BUSYBOX_OCI=${BUSYBOX_OCI} --substitute SNOOZ=15 &

sleep 5

unshare -m bash <<EOF
mount --bind 2/roots aliased-rootsdir
${ROOT_DIR}/stacker --debug --roots-dir=aliased-rootsdir --stacker-dir=2/stacker --oci-dir=2/oci --log-file=2.log \
build --substitute BUSYBOX_OCI=${BUSYBOX_OCI} --substitute SNOOZ=0
EOF

}

0 comments on commit 669c12a

Please sign in to comment.