Skip to content

Commit be3dbe2

Browse files
feat: add user flag to service exec command (#2626)
## Description We depend on some containers that use non-root users for certain things, so would be nice to be able to `service exec --user foo` as those users, similar as the docker CLI interface. This PR adds --user to `service exec` and passes the user on the RunExecCommand in the docker and kubernetes managers. I could not find a good way to do it for kubernetes, but that might be appropriate for more production like configurations. ## REMINDER: @tedim52 ## Is this change user facing? YES
1 parent 593f9c2 commit be3dbe2

File tree

14 files changed

+258
-50
lines changed

14 files changed

+258
-50
lines changed

cli/cli/commands/service/exec/exec.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package exec
33
import (
44
"context"
55
"fmt"
6+
67
"github.com/kurtosis-tech/kurtosis/api/golang/engine/kurtosis_engine_rpc_api_bindings"
78
"github.com/kurtosis-tech/kurtosis/api/golang/engine/lib/kurtosis_context"
89
"github.com/kurtosis-tech/kurtosis/cli/cli/command_framework/highlevel/enclave_id_arg"
@@ -32,6 +33,10 @@ const (
3233
isExecCommandArgOptional = false
3334
isExecCommandArgGreedy = false
3435

36+
containerUserKey = "user"
37+
containerUserShortKey = "u"
38+
containerUserDefault = "root"
39+
3540
kurtosisBackendCtxKey = "kurtosis-backend"
3641
engineClientCtxKey = "engine-client"
3742

@@ -45,7 +50,13 @@ var ServiceShellCmd = &engine_consuming_kurtosis_command.EngineConsumingKurtosis
4550
LongDescription: "Execute a command in a service. Note if the command being run is multiple words you should wrap it in quotes",
4651
KurtosisBackendContextKey: kurtosisBackendCtxKey,
4752
EngineClientContextKey: engineClientCtxKey,
48-
Flags: []*flags.FlagConfig{},
53+
Flags: []*flags.FlagConfig{{
54+
Key: containerUserKey,
55+
Usage: "optional service container user for command",
56+
Shorthand: containerUserShortKey,
57+
Type: flags.FlagType_String,
58+
Default: containerUserDefault,
59+
}},
4960
Args: []*args.ArgConfig{
5061
enclave_id_arg.NewEnclaveIdentifierArg(
5162
enclaveIdentifierArgKey,
@@ -109,7 +120,17 @@ func run(
109120
}
110121
serviceUuid := service.ServiceUUID(serviceCtx.GetServiceUUID())
111122

112-
results, resultErrors, err := kurtosisBackend.RunUserServiceExecCommands(ctx, enclaveUuid, map[service.ServiceUUID][]string{
123+
containerUser, err := flags.GetString(containerUserKey)
124+
if err != nil {
125+
return stacktrace.Propagate(err, "An error occurred getting the exec container user flag '%v'", containerUserKey)
126+
}
127+
// convert "root" to "" as it is implied if empty. This simplifies the backend
128+
// impl usages that do not support --user
129+
if containerUser == containerUserDefault {
130+
containerUser = ""
131+
}
132+
133+
results, resultErrors, err := kurtosisBackend.RunUserServiceExecCommands(ctx, enclaveUuid, containerUser, map[service.ServiceUUID][]string{
113134
serviceUuid: {
114135
binShCommand,
115136
binShCommandFlag,

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/docker_kurtosis_backend.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,14 @@ func (backend *DockerKurtosisBackend) GetUserServiceLogs(
297297
func (backend *DockerKurtosisBackend) RunUserServiceExecCommands(
298298
ctx context.Context,
299299
enclaveUuid enclave.EnclaveUUID,
300+
containerUser string,
300301
userServiceCommands map[service.ServiceUUID][]string,
301302
) (
302303
map[service.ServiceUUID]*exec_result.ExecResult,
303304
map[service.ServiceUUID]error,
304305
error,
305306
) {
306-
return user_service_functions.RunUserServiceExecCommands(ctx, enclaveUuid, userServiceCommands, backend.dockerManager)
307+
return user_service_functions.RunUserServiceExecCommands(ctx, enclaveUuid, containerUser, userServiceCommands, backend.dockerManager)
307308
}
308309

309310
func (backend *DockerKurtosisBackend) RunUserServiceExecCommandWithStreamedOutput(

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/engine_functions/docker_config_storage_creator/docker_config_storage_creator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func storeConfigInVolume(
142142
}
143143
for i := uint(0); i < maxRetries; i++ {
144144
outputBuffer := &bytes.Buffer{}
145-
exitCode, err := dockerManager.RunExecCommand(ctx, containerId, execCmd, outputBuffer)
145+
exitCode, err := dockerManager.RunUserServiceExecCommands(ctx, containerId, "", execCmd, outputBuffer)
146146
if err == nil {
147147
if exitCode == creationSuccessExitCode {
148148
logrus.Debugf("The Docker config file was successfully added into the volume.")

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/engine_functions/github_auth_storage_creator/github_auth_storage_creator.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"os"
8+
"path"
9+
"time"
10+
711
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/consts"
812
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/docker_manager"
913
"github.com/kurtosis-tech/stacktrace"
1014
"github.com/sirupsen/logrus"
11-
"os"
12-
"path"
13-
"time"
1415
)
1516

1617
const (
@@ -124,7 +125,7 @@ func storeTokenInVolume(
124125
}
125126
for i := uint(0); i < maxRetries; i++ {
126127
outputBuffer := &bytes.Buffer{}
127-
exitCode, err := dockerManager.RunExecCommand(ctx, containerId, execCmd, outputBuffer)
128+
exitCode, err := dockerManager.RunUserServiceExecCommands(ctx, containerId, "", execCmd, outputBuffer)
128129
if err == nil {
129130
if exitCode == authStorageCreationSuccessExitCode {
130131
logrus.Debugf("The GitHub auth token was successfully added into the volume.")

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/logs_collector_functions/implementations/fluentbit/fluentbit_configuration_creator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (fluent *fluentbitConfigurationCreator) createFluentbitConfigFileInVolume(
129129
}
130130
for i := uint(0); i < maxRetries; i++ {
131131
outputBuffer := &bytes.Buffer{}
132-
exitCode, err := dockerManager.RunExecCommand(ctx, containerId, execCmd, outputBuffer)
132+
exitCode, err := dockerManager.RunUserServiceExecCommands(ctx, containerId, "", execCmd, outputBuffer)
133133
if err == nil {
134134
if exitCode == configFileCreationSuccessExitCode {
135135
logrus.Debugf("The Fluentbit config file with content '%v' was successfully added into the volume", configFileContentStr)

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/shared_helpers/shared_helpers.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"context"
66
"encoding/json"
77
"fmt"
8-
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/object_attributes_provider/docker_label_key"
98
"io"
109
"net"
1110
"os"
@@ -14,6 +13,8 @@ import (
1413
"strings"
1514
"time"
1615

16+
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/object_attributes_provider/docker_label_key"
17+
1718
"github.com/docker/docker/pkg/stdcopy"
1819
"github.com/docker/go-connections/nat"
1920
"github.com/gammazero/workerpool"
@@ -379,7 +380,7 @@ func WaitForPortAvailabilityUsingNetstat(
379380
}
380381
for i := uint(0); i < maxRetries; i++ {
381382
outputBuffer := &bytes.Buffer{}
382-
exitCode, err := dockerManager.RunExecCommand(ctx, containerId, execCmd, outputBuffer)
383+
exitCode, err := dockerManager.RunUserServiceExecCommands(ctx, containerId, "", execCmd, outputBuffer)
383384
if err == nil {
384385
if exitCode == netstatSuccessExitCode {
385386
return nil

container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/user_services_functions/run_user_service_exec_commands.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,22 @@ package user_service_functions
33
import (
44
"bytes"
55
"context"
6+
"reflect"
7+
68
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/docker_kurtosis_backend/shared_helpers"
79
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_impls/docker/docker_manager"
810
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/enclave"
911
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/exec_result"
1012
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
1113
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/operation_parallelizer"
1214
"github.com/kurtosis-tech/stacktrace"
13-
"reflect"
1415
)
1516

1617
// TODO Switch these to streaming so that huge command outputs don't blow up the API container memory
1718
func RunUserServiceExecCommands(
1819
ctx context.Context,
1920
enclaveId enclave.EnclaveUUID,
21+
containerUser string,
2022
userServiceCommands map[service.ServiceUUID][]string,
2123
dockerManager *docker_manager.DockerManager,
2224
) (
@@ -46,7 +48,7 @@ func RunUserServiceExecCommands(
4648
// the error to the map downstream
4749
}
4850

49-
successfulExecs, failedExecs, err := runExecOperationsInParallel(ctx, userServiceCommands, userServiceDockerResources, dockerManager)
51+
successfulExecs, failedExecs, err := runExecOperationsInParallel(ctx, containerUser, userServiceCommands, userServiceDockerResources, dockerManager)
5052
if err != nil {
5153
return nil, nil, stacktrace.Propagate(err, "An unexpected error occurred running the exec commands in parallel")
5254
}
@@ -55,6 +57,7 @@ func RunUserServiceExecCommands(
5557

5658
func runExecOperationsInParallel(
5759
ctx context.Context,
60+
containerUser string,
5861
commandArgs map[service.ServiceUUID][]string,
5962
userServiceDockerResources map[service.ServiceUUID]*shared_helpers.UserServiceDockerResources,
6063
dockerManager *docker_manager.DockerManager,
@@ -79,7 +82,7 @@ func runExecOperationsInParallel(
7982
}
8083

8184
execOperationId := operation_parallelizer.OperationID(serviceUuid)
82-
execOperation := createExecOperation(ctx, serviceUuid, userServiceDockerResource, commandArg, dockerManager)
85+
execOperation := createExecOperation(ctx, serviceUuid, containerUser, userServiceDockerResource, commandArg, dockerManager)
8386
execOperations[execOperationId] = execOperation
8487
}
8588

@@ -108,6 +111,7 @@ func runExecOperationsInParallel(
108111
func createExecOperation(
109112
ctx context.Context,
110113
serviceUuid service.ServiceUUID,
114+
containerUser string,
111115
userServiceDockerResource *shared_helpers.UserServiceDockerResources,
112116
commandArg []string,
113117
dockerManager *docker_manager.DockerManager,
@@ -116,9 +120,10 @@ func createExecOperation(
116120
execOutputBuf := &bytes.Buffer{}
117121
userServiceDockerContainer := userServiceDockerResource.ServiceContainer
118122

119-
exitCode, err := dockerManager.RunExecCommand(
123+
exitCode, err := dockerManager.RunUserServiceExecCommands(
120124
ctx,
121125
userServiceDockerContainer.GetId(),
126+
containerUser,
122127
commandArg,
123128
execOutputBuf,
124129
)

container-engine-lib/lib/backend_impls/docker/docker_manager/docker_manager.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,13 +990,13 @@ func (manager *DockerManager) GetContainerLogs(
990990
}
991991

992992
/*
993-
RunExecCommand
993+
RunUserServiceExecCommands
994994
Executes the given command inside the container with the given ID, blocking until the command completes
995995
*/
996-
func (manager *DockerManager) RunExecCommand(context context.Context, containerId string, command []string, logOutput io.Writer) (int32, error) {
996+
func (manager *DockerManager) RunUserServiceExecCommands(context context.Context, containerId, userId string, command []string, logOutput io.Writer) (int32, error) {
997997
dockerClient := manager.dockerClient
998998
execConfig := types.ExecConfig{
999-
User: "",
999+
User: userId,
10001000
Privileged: false,
10011001
Tty: false,
10021002
ConsoleSize: nil,

container-engine-lib/lib/backend_impls/kubernetes/kubernetes_kurtosis_backend/kubernetes_kurtosis_backend.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,17 @@ func (backend *KubernetesKurtosisBackend) GetUserServiceLogs(
347347
func (backend *KubernetesKurtosisBackend) RunUserServiceExecCommands(
348348
ctx context.Context,
349349
enclaveUuid enclave.EnclaveUUID,
350+
containerUser string,
350351
userServiceCommands map[service.ServiceUUID][]string,
351352
) (
352353
succesfulUserServiceExecResults map[service.ServiceUUID]*exec_result.ExecResult,
353354
erroredUserServiceUuids map[service.ServiceUUID]error,
354355
resultErr error,
355356
) {
357+
if containerUser != "" {
358+
resultErr = stacktrace.NewError("--user not implemented for kurtosis backend")
359+
return
360+
}
356361
return user_services_functions.RunUserServiceExecCommands(
357362
ctx,
358363
enclaveUuid,

container-engine-lib/lib/backend_impls/metrics_reporting/metrics_reporting_kurtosis_backend.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,14 @@ func (backend *MetricsReportingKurtosisBackend) GetUserServiceLogs(
322322
func (backend *MetricsReportingKurtosisBackend) RunUserServiceExecCommands(
323323
ctx context.Context,
324324
enclaveUuid enclave.EnclaveUUID,
325+
containerUser string,
325326
userServiceCommands map[service.ServiceUUID][]string,
326327
) (
327-
succesfulUserServiceExecResults map[service.ServiceUUID]*exec_result.ExecResult,
328+
successfulUserServiceExecResults map[service.ServiceUUID]*exec_result.ExecResult,
328329
erroredUserServiceUuids map[service.ServiceUUID]error,
329330
resultErr error,
330331
) {
331-
succesfulUserServiceExecResults, erroredUserServiceUuids, err := backend.underlying.RunUserServiceExecCommands(ctx, enclaveUuid, userServiceCommands)
332+
successfulUserServiceExecResults, erroredUserServiceUuids, err := backend.underlying.RunUserServiceExecCommands(ctx, enclaveUuid, containerUser, userServiceCommands)
332333
if err != nil {
333334
return nil, nil, stacktrace.Propagate(
334335
err,
@@ -337,7 +338,7 @@ func (backend *MetricsReportingKurtosisBackend) RunUserServiceExecCommands(
337338
enclaveUuid,
338339
)
339340
}
340-
return succesfulUserServiceExecResults, erroredUserServiceUuids, nil
341+
return successfulUserServiceExecResults, erroredUserServiceUuids, nil
341342
}
342343

343344
func (backend *MetricsReportingKurtosisBackend) RunUserServiceExecCommandWithStreamedOutput(

0 commit comments

Comments
 (0)