Skip to content

Commit df08a04

Browse files
committed
kms/health: fieldManager static or uid
1 parent 4f827b8 commit df08a04

4 files changed

Lines changed: 39 additions & 25 deletions

File tree

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ const (
2626
var kmsSocketPattern = regexp.MustCompile(`^unix:///var/run/kmsplugin/kms-(\d+)\.sock$`)
2727

2828
// NewEncryptionStatusWriterFunc builds the EncryptionStatusWriter for a target
29-
// apiserver operator status CR. fieldManager sets the owner in the
30-
// managedFields when doing SSA.
31-
type NewEncryptionStatusWriterFunc func(restConfig *rest.Config, fieldManager string) (EncryptionStatusWriter, error)
29+
// apiserver operator status CR. The writer derives its own SSA fieldManager
30+
// from nodeName, because only it knows whether its status collects many
31+
// per-node reporters (kube-apiserver: fieldManager from the node UID) or a
32+
// single one (a constant fieldManager).
33+
type NewEncryptionStatusWriterFunc func(restConfig *rest.Config, nodeName string) (EncryptionStatusWriter, error)
3234

3335
// EncryptionStatusWriter is capable of applying the
3436
// KMSEncryptionStatusApplyConfiguration at the correct place in the operator's

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77

88
"github.com/spf13/pflag"
99

10-
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
1110
"k8s.io/apimachinery/pkg/util/sets"
1211
"k8s.io/client-go/tools/clientcmd"
1312
)
@@ -61,9 +60,6 @@ func (o *options) validate() error {
6160
if o.NodeName == "" {
6261
return fmt.Errorf("--node-name is required")
6362
}
64-
if fieldManager := fmt.Sprintf("%s-%s", Subcommand, o.NodeName); len(fieldManager) > metav1validation.FieldManagerMaxLength {
65-
return fmt.Errorf("--node-name too long: reporter identity %q is %d chars, exceeds the %d-char fieldManager limit", fieldManager, len(fieldManager), metav1validation.FieldManagerMaxLength)
66-
}
6763

6864
return nil
6965
}
@@ -76,9 +72,10 @@ func (o *options) Config(ctx context.Context) (*Config, error) {
7672
return nil, fmt.Errorf("build rest config: %w", err)
7773
}
7874

79-
// fieldManager is the per-node ownership-identity.
80-
fieldManager := fmt.Sprintf("%s-%s", Subcommand, o.NodeName)
81-
writeStatus, err := o.newWriter(restCfg, fieldManager)
75+
// The writer owns its fieldManager: it turns the node name into whatever
76+
// ownership identity its status needs (a per-node UID for the kube-apiserver,
77+
// a constant for the single-reporter operators).
78+
writeStatus, err := o.newWriter(restCfg, o.NodeName)
8279
if err != nil {
8380
return nil, fmt.Errorf("build encryption status writer: %w", err)
8481
}

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package health
22

33
import (
4-
"strings"
54
"testing"
65
"time"
76

@@ -104,15 +103,6 @@ func TestValidate(t *testing.T) {
104103
mutate: func(o *options) { o.NodeName = "" },
105104
wantErr: true,
106105
},
107-
{
108-
name: "node name at fieldManager limit",
109-
mutate: func(o *options) { o.NodeName = strings.Repeat("n", 108) }, // 20-char prefix + 108 == 128
110-
},
111-
{
112-
name: "node name over fieldManager limit",
113-
mutate: func(o *options) { o.NodeName = strings.Repeat("n", 109) }, // 20-char prefix + 109 > 128
114-
wantErr: true,
115-
},
116106
}
117107

118108
for _, tc := range tests {

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

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ package writers
99

1010
import (
1111
"context"
12+
"fmt"
1213

1314
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/client-go/kubernetes"
1416
"k8s.io/client-go/rest"
1517

1618
applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
@@ -22,7 +24,7 @@ import (
2224
// NewAuthenticationWriter writes into Authentication/cluster at
2325
// .status.oauthAPIServer.encryptionStatus. The auth operator manages the
2426
// oauth-apiserver. There is an extra hop the other two operators don't have.
25-
func NewAuthenticationWriter(restConfig *rest.Config, fieldManager string) (health.EncryptionStatusWriter, error) {
27+
func NewAuthenticationWriter(restConfig *rest.Config, _ string) (health.EncryptionStatusWriter, error) {
2628
client, err := operatorclient.NewForConfig(restConfig)
2729
if err != nil {
2830
return nil, err
@@ -37,21 +39,42 @@ func NewAuthenticationWriter(restConfig *rest.Config, fieldManager string) (heal
3739
),
3840
),
3941

40-
metav1.ApplyOptions{FieldManager: fieldManager, Force: true},
42+
// A single reporter writes this status, so a constant fieldManager
43+
// is enough and always fits the apiserver's length limit.
44+
metav1.ApplyOptions{FieldManager: health.Subcommand, Force: true},
4145
)
4246
return err
4347
}, nil
4448
}
4549

4650
// NewKubeAPIServerWriter writes into KubeAPIServer/cluster at
4751
// .status.encryptionStatus.
48-
func NewKubeAPIServerWriter(restConfig *rest.Config, fieldManager string) (health.EncryptionStatusWriter, error) {
52+
func NewKubeAPIServerWriter(restConfig *rest.Config, nodeName string) (health.EncryptionStatusWriter, error) {
4953
client, err := operatorclient.NewForConfig(restConfig)
5054
if err != nil {
5155
return nil, err
5256
}
57+
kubeClient, err := kubernetes.NewForConfig(restConfig)
58+
if err != nil {
59+
return nil, err
60+
}
5361

62+
// One reporter runs per control-plane node and each applies its own row, so
63+
// the fieldManager must be per-node. The node UID is a fixed-length,
64+
// instance-stable identity that fits the fieldManager length limit, unlike
65+
// the node name (a DNS subdomain up to 253 chars).
66+
//
67+
// Lazy evaluation on first call as constructor isn't concerned with any context.
68+
var fieldManager string
5469
return func(ctx context.Context, status *applyoperatorv1.KMSEncryptionStatusApplyConfiguration) error {
70+
if fieldManager == "" {
71+
node, err := kubeClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
72+
if err != nil {
73+
return fmt.Errorf("get node %q: %w", nodeName, err)
74+
}
75+
fieldManager = fmt.Sprintf("%s-%s", health.Subcommand, node.UID)
76+
}
77+
5578
_, err := client.OperatorV1().KubeAPIServers().ApplyStatus(
5679
ctx,
5780
applyoperatorv1.KubeAPIServer("cluster").WithStatus(
@@ -65,7 +88,7 @@ func NewKubeAPIServerWriter(restConfig *rest.Config, fieldManager string) (healt
6588

6689
// NewOpenShiftAPIServerWriter writes into OpenShiftAPIServer/cluster at
6790
// .status.encryptionStatus.
68-
func NewOpenShiftAPIServerWriter(restConfig *rest.Config, fieldManager string) (health.EncryptionStatusWriter, error) {
91+
func NewOpenShiftAPIServerWriter(restConfig *rest.Config, _ string) (health.EncryptionStatusWriter, error) {
6992
client, err := operatorclient.NewForConfig(restConfig)
7093
if err != nil {
7194
return nil, err
@@ -78,7 +101,9 @@ func NewOpenShiftAPIServerWriter(restConfig *rest.Config, fieldManager string) (
78101
applyoperatorv1.OpenShiftAPIServerStatus().WithEncryptionStatus(status),
79102
),
80103

81-
metav1.ApplyOptions{FieldManager: fieldManager, Force: true},
104+
// A single reporter writes this status, so a constant fieldManager
105+
// is enough and always fits the apiserver's length limit.
106+
metav1.ApplyOptions{FieldManager: health.Subcommand, Force: true},
82107
)
83108
return err
84109
}, nil

0 commit comments

Comments
 (0)