cmd, test/system: Support intentially failing the entry point for tests

A subsequent commit will show the debug logs and errors from a Toolbx
container's entry point as part of the 'enter' and 'run' commands.  To
test this behaviour, it will be necessary to intentially fail the entry
point.

Moreover, container start-up is a concurrent operation.  If the entry
point fails too early, then it will be caught by the 'podman inspect'
right after the 'podman start' before the inotify(7) watches are put in
place.  Otherwise, it will be handled by the timeout.  Therefore, it
will be necessary to shake out any bugs arising out of unexpected races.

To address this, two environment variables have been introduced:
  * TOOLBX_DELAY_ENTRY_POINT
  * TOOLBX_FAIL_ENTRY_POINT

The TOOLBX_DELAY_ENTRY_POINT environment variable can be set to a
positive integer during the 'create' command to add a delay, in terms of
seconds, when the Toolbx container's entry point is started by 'enter'
and 'run'.

Similarly, if the TOOLBX_FAIL_ENTRY_POINT environment variable is set to
a positive integer during the 'create' command, the entry point will
later fail during 'enter' and 'run'.  The error message will have only
one line if its value is one, else it will have two.

https://github.com/containers/toolbox/issues/750
This commit is contained in:
Debarshi Ray 2024-05-29 19:22:44 +02:00
parent 9c629ff46f
commit e390f15469
4 changed files with 241 additions and 3 deletions

View File

