Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/user/gen-docs/kyma_dashboard_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
87 changes: 87 additions & 0 deletions internal/busola/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package busola

import (
"context"
"fmt"

"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"
)

const (
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
docker *docker.Client
verbose bool
}

// New creates a new dashboard container with the given configuration
func New(name, port string, verbose bool) (*Container, error) {
dockerClient, err := docker.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 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)
}
return nil
}

// Opens the kyma dashboard in a browser.
func (c *Container) Open(path string) error {
url := fmt.Sprintf("http://localhost:%s%s/clusters", c.port, path)

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)
}

// Stop stops the dashboard container.
func (c *Container) Stop(ctx context.Context) error {
return c.docker.ContainerStop(ctx, c.id, container.StopOptions{})
}

func (c *Container) containerOpts(envs []string) docker.ContainerRunOpts {
containerRunOpts := docker.ContainerRunOpts{
Envs: envs,
ContainerName: c.name,
Image: dashboardImage,
Ports: map[string]string{
"3001": c.port,
},
}

return containerRunOpts
}
31 changes: 27 additions & 4 deletions internal/cmd/dashboard/start.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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/spf13/cobra"
Expand All @@ -10,8 +11,8 @@ 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
verbose bool
open bool
}

func NewDashboardStartCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
Expand All @@ -24,16 +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 {
//To be implemented in a future PR
dash, err := busola.New(
cfg.containerName,
cfg.port,
cfg.verbose,
)

if err != nil {
return clierror.Wrap(err, clierror.New("failed to initialize docker client"))
}

if err = dash.Start(); err != nil {
return clierror.Wrap(err, clierror.New("failed to start kyma dashboard"))
}

if cfg.open {
err = dash.Open("")
}
if err != nil {
return clierror.Wrap(err, clierror.New("failed to open kyma dashboard"))
}

return nil
}
2 changes: 1 addition & 1 deletion internal/docker/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
6 changes: 3 additions & 3 deletions internal/docker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import (
)

type Client struct {
client client.APIClient
client.APIClient
}

func NewClient() (*Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
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}
}
32 changes: 32 additions & 0 deletions internal/docker/containerfollowrun.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package docker

import (
"context"
"io"

"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 {
buf, err := c.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 = out.Default.MsgWriter()
dsterr = out.Default.ErrWriter()
}

_, err = stdcopy.StdCopy(dstout, dsterr, buf.Reader)

return err
}
7 changes: 3 additions & 4 deletions internal/docker/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ 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{})
r, err := c.ImagePull(ctx, config.Image, image.PullOptions{})
if err != nil {
return "", err
}
Expand All @@ -54,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
}
Expand Down