-
Notifications
You must be signed in to change notification settings - Fork 244
/
status.go
136 lines (121 loc) · 3.8 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Hubble
package status
import (
"context"
"errors"
"fmt"
"io"
observerpb "github.com/cilium/cilium/api/v1/observer"
v1 "github.com/cilium/cilium/pkg/hubble/api/v1"
"github.com/cilium/hubble/cmd/common/config"
"github.com/cilium/hubble/cmd/common/conn"
"github.com/cilium/hubble/cmd/common/template"
"github.com/cilium/hubble/pkg/printer"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"google.golang.org/grpc"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)
var formattingOpts struct {
output string
}
// New status command.
func New(vp *viper.Viper) *cobra.Command {
statusCmd := &cobra.Command{
Use: "status",
Short: "Display status of Hubble server",
Long: `Display shows the status of the Hubble server. This is intended as a basic
connectivity health check.`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
hubbleConn, err := conn.New(ctx, vp.GetString(config.KeyServer), vp.GetDuration(config.KeyTimeout))
if err != nil {
return err
}
defer hubbleConn.Close()
return runStatus(ctx, cmd.OutOrStdout(), hubbleConn)
},
}
formattingFlags := pflag.NewFlagSet("Formatting", pflag.ContinueOnError)
formattingFlags.StringVarP(
&formattingOpts.output, "output", "o", "compact",
`Specify the output format, one of:
compact: Compact output
dict: Status is shown as KEY:VALUE pair
json: JSON encoding
table: Tab-aligned columns
`)
statusCmd.Flags().AddFlagSet(formattingFlags)
// advanced completion for flags
statusCmd.RegisterFlagCompletionFunc("output", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
return []string{
"compact",
"dict",
"json",
"table",
}, cobra.ShellCompDirectiveDefault
})
// add config.ServerFlags to the help template as these flags are used by
// this command
template.RegisterFlagSets(statusCmd, config.ServerFlags)
return statusCmd
}
func runStatus(ctx context.Context, out io.Writer, conn *grpc.ClientConn) error {
// get the standard GRPC health check to see if the server is up
healthy, status, err := getHC(ctx, conn)
if err != nil {
return fmt.Errorf("failed getting status: %v", err)
}
if formattingOpts.output == "compact" {
fmt.Fprintf(out, "Healthcheck (via %s): %s\n", conn.Target(), status)
}
if !healthy {
return errors.New("not healthy")
}
// if the server is up, lets try to get hubble specific status
ss, err := getStatus(ctx, conn)
if err != nil {
return fmt.Errorf("failed to get hubble server status: %v", err)
}
var opts = []printer.Option{
printer.Writer(out),
}
switch formattingOpts.output {
case "compact":
opts = append(opts, printer.Compact())
case "dict":
opts = append(opts, printer.Dict())
case "json", "JSON", "jsonpb":
opts = append(opts, printer.JSONPB())
case "tab", "table":
opts = append(opts, printer.Tab())
default:
return fmt.Errorf("invalid output format: %s", formattingOpts.output)
}
p := printer.New(opts...)
if err := p.WriteServerStatusResponse(ss); err != nil {
return err
}
return p.Close()
}
func getHC(ctx context.Context, conn *grpc.ClientConn) (healthy bool, status string, err error) {
req := &healthpb.HealthCheckRequest{Service: v1.ObserverServiceName}
resp, err := healthpb.NewHealthClient(conn).Check(ctx, req)
if err != nil {
return false, "", err
}
if st := resp.GetStatus(); st != healthpb.HealthCheckResponse_SERVING {
return false, fmt.Sprintf("Unavailable: %s", st), nil
}
return true, "Ok", nil
}
func getStatus(ctx context.Context, conn *grpc.ClientConn) (*observerpb.ServerStatusResponse, error) {
req := &observerpb.ServerStatusRequest{}
res, err := observerpb.NewObserverClient(conn).ServerStatus(ctx, req)
if err != nil {
return nil, err
}
return res, nil
}