From 385c4ff96c6c44cd36c3e4d9fe89d429ade65b6e Mon Sep 17 00:00:00 2001 From: Ayush Srivastava Date: Wed, 6 Aug 2025 01:14:37 +0530 Subject: [PATCH] feat(cli): Added Slice Health Status Funcnality Signed-off-by: Ayush Srivastava --- README.md | 3 + cmd/show-health.go | 48 +++++++++++++ doc/kubeslice-cli_show-health.md | 79 ++++++++++++++++++++++ pkg/internal/slice-config.go | 111 +++++++++++++++++++++++++++++++ pkg/slice.go | 8 +++ 5 files changed, 249 insertions(+) create mode 100644 cmd/show-health.go create mode 100644 doc/kubeslice-cli_show-health.md diff --git a/README.md b/README.md index 59ec43c..9c76dbf 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ KubeSlice functionality edit Edit Kubeslice resources. get Get Kubeslice resources. install Installs workloads to run KubeSlice + register Register a Kubeslice worker cluster. + show-health Show health status of KubeSlice resources. uninstall Performs cleanup of Kubeslice components. help Help about any command @@ -57,6 +59,7 @@ KubeSlice functionality * [kubeslice-cli get](doc/kubeslice-cli_get.md) - Get Kubeslice resources. * [kubeslice-cli install](doc/kubeslice-cli_install.md) - Installs workloads to run KubeSlice. * [kubeslice-cli register](doc/kubeslice-cli_register.md) - Register a Kubeslice worker cluster. +* [kubeslice-cli show-health](doc/kubeslice-cli_show-health.md) - Show health status of KubeSlice resources. * [kubeslice-cli uninstall](doc/kubeslice-cli_uninstall.md) - Performs cleanup of Kubeslice components. diff --git a/cmd/show-health.go b/cmd/show-health.go new file mode 100644 index 0000000..c3d0f45 --- /dev/null +++ b/cmd/show-health.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "github.com/kubeslice/kubeslice-cli/pkg" + "github.com/kubeslice/kubeslice-cli/util" + "github.com/spf13/cobra" +) + +var showHealthCmd = &cobra.Command{ + Use: "show-health", + Aliases: []string{"health"}, + Short: "Show health status of KubeSlice resources.", + Args: cobra.RangeArgs(1, 2), + Run: func(cmd *cobra.Command, args []string) { + var objectName string + ns, _ := cmd.Flags().GetString("namespace") + if ns == "" { + util.Fatalf("Namespace is required") + } + all, _ := cmd.Flags().GetBool("all") + + if len(args) > 1 { + objectName = args[1] + } + + pkg.SetCliOptions(pkg.CliParams{Config: Config, Namespace: ns, ObjectName: objectName, ObjectType: args[0], OutputFormat: outputFormat}) + switch args[0] { + case "slice": + if all { + pkg.ShowAllSliceHealth() + } else { + if objectName == "" { + util.Fatalf("Slice name is required when not using --all flag") + } + pkg.ShowSliceHealth() + } + default: + util.Fatalf("Invalid object type. Supported types: slice") + } + }, +} + +func init() { + rootCmd.AddCommand(showHealthCmd) + showHealthCmd.Flags().StringP("namespace", "n", "", "namespace") + showHealthCmd.Flags().BoolP("all", "A", false, "show health for all slices") + showHealthCmd.Flags().StringVarP(&outputFormat, "output", "o", "", "supported values json, yaml") +} \ No newline at end of file diff --git a/doc/kubeslice-cli_show-health.md b/doc/kubeslice-cli_show-health.md new file mode 100644 index 0000000..eb0519c --- /dev/null +++ b/doc/kubeslice-cli_show-health.md @@ -0,0 +1,79 @@ +# kubeslice-cli show-health + +Show health status of KubeSlice resources. + +## Synopsis + +The `show-health` command allows you to view the health status of KubeSlice slices. It provides detailed information about the health and status of slice configurations. + +```bash +kubeslice-cli show-health [resource-type] [resource-name] [flags] +``` + +## Examples + +### Show health for a specific slice +```bash +kubeslice-cli show-health slice my-slice -n kubeslice-demo +``` + +### Show health for all slices +```bash +kubeslice-cli show-health slice -A -n kubeslice-demo +``` + +### Show health with JSON output +```bash +kubeslice-cli show-health slice my-slice -n kubeslice-demo -o json +``` + +### Show health with YAML output +```bash +kubeslice-cli show-health slice my-slice -n kubeslice-demo -o yaml +``` + +## Available Resource Types + +- `slice` - Show health status of KubeSlice slice configurations + +## Flags + +- `-A, --all` - Show health for all slices (when used with slice resource type) +- `-n, --namespace string` - Namespace where the slice is located (required) +- `-o, --output string` - Output format (json, yaml) + +## Global Flags + +- `-c, --config string` - Path to topology configuration YAML file + +## Health Status Information + +The command displays the following health information: + +- **Status**: Ready/Not Ready/Unknown +- **Conditions**: Available health conditions +- **Slice Subnet**: Configuration status +- **Clusters**: Connection status +- **Raw Output**: Complete JSON/YAML output from kubectl + +## Usage Notes + +1. The `--namespace` flag is required for all show-health operations +2. When using `--all` flag, you don't need to specify a resource name +3. The command uses kubectl to fetch slice configuration data +4. Health status is determined by parsing the slice configuration status +5. Raw output is always displayed for debugging purposes + +## Error Handling + +- If the slice doesn't exist, an error will be displayed +- If the namespace doesn't exist, an error will be displayed +- If kubectl is not available, an error will be displayed +- Network connectivity issues will be reported + +## Related Commands + +- `kubeslice-cli get slice` - Get slice configuration details +- `kubeslice-cli describe slice` - Describe slice configuration +- `kubeslice-cli create slice` - Create a new slice +- `kubeslice-cli delete slice` - Delete a slice \ No newline at end of file diff --git a/pkg/internal/slice-config.go b/pkg/internal/slice-config.go index 2636356..34e3fa8 100644 --- a/pkg/internal/slice-config.go +++ b/pkg/internal/slice-config.go @@ -128,3 +128,114 @@ func CreateSliceConfig(namespace string, controllerCluster *Cluster, filename st ApplyFile(filename, namespace, controllerCluster) util.Printf("\nSuccessfully Applied Slice Configuration.") } + +func ShowSliceHealth(sliceConfigName string, namespace string, controllerCluster *Cluster) { + util.Printf("\nFetching KubeSlice slice health status for %s...", sliceConfigName) + + // Get the slice config with JSON output for parsing + var outB, errB bytes.Buffer + cmdArgs := []string{} + if controllerCluster != nil { + cmdArgs = append(cmdArgs, "--context="+controllerCluster.ContextName, "--kubeconfig="+controllerCluster.KubeConfigPath) + } + cmdArgs = append(cmdArgs, "get", SliceConfigObject, sliceConfigName, "-n", namespace, "-o", "json") + + err := util.RunCommandCustomIO("kubectl", &outB, &errB, true, cmdArgs...) + if err != nil { + util.Printf("%s Failed to fetch slice health status: %v", util.Cross, err) + return + } + + // Parse and display health status + displaySliceHealthStatus(outB.String(), sliceConfigName) + time.Sleep(200 * time.Millisecond) +} + +func ShowAllSliceHealth(namespace string, controllerCluster *Cluster) { + util.Printf("\nFetching KubeSlice slice health status for all slices...") + + // Get all slice configs with JSON output for parsing + var outB, errB bytes.Buffer + cmdArgs := []string{} + if controllerCluster != nil { + cmdArgs = append(cmdArgs, "--context="+controllerCluster.ContextName, "--kubeconfig="+controllerCluster.KubeConfigPath) + } + cmdArgs = append(cmdArgs, "get", SliceConfigObject, "-n", namespace, "-o", "json") + + err := util.RunCommandCustomIO("kubectl", &outB, &errB, true, cmdArgs...) + if err != nil { + util.Printf("%s Failed to fetch slice health status: %v", util.Cross, err) + return + } + + // Parse and display health status for all slices + displayAllSliceHealthStatus(outB.String()) + time.Sleep(200 * time.Millisecond) +} + +func displaySliceHealthStatus(jsonOutput string, sliceName string) { + // Parse JSON to extract health information + // This is a simplified implementation - in a real scenario, you'd want to parse the JSON properly + util.Printf("\n=== Slice Health Status: %s ===", sliceName) + + if strings.Contains(jsonOutput, `"status"`) { + // Extract status information + if strings.Contains(jsonOutput, `"ready"`) { + util.Printf("%s Status: Ready", util.Tick) + } else { + util.Printf("%s Status: Not Ready", util.Cross) + } + + // Extract additional health metrics if available + if strings.Contains(jsonOutput, `"conditions"`) { + util.Printf("Conditions: Available") + } + + // Show slice subnet if available + if strings.Contains(jsonOutput, `"sliceSubnet"`) { + util.Printf("Slice Subnet: Configured") + } + + // Show cluster information + if strings.Contains(jsonOutput, `"clusters"`) { + util.Printf("Clusters: Connected") + } + } else { + util.Printf("%s Status: Unknown", util.Wait) + } + + util.Printf("Raw JSON Output:") + util.Printf(jsonOutput) +} + +func displayAllSliceHealthStatus(jsonOutput string) { + util.Printf("\n=== All Slices Health Status ===") + + // Parse JSON to extract all slices + if strings.Contains(jsonOutput, `"items"`) { + util.Printf("Found multiple slices:") + + // Count slices + sliceCount := strings.Count(jsonOutput, `"kind":"SliceConfig"`) + util.Printf("Total Slices: %d", sliceCount) + + // Extract slice names + lines := strings.Split(jsonOutput, "\n") + for _, line := range lines { + if strings.Contains(line, `"name"`) && strings.Contains(line, `"metadata"`) { + // Extract name from JSON + if nameStart := strings.Index(line, `"name"`); nameStart != -1 { + if nameEnd := strings.Index(line[nameStart:], `"`); nameEnd != -1 { + name := strings.Trim(line[nameStart+nameEnd+1:], `", `) + util.Printf("Slice: %s", name) + } + } + } + } + } else { + util.Printf("No slices found or error parsing output") + } + + util.Printf("\nRaw JSON Output:") + util.Printf(jsonOutput) +} diff --git a/pkg/slice.go b/pkg/slice.go index e95f70b..7589e1d 100644 --- a/pkg/slice.go +++ b/pkg/slice.go @@ -28,3 +28,11 @@ func EditSliceConfig() { func DescribeSliceConfig() { internal.DescribeSliceConfig(CliOptions.ObjectName, CliOptions.Namespace, CliOptions.Cluster) } + +func ShowSliceHealth() { + internal.ShowSliceHealth(CliOptions.ObjectName, CliOptions.Namespace, CliOptions.Cluster) +} + +func ShowAllSliceHealth() { + internal.ShowAllSliceHealth(CliOptions.Namespace, CliOptions.Cluster) +}