diff --git a/cmd/cli/commands/install-runner.go b/cmd/cli/commands/install-runner.go index a70e824bf..9f9998f0b 100644 --- a/cmd/cli/commands/install-runner.go +++ b/cmd/cli/commands/install-runner.go @@ -160,13 +160,14 @@ func ensureStandaloneRunnerAvailable(ctx context.Context, printer standalone.Sta return inspectStandaloneRunner(container), nil } -// runnerOptions holds common configuration for install/start commands +// runnerOptions holds common configuration for install/start/reinstall commands type runnerOptions struct { - port uint16 - host string - gpuMode string - doNotTrack bool - pullImage bool + port uint16 + host string + gpuMode string + doNotTrack bool + pullImage bool + pruneContainers bool } // runInstallOrStart is shared logic for install-runner and start-runner commands @@ -216,16 +217,23 @@ func runInstallOrStart(cmd *cobra.Command, opts runnerOptions) error { return fmt.Errorf("failed to create Docker client: %w", err) } - // Check if an active model runner container already exists. - if ctrID, ctrName, _, err := standalone.FindControllerContainer(cmd.Context(), dockerClient); err != nil { - return err - } else if ctrID != "" { - if ctrName != "" { - cmd.Printf("Model Runner container %s (%s) is already running\n", ctrName, ctrID[:12]) - } else { - cmd.Printf("Model Runner container %s is already running\n", ctrID[:12]) + // If pruning containers (reinstall), remove any existing model runner containers. + if opts.pruneContainers { + if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, false, cmd); err != nil { + return fmt.Errorf("unable to remove model runner container(s): %w", err) + } + } else { + // Check if an active model runner container already exists (install only). + if ctrID, ctrName, _, err := standalone.FindControllerContainer(cmd.Context(), dockerClient); err != nil { + return err + } else if ctrID != "" { + if ctrName != "" { + cmd.Printf("Model Runner container %s (%s) is already running\n", ctrName, ctrID[:12]) + } else { + cmd.Printf("Model Runner container %s is already running\n", ctrID[:12]) + } + return nil } - return nil } // Determine GPU support. @@ -272,11 +280,12 @@ func newInstallRunner() *cobra.Command { Short: "Install Docker Model Runner (Docker Engine only)", RunE: func(cmd *cobra.Command, args []string) error { return runInstallOrStart(cmd, runnerOptions{ - port: port, - host: host, - gpuMode: gpuMode, - doNotTrack: doNotTrack, - pullImage: true, + port: port, + host: host, + gpuMode: gpuMode, + doNotTrack: doNotTrack, + pullImage: true, + pruneContainers: false, }) }, ValidArgsFunction: completion.NoComplete, diff --git a/cmd/cli/commands/reinstall-runner.go b/cmd/cli/commands/reinstall-runner.go new file mode 100644 index 000000000..dcec2bc73 --- /dev/null +++ b/cmd/cli/commands/reinstall-runner.go @@ -0,0 +1,34 @@ +package commands + +import ( + "github.com/docker/model-runner/cmd/cli/commands/completion" + "github.com/spf13/cobra" +) + +func newReinstallRunner() *cobra.Command { + var port uint16 + var host string + var gpuMode string + var doNotTrack bool + c := &cobra.Command{ + Use: "reinstall-runner", + Short: "Reinstall Docker Model Runner (Docker Engine only)", + RunE: func(cmd *cobra.Command, args []string) error { + return runInstallOrStart(cmd, runnerOptions{ + port: port, + host: host, + gpuMode: gpuMode, + doNotTrack: doNotTrack, + pullImage: true, + pruneContainers: true, + }) + }, + ValidArgsFunction: completion.NoComplete, + } + c.Flags().Uint16Var(&port, "port", 0, + "Docker container port for Docker Model Runner (default: 12434 for Docker Engine, 12435 for Cloud mode)") + c.Flags().StringVar(&host, "host", "127.0.0.1", "Host address to bind Docker Model Runner") + c.Flags().StringVar(&gpuMode, "gpu", "auto", "Specify GPU support (none|auto|cuda)") + c.Flags().BoolVar(&doNotTrack, "do-not-track", false, "Do not track models usage in Docker Model Runner") + return c +} diff --git a/cmd/cli/commands/reinstall-runner_test.go b/cmd/cli/commands/reinstall-runner_test.go new file mode 100644 index 000000000..a6f160361 --- /dev/null +++ b/cmd/cli/commands/reinstall-runner_test.go @@ -0,0 +1,76 @@ +package commands + +import ( + "testing" +) + +func TestReinstallRunnerHostFlag(t *testing.T) { + testCases := []struct { + name string + value string + }{ + {"localhost", "127.0.0.1"}, + {"all_interfaces", "0.0.0.0"}, + {"specific_IP", "192.168.1.100"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Reset the command for each test + cmd := newReinstallRunner() + err := cmd.Flags().Set("host", tc.value) + if err != nil { + t.Errorf("Failed to set host flag to '%s': %v", tc.value, err) + } + + // Verify the value was set + hostValue, err := cmd.Flags().GetString("host") + if err != nil { + t.Errorf("Failed to get host flag value: %v", err) + } + if hostValue != tc.value { + t.Errorf("Expected host value to be '%s', got '%s'", tc.value, hostValue) + } + }) + } +} + +func TestReinstallRunnerCommandFlags(t *testing.T) { + cmd := newReinstallRunner() + + // Verify all expected flags exist + expectedFlags := []string{"port", "host", "gpu", "do-not-track"} + for _, flagName := range expectedFlags { + if cmd.Flags().Lookup(flagName) == nil { + t.Errorf("Expected flag '--%s' not found", flagName) + } + } +} + +func TestReinstallRunnerCommandType(t *testing.T) { + cmd := newReinstallRunner() + + // Verify command properties + if cmd.Use != "reinstall-runner" { + t.Errorf("Expected command Use to be 'reinstall-runner', got '%s'", cmd.Use) + } + + if cmd.Short != "Reinstall Docker Model Runner (Docker Engine only)" { + t.Errorf("Unexpected command Short description: %s", cmd.Short) + } + + // Verify RunE is set + if cmd.RunE == nil { + t.Error("Expected RunE to be set") + } +} + +func TestReinstallRunnerValidArgsFunction(t *testing.T) { + cmd := newReinstallRunner() + + // The reinstall-runner command should not accept any arguments + // So ValidArgsFunction should be set to handle no arguments + if cmd.ValidArgsFunction == nil { + t.Error("Expected ValidArgsFunction to be set") + } +} diff --git a/cmd/cli/commands/root.go b/cmd/cli/commands/root.go index 26400bc6e..0aa5b1a79 100644 --- a/cmd/cli/commands/root.go +++ b/cmd/cli/commands/root.go @@ -109,6 +109,7 @@ func NewRootCmd(cli *command.DockerCli) *cobra.Command { newStartRunner(), newStopRunner(), newRestartRunner(), + newReinstallRunner(), newConfigureCmd(), newPSCmd(), newDFCmd(), diff --git a/cmd/cli/docs/reference/docker_model.yaml b/cmd/cli/docs/reference/docker_model.yaml index c62069091..8e394ab56 100644 --- a/cmd/cli/docs/reference/docker_model.yaml +++ b/cmd/cli/docs/reference/docker_model.yaml @@ -16,6 +16,7 @@ cname: - docker model ps - docker model pull - docker model push + - docker model reinstall-runner - docker model requests - docker model restart-runner - docker model rm @@ -38,6 +39,7 @@ clink: - docker_model_ps.yaml - docker_model_pull.yaml - docker_model_push.yaml + - docker_model_reinstall-runner.yaml - docker_model_requests.yaml - docker_model_restart-runner.yaml - docker_model_rm.yaml diff --git a/cmd/cli/docs/reference/docker_model_reinstall-runner.yaml b/cmd/cli/docs/reference/docker_model_reinstall-runner.yaml new file mode 100644 index 000000000..1c318e276 --- /dev/null +++ b/cmd/cli/docs/reference/docker_model_reinstall-runner.yaml @@ -0,0 +1,56 @@ +command: docker model reinstall-runner +short: Reinstall Docker Model Runner (Docker Engine only) +long: | + This command removes the existing Docker Model Runner container and reinstalls it with the specified configuration. Models and images are preserved during reinstallation. +usage: docker model reinstall-runner +pname: docker model +plink: docker_model.yaml +options: + - option: do-not-track + value_type: bool + default_value: "false" + description: Do not track models usage in Docker Model Runner + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: gpu + value_type: string + default_value: auto + description: Specify GPU support (none|auto|cuda) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: host + value_type: string + default_value: 127.0.0.1 + description: Host address to bind Docker Model Runner + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false + - option: port + value_type: uint16 + default_value: "0" + description: | + Docker container port for Docker Model Runner (default: 12434 for Docker Engine, 12435 for Cloud mode) + deprecated: false + hidden: false + experimental: false + experimentalcli: false + kubernetes: false + swarm: false +deprecated: false +hidden: false +experimental: false +experimentalcli: false +kubernetes: false +swarm: false + diff --git a/cmd/cli/docs/reference/model.md b/cmd/cli/docs/reference/model.md index c74a6fa84..17aec2202 100644 --- a/cmd/cli/docs/reference/model.md +++ b/cmd/cli/docs/reference/model.md @@ -17,6 +17,7 @@ Docker Model Runner | [`ps`](model_ps.md) | List running models | | [`pull`](model_pull.md) | Pull a model from Docker Hub or HuggingFace to your local environment | | [`push`](model_push.md) | Push a model to Docker Hub | +| [`reinstall-runner`](model_reinstall-runner.md) | Reinstall Docker Model Runner (Docker Engine only) | | [`requests`](model_requests.md) | Fetch requests+responses from Docker Model Runner | | [`restart-runner`](model_restart-runner.md) | Restart Docker Model Runner (Docker Engine only) | | [`rm`](model_rm.md) | Remove local models downloaded from Docker Hub | diff --git a/cmd/cli/docs/reference/model_reinstall-runner.md b/cmd/cli/docs/reference/model_reinstall-runner.md new file mode 100644 index 000000000..11b1fe767 --- /dev/null +++ b/cmd/cli/docs/reference/model_reinstall-runner.md @@ -0,0 +1,20 @@ +# docker model reinstall-runner + + +Reinstall Docker Model Runner (Docker Engine only) + +### Options + +| Name | Type | Default | Description | +|:-----------------|:---------|:------------|:-------------------------------------------------------------------------------------------------------| +| `--do-not-track` | `bool` | | Do not track models usage in Docker Model Runner | +| `--gpu` | `string` | `auto` | Specify GPU support (none\|auto\|cuda) | +| `--host` | `string` | `127.0.0.1` | Host address to bind Docker Model Runner | +| `--port` | `uint16` | `0` | Docker container port for Docker Model Runner (default: 12434 for Docker Engine, 12435 for Cloud mode) | + + + + +## Description + +This command removes the existing Docker Model Runner container and reinstalls it with the specified configuration. Models and images are preserved during reinstallation.