Skip to content

Commit b10d8b1

Browse files
authored
Add kyma dashboard command (#2800)
1 parent 5d18aed commit b10d8b1

File tree

6 files changed

+112
-12
lines changed

6 files changed

+112
-12
lines changed

docs/user/gen-docs/kyma_dashboard.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ kyma dashboard <command> [flags]
2020
## Flags
2121

2222
```text
23+
--container-name string Specifies the name of the local container. (default "kyma-dashboard")
24+
-p, --port string Specifies the port on which the local dashboard will be exposed. (default "3001")
25+
-v, --verbose Enables verbose output with detailed logs.
2326
--context string The name of the kubeconfig context to use
2427
-h, --help Help for the command
2528
--kubeconfig string Path to the Kyma kubeconfig file

internal/busola/container.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ func (c *Container) Start() error {
5252
}
5353

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

5858
err := browser.OpenURL(url)
5959
if err != nil {
@@ -62,9 +62,9 @@ func (c *Container) Open(path string) error {
6262
return nil
6363
}
6464

65-
// Watch attaches to the running docker container and forwards its output.
66-
func (c *Container) Watch(ctx context.Context) error {
67-
return c.docker.ContainerFollowRun(ctx, c.id, c.verbose)
65+
// Watch attaches to the running docker container, streams its output, and handles graceful shutdown on user interrupt.
66+
func (c *Container) Watch() error {
67+
return c.docker.ContainerFollowRun(c.id, c.verbose)
6868
}
6969

7070
func (c *Container) containerOpts(envs []string) docker.ContainerRunOpts {
Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,64 @@
11
package dashboard
22

33
import (
4+
"github.com/kyma-project/cli.v3/internal/busola"
5+
"github.com/kyma-project/cli.v3/internal/clierror"
46
"github.com/kyma-project/cli.v3/internal/cmdcommon"
57
"github.com/spf13/cobra"
68
)
79

10+
type dashboardConfig struct {
11+
*cmdcommon.KymaConfig
12+
port string
13+
containerName string
14+
verbose bool
15+
}
16+
817
func NewDashboardCMD(kymaConfig *cmdcommon.KymaConfig) *cobra.Command {
18+
cfg := dashboardConfig{
19+
KymaConfig: kymaConfig,
20+
}
21+
922
cmd := &cobra.Command{
1023
Use: "dashboard <command> [flags]",
1124
Short: "Manages Kyma dashboard locally.",
1225
Long: `Use this command to manage Kyma dashboard locally in a Docker container.`,
13-
}
26+
Run: func(_ *cobra.Command, _ []string) {
27+
clierror.Check(runDashboard(&cfg))
28+
}}
29+
30+
cmd.Flags().StringVarP(&cfg.port, "port", "p", "3001", `Specifies the port on which the local dashboard will be exposed.`)
31+
cmd.Flags().StringVar(&cfg.containerName, "container-name", "kyma-dashboard", `Specifies the name of the local container.`)
32+
cmd.Flags().BoolVarP(&cfg.verbose, "verbose", "v", true, `Enables verbose output with detailed logs.`)
1433

1534
cmd.AddCommand(NewDashboardStartCMD(kymaConfig))
1635
cmd.AddCommand(NewDashboardStopCMD(kymaConfig))
1736

1837
return cmd
1938
}
39+
40+
func runDashboard(cfg *dashboardConfig) clierror.Error {
41+
dash, err := busola.New(
42+
cfg.containerName,
43+
cfg.port,
44+
cfg.verbose,
45+
)
46+
47+
if err != nil {
48+
return clierror.Wrap(err, clierror.New("failed to initialize docker client"))
49+
}
50+
51+
if err = dash.Start(); err != nil {
52+
return clierror.Wrap(err, clierror.New("failed to start kyma dashboard"))
53+
}
54+
55+
if err = dash.Open(); err != nil {
56+
return clierror.Wrap(err, clierror.New("failed to open kyma dashboard"))
57+
}
58+
59+
if err = dash.Watch(); err != nil {
60+
return clierror.Wrap(err, clierror.New("failed to watch kyma dashboard"))
61+
}
62+
63+
return nil
64+
}

internal/cmd/dashboard/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func runDashboardStart(cfg *dashboardStartConfig) clierror.Error {
5252
}
5353

5454
if cfg.open {
55-
err = dash.Open("")
55+
err = dash.Open()
5656
}
5757
if err != nil {
5858
return clierror.Wrap(err, clierror.New("failed to open kyma dashboard"))

internal/docker/containerfollowrun.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import (
55
"io"
66

77
"github.com/docker/docker/api/types/container"
8-
"github.com/docker/docker/pkg/stdcopy"
98
"github.com/kyma-project/cli.v3/internal/out"
109
)
1110

12-
func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, forwardOutput bool) error {
13-
buf, err := c.ContainerAttach(ctx, containerID, container.AttachOptions{
11+
func (c *Client) ContainerFollowRun(containerID string, forwardOutput bool) error {
12+
buf, err := c.ContainerAttach(context.Background(), containerID, container.AttachOptions{
1413
Stdout: true,
1514
Stderr: true,
1615
Stream: true,
@@ -26,7 +25,12 @@ func (c *Client) ContainerFollowRun(ctx context.Context, containerID string, for
2625
dsterr = out.Default.ErrWriter()
2726
}
2827

29-
_, err = stdcopy.StdCopy(dstout, dsterr, buf.Reader)
28+
c.stopContainerOnSigInt(
29+
containerID,
30+
dstout,
31+
dsterr,
32+
buf.Reader,
33+
)
3034

31-
return err
35+
return nil
3236
}

internal/docker/stopcontainer.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package docker
2+
3+
import (
4+
"context"
5+
"io"
6+
"os"
7+
"os/signal"
8+
"time"
9+
10+
"github.com/docker/docker/api/types/container"
11+
"github.com/docker/docker/pkg/stdcopy"
12+
"github.com/kyma-project/cli.v3/internal/out"
13+
)
14+
15+
func (c *Client) stopContainerOnSigInt(
16+
containerID string,
17+
dstout io.Writer,
18+
dsterr io.Writer,
19+
reader io.Reader,
20+
) {
21+
sigCh := make(chan os.Signal, 1)
22+
signal.Notify(sigCh, os.Interrupt)
23+
defer signal.Stop(sigCh)
24+
25+
done := make(chan struct{})
26+
27+
go func() {
28+
_, _ = stdcopy.StdCopy(dstout, dsterr, reader)
29+
close(done)
30+
}()
31+
32+
select {
33+
case <-sigCh:
34+
stopCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
35+
defer cancel()
36+
37+
if err := c.ContainerStop(stopCtx, containerID, container.StopOptions{}); err != nil {
38+
out.Default.Errfln(
39+
"Failed to stop the running container. The container may still be running.\n"+
40+
"You can try stopping it again using Kyma Dashboard.\n"+
41+
"Error: %v",
42+
err,
43+
)
44+
}
45+
<-done
46+
case <-done:
47+
}
48+
}

0 commit comments

Comments
 (0)