@ -244,6 +244,20 @@ func createContainer(container, image, release, authFile string, showCommandToEn
}
}
var toolbxDelayEntryPointEnv []string
if toolbxDelayEntryPoint, ok := os.LookupEnv("TOOLBX_DELAY_ENTRY_POINT"); ok {
toolbxDelayEntryPointEnvArg := "TOOLBX_DELAY_ENTRY_POINT=" + toolbxDelayEntryPoint
toolbxDelayEntryPointEnv = []string{"--env", toolbxDelayEntryPointEnvArg}
}
var toolbxFailEntryPointEnv []string
if toolbxFailEntryPoint, ok := os.LookupEnv("TOOLBX_FAIL_ENTRY_POINT"); ok {
toolbxFailEntryPointEnvArg := "TOOLBX_FAIL_ENTRY_POINT=" + toolbxFailEntryPoint
toolbxFailEntryPointEnv = []string{"--env", toolbxFailEntryPointEnvArg}
}
toolboxPath := os.Getenv("TOOLBOX_PATH")
toolboxPathEnvArg := "TOOLBOX_PATH=" + toolboxPath
toolboxPathMountArg := toolboxPath + ":/usr/bin/toolbox:ro"
@ -416,9 +430,15 @@ func createContainer(container, image, release, authFile string, showCommandToEn
"create",
"--cgroupns", "host",
"--dns", "none",
"--env", toolboxPathEnvArg,
}
createArgs = append(createArgs, toolbxDelayEntryPointEnv...)
createArgs = append(createArgs, toolbxFailEntryPointEnv...)
createArgs = append(createArgs, []string{
"--env", toolboxPathEnvArg,
}...)
createArgs = append(createArgs, xdgRuntimeDirEnv...)
createArgs = append(createArgs, []string{

View File

@ -168,6 +168,24 @@ func initContainer(cmd *cobra.Command, args []string) error {
defer toolboxEnvFile.Close()
if toolbxDelayEntryPoint, ok := getDelayEntryPoint(); ok {
delayString := toolbxDelayEntryPoint.String()
logrus.Debugf("Adding a delay of %s", delayString)
time.Sleep(toolbxDelayEntryPoint)
}
if toolbxFailEntryPoint, ok := getFailEntryPoint(); ok {
var builder strings.Builder
fmt.Fprintf(&builder, "TOOLBX_FAIL_ENTRY_POINT is set")
if toolbxFailEntryPoint > 1 {
fmt.Fprintf(&builder, "\n")
fmt.Fprintf(&builder, "This environment variable should only be set when testing.")
}
errMsg := builder.String()
return errors.New(errMsg)
}
if utils.PathExists("/run/host/etc") {
logrus.Debug("Path /run/host/etc exists")
@ -451,6 +469,33 @@ func configureUsers(targetUserUid int, targetUser, targetUserHome, targetUserShe
return nil
}
func getDelayEntryPoint() (time.Duration, bool) {
valueString := os.Getenv("TOOLBX_DELAY_ENTRY_POINT")
if valueString == "" {
return 0, false
}
if valueN, err := strconv.Atoi(valueString); valueN > 0 && err == nil {
delay := time.Duration(valueN) * time.Second
return delay, true
}
return 0, false
}
func getFailEntryPoint() (uint, bool) {
valueString := os.Getenv("TOOLBX_FAIL_ENTRY_POINT")
if valueString == "" {
return 0, false
}
if valueN, err := strconv.Atoi(valueString); valueN > 0 && err == nil {
return uint(valueN), true
}
return 0, false
}
func handleDailyTick(event time.Time) {
eventString := event.String()
logrus.Debugf("Handling daily tick %s", eventString)

View File

@ -144,6 +144,12 @@ func preRun(cmd *cobra.Command, args []string) error {
}
}
toolbxDelayEntryPoint := os.Getenv("TOOLBX_DELAY_ENTRY_POINT")
logrus.Debugf("TOOLBX_DELAY_ENTRY_POINT is %s", toolbxDelayEntryPoint)
toolbxFailEntryPoint := os.Getenv("TOOLBX_FAIL_ENTRY_POINT")
logrus.Debugf("TOOLBX_FAIL_ENTRY_POINT is %s", toolbxFailEntryPoint)
toolboxPath := os.Getenv("TOOLBOX_PATH")
if toolboxPath == "" {

View File

@ -60,6 +60,21 @@ teardown() {
assert_output --partial "Handling polling tick"
}
@test "run: Smoke test with true(1) (using entry point with 5s delay)" {
# shellcheck disable=SC2030
export TOOLBX_DELAY_ENTRY_POINT=5
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_success
assert [ ${#lines[@]} -eq 0 ]
# shellcheck disable=SC2154
assert [ ${#stderr_lines[@]} -eq 0 ]
}
@test "run: Smoke test with false(1)" {
create_default_container
@ -76,8 +91,6 @@ teardown() {
assert_success
assert [ ${#lines[@]} -eq 0 ]
# shellcheck disable=SC2154
assert [ ${#stderr_lines[@]} -eq 0 ]
}
@ -629,6 +642,160 @@ teardown() {
assert [ ${#stderr_lines[@]} -eq 3 ]
}
@test "run: Try a failing entry point with a short error and no delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030
export TOOLBX_FAIL_ENTRY_POINT=1
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
regexp="^Error: (invalid entry point PID of container|failed to initialize container) $default_container_name$"
assert_line --index 0 --regexp "$regexp"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a failing entry point with a short error and 5s delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030,SC2031
export TOOLBX_DELAY_ENTRY_POINT=5
# shellcheck disable=SC2030,SC2031
export TOOLBX_FAIL_ENTRY_POINT=1
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
if [ "${lines[0]}" = "Error: invalid entry point PID of container $default_container_name" ]; then
skip "wrong timing"
fi
assert_line --index 0 "Error: failed to initialize container $default_container_name"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a failing entry point with a short error and 30s delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030,SC2031
export TOOLBX_DELAY_ENTRY_POINT=30
# shellcheck disable=SC2030,SC2031
export TOOLBX_FAIL_ENTRY_POINT=1
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
assert_line --index 0 "Error: failed to initialize container $default_container_name"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a failing entry point with a long error and no delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030,SC2031
export TOOLBX_FAIL_ENTRY_POINT=2
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
regexp="^Error: (invalid entry point PID of container|failed to initialize container) $default_container_name$"
assert_line --index 0 --regexp "$regexp"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a failing entry point with a long error and 5s delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030,SC2031
export TOOLBX_DELAY_ENTRY_POINT=5
# shellcheck disable=SC2030,SC2031
export TOOLBX_FAIL_ENTRY_POINT=2
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
if [ "${lines[0]}" = "Error: invalid entry point PID of container $default_container_name" ]; then
skip "wrong timing"
fi
assert_line --index 0 "Error: failed to initialize container $default_container_name"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a failing entry point with a long error and 30s delay" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2030,SC2031
export TOOLBX_DELAY_ENTRY_POINT=30
# shellcheck disable=SC2031
export TOOLBX_FAIL_ENTRY_POINT=2
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
assert_line --index 0 "Error: failed to initialize container $default_container_name"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Try a slow entry point that times out" {
local default_container_name
default_container_name="$(get_system_id)-toolbox-$(get_system_version)"
# shellcheck disable=SC2031
export TOOLBX_DELAY_ENTRY_POINT=30
create_default_container
run --keep-empty-lines --separate-stderr "$TOOLBX" run true
assert_failure
assert [ ${#lines[@]} -eq 0 ]
lines=("${stderr_lines[@]}")
assert_line --index 0 "Error: failed to initialize container $default_container_name"
assert [ ${#stderr_lines[@]} -eq 1 ]
}
@test "run: Smoke test with 'exit 2'" {
create_default_container