diff --git a/cmd/uncloud/service/exec.go b/cmd/uncloud/service/exec.go index 0577cd6c..59dcbdf7 100644 --- a/cmd/uncloud/service/exec.go +++ b/cmd/uncloud/service/exec.go @@ -28,7 +28,7 @@ func NewExecCommand() *cobra.Command { Use: "exec [OPTIONS] SERVICE [COMMAND ARGS...]", Short: "Execute a command in a running service container", Long: `Execute a command (interactive shell by default) in a running container within a service. -If the service has multiple replicas, the command will be executed in a random container. +If the service has multiple replicas and no container ID is specified, the command will be executed in a random container. `, Example: ` # Start an interactive shell ("bash" or "sh" will be tried by default) @@ -37,8 +37,8 @@ If the service has multiple replicas, the command will be executed in a random c # Start an interactive shell with explicit command uc exec web-service /bin/zsh - # List files in the specific container of the service - uc exec --container d792ea7347e5 web-service ls -la + # List files in the specific container of the service; --container accepts full ID or a (unique) prefix + uc exec --container d792e web-service ls -la # Pipe input to a command inside the service container cat backup.sql | uc exec -T db-service psql -U postgres mydb diff --git a/pkg/client/container.go b/pkg/client/container.go index 1ac5a02a..7c05c58e 100644 --- a/pkg/client/container.go +++ b/pkg/client/container.go @@ -10,7 +10,6 @@ import ( "github.com/docker/compose/v2/pkg/progress" "github.com/docker/docker/api/types/container" "github.com/docker/docker/pkg/jsonmessage" - "github.com/docker/docker/pkg/stringid" "github.com/psviderski/uncloud/internal/docker" machinedocker "github.com/psviderski/uncloud/internal/machine/docker" "github.com/psviderski/uncloud/internal/secret" @@ -200,7 +199,7 @@ func toPullProgressEvent(jm jsonmessage.JSONMessage) *progress.Event { } // InspectContainer returns the information about the specified container within the service. -// containerNameOrID can be name, ID, or truncated ID of the container. +// containerNameOrID can be name, full ID, or ID prefix of the container. func (cli *Client) InspectContainer( ctx context.Context, serviceNameOrID, containerNameOrID string, ) (api.MachineServiceContainer, error) { @@ -209,13 +208,23 @@ func (cli *Client) InspectContainer( return api.MachineServiceContainer{}, fmt.Errorf("inspect service: %w", err) } - // TODO: support matching by any prefix of the container ID + prefixMatchCandidates := []api.MachineServiceContainer{} for _, c := range svc.Containers { if c.Container.ID == containerNameOrID || - c.Container.Name == containerNameOrID || - stringid.TruncateID(c.Container.ID) == containerNameOrID { + c.Container.Name == containerNameOrID { return c, nil } + + if strings.HasPrefix(c.Container.ID, containerNameOrID) { + prefixMatchCandidates = append(prefixMatchCandidates, c) + } + } + + if len(prefixMatchCandidates) == 1 { + return prefixMatchCandidates[0], nil + } else if len(prefixMatchCandidates) > 1 { + return api.MachineServiceContainer{}, fmt.Errorf( + "multiple containers found with ID prefix '%s'", containerNameOrID) } return api.MachineServiceContainer{}, api.ErrNotFound diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index c3cc959f..0dbfc846 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -224,7 +224,8 @@ func TestExecBasicCommands(t *testing.T) { var stdout, stderr bytes.Buffer - containerID := service.Containers[1].Container.ID + // Use container prefix + containerIDPrefix := service.Containers[1].Container.ID[:3] execOptions := api.ExecOptions{ Command: []string{"hostname"}, AttachStdout: true, @@ -233,7 +234,7 @@ func TestExecBasicCommands(t *testing.T) { Stderr: &stderr, } - exitCode, err := cli.ExecContainer(ctx, multiServiceName, containerID, execOptions) + exitCode, err := cli.ExecContainer(ctx, multiServiceName, containerIDPrefix, execOptions) require.NoError(t, err) assert.Equal(t, 0, exitCode) diff --git a/website/docs/9-cli-reference/uc_exec.md b/website/docs/9-cli-reference/uc_exec.md index 924f16df..afdeb611 100644 --- a/website/docs/9-cli-reference/uc_exec.md +++ b/website/docs/9-cli-reference/uc_exec.md @@ -5,7 +5,7 @@ Execute a command in a running service container ## Synopsis Execute a command (interactive shell by default) in a running container within a service. -If the service has multiple replicas, the command will be executed in a random container. +If the service has multiple replicas and no container ID is specified, the command will be executed in a random container. ``` @@ -22,8 +22,8 @@ uc exec [OPTIONS] SERVICE [COMMAND ARGS...] [flags] # Start an interactive shell with explicit command uc exec web-service /bin/zsh - # List files in the specific container of the service - uc exec --container d792ea7347e5 web-service ls -la + # List files in the specific container of the service; --container accepts full ID or a (unique) prefix + uc exec --container d792e web-service ls -la # Pipe input to a command inside the service container cat backup.sql | uc exec -T db-service psql -U postgres mydb diff --git a/website/docs/9-cli-reference/uc_service_exec.md b/website/docs/9-cli-reference/uc_service_exec.md index 4a57b679..9c8a5616 100644 --- a/website/docs/9-cli-reference/uc_service_exec.md +++ b/website/docs/9-cli-reference/uc_service_exec.md @@ -5,7 +5,7 @@ Execute a command in a running service container ## Synopsis Execute a command (interactive shell by default) in a running container within a service. -If the service has multiple replicas, the command will be executed in a random container. +If the service has multiple replicas and no container ID is specified, the command will be executed in a random container. ``` @@ -22,8 +22,8 @@ uc service exec [OPTIONS] SERVICE [COMMAND ARGS...] [flags] # Start an interactive shell with explicit command uc exec web-service /bin/zsh - # List files in the specific container of the service - uc exec --container d792ea7347e5 web-service ls -la + # List files in the specific container of the service; --container accepts full ID or a (unique) prefix + uc exec --container d792e web-service ls -la # Pipe input to a command inside the service container cat backup.sql | uc exec -T db-service psql -U postgres mydb