From 4cdaf9552a24ebc863747d8e6e07ec81402d3fcc Mon Sep 17 00:00:00 2001 From: Filip Rudy Date: Tue, 9 Dec 2025 11:41:38 +0100 Subject: [PATCH 1/6] add container functionality, add initial dashboard start functionality --- go.mod | 1 + go.sum | 3 + internal/cmd/dashboard/start.go | 26 +++++-- internal/docker/container.go | 101 ++++++++++++++++++++++++++ internal/docker/containerfollowrun.go | 31 ++++++++ internal/docker/pull.go | 10 --- internal/docker/stop.go | 18 +++++ 7 files changed, 175 insertions(+), 15 deletions(-) create mode 100644 internal/docker/container.go create mode 100644 internal/docker/containerfollowrun.go create mode 100644 internal/docker/stop.go diff --git a/go.mod b/go.mod index cdf8c644f..75a117df2 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/kyma-project/api-gateway v0.0.0-20250814120053-7d617def4106 github.com/moby/go-archive v0.1.0 github.com/moby/term v0.5.2 + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 diff --git a/go.sum b/go.sum index fcb75afaf..5287aacbf 100644 --- a/go.sum +++ b/go.sum @@ -463,6 +463,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -679,6 +681,7 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/cmd/dashboard/start.go b/internal/cmd/dashboard/start.go index 2694a550d..0f3c8345b 100644 --- a/internal/cmd/dashboard/start.go +++ b/internal/cmd/dashboard/start.go @@ -1,17 +1,20 @@ package dashboard import ( + "context" + "github.com/kyma-project/cli.v3/internal/clierror" "github.com/kyma-project/cli.v3/internal/cmdcommon" + "github.com/kyma-project/cli.v3/internal/docker" "github.com/spf13/cobra" ) type dashboardStartConfig struct { *cmdcommon.KymaConfig - port string - containerName string - //kubeconfigPath string <- to be used in a future PR - //verbose bool <- to be used in a future PR + port string + containerName string + kubeconfigPath string + verbose bool } func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command { @@ -34,6 +37,19 @@ func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command { } func runDashboardStart(cfg *dashboardStartConfig) clierror.Error { - //To be implemented in a future PR + + dash := docker.New(cfg.containerName, cfg.port, cfg.kubeconfigPath, cfg.verbose) + + if err := dash.Start(); err != nil { + return clierror.Wrap(err, clierror.New("failed to start kyma dashboard")) + } + + if err := dash.Open(""); err != nil { + return clierror.Wrap(err, clierror.New("failed to build envs from configmap")) + } + + if err := dash.Watch(context.Background()); err != nil { + return clierror.Wrap(err, clierror.New("failed to start kyma dashboard")) + } return nil } diff --git a/internal/docker/container.go b/internal/docker/container.go new file mode 100644 index 000000000..21dd607d1 --- /dev/null +++ b/internal/docker/container.go @@ -0,0 +1,101 @@ +package docker + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types/mount" + "github.com/pkg/browser" +) + +const ( + containerKubeconfigFile = "config.yaml" // this is the kubeconfig filename in the container + dashboardImage = "europe-docker.pkg.dev/kyma-project/prod/kyma-dashboard-local-prod:latest" +) + +// Container is a wrapper around the kyma dashboard docker container, providing an easy to use API to manage the kyam dashboard. +type Container struct { + name string + id string + port string + kubeconfigPath string + kubeconfigMounted bool + docker *Client + verbose bool +} + +type ContainerRunOpts struct { + ContainerName string + Envs []string + Image string + Mounts []mount.Mount + NetworkMode string + Ports map[string]string +} + +// New creates a new dashboard container with the given configuration +func New(name, port, kubeconfigPath string, verbose bool) *Container { + return &Container{ + name: name, + port: port, + kubeconfigPath: kubeconfigPath, + verbose: verbose, + } +} + +// Start runs the dashboard container. +func (c *Container) Start() error { + var err error + c.docker, err = NewClient() + + if err != nil { + return fmt.Errorf("could not create docker client: %w", err) + } + + var envs []string + + opts := c.containerOpts(envs) + fmt.Print("\n") + if c.id, err = c.docker.PullImageAndStartContainer(context.Background(), opts); err != nil { + return fmt.Errorf("unable to start container: %w", err) + } + return nil +} + +// Opens the kyma dashboard in a browser. +func (c *Container) Open(path string) error { + url := fmt.Sprintf("http://localhost:%s%s", c.port, path) + + if c.kubeconfigMounted { + url = fmt.Sprintf("%s?kubeconfigID=%s", url, containerKubeconfigFile) + } + + err := browser.OpenURL(url) + if err != nil { + return fmt.Errorf("dashboard at %q could not be opened: %w", url, err) + } + return nil +} + +// Watch attaches to the running docker container and forwards its output. +func (c *Container) Watch(ctx context.Context) error { + return c.docker.ContainerFollowRun(ctx, c.id, c.verbose) +} + +// StopFunc returns a function to stop the dashboard container with the given context and logging function. +func (c *Container) StopFunc(ctx context.Context, log func(...interface{})) func() { + return c.docker.Stop(ctx, c.id, log) +} + +func (c *Container) containerOpts(envs []string) ContainerRunOpts { + containerRunOpts := ContainerRunOpts{ + Envs: envs, + ContainerName: c.name, + Image: dashboardImage, + Ports: map[string]string{ + "3001": c.port, + }, + } + + return containerRunOpts +} diff --git a/internal/docker/containerfollowrun.go b/internal/docker/containerfollowrun.go new file mode 100644 index 000000000..c9cf6e671 --- /dev/null +++ b/internal/docker/containerfollowrun.go @@ -0,0 +1,31 @@ +package docker + +import ( + "context" + "io" + "os" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/pkg/stdcopy" +) + +func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, forwardOutput bool) error { + buf, err := c.client.ContainerAttach(ctx, containerID, container.AttachOptions{ + Stdout: true, + Stderr: true, + Stream: true, + }) + if err != nil { + return err + } + defer buf.Close() + + dstout, dsterr := io.Discard, io.Discard + if forwardOutput { + dstout, dsterr = os.Stdout, os.Stderr + } + + _, err = stdcopy.StdCopy(dstout, dsterr, buf.Reader) + + return err +} diff --git a/internal/docker/pull.go b/internal/docker/pull.go index e2f07460c..8b1bc0fd9 100644 --- a/internal/docker/pull.go +++ b/internal/docker/pull.go @@ -7,7 +7,6 @@ import ( "github.com/docker/cli/cli/streams" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" - "github.com/docker/docker/api/types/mount" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/go-connections/nat" "github.com/kyma-project/cli.v3/internal/out" @@ -18,15 +17,6 @@ type ErrorMessage struct { Error string } -type ContainerRunOpts struct { - ContainerName string - Envs []string - Image string - Mounts []mount.Mount - NetworkMode string - Ports map[string]string -} - // PullImageAndStartContainer creates, pulls and starts a container func (c *Client) PullImageAndStartContainer(ctx context.Context, opts ContainerRunOpts) (string, error) { config := &container.Config{ diff --git a/internal/docker/stop.go b/internal/docker/stop.go new file mode 100644 index 000000000..4662223ae --- /dev/null +++ b/internal/docker/stop.go @@ -0,0 +1,18 @@ +package docker + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types/container" +) + +func (c *Client) Stop(ctx context.Context, containerID string, log func(...interface{})) func() { + return func() { + log(fmt.Sprintf("\r- Removing container %s...\n", containerID)) + err := c.client.ContainerStop(ctx, containerID, container.StopOptions{}) + if err != nil { + log(err) + } + } +} From 13e51c396b64cd26a3c7bb58672a50eb0856706e Mon Sep 17 00:00:00 2001 From: Filip Rudy Date: Wed, 10 Dec 2025 08:38:26 +0100 Subject: [PATCH 2/6] fix out. usage --- internal/docker/container.go | 3 ++- internal/docker/containerfollowrun.go | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/docker/container.go b/internal/docker/container.go index 21dd607d1..049848eb3 100644 --- a/internal/docker/container.go +++ b/internal/docker/container.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/docker/docker/api/types/mount" + "github.com/kyma-project/cli.v3/internal/out" "github.com/pkg/browser" ) @@ -55,7 +56,7 @@ func (c *Container) Start() error { var envs []string opts := c.containerOpts(envs) - fmt.Print("\n") + out.Msg("\n") if c.id, err = c.docker.PullImageAndStartContainer(context.Background(), opts); err != nil { return fmt.Errorf("unable to start container: %w", err) } diff --git a/internal/docker/containerfollowrun.go b/internal/docker/containerfollowrun.go index c9cf6e671..9796fc21c 100644 --- a/internal/docker/containerfollowrun.go +++ b/internal/docker/containerfollowrun.go @@ -3,10 +3,10 @@ package docker import ( "context" "io" - "os" "github.com/docker/docker/api/types/container" "github.com/docker/docker/pkg/stdcopy" + "github.com/kyma-project/cli.v3/internal/out" ) func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, forwardOutput bool) error { @@ -22,7 +22,8 @@ func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, for dstout, dsterr := io.Discard, io.Discard if forwardOutput { - dstout, dsterr = os.Stdout, os.Stderr + dstout = out.New() + dsterr = out.New() } _, err = stdcopy.StdCopy(dstout, dsterr, buf.Reader) From bb133b5f8e053770aec26ed53279970c25ec5486 Mon Sep 17 00:00:00 2001 From: Filip Rudy Date: Mon, 15 Dec 2025 18:40:56 +0100 Subject: [PATCH 3/6] apply code suggestions for review, remove kubeconfig variable --- internal/cmd/dashboard/start.go | 37 +++++++++++--------- internal/docker/container.go | 60 ++++++++++++++++----------------- internal/docker/pull.go | 1 - internal/docker/stop.go | 11 ++---- 4 files changed, 54 insertions(+), 55 deletions(-) diff --git a/internal/cmd/dashboard/start.go b/internal/cmd/dashboard/start.go index 0f3c8345b..59dd1592f 100644 --- a/internal/cmd/dashboard/start.go +++ b/internal/cmd/dashboard/start.go @@ -1,8 +1,6 @@ package dashboard import ( - "context" - "github.com/kyma-project/cli.v3/internal/clierror" "github.com/kyma-project/cli.v3/internal/cmdcommon" "github.com/kyma-project/cli.v3/internal/docker" @@ -11,10 +9,10 @@ import ( type dashboardStartConfig struct { *cmdcommon.KymaConfig - port string - containerName string - kubeconfigPath string - verbose bool + port string + containerName string + verbose bool + open bool } func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command { @@ -27,29 +25,38 @@ func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command { Short: `Runs Kyma dashboard locally.`, Long: `Use this command to run Kyma dashboard locally in a Docker container and open it directly in a web browser.`, Run: func(_ *cobra.Command, _ []string) { - clierror.Check(runDashboardStart(&dashboardStartConfig{})) + clierror.Check(runDashboardStart(&cfg)) }} cmd.Flags().StringVarP(&cfg.port, "port", "p", "3001", `Specify the port on which the local dashboard will be exposed.`) cmd.Flags().StringVar(&cfg.containerName, "container-name", "kyma-dashboard", `Specify the name of the local container.`) + cmd.Flags().BoolVarP(&cfg.verbose, "verbose", "v", true, `Enable verbose output with detailed logs.`) + cmd.Flags().BoolVarP(&cfg.open, "open", "o", false, `Specify if the browser should open after executing the command.`) return cmd } func runDashboardStart(cfg *dashboardStartConfig) clierror.Error { + dash, err := docker.New( + cfg.containerName, + cfg.port, + cfg.verbose, + ) + + if err != nil { + return clierror.Wrap(err, clierror.New("failed to initialize docker client")) + } - dash := docker.New(cfg.containerName, cfg.port, cfg.kubeconfigPath, cfg.verbose) - - if err := dash.Start(); err != nil { + if err = dash.Start(); err != nil { return clierror.Wrap(err, clierror.New("failed to start kyma dashboard")) } - if err := dash.Open(""); err != nil { - return clierror.Wrap(err, clierror.New("failed to build envs from configmap")) + if cfg.open { + err = dash.Open("") } - - if err := dash.Watch(context.Background()); err != nil { - return clierror.Wrap(err, clierror.New("failed to start kyma dashboard")) + if err != nil { + return clierror.Wrap(err, clierror.New("failed to open kyma dashboard")) } + return nil } diff --git a/internal/docker/container.go b/internal/docker/container.go index 049848eb3..d2ec8a9ba 100644 --- a/internal/docker/container.go +++ b/internal/docker/container.go @@ -10,19 +10,16 @@ import ( ) const ( - containerKubeconfigFile = "config.yaml" // this is the kubeconfig filename in the container - dashboardImage = "europe-docker.pkg.dev/kyma-project/prod/kyma-dashboard-local-prod:latest" + dashboardImage = "europe-docker.pkg.dev/kyma-project/prod/kyma-dashboard-local-prod:latest" ) // Container is a wrapper around the kyma dashboard docker container, providing an easy to use API to manage the kyam dashboard. type Container struct { - name string - id string - port string - kubeconfigPath string - kubeconfigMounted bool - docker *Client - verbose bool + name string + id string + port string + docker *Client + verbose bool } type ContainerRunOpts struct { @@ -35,28 +32,28 @@ type ContainerRunOpts struct { } // New creates a new dashboard container with the given configuration -func New(name, port, kubeconfigPath string, verbose bool) *Container { - return &Container{ - name: name, - port: port, - kubeconfigPath: kubeconfigPath, - verbose: verbose, +func New(name, port string, verbose bool) (*Container, error) { + dockerClient, err := NewClient() + if err != nil { + return nil, fmt.Errorf("could not create docker client: %w", err) } + + return &Container{ + name: name, + port: port, + docker: dockerClient, + verbose: verbose, + }, nil } // Start runs the dashboard container. func (c *Container) Start() error { - var err error - c.docker, err = NewClient() - - if err != nil { - return fmt.Errorf("could not create docker client: %w", err) - } - var envs []string opts := c.containerOpts(envs) out.Msg("\n") + + var err error if c.id, err = c.docker.PullImageAndStartContainer(context.Background(), opts); err != nil { return fmt.Errorf("unable to start container: %w", err) } @@ -65,11 +62,7 @@ func (c *Container) Start() error { // Opens the kyma dashboard in a browser. func (c *Container) Open(path string) error { - url := fmt.Sprintf("http://localhost:%s%s", c.port, path) - - if c.kubeconfigMounted { - url = fmt.Sprintf("%s?kubeconfigID=%s", url, containerKubeconfigFile) - } + url := fmt.Sprintf("http://localhost:%s%s/clusters", c.port, path) err := browser.OpenURL(url) if err != nil { @@ -83,9 +76,16 @@ func (c *Container) Watch(ctx context.Context) error { return c.docker.ContainerFollowRun(ctx, c.id, c.verbose) } -// StopFunc returns a function to stop the dashboard container with the given context and logging function. -func (c *Container) StopFunc(ctx context.Context, log func(...interface{})) func() { - return c.docker.Stop(ctx, c.id, log) +// Stop stops the dashboard container. +func (c *Container) Stop(ctx context.Context, log func(...interface{})) error { + log(fmt.Sprintf("\r- Removing container %s...\n", c.id)) + + if err := c.docker.Stop(ctx, c.id); err != nil { + log(err) + return err + } + + return nil } func (c *Container) containerOpts(envs []string) ContainerRunOpts { diff --git a/internal/docker/pull.go b/internal/docker/pull.go index 8b1bc0fd9..12089f4e3 100644 --- a/internal/docker/pull.go +++ b/internal/docker/pull.go @@ -32,7 +32,6 @@ func (c *Client) PullImageAndStartContainer(ctx context.Context, opts ContainerR } var r io.ReadCloser - //mozliwosc dlugiego pullowania, wskazanie writera do streams out r, err := c.client.ImagePull(ctx, config.Image, image.PullOptions{}) if err != nil { return "", err diff --git a/internal/docker/stop.go b/internal/docker/stop.go index 4662223ae..ddd7dcae3 100644 --- a/internal/docker/stop.go +++ b/internal/docker/stop.go @@ -2,17 +2,10 @@ package docker import ( "context" - "fmt" "github.com/docker/docker/api/types/container" ) -func (c *Client) Stop(ctx context.Context, containerID string, log func(...interface{})) func() { - return func() { - log(fmt.Sprintf("\r- Removing container %s...\n", containerID)) - err := c.client.ContainerStop(ctx, containerID, container.StopOptions{}) - if err != nil { - log(err) - } - } +func (c *Client) Stop(ctx context.Context, containerID string) error { + return c.client.ContainerStop(ctx, containerID, container.StopOptions{}) } From e95e53377ad1d110919648a2b1dfb58c7dab8599 Mon Sep 17 00:00:00 2001 From: Filip Rudy Date: Mon, 15 Dec 2025 18:43:21 +0100 Subject: [PATCH 4/6] update docs --- docs/user/gen-docs/kyma_dashboard_start.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/user/gen-docs/kyma_dashboard_start.md b/docs/user/gen-docs/kyma_dashboard_start.md index 122484dba..7f3dd5dd7 100644 --- a/docs/user/gen-docs/kyma_dashboard_start.md +++ b/docs/user/gen-docs/kyma_dashboard_start.md @@ -14,7 +14,9 @@ kyma dashboard start [flags] ```text --container-name string Specify the name of the local container. (default "kyma-dashboard") + -o, --open Specify if the browser should open after executing the command. -p, --port string Specify the port on which the local dashboard will be exposed. (default "3001") + -v, --verbose Enable verbose output with detailed logs. --context string The name of the kubeconfig context to use -h, --help Help for the command --kubeconfig string Path to the Kyma kubeconfig file From 829f845b0661e4f8fedb3d2bf8a5c47652480feb Mon Sep 17 00:00:00 2001 From: Filip Rudy Date: Tue, 16 Dec 2025 14:54:21 +0100 Subject: [PATCH 5/6] apply suggestions from code review, refactor docker package --- internal/{docker => busola}/container.go | 30 +++++++----------------- internal/cmd/dashboard/start.go | 4 ++-- internal/docker/build.go | 2 +- internal/docker/client.go | 6 ++--- internal/docker/containerfollowrun.go | 6 ++--- internal/docker/pull.go | 16 ++++++++++--- internal/docker/stop.go | 11 --------- 7 files changed, 31 insertions(+), 44 deletions(-) rename internal/{docker => busola}/container.go (74%) delete mode 100644 internal/docker/stop.go diff --git a/internal/docker/container.go b/internal/busola/container.go similarity index 74% rename from internal/docker/container.go rename to internal/busola/container.go index d2ec8a9ba..f2956ab75 100644 --- a/internal/docker/container.go +++ b/internal/busola/container.go @@ -1,10 +1,11 @@ -package docker +package busola import ( "context" "fmt" - "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/api/types/container" + "github.com/kyma-project/cli.v3/internal/docker" "github.com/kyma-project/cli.v3/internal/out" "github.com/pkg/browser" ) @@ -18,22 +19,13 @@ type Container struct { name string id string port string - docker *Client + docker *docker.Client verbose bool } -type ContainerRunOpts struct { - ContainerName string - Envs []string - Image string - Mounts []mount.Mount - NetworkMode string - Ports map[string]string -} - // New creates a new dashboard container with the given configuration func New(name, port string, verbose bool) (*Container, error) { - dockerClient, err := NewClient() + dockerClient, err := docker.NewClient() if err != nil { return nil, fmt.Errorf("could not create docker client: %w", err) } @@ -77,19 +69,15 @@ func (c *Container) Watch(ctx context.Context) error { } // Stop stops the dashboard container. -func (c *Container) Stop(ctx context.Context, log func(...interface{})) error { - log(fmt.Sprintf("\r- Removing container %s...\n", c.id)) - - if err := c.docker.Stop(ctx, c.id); err != nil { - log(err) +func (c *Container) Stop(ctx context.Context) error { + if err := c.docker.ContainerStop(ctx, c.id, container.StopOptions{}); err != nil { return err } - return nil } -func (c *Container) containerOpts(envs []string) ContainerRunOpts { - containerRunOpts := ContainerRunOpts{ +func (c *Container) containerOpts(envs []string) docker.ContainerRunOpts { + containerRunOpts := docker.ContainerRunOpts{ Envs: envs, ContainerName: c.name, Image: dashboardImage, diff --git a/internal/cmd/dashboard/start.go b/internal/cmd/dashboard/start.go index 59dd1592f..ffbe9fae2 100644 --- a/internal/cmd/dashboard/start.go +++ b/internal/cmd/dashboard/start.go @@ -1,9 +1,9 @@ package dashboard import ( + "github.com/kyma-project/cli.v3/internal/busola" "github.com/kyma-project/cli.v3/internal/clierror" "github.com/kyma-project/cli.v3/internal/cmdcommon" - "github.com/kyma-project/cli.v3/internal/docker" "github.com/spf13/cobra" ) @@ -37,7 +37,7 @@ func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command { } func runDashboardStart(cfg *dashboardStartConfig) clierror.Error { - dash, err := docker.New( + dash, err := busola.New( cfg.containerName, cfg.port, cfg.verbose, diff --git a/internal/docker/build.go b/internal/docker/build.go index 7b6f420f1..c9b3291d9 100644 --- a/internal/docker/build.go +++ b/internal/docker/build.go @@ -57,7 +57,7 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { progressOutput := streamformatter.NewProgressOutput(out.Default.MsgWriter()) bodyProgressReader := progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon") - response, err := c.client.ImageBuild( + response, err := c.ImageBuild( ctx, bodyProgressReader, dockerbuild.ImageBuildOptions{ diff --git a/internal/docker/client.go b/internal/docker/client.go index 54a770693..e5fd2a9af 100644 --- a/internal/docker/client.go +++ b/internal/docker/client.go @@ -5,7 +5,7 @@ import ( ) type Client struct { - client client.APIClient + client.APIClient } func NewClient() (*Client, error) { @@ -13,9 +13,9 @@ func NewClient() (*Client, error) { if err != nil { return nil, err } - return &Client{client: cli}, nil + return &Client{APIClient: cli}, nil } func NewTestClient(mock client.APIClient) *Client { - return &Client{client: mock} + return &Client{APIClient: mock} } diff --git a/internal/docker/containerfollowrun.go b/internal/docker/containerfollowrun.go index 9796fc21c..f2e04e119 100644 --- a/internal/docker/containerfollowrun.go +++ b/internal/docker/containerfollowrun.go @@ -10,7 +10,7 @@ import ( ) func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, forwardOutput bool) error { - buf, err := c.client.ContainerAttach(ctx, containerID, container.AttachOptions{ + buf, err := c.ContainerAttach(ctx, containerID, container.AttachOptions{ Stdout: true, Stderr: true, Stream: true, @@ -22,8 +22,8 @@ func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, for dstout, dsterr := io.Discard, io.Discard if forwardOutput { - dstout = out.New() - dsterr = out.New() + dstout = out.Default.MsgWriter() + dsterr = out.Default.ErrWriter() } _, err = stdcopy.StdCopy(dstout, dsterr, buf.Reader) diff --git a/internal/docker/pull.go b/internal/docker/pull.go index 12089f4e3..ccfc2c559 100644 --- a/internal/docker/pull.go +++ b/internal/docker/pull.go @@ -7,6 +7,7 @@ import ( "github.com/docker/cli/cli/streams" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/mount" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/go-connections/nat" "github.com/kyma-project/cli.v3/internal/out" @@ -17,6 +18,15 @@ type ErrorMessage struct { Error string } +type ContainerRunOpts struct { + ContainerName string + Envs []string + Image string + Mounts []mount.Mount + NetworkMode string + Ports map[string]string +} + // PullImageAndStartContainer creates, pulls and starts a container func (c *Client) PullImageAndStartContainer(ctx context.Context, opts ContainerRunOpts) (string, error) { config := &container.Config{ @@ -32,7 +42,7 @@ func (c *Client) PullImageAndStartContainer(ctx context.Context, opts ContainerR } var r io.ReadCloser - r, err := c.client.ImagePull(ctx, config.Image, image.PullOptions{}) + r, err := c.ImagePull(ctx, config.Image, image.PullOptions{}) if err != nil { return "", err } @@ -43,12 +53,12 @@ func (c *Client) PullImageAndStartContainer(ctx context.Context, opts ContainerR return "", err } - body, err := c.client.ContainerCreate(ctx, config, hostConfig, nil, nil, opts.ContainerName) + body, err := c.ContainerCreate(ctx, config, hostConfig, nil, nil, opts.ContainerName) if err != nil { return "", err } - err = c.client.ContainerStart(ctx, body.ID, container.StartOptions{}) + err = c.ContainerStart(ctx, body.ID, container.StartOptions{}) if err != nil { return "", err } diff --git a/internal/docker/stop.go b/internal/docker/stop.go deleted file mode 100644 index ddd7dcae3..000000000 --- a/internal/docker/stop.go +++ /dev/null @@ -1,11 +0,0 @@ -package docker - -import ( - "context" - - "github.com/docker/docker/api/types/container" -) - -func (c *Client) Stop(ctx context.Context, containerID string) error { - return c.client.ContainerStop(ctx, containerID, container.StopOptions{}) -} From 0d356026b5c96c114cb02b6552346b6addc5902b Mon Sep 17 00:00:00 2001 From: Filip Rudy <60617827+FilipRudy@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:01:34 +0100 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: Filip Strozik --- internal/busola/container.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/busola/container.go b/internal/busola/container.go index f2956ab75..5039c199e 100644 --- a/internal/busola/container.go +++ b/internal/busola/container.go @@ -70,10 +70,7 @@ func (c *Container) Watch(ctx context.Context) error { // Stop stops the dashboard container. func (c *Container) Stop(ctx context.Context) error { - if err := c.docker.ContainerStop(ctx, c.id, container.StopOptions{}); err != nil { - return err - } - return nil + return c.docker.ContainerStop(ctx, c.id, container.StopOptions{}) } func (c *Container) containerOpts(envs []string) docker.ContainerRunOpts {