Fix sdlcli healthcheck DBAAS status in SEP install
[ric-plt/sdlgo.git] / internal / cli / healthcheck.go
index 94467a9..257bd5d 100644 (file)
 package cli
 
 import (
-       "bytes"
        "fmt"
        "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
        "github.com/spf13/cobra"
        "os"
+       "text/tabwriter"
 )
 
-func NewHealthCheckCmd() *cobra.Command {
-       return newHealthCheckCmd(newDatabase)
+func init() {
+       rootCmd.AddCommand(newHealthCheckCmd(newDatabase))
 }
 
 func newHealthCheckCmd(dbCreateCb DbCreateCb) *cobra.Command {
        cmd := &cobra.Command{
                Use:   "healthcheck",
-               Short: "healthcheck - validates database healthiness",
-               Long:  `healthcheck - validates database healthiness`,
+               Short: "Validate SDL database healthiness",
+               Long:  `Validate SDL database healthiness`,
+               Args:  cobra.ExactArgs(0),
                RunE: func(cmd *cobra.Command, args []string) error {
-                       var buf bytes.Buffer
-                       sdlgoredis.SetDbLogger(&buf)
-                       out, err := runHealthCheck(dbCreateCb)
-                       cmd.Println(out)
-                       if err != nil {
-                               cmd.PrintErrf("%s\n", buf.String())
-                       }
+                       states, err := runHealthCheck(dbCreateCb)
+                       printHealthStatus(cmd, states)
                        return err
                },
        }
@@ -54,53 +50,113 @@ func newHealthCheckCmd(dbCreateCb DbCreateCb) *cobra.Command {
        return cmd
 }
 
-func runHealthCheck(dbCreateCb DbCreateCb) (string, error) {
+func runHealthCheck(dbCreateCb DbCreateCb) ([]sdlgoredis.DbState, error) {
        var anyErr error
-       var str string
        var states []sdlgoredis.DbState
        for _, dbInst := range dbCreateCb().Instances {
-               info, err := dbInst.State()
+               state, err := dbInst.State()
                if err != nil {
-                       anyErr = fmt.Errorf("SDL CLI error: %v", err)
+                       anyErr = err
                }
-               states = append(states, *info)
+               states = append(states, *state)
        }
-       str = writeStateResults(states)
-       return str, anyErr
+       return states, anyErr
 }
 
-func writeStateResults(dbStates []sdlgoredis.DbState) string {
-       var str string
+func printHealthStatus(cmd *cobra.Command, dbStates []sdlgoredis.DbState) {
        var anyErr error
+       w := tabwriter.NewWriter(cmd.OutOrStdout(), 6, 4, 3, ' ', 0)
+       fmt.Fprintln(w, "CLUSTER\tROLE\tADDRESS\tSTATUS\tERROR\t")
+
        for i, dbState := range dbStates {
                if err := dbState.IsOnline(); err != nil {
                        anyErr = err
                }
-               str = str + fmt.Sprintf("  SDL DB backend #%d\n", (i+1))
-               mAddr := dbState.MasterDbState.GetAddress()
-               err := dbState.MasterDbState.IsOnline()
-               if err == nil {
-                       str = str + fmt.Sprintf("    Master (%s): OK\n", mAddr)
-               } else {
-                       str = str + fmt.Sprintf("    Master (%s): NOK\n", mAddr)
-                       str = str + fmt.Sprintf("      %s\n", err.Error())
+
+               if err := printPrimaryHealthStatus(w, i, &dbState); err != nil {
+                       anyErr = err
+               }
+
+               if err := printReplicasHealthStatus(w, i, &dbState); err != nil {
+                       anyErr = err
                }
-               if dbState.ReplicasDbState != nil {
-                       for j, rInfo := range dbState.ReplicasDbState.States {
-                               err := rInfo.IsOnline()
-                               if err == nil {
-                                       str = str + fmt.Sprintf("    Replica #%d (%s): OK\n", (j+1), rInfo.GetAddress())
-                               } else {
-                                       str = str + fmt.Sprintf("    Replica #%d (%s): NOK\n", (j+1), rInfo.GetAddress())
-                                       str = str + fmt.Sprintf("      %s\n", err.Error())
-                               }
-                       }
+
+               if err := printSentinelsHealthStatus(w, i, &dbState); err != nil {
+                       anyErr = err
                }
        }
        if anyErr == nil {
-               str = fmt.Sprintf("Overall status: OK\n\n") + str
+               cmd.Println("Overall status: OK")
+       } else {
+               cmd.Println("Overall status: NOK")
+       }
+       cmd.Println("")
+       w.Flush()
+}
+
+func printPrimaryHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+       addr := printAddress(dbState.PrimaryDbState.GetAddress())
+       err := dbState.PrimaryDbState.IsOnline()
+       if err != nil {
+               fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "primary", addr, "NOK", err.Error())
        } else {
-               str = fmt.Sprintf("Overall status: NOK\n\n") + str
+               fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "primary", addr, "OK", "<none>")
+       }
+       return err
+}
+
+func printReplicasHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+       var anyErr error
+
+       if dbState.ReplicasDbState != nil {
+               if dbState.ConfigNodeCnt > len(dbState.ReplicasDbState.States)+1 {
+                       err := fmt.Errorf("Configured DBAAS nodes %d but only 1 primary and %d replicas",
+                               dbState.ConfigNodeCnt, len(dbState.ReplicasDbState.States))
+                       fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", "<none>", "NOK", err.Error())
+                       anyErr = err
+               }
+               for _, state := range dbState.ReplicasDbState.States {
+                       if err := printReplicaHealthStatus(w, clusterID, state); err != nil {
+                               anyErr = err
+                       }
+               }
+       }
+       return anyErr
+}
+
+func printReplicaHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.ReplicaDbState) error {
+       addr := printAddress(dbState.GetAddress())
+       err := dbState.IsOnline()
+       if err != nil {
+               fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", addr, "NOK", err.Error())
+       } else {
+               fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", addr, "OK", "<none>")
+       }
+       return err
+}
+
+func printSentinelsHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+       var anyErr error
+       if dbState.SentinelsDbState != nil {
+               for _, state := range dbState.SentinelsDbState.States {
+                       if err := printSentinelHealthStatus(w, clusterID, state); err != nil {
+                               anyErr = err
+                       }
+               }
+       }
+       return anyErr
+}
+func printSentinelHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.SentinelDbState) error {
+       err := dbState.IsOnline()
+       if err != nil {
+               fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "sentinel", dbState.GetAddress(), "NOK", err.Error())
+       }
+       return err
+}
+
+func printAddress(address string) string {
+       if address == "" {
+               return "<none>"
        }
-       return str
+       return address
 }