Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add edit dashboards command #1573

Merged
merged 10 commits into from
Dec 1, 2023
Merged
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,20 @@ Use this command to dump objects installed by Fleet as part of a package.

Use this command as an exploratory tool to dump objects as they are installed by Fleet when installing a package. Dumped objects are stored in files as they are returned by APIs of the stack, without any processing.

### `elastic-package edit`

_Context: package_

Use this command to edit assets relevant for the package, e.g. Kibana dashboards.

### `elastic-package edit dashboards`

_Context: package_

Use this command to make dashboards editable.

Pass a comma-separated list of dashboard ids with -d or use the interactive prompt to make managed dashboards editable in Kibana.

### `elastic-package export`

_Context: package_
Expand Down
117 changes: 117 additions & 0 deletions cmd/edit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package cmd

import (
"fmt"

"github.com/spf13/cobra"

"github.com/elastic/elastic-package/internal/cobraext"
"github.com/elastic/elastic-package/internal/common"
"github.com/elastic/elastic-package/internal/install"
"github.com/elastic/elastic-package/internal/kibana"
"github.com/elastic/elastic-package/internal/stack"
)

const editLongDescription = `Use this command to edit assets relevant for the package, e.g. Kibana dashboards.`

const editDashboardsLongDescription = `Use this command to make dashboards editable.

Pass a comma-separated list of dashboard ids with -d or use the interactive prompt to make managed dashboards editable in Kibana.`

func setupEditCommand() *cobraext.Command {
editDashboardsCmd := &cobra.Command{
Use: "dashboards",
Short: "Make dashboards editable in Kibana",
Long: editDashboardsLongDescription,
Args: cobra.NoArgs,
RunE: editDashboardsCmd,
}
editDashboardsCmd.Flags().StringSliceP(cobraext.DashboardIDsFlagName, "d", nil, cobraext.DashboardIDsFlagDescription)
editDashboardsCmd.Flags().Bool(cobraext.TLSSkipVerifyFlagName, false, cobraext.TLSSkipVerifyFlagDescription)
editDashboardsCmd.Flags().Bool(cobraext.AllowSnapshotFlagName, false, cobraext.AllowSnapshotDescription)

cmd := &cobra.Command{
Use: "edit",
Short: "Edit package assets",
Long: editLongDescription,
}
cmd.AddCommand(editDashboardsCmd)
cmd.PersistentFlags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar))

return cobraext.NewCommand(cmd, cobraext.ContextPackage)
}

func editDashboardsCmd(cmd *cobra.Command, args []string) error {
cmd.Println("Make Kibana dashboards editable")

dashboardIDs, err := cmd.Flags().GetStringSlice(cobraext.DashboardIDsFlagName)
if err != nil {
return cobraext.FlagParsingError(err, cobraext.DashboardIDsFlagName)
}

common.TrimStringSlice(dashboardIDs)

var opts []kibana.ClientOption
tlsSkipVerify, _ := cmd.Flags().GetBool(cobraext.TLSSkipVerifyFlagName)
if tlsSkipVerify {
opts = append(opts, kibana.TLSSkipVerify())
}

allowSnapshot, _ := cmd.Flags().GetBool(cobraext.AllowSnapshotFlagName)
if err != nil {
return cobraext.FlagParsingError(err, cobraext.AllowSnapshotFlagName)
}

profile, err := cobraext.GetProfileFlag(cmd)
if err != nil {
return err
}

kibanaClient, err := stack.NewKibanaClientFromProfile(profile, opts...)
if err != nil {
return fmt.Errorf("can't create Kibana client: %w", err)
}

jsoriano marked this conversation as resolved.
Show resolved Hide resolved
kibanaVersion, err := kibanaClient.Version()
if err != nil {
return fmt.Errorf("can't get Kibana status information: %w", err)
}

if kibanaVersion.IsSnapshot() {
message := fmt.Sprintf("editing dashboards from a SNAPSHOT version of Kibana (%s) is discouraged. It could lead to invalid dashboards (for example if they use features that are reverted or modified before the final release)", kibanaVersion.Version())
if !allowSnapshot {
return fmt.Errorf("%s. --%s flag can be used to ignore this error", message, cobraext.AllowSnapshotFlagName)
}
fmt.Printf("Warning: %s\n", message)
}

if len(dashboardIDs) == 0 {
dashboardIDs, err = promptDashboardIDs(kibanaClient)
if err != nil {
return fmt.Errorf("prompt for dashboard selection failed: %w", err)
}

if len(dashboardIDs) == 0 {
fmt.Println("No dashboards were found in Kibana.")
return nil
}
}

kibanaHost := kibana.GetAddress(*kibanaClient)
urls := ""
for _, dashboardID := range dashboardIDs {
err = kibanaClient.SetManagedSavedObject("dashboard", dashboardID, false)
if err != nil {
return fmt.Errorf("failed to make dashboards editable: %w", err)
}
urls += fmt.Sprintf("\n%s/app/dashboards#/view/%s", kibanaHost, dashboardID)
}
jillguyonnet marked this conversation as resolved.
Show resolved Hide resolved

cmd.Println("Done")
jillguyonnet marked this conversation as resolved.
Show resolved Hide resolved
jillguyonnet marked this conversation as resolved.
Show resolved Hide resolved
cmd.Println(fmt.Sprintf("Dashboards URLs:%s", urls))
return nil
jsoriano marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var commands = []*cobraext.Command{
setupCleanCommand(),
setupCreateCommand(),
setupDumpCommand(),
setupEditCommand(),
setupExportCommand(),
setupFormatCommand(),
setupInstallCommand(),
Expand Down
5 changes: 5 additions & 0 deletions internal/kibana/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ func NewClient(opts ...ClientOption) (*Client, error) {
return c, nil
}

// Get client host
func GetAddress(c Client) string {
return c.host
}
jillguyonnet marked this conversation as resolved.
Show resolved Hide resolved

// Address option sets the host to use to connect to Kibana.
func Address(address string) ClientOption {
return func(c *Client) {
Expand Down