Skip to content

Commit d8a439a

Browse files
authored
Merge pull request #2389 from vmware-tanzu/agentConfig_priorityClassName
New configuration option for Concierge: kube cert agent `priorityClassName`
2 parents 33c68e2 + 1254f73 commit d8a439a

File tree

17 files changed

+407
-32
lines changed

17 files changed

+407
-32
lines changed

deploy/concierge/deployment.yaml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@
33

44
#@ load("@ytt:data", "data")
55
#@ load("@ytt:json", "json")
6-
#@ load("helpers.lib.yaml", "defaultLabel", "labels", "deploymentPodLabel", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix", "getAndValidateLogLevel", "pinnipedDevAPIGroupWithPrefix")
6+
#@ load("helpers.lib.yaml",
7+
#@ "defaultLabel",
8+
#@ "labels",
9+
#@ "deploymentPodLabel",
10+
#@ "namespace",
11+
#@ "defaultResourceName",
12+
#@ "defaultResourceNameWithSuffix",
13+
#@ "getAndValidateLogLevel",
14+
#@ "pinnipedDevAPIGroupWithPrefix",
15+
#@ )
716
#@ load("@ytt:template", "template")
817

918
#@ if not data.values.into_namespace:
@@ -84,6 +93,7 @@ data:
8493
labels: (@= json.encode(labels()).rstrip() @)
8594
kubeCertAgent:
8695
namePrefix: (@= defaultResourceNameWithSuffix("kube-cert-agent-") @)
96+
priorityClassName: (@= data.values.kube_cert_agent_priority_class_name @)
8797
(@ if data.values.kube_cert_agent_image: @)
8898
image: (@= data.values.kube_cert_agent_image @)
8999
(@ else: @)
@@ -95,12 +105,12 @@ data:
95105
(@ end @)
96106
(@ if data.values.image_pull_dockerconfigjson: @)
97107
imagePullSecrets:
98-
- image-pull-secret
108+
- image-pull-secret
99109
(@ end @)
100110
(@ if data.values.log_level: @)
101111
log:
102112
level: (@= getAndValidateLogLevel() @)
103-
(@ end @)
113+
(@ end @)
104114
tls:
105115
onedottwo:
106116
allowedCiphers: (@= str(data.values.allowed_ciphers_for_tls_onedottwo) @)

deploy/concierge/helpers.lib.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
1+
#! Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
22
#! SPDX-License-Identifier: Apache-2.0
33

44
#@ load("@ytt:data", "data")

deploy/concierge/values.yaml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#! Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
1+
#! Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
22
#! SPDX-License-Identifier: Apache-2.0
33

44
#@ def validate_strings_map(obj):
@@ -68,15 +68,24 @@ image_digest: ""
6868
image_tag: latest
6969

7070
#@schema/title "Kube Cert Agent image"
71-
#@ kube_cert_agent_image = "Optionally specify a different image for the 'kube-cert-agent' pod which is scheduled \
71+
#@ kube_cert_agent_image_desc = "Optionally specify a different image for the 'kube-cert-agent' pod which is scheduled \
7272
#@ on the control plane. This image needs only to include `sleep` and `cat` binaries. \
7373
#@ By default, the same image specified for image_repo/image_digest/image_tag will be re-used."
74-
#@schema/desc kube_cert_agent_image
74+
#@schema/desc kube_cert_agent_image_desc
7575
#@schema/examples ("Image including tag or digest", "ghcr.io/vmware-tanzu/pinniped/pinniped-server:latest")
7676
#@schema/nullable
7777
#@schema/validation min_len=1
7878
kube_cert_agent_image: ""
7979

80+
#@schema/title "Kube Cert Agent Priority Class Name"
81+
#@ kube_cert_agent_priority_class_name_desc = "Optionally specify a PriorityClassName for the 'kube-cert-agent' pod. \
82+
#@ See https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/ for more details. \
83+
#@ By default, this is the empty string."
84+
#@schema/desc kube_cert_agent_priority_class_name_desc
85+
#@schema/examples ("name of a PriorityClass object", "high-priority")
86+
#@schema/validation min_len=0
87+
kube_cert_agent_priority_class_name: ""
88+
8089
#@schema/title "Image pull dockerconfigjson"
8190
#@ image_pull_dockerconfigjson_desc = "A base64 encoded secret to be used when pulling the `image_repo` container image. \
8291
#@ Can be used when the image_repo is a private registry. Typically, the value would be the output of: \

