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
49 changes: 47 additions & 2 deletions docs/reference/99_monitor_clusters.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ NOTE: The `monitor cluster` command is currently experimental only and may be ch

* <<monitor-cluster, `cohctl monitor cluster`>> - monitors the cluster using text based UI
* <<monitor-cluster-panels, `cohctl monitor cluster --show-panels`>> - shows all available panels
* <<get-panels, `cohctl get panels`>> - displays the panels that have been created
* <<add-panel, `cohctl add panel`>> - adds a panel to the list of panels that can be displayed
* <<remove-panel, `cohctl remove panel`>> - removes a panel that has been created

[#monitor-cluster]
==== Monitor Cluster
Expand Down Expand Up @@ -183,8 +186,6 @@ Coherence CLI: 2024-05-06 11:13:59 - Monitoring cluster local (22.06.8) ESC to q
NOTE: Any of the panels or layouts that specify `cache-*` or `service-*` must have the cache or service specified using
`-C` or `-S` respectively.



[#monitor-cluster-panels]
==== Monitor Cluster Show Panels

Expand All @@ -196,6 +197,50 @@ Output:

include::../../build/_output/docs-gen/monitor_cluster_panels.adoc[tag=text]

[#get-panels]
==== Get Panels

include::../../build/_output/docs-gen/get_panels.adoc[tag=text]

[source,bash]
----
cohctl get panels

PANEL LAYOUT
caches caches:services
test caches,services:persistence
----

NOTE: Added panels cant be used by specifying the `-l` option in the `monitor cluster` command.

[#add-panel]
==== Add Panel

include::../../build/_output/docs-gen/add_panel.adoc[tag=text]

[source,bash]
----
cohctl add panel my-panel -l "caches:services,persistence"

Are you sure you want to add the panel my-panel with layout of [caches:services,persistence]? (y/n) y
panel my-panel was added with layout [caches:services,persistence]
----

NOTE: Added panels cant be used by specifying the `-l` option on `monitor cluster` command.

[#remove-panel]
==== Remove Panel

include::../../build/_output/docs-gen/remove_panel.adoc[tag=text]

[source,bash]
----
cohctl remove panel my-panel

Are you sure you want to remove the panel my-panel? (y/n) y
panel my-panel was removed
----

=== See Also

* <<docs/reference/05_clusters.adoc,Clusters>>
Expand Down
9 changes: 9 additions & 0 deletions pkg/cmd/completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ func completionAllProfiles(_ *cobra.Command, _ []string, _ string) ([]string, co
return profiles, cobra.ShellCompDirectiveNoFileComp
}

// completionAllPanels provides a completion function to return all panels.
func completionAllPanels(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
panels := make([]string, 0)
for _, p := range Config.Panels {
panels = append(panels, p.Name)
}
return panels, cobra.ShellCompDirectiveNoFileComp
}

// completionCaches provides a completion function to return all cache names.
func completionCaches(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
var (
Expand Down
24 changes: 20 additions & 4 deletions pkg/cmd/formatting.go
Original file line number Diff line number Diff line change
Expand Up @@ -1140,14 +1140,13 @@ func FormatDiscoveredClusters(clusters []discovery.DiscoveredCluster) string {

// FormatProfiles returns the profiles in a column formatted output.
func FormatProfiles(profiles []ProfileValue) string {
var (
profileCount = len(profiles)
)
var profileCount = len(profiles)

if profileCount == 0 {
return ""
}

table := newFormattedTable().WithHeader("PROFILE", "VALUE")
table := newFormattedTable().WithHeader("PROFILE", "VALUE").WithSortingColumn("PROFILE")

for _, value := range profiles {
table.AddRow(value.Name, value.Value)
Expand All @@ -1156,6 +1155,23 @@ func FormatProfiles(profiles []ProfileValue) string {
return table.String()
}

// FormatPanels returns the panels in a column formatted output.
func FormatPanels(panels []Panel) string {
var panelCount = len(panels)

if panelCount == 0 {
return ""
}

table := newFormattedTable().WithHeader("PANEL", "LAYOUT").WithSortingColumn("PANEL")

for _, value := range panels {
table.AddRow(value.Name, value.Layout)
}

return table.String()
}

// FormatClusterConnections returns the cluster information in a column formatted output.
func FormatClusterConnections(clusters []ClusterConnection) string {
var (
Expand Down
8 changes: 8 additions & 0 deletions pkg/cmd/monitor_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ Use --show-panels to show all available panels.`,
padMaxHeightParam = false
}

// check for custom panel layouts added by "add panel"
if layoutParam != "" {
if l := getPanelLayout(layoutParam); l != "" {
layoutParam = l

}
}

// check for default layouts
if l, ok := defaultMap[layoutParam]; ok {
layoutParam = l
Expand Down
165 changes: 165 additions & 0 deletions pkg/cmd/panel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/

package cmd

import (
"errors"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

const providePanelName = "you must provide a panel name"

var panelLayout string

// addPanelCmd represents the add profile command.
var addPanelCmd = &cobra.Command{
Use: "panel panel-name",
Short: "add a panel and layout for displaying in monitor clusters.",
Long: `The 'add panel' command adds a panel to the list of panels that can be displayed
byt the 'monitor clusters' command.`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
displayErrorAndExit(cmd, providePanelName)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var (
panelName = args[0]
err error
panels = Config.Panels
)

// validate panel name
if err = validateProfileName(panelName); err != nil {
return err
}

if len(panelLayout) == 0 {
return errors.New("you must provide a value for the panel")
}

if getPanelLayout(panelName) != "" {
return fmt.Errorf("the panel '%s' already exists", panelName)
}

if panelAlreadyExists(panelName) {
return fmt.Errorf("the panel '%s' already exists in the list of panels in monitor cluster", panelName)
}

// confirm the operation
if !confirmOperation(cmd, fmt.Sprintf("Are you sure you want to add the panel %s with layout of [%s]? (y/n) ", panelName, panelLayout)) {
return nil
}

panels = append(panels, Panel{Name: panelName, Layout: panelLayout})

viper.Set(panelsKey, panels)
err = WriteConfig()
if err != nil {
return err
}
cmd.Printf("panel %s was added with layout [%s]\n", panelName, panelLayout)
return nil
},
}

// removePanelCmd represents the remove panel command.
var removePanelCmd = &cobra.Command{
Use: "panel panel-name",
Short: "remove a panel from the list of panels",
Long: `The 'remove panel' command removes a panel from the list of panels.`,
ValidArgsFunction: completionAllPanels,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
displayErrorAndExit(cmd, providePanelName)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
var (
panelName = args[0]
err error
panels = Config.Panels
)

if getPanelLayout(panelName) == "" {
return fmt.Errorf("a panel with the name %s does not exist", panelName)
}

// confirm the operation
if !confirmOperation(cmd, fmt.Sprintf("Are you sure you want to remove the panel %s? (y/n) ", panelName)) {
return nil
}

newPanels := make([]Panel, 0)

// loop though the list of panels
for _, v := range panels {
if v.Name != panelName {
newPanels = append(newPanels, v)
}
}

viper.Set(panelsKey, newPanels)
err = WriteConfig()
if err != nil {
return err
}
cmd.Printf("panel %s was removed\n", panelName)
return nil
},
}

// panelAlreadyExists returns true if the panel exists in either the default panel or
// in the list of panels
func panelAlreadyExists(panelName string) bool {
// also check for other panels
if validatePanels([]string{panelName}) == nil {
return true
}

// validate that the panel is not in the list of known default panels in the monitor cluster command
if _, ok := defaultMap[panelName]; ok {
return true
}

return false
}

// getProfilesCmd represents the get profiles command.
var getPanelsCmd = &cobra.Command{
Use: "panels",
Short: "display the panels that have been created",
Long: `The 'get panels' displays the panels that have been created.`,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, _ []string) error {
cmd.Println(FormatPanels(Config.Panels))
return nil
},
}

func init() {
addPanelCmd.Flags().StringVarP(&panelLayout, "layout", "l", "", "panel layout")
_ = addPanelCmd.MarkFlagRequired("layout")
addPanelCmd.Flags().BoolVarP(&automaticallyConfirm, "yes", "y", false, confirmOptionMessage)

removePanelCmd.Flags().BoolVarP(&automaticallyConfirm, "yes", "y", false, confirmOptionMessage)
}

// getPanelLayout returns the layout for a given panel or "" if the panel doesn't exist.
func getPanelLayout(panelName string) string {
for _, v := range Config.Panels {
if v.Name == panelName {
return v.Layout
}
}

return ""
}
12 changes: 12 additions & 0 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ const (
ignoreCertsContextKey = "ignoreInvalidCerts"
requestTimeoutKey = "requestTimeout"
defaultBytesFormatKey = "defaultBytesFormat"
defaultLayoutKey = "defaultLayout"
defaultHeapKey = "defaultHeap"
profilesKey = "profiles"
panelsKey = "panels"

confirmOptionMessage = "automatically confirm the operation"
timeoutMessage = "timeout in seconds for NS Lookup requests"
Expand Down Expand Up @@ -171,6 +173,7 @@ type CoherenceCLIConfig struct {
DefaultHeap string `json:"defaultHeap"`
UseGradle bool `json:"useGradle"`
Profiles []ProfileValue `mapstructure:"profiles"`
Panels []Panel `mapstructure:"panels"`
}

// ProfileValue describes a profile to be used for creating and starting clusters.
Expand All @@ -179,6 +182,12 @@ type ProfileValue struct {
Value string `json:"value"`
}

// Panel describes a panel and layout that can be used by the monitor cluster command.
type Panel struct {
Name string `json:"name"`
Layout string `json:"layout"`
}

// ClusterConnection describes an individual connection to a cluster.
type ClusterConnection struct {
Name string `json:"name"` // the name the user gives to the cluster connection
Expand Down Expand Up @@ -538,6 +547,7 @@ func Initialize(command *cobra.Command) *cobra.Command {
getCmd.AddCommand(getViewCachesCmd)
getCmd.AddCommand(getCachePartitionsCmd)
getCmd.AddCommand(getFederationIncomingCmd)
getCmd.AddCommand(getPanelsCmd)

// set command
command.AddCommand(setCmd)
Expand Down Expand Up @@ -572,6 +582,7 @@ func Initialize(command *cobra.Command) *cobra.Command {
// add
command.AddCommand(addCmd)
addCmd.AddCommand(addClusterCmd)
addCmd.AddCommand(addPanelCmd)

// replicate
command.AddCommand(replicateCmd)
Expand Down Expand Up @@ -618,6 +629,7 @@ func Initialize(command *cobra.Command) *cobra.Command {
removeCmd.AddCommand(removeClusterCmd)
removeCmd.AddCommand(removeSnapshotCmd)
removeCmd.AddCommand(removeProfileCmd)
removeCmd.AddCommand(removePanelCmd)

// describe
command.AddCommand(describeCmd)
Expand Down
5 changes: 5 additions & 0 deletions scripts/generate-doc-snippets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ create_doc $DOCS_DIR/discover_clusters "${COHCTL} discover clusters --help"
create_doc $DOCS_DIR/get_cluster_config "${COHCTL} get cluster-config --help"
create_doc $DOCS_DIR/get_cluster_description "${COHCTL} get cluster-description --help"
create_doc $DOCS_DIR/monitor_cluster "${COHCTL} monitor cluster --help"
create_doc $DOCS_DIR/add_panel "${COHCTL} add panel --help"
create_doc $DOCS_DIR/get_panels "${COHCTL} get panels --help"
create_doc $DOCS_DIR/remove_panel "${COHCTL} remove panel --help"


(
echo "// # tag::text[]"
echo "----"
Expand Down
Loading
Loading