Skip to content

Commit 5100a46

Browse files
committed
kms/health: address review comments
- guard against a (nil, nil) Status response instead of panicking - reject duplicate --kms-sockets entries in validate - move client construction from run into complete, following the complete/validate/run convention; run receives the operator client
1 parent bd36df8 commit 5100a46

4 files changed

Lines changed: 35 additions & 8 deletions

File tree

pkg/operator/encryption/kms/health/cmd.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ func NewCommand(ctx context.Context, newOperatorClient func(*rest.Config) (v1hel
6060
if err := o.validate(); err != nil {
6161
return err
6262
}
63-
return o.run(ctx)
63+
operatorClient, err := o.complete()
64+
if err != nil {
65+
return err
66+
}
67+
return o.run(ctx, operatorClient)
6468
},
6569
}
6670
o.addFlags(cmd.Flags())
@@ -80,10 +84,15 @@ func (o *options) validate() error {
8084
if len(o.KMSSockets) == 0 {
8185
return fmt.Errorf("--kms-sockets is required, at least one")
8286
}
87+
socketSet := make(map[string]struct{}, len(o.KMSSockets))
8388
for _, s := range o.KMSSockets {
8489
if !kmsSocketPattern.MatchString(s) {
8590
return fmt.Errorf("--kms-sockets entry %q must match %s", s, kmsSocketPattern)
8691
}
92+
if _, ok := socketSet[s]; ok {
93+
return fmt.Errorf("--kms-sockets entry %q is duplicated", s)
94+
}
95+
socketSet[s] = struct{}{}
8796
}
8897

8998
if o.Interval <= 0 {
@@ -102,20 +111,25 @@ func (o *options) validate() error {
102111
return nil
103112
}
104113

105-
func (o *options) run(ctx context.Context) error {
106-
ctx = setupSignalContext(ctx)
107-
114+
func (o *options) complete() (v1helpers.OperatorClient, error) {
108115
// Empty kubeconfig falls back to the in-cluster config (service account
109116
// token + KUBERNETES_SERVICE_HOST), which is the deployed path.
110117
cfg, err := clientcmd.BuildConfigFromFlags("", o.Kubeconfig)
111118
if err != nil {
112-
return fmt.Errorf("build rest config: %w", err)
119+
return nil, fmt.Errorf("build rest config: %w", err)
113120
}
114121

115-
if _, err := o.newOperatorClient(cfg); err != nil {
116-
return fmt.Errorf("build operator client: %w", err)
122+
operatorClient, err := o.newOperatorClient(cfg)
123+
if err != nil {
124+
return nil, fmt.Errorf("build operator client: %w", err)
117125
}
118126

127+
return operatorClient, nil
128+
}
129+
130+
func (o *options) run(ctx context.Context, operatorClient v1helpers.OperatorClient) error {
131+
ctx = setupSignalContext(ctx)
132+
119133
plugins, err := buildPlugins(ctx, o.KMSSockets, o.ReadTimeout)
120134
if err != nil {
121135
return err
@@ -128,7 +142,8 @@ func (o *options) run(ctx context.Context) error {
128142
// Each Status RPC enforces o.ReadTimeout internally (set at dial time);
129143
// ctx here only carries shutdown cancellation.
130144
conditions := prober.probeAll(ctx)
131-
// TODO: hand conditions to the writer once it lands; logging is a placeholder.
145+
// TODO: hand conditions to the writer (via operatorClient) once it lands;
146+
// logging is a placeholder.
132147
klog.InfoS("kms plugin health", "conditions", conditions)
133148
}, o.Interval, 0.1, false)
134149

pkg/operator/encryption/kms/health/cmd_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ func TestValidate(t *testing.T) {
4343
name: "multiple valid sockets",
4444
mutate: func(o *options) { o.KMSSockets = append(o.KMSSockets, "unix:///var/run/kmsplugin/kms-2.sock") },
4545
},
46+
{
47+
name: "duplicate sockets",
48+
mutate: func(o *options) { o.KMSSockets = append(o.KMSSockets, o.KMSSockets[0]) },
49+
wantErr: true,
50+
},
4651
{
4752
name: "socket missing unix scheme",
4853
mutate: func(o *options) { o.KMSSockets = []string{"/var/run/kmsplugin/kms-1.sock"} },

pkg/operator/encryption/kms/health/prober.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ func (p *prober) probe(ctx context.Context, plugin pluginClient) pluginHealthRep
7676
case err != nil:
7777
report.Status = statusError
7878
report.Detail = err.Error()
79+
case resp == nil:
80+
// The in-tree gRPC client never returns (nil, nil), but a misbehaving
81+
// plugin must not panic the reporter.
82+
report.Status = statusError
83+
report.Detail = "kms plugin returned nil status response"
7984
case resp.Healthz == healthzOK:
8085
report.Status = statusHealthy
8186
report.KEKID = resp.KeyID

pkg/operator/encryption/kms/health/prober_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func TestProber_ProbeAll(t *testing.T) {
3535
{keyID: "1", service: &fakeService{resp: &kmsservice.StatusResponse{Healthz: "ok", KeyID: "kek-abc"}}},
3636
{keyID: "2", service: &fakeService{err: fmt.Errorf("connection refused")}},
3737
{keyID: "3", service: &fakeService{resp: &kmsservice.StatusResponse{Healthz: "degraded"}}},
38+
{keyID: "4", service: &fakeService{}},
3839
},
3940
now: func() time.Time { return fixed },
4041
}
@@ -44,6 +45,7 @@ func TestProber_ProbeAll(t *testing.T) {
4445
{KeyID: "1", KEKID: "kek-abc", Status: "healthy", LastChecked: fixed},
4546
{KeyID: "2", Status: "error", Detail: "connection refused", LastChecked: fixed},
4647
{KeyID: "3", Status: "unhealthy", Detail: "degraded", LastChecked: fixed},
48+
{KeyID: "4", Status: "error", Detail: "kms plugin returned nil status response", LastChecked: fixed},
4749
}
4850
if !reflect.DeepEqual(have, want) {
4951
t.Errorf("probeAll():\n have: %+v\n want: %+v", have, want)

0 commit comments

Comments
 (0)