deploy/supervisor/deployment.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
1+
#! Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
22
#! SPDX-License-Identifier: Apache-2.0
33

44
#@ load("@ytt:data", "data")
@@ -13,7 +13,7 @@
1313
#@ "pinnipedDevAPIGroupWithPrefix",
1414
#@ "getPinnipedConfigMapData",
1515
#@ "hasUnixNetworkEndpoint",
16-
#@ )
16+
#@ )
1717
#@ load("@ytt:template", "template")
1818

1919
#@ if not data.values.into_namespace:

hack/module.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
99

1010
function usage() {
1111
echo "Error: <task> must be specified"
12-
echo " module.sh <task> [tidy, lint, test, unittest]"
12+
echo " module.sh <task> [tidy, lint, unit, unittest]"
1313
exit 1
1414
}
1515

@@ -49,10 +49,12 @@ function main() {
4949
# Temporarily avoid using the race detector for the impersonator package due to https://github.com/kubernetes/kubernetes/issues/128548
5050
KUBE_CACHE_MUTATION_DETECTOR=${kube_cache_mutation_detector} \
5151
KUBE_PANIC_WATCH_DECODE_ERROR=${kube_panic_watch_decode_error} \
52+
CGO_ENABLED=0 \
5253
go test -short -race $(go list ./... | grep -v internal/concierge/impersonator)
5354
# TODO: change this back to using the race detector everywhere
5455
KUBE_CACHE_MUTATION_DETECTOR=${kube_cache_mutation_detector} \
5556
KUBE_PANIC_WATCH_DECODE_ERROR=${kube_panic_watch_decode_error} \
57+
CGO_ENABLED=0 \
5658
go test -short ./internal/concierge/impersonator
5759
;;
5860
'generate')

internal/config/concierge/config.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"strings"
1313

14+
"k8s.io/apimachinery/pkg/util/validation"
1415
"k8s.io/utils/ptr"
1516
"sigs.k8s.io/yaml"
1617

@@ -85,6 +86,10 @@ func FromPath(ctx context.Context, path string, setAllowedCiphers ptls.SetAllowe
8586
return nil, fmt.Errorf("validate names: %w", err)
8687
}
8788

89+
if err := validateKubeCertAgent(&config.KubeCertAgentConfig); err != nil {
90+
return nil, fmt.Errorf("validate kubeCertAgent: %w", err)
91+
}
92+
8893
if err := plog.ValidateAndSetLogLevelAndFormatGlobally(ctx, config.Log); err != nil {
8994
return nil, fmt.Errorf("validate log level: %w", err)
9095
}
@@ -186,6 +191,22 @@ func validateNames(names *NamesConfigSpec) error {
186191
return nil
187192
}
188193

194+
func validateKubeCertAgent(agentConfig *KubeCertAgentSpec) error {
195+
if len(agentConfig.PriorityClassName) == 0 {
196+
// Optional, so empty is valid.
197+
return nil
198+
}
199+
200+
// See https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass
201+
// for PriorityClassName rules.
202+
errStrings := validation.IsDNS1123Subdomain(agentConfig.PriorityClassName)
203+
if len(errStrings) > 0 {
204+
// Always good enough to return the first error. IsDNS1123Subdomain only has two errors that it can return.
205+
return fmt.Errorf("invalid priorityClassName: %s", errStrings[0])
206+
}
207+
return nil
208+
}
209+
189210
func validateAPI(apiConfig *APIConfigSpec) error {
190211
if *apiConfig.ServingCertificateConfig.DurationSeconds < *apiConfig.ServingCertificateConfig.RenewBeforeSeconds {
191212
return constable.Error("durationSeconds cannot be smaller than renewBeforeSeconds")

internal/config/concierge/config_test.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"fmt"
99
"os"
10+
"strings"
1011
"testing"
1112

1213
"github.com/stretchr/testify/require"
@@ -17,6 +18,9 @@ import (
1718
)
1819

1920
func TestFromPath(t *testing.T) {
21+
stringOfLength253 := strings.Repeat("a", 253)
22+
stringOfLength254 := strings.Repeat("a", 254)
23+
2024
tests := []struct {
2125
name string
2226
yaml string
@@ -26,7 +30,7 @@ func TestFromPath(t *testing.T) {
2630
}{
2731
{
2832
name: "Fully filled out",
29-
yaml: here.Doc(`
33+
yaml: here.Docf(`
3034
---
3135
discovery:
3236
url: https://some.discovery/url
@@ -64,6 +68,7 @@ func TestFromPath(t *testing.T) {
6468
namePrefix: kube-cert-agent-name-prefix-
6569
image: kube-cert-agent-image
6670
imagePullSecrets: [kube-cert-agent-image-pull-secret]
71+
priorityClassName: %s
6772
log:
6873
level: debug
6974
tls:
@@ -74,7 +79,7 @@ func TestFromPath(t *testing.T) {
7479
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
7580
audit:
7681
logUsernamesAndGroups: enabled
77-
`),
82+
`, stringOfLength253),
7883
wantConfig: &Config{
7984
DiscoveryInfo: DiscoveryInfoSpec{
8085
URL: ptr.To("https://some.discovery/url"),
@@ -112,9 +117,10 @@ func TestFromPath(t *testing.T) {
112117
"myLabelKey2": "myLabelValue2",
113118
},
114119
KubeCertAgentConfig: KubeCertAgentSpec{
115-
NamePrefix: ptr.To("kube-cert-agent-name-prefix-"),
116-
Image: ptr.To("kube-cert-agent-image"),
117-
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
120+
NamePrefix: ptr.To("kube-cert-agent-name-prefix-"),
121+
Image: ptr.To("kube-cert-agent-image"),
122+
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
123+
PriorityClassName: stringOfLength253,
118124
},
119125
Log: plog.LogSpec{
120126
Level: plog.LevelDebug,
@@ -173,6 +179,7 @@ func TestFromPath(t *testing.T) {
173179
namePrefix: kube-cert-agent-name-prefix-
174180
image: kube-cert-agent-image
175181
imagePullSecrets: [kube-cert-agent-image-pull-secret]
182+
priorityClassName: kube-cert-agent-priority-class-name
176183
log:
177184
level: all
178185
format: json
@@ -216,9 +223,10 @@ func TestFromPath(t *testing.T) {
216223
"myLabelKey2": "myLabelValue2",
217224
},
218225
KubeCertAgentConfig: KubeCertAgentSpec{
219-
NamePrefix: ptr.To("kube-cert-agent-name-prefix-"),
220-
Image: ptr.To("kube-cert-agent-image"),
221-
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
226+
NamePrefix: ptr.To("kube-cert-agent-name-prefix-"),
227+
Image: ptr.To("kube-cert-agent-image"),
228+
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
229+
PriorityClassName: "kube-cert-agent-priority-class-name",
222230
},
223231
Log: plog.LogSpec{
224232
Level: plog.LevelAll,
@@ -703,6 +711,50 @@ func TestFromPath(t *testing.T) {
703711
`),
704712
wantError: "validate audit: invalid logUsernamesAndGroups format, valid choices are 'enabled', 'disabled', or empty string (equivalent to 'disabled')",
705713
},
714+
{
715+
name: "invalid kubeCertAgent.priorityClassName length",
716+
yaml: here.Docf(`
717+
---
718+
names:
719+
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
720+
credentialIssuer: pinniped-config
721+
apiService: pinniped-api
722+
impersonationLoadBalancerService: impersonationLoadBalancerService-value
723+
impersonationClusterIPService: impersonationClusterIPService-value
724+
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
725+
impersonationCACertificateSecret: impersonationCACertificateSecret-value
726+
impersonationSignerSecret: impersonationSignerSecret-value
727+
impersonationSignerSecret: impersonationSignerSecret-value
728+
agentServiceAccount: agentServiceAccount-value
729+
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
730+
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
731+
kubeCertAgent:
732+
priorityClassName: %s
733+
`, stringOfLength254),
734+
wantError: "validate kubeCertAgent: invalid priorityClassName: must be no more than 253 characters",
735+
},
736+
{
737+
name: "invalid kubeCertAgent.priorityClassName format",
738+
yaml: here.Doc(`
739+
---
740+
names:
741+
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
742+
credentialIssuer: pinniped-config
743+
apiService: pinniped-api
744+
impersonationLoadBalancerService: impersonationLoadBalancerService-value
745+
impersonationClusterIPService: impersonationClusterIPService-value
746+
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
747+
impersonationCACertificateSecret: impersonationCACertificateSecret-value
748+
impersonationSignerSecret: impersonationSignerSecret-value
749+
impersonationSignerSecret: impersonationSignerSecret-value
750+
agentServiceAccount: agentServiceAccount-value
751+
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
752+
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
753+
kubeCertAgent:
754+
priorityClassName: thisIsNotAValidPriorityClassName
755+
`),
756+
wantError: `validate kubeCertAgent: invalid priorityClassName: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')`,
757+
},
706758
}
707759
for _, test := range tests {
708760
t.Run(test.name, func(t *testing.T) {

internal/config/concierge/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,7 @@ type KubeCertAgentSpec struct {
108108
// ImagePullSecrets is a list of names of Kubernetes Secret objects that will be used as
109109
// ImagePullSecrets on the kube-cert-agent pods.
110110
ImagePullSecrets []string
111+
112+
// PriorityClassName optionally sets the PriorityClassName for the agent's pod.
113+
PriorityClassName string `json:"priorityClassName"`
111114
}

internal/controller/kubecertagent/kubecertagent.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved.
1+
// Copyright 2021-2025 the Pinniped contributors. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

44
// Package kubecertagent provides controllers that ensure a pod (the kube-cert-agent), is
@@ -101,6 +101,9 @@ type AgentConfig struct {
101101
// DiscoveryURLOverride is the Kubernetes server endpoint to report in the CredentialIssuer, overriding any
102102
// value discovered in the kube-public/cluster-info ConfigMap.
103103
DiscoveryURLOverride *string
104+
105+
// PriorityClassName optionally sets the PriorityClassName for the agent's pod.
106+
PriorityClassName string
104107
}
105108

106109
// Only select using the unique label which will not match the pods of any other Deployment.
@@ -429,12 +432,14 @@ func (c *agentController) createOrUpdateDeployment(ctx context.Context, newestCo
429432
updatedDeployment.ObjectMeta = mergeLabelsAndAnnotations(updatedDeployment.ObjectMeta, expectedDeployment.ObjectMeta)
430433
desireSelectorUpdate := !apiequality.Semantic.DeepEqual(updatedDeployment.Spec.Selector, existingDeployment.Spec.Selector)
431434
desireTemplateLabelsUpdate := !apiequality.Semantic.DeepEqual(updatedDeployment.Spec.Template.Labels, existingDeployment.Spec.Template.Labels)
435+
// The user might want to set PriorityClassName back to the default value of empty string. DeepDerivative() won't detect this case below.
436+
desirePriorityClassNameUpdate := updatedDeployment.Spec.Template.Spec.PriorityClassName != existingDeployment.Spec.Template.Spec.PriorityClassName
432437

433438
// If the existing Deployment already matches our desired spec, we're done.
434439
if apiequality.Semantic.DeepDerivative(updatedDeployment, existingDeployment) {
435440
// DeepDerivative allows the map fields of updatedDeployment to be a subset of existingDeployment,
436441
// but we want to check that certain of those map fields are exactly equal before deciding to skip the update.
437-
if !desireSelectorUpdate && !desireTemplateLabelsUpdate {
442+
if !desireSelectorUpdate && !desireTemplateLabelsUpdate && !desirePriorityClassNameUpdate {
438443
return nil // already equal enough, so skip update
439444
}
440445
}
@@ -661,7 +666,8 @@ func (c *agentController) newAgentDeployment(controllerManagerPod *corev1.Pod) *
661666
RunAsUser: ptr.To[int64](0),
662667
RunAsGroup: ptr.To[int64](0),
663668
},
664-
HostNetwork: controllerManagerPod.Spec.HostNetwork,
669+
HostNetwork: controllerManagerPod.Spec.HostNetwork,
670+
PriorityClassName: c.cfg.PriorityClassName,
665671
},
666672
},
667673

0 commit comments

Comments
 (0)