feat: implement strategic merge patching for API server admission config
The testcase explains it better, but tl;dr is that this allows to do strategic merge patching e.g. for the Pod Security configuration. Fixes #5895 Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
parent
be98cb82b5
commit
f1c2b5c558
@ -42,6 +42,10 @@ var (
|
||||
|
||||
//nolint:gocyclo,cyclop
|
||||
func merge(vl, vr reflect.Value, replace bool) error {
|
||||
if vl == zeroValue && vr == zeroValue {
|
||||
return nil
|
||||
}
|
||||
|
||||
tl, tr := vl.Type(), vr.Type()
|
||||
|
||||
if tl != tr {
|
||||
@ -53,7 +57,7 @@ func merge(vl, vr reflect.Value, replace bool) error {
|
||||
}
|
||||
|
||||
switch tl.Kind() { //nolint:exhaustive
|
||||
case reflect.Pointer:
|
||||
case reflect.Pointer, reflect.Interface:
|
||||
if vr.IsZero() {
|
||||
return nil
|
||||
}
|
||||
@ -102,11 +106,32 @@ func merge(vl, vr reflect.Value, replace bool) error {
|
||||
|
||||
for _, k := range vr.MapKeys() {
|
||||
if vl.MapIndex(k) != zeroValue {
|
||||
v := reflect.New(tl.Elem()).Elem()
|
||||
v.Set(vl.MapIndex(k))
|
||||
valueType := tl.Elem()
|
||||
|
||||
if err := merge(v, vr.MapIndex(k), false); err != nil {
|
||||
return err
|
||||
var v, rightV reflect.Value
|
||||
|
||||
if valueType.Kind() == reflect.Interface { // special case for map[string]interface{}
|
||||
// here we have to instantiate the actual type behind in the `interface{}`, otherwise it's not settable
|
||||
valueType = vl.MapIndex(k).Elem().Type()
|
||||
|
||||
if valueType != vr.MapIndex(k).Elem().Type() {
|
||||
return fmt.Errorf("merge type mismatch left %v right %v", valueType, vr.MapIndex(k).Elem().Type())
|
||||
}
|
||||
|
||||
v = reflect.New(valueType).Elem()
|
||||
v.Set(vl.MapIndex(k).Elem())
|
||||
|
||||
rightV = reflect.New(valueType).Elem()
|
||||
rightV.Set(vr.MapIndex(k).Elem())
|
||||
} else { // "normal" maps
|
||||
v = reflect.New(valueType).Elem()
|
||||
v.Set(vl.MapIndex(k))
|
||||
|
||||
rightV = vr.MapIndex(k)
|
||||
}
|
||||
|
||||
if err := merge(v, rightV, false); err != nil {
|
||||
return fmt.Errorf("merge map key %v[%v]: %w", tl, k, err)
|
||||
}
|
||||
|
||||
vl.SetMapIndex(k, v)
|
||||
@ -135,7 +160,7 @@ func merge(vl, vr reflect.Value, replace bool) error {
|
||||
fr := vr.FieldByIndex(tr.Field(i).Index)
|
||||
|
||||
if err := merge(fl, fr, replace); err != nil {
|
||||
return fmt.Errorf("merge field %v.%v: %v", tl, tl.Field(i).Name, err)
|
||||
return fmt.Errorf("merge field %v.%v: %w", tl, tl.Field(i).Name, err)
|
||||
}
|
||||
}
|
||||
case
|
||||
|
@ -45,18 +45,20 @@ func (s *CustomSlice) Merge(other interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Unstructured map[string]interface{}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
left, right Config
|
||||
expected Config
|
||||
left, right interface{}
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
},
|
||||
{
|
||||
name: "partial merge",
|
||||
left: Config{
|
||||
left: &Config{
|
||||
A: "a",
|
||||
B: 3,
|
||||
C: pointer.To(true),
|
||||
@ -75,7 +77,7 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
right: Config{
|
||||
right: &Config{
|
||||
A: "aa",
|
||||
B: 4,
|
||||
Slice: []Struct{
|
||||
@ -97,7 +99,7 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: Config{
|
||||
expected: &Config{
|
||||
A: "aa",
|
||||
B: 4,
|
||||
C: pointer.To(true),
|
||||
@ -127,7 +129,7 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "merge with zero",
|
||||
left: Config{
|
||||
left: &Config{
|
||||
A: "a",
|
||||
B: 3,
|
||||
C: pointer.To(true),
|
||||
@ -146,8 +148,8 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
right: Config{},
|
||||
expected: Config{
|
||||
right: &Config{},
|
||||
expected: &Config{
|
||||
A: "a",
|
||||
B: 3,
|
||||
C: pointer.To(true),
|
||||
@ -169,8 +171,8 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "merge from zero",
|
||||
left: Config{},
|
||||
right: Config{
|
||||
left: &Config{},
|
||||
right: &Config{
|
||||
A: "a",
|
||||
B: 3,
|
||||
C: pointer.To(true),
|
||||
@ -189,7 +191,7 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: Config{
|
||||
expected: &Config{
|
||||
A: "a",
|
||||
B: 3,
|
||||
C: pointer.To(true),
|
||||
@ -211,41 +213,74 @@ func TestMerge(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "replace slice",
|
||||
left: Config{
|
||||
left: &Config{
|
||||
ReplacedSlice: []string{"a", "b"},
|
||||
},
|
||||
right: Config{
|
||||
right: &Config{
|
||||
ReplacedSlice: []string{"c", "d"},
|
||||
},
|
||||
expected: Config{
|
||||
expected: &Config{
|
||||
ReplacedSlice: []string{"c", "d"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "zero slice",
|
||||
left: Config{},
|
||||
right: Config{
|
||||
left: &Config{},
|
||||
right: &Config{
|
||||
Slice: []Struct{},
|
||||
},
|
||||
expected: Config{
|
||||
expected: &Config{
|
||||
Slice: []Struct{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "custom slice",
|
||||
left: Config{
|
||||
left: &Config{
|
||||
CustomSlice: []string{"a", "c"},
|
||||
},
|
||||
right: Config{
|
||||
right: &Config{
|
||||
CustomSlice: []string{"b", "d"},
|
||||
},
|
||||
expected: Config{
|
||||
expected: &Config{
|
||||
CustomSlice: []string{"a", "b", "c", "d"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unstructured",
|
||||
left: &Unstructured{
|
||||
"a": "aa",
|
||||
"map": map[string]interface{}{
|
||||
"slice": []interface{}{
|
||||
"s1",
|
||||
},
|
||||
"some": "value",
|
||||
},
|
||||
},
|
||||
right: &Unstructured{
|
||||
"b": "bb",
|
||||
"map": map[string]interface{}{
|
||||
"slice": []interface{}{
|
||||
"s2",
|
||||
},
|
||||
"other": "thing",
|
||||
},
|
||||
},
|
||||
expected: &Unstructured{
|
||||
"a": "aa",
|
||||
"b": "bb",
|
||||
"map": map[string]interface{}{
|
||||
"slice": []interface{}{
|
||||
"s1",
|
||||
"s2",
|
||||
},
|
||||
"some": "value",
|
||||
"other": "thing",
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := merge.Merge(&tt.left, &tt.right)
|
||||
err := merge.Merge(tt.left, tt.right)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.expected, tt.left)
|
||||
|
89
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/expected.yaml
vendored
Normal file
89
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/expected.yaml
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
version: v1alpha1
|
||||
debug: false
|
||||
persist: true
|
||||
machine:
|
||||
type: controlplane
|
||||
token: u8ei4i.iymakyzguuqaw30r
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K
|
||||
certSANs: []
|
||||
kubelet:
|
||||
image: ghcr.io/siderolabs/kubelet:v1.24.2
|
||||
network:
|
||||
hostname:
|
||||
interfaces:
|
||||
- interface: eth0
|
||||
addresses:
|
||||
- 172.20.0.2/24
|
||||
dhcp: true
|
||||
- deviceSelector:
|
||||
driver: macvtap
|
||||
dhcp: false
|
||||
install:
|
||||
disk: /dev/sda
|
||||
image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e
|
||||
bootloader: true
|
||||
wipe: false
|
||||
features:
|
||||
rbac: true
|
||||
cluster:
|
||||
id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=
|
||||
secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=
|
||||
controlPlane:
|
||||
endpoint: https://127.0.0.1:6643/
|
||||
clusterName: foo
|
||||
network:
|
||||
dnsDomain: cluster.local
|
||||
podSubnets:
|
||||
- 10.244.0.0/16
|
||||
serviceSubnets:
|
||||
- 10.96.0.0/12
|
||||
token: 4pcl58.l0i5cv8h9k3k1az8
|
||||
aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
aggregatorCA:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
serviceAccount:
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
apiServer:
|
||||
image: k8s.gcr.io/kube-apiserver:v1.24.2
|
||||
certSANs:
|
||||
- 127.0.0.1
|
||||
disablePodSecurityPolicy: true
|
||||
admissionControl:
|
||||
- name: PodSecurity
|
||||
configuration:
|
||||
apiVersion: pod-security.admission.config.k8s.io/v1alpha1
|
||||
defaults:
|
||||
audit: restricted
|
||||
audit-version: latest
|
||||
enforce: restricted
|
||||
enforce-version: latest
|
||||
warn: restricted
|
||||
warn-version: latest
|
||||
exemptions:
|
||||
namespaces:
|
||||
- kube-system
|
||||
- rook-system
|
||||
runtimeClasses: []
|
||||
usernames: []
|
||||
kind: PodSecurityConfiguration
|
||||
controllerManager:
|
||||
image: k8s.gcr.io/kube-controller-manager:v1.24.2
|
||||
proxy:
|
||||
image: k8s.gcr.io/kube-proxy:v1.24.2
|
||||
scheduler:
|
||||
image: k8s.gcr.io/kube-scheduler:v1.24.2
|
||||
discovery:
|
||||
enabled: true
|
||||
registries:
|
||||
kubernetes: {}
|
||||
service: {}
|
||||
etcd:
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
88
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/left.yaml
vendored
Normal file
88
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/left.yaml
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
version: v1alpha1
|
||||
debug: false
|
||||
persist: true
|
||||
machine:
|
||||
type: controlplane
|
||||
token: u8ei4i.iymakyzguuqaw30r
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K
|
||||
certSANs: []
|
||||
kubelet:
|
||||
image: ghcr.io/siderolabs/kubelet:v1.24.2
|
||||
network:
|
||||
hostname:
|
||||
interfaces:
|
||||
- interface: eth0
|
||||
addresses:
|
||||
- 172.20.0.2/24
|
||||
dhcp: true
|
||||
- deviceSelector:
|
||||
driver: macvtap
|
||||
dhcp: false
|
||||
install:
|
||||
disk: /dev/sda
|
||||
image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e
|
||||
bootloader: true
|
||||
wipe: false
|
||||
features:
|
||||
rbac: true
|
||||
cluster:
|
||||
id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=
|
||||
secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=
|
||||
controlPlane:
|
||||
endpoint: https://127.0.0.1:6643/
|
||||
clusterName: foo
|
||||
network:
|
||||
dnsDomain: cluster.local
|
||||
podSubnets:
|
||||
- 10.244.0.0/16
|
||||
serviceSubnets:
|
||||
- 10.96.0.0/12
|
||||
token: 4pcl58.l0i5cv8h9k3k1az8
|
||||
aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
aggregatorCA:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
serviceAccount:
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
||||
apiServer:
|
||||
image: k8s.gcr.io/kube-apiserver:v1.24.2
|
||||
certSANs:
|
||||
- 127.0.0.1
|
||||
disablePodSecurityPolicy: true
|
||||
admissionControl:
|
||||
- name: PodSecurity
|
||||
configuration:
|
||||
apiVersion: pod-security.admission.config.k8s.io/v1alpha1
|
||||
defaults:
|
||||
audit: restricted
|
||||
audit-version: latest
|
||||
enforce: baseline
|
||||
enforce-version: latest
|
||||
warn: restricted
|
||||
warn-version: latest
|
||||
exemptions:
|
||||
namespaces:
|
||||
- kube-system
|
||||
runtimeClasses: []
|
||||
usernames: []
|
||||
kind: PodSecurityConfiguration
|
||||
controllerManager:
|
||||
image: k8s.gcr.io/kube-controller-manager:v1.24.2
|
||||
proxy:
|
||||
image: k8s.gcr.io/kube-proxy:v1.24.2
|
||||
scheduler:
|
||||
image: k8s.gcr.io/kube-scheduler:v1.24.2
|
||||
discovery:
|
||||
enabled: true
|
||||
registries:
|
||||
kubernetes: {}
|
||||
service: {}
|
||||
etcd:
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
|
11
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/right.yaml
vendored
Normal file
11
pkg/machinery/config/types/v1alpha1/testdata/strategic/004/right.yaml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
cluster:
|
||||
apiServer:
|
||||
image: k8s.gcr.io/kube-apiserver:v1.24.2
|
||||
admissionControl:
|
||||
- name: PodSecurity
|
||||
configuration:
|
||||
defaults:
|
||||
enforce: restricted
|
||||
exemptions:
|
||||
namespaces:
|
||||
- rook-system
|
@ -1492,7 +1492,48 @@ type APIServerConfig struct {
|
||||
// Configure the API server admission plugins.
|
||||
// examples:
|
||||
// - value: admissionControlConfigExample
|
||||
AdmissionControlConfig []*AdmissionPluginConfig `yaml:"admissionControl,omitempty"`
|
||||
AdmissionControlConfig AdmissionPluginConfigList `yaml:"admissionControl,omitempty"`
|
||||
}
|
||||
|
||||
// AdmissionPluginConfigList represents the admission plugin configuration list.
|
||||
//
|
||||
//docgen:alias
|
||||
type AdmissionPluginConfigList []*AdmissionPluginConfig
|
||||
|
||||
// Merge the admission plugin configuration intelligently.
|
||||
func (configs *AdmissionPluginConfigList) Merge(other interface{}) error {
|
||||
otherConfigs, ok := other.(AdmissionPluginConfigList)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type for device merge %T", other)
|
||||
}
|
||||
|
||||
for _, config := range otherConfigs {
|
||||
if err := configs.mergeConfig(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (configs *AdmissionPluginConfigList) mergeConfig(config *AdmissionPluginConfig) error {
|
||||
var existing *AdmissionPluginConfig
|
||||
|
||||
for _, c := range *configs {
|
||||
if c.PluginName == config.PluginName {
|
||||
existing = c
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if existing != nil {
|
||||
return merge.Merge(existing, config)
|
||||
}
|
||||
|
||||
*configs = append(*configs, config)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AdmissionPluginConfig represents the API server admission plugin configuration.
|
||||
|
@ -43,7 +43,7 @@ func (in *APIServerConfig) DeepCopyInto(out *APIServerConfig) {
|
||||
}
|
||||
if in.AdmissionControlConfig != nil {
|
||||
in, out := &in.AdmissionControlConfig, &out.AdmissionControlConfig
|
||||
*out = make([]*AdmissionPluginConfig, len(*in))
|
||||
*out = make(AdmissionPluginConfigList, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
@ -98,6 +98,32 @@ func (in *AdmissionPluginConfig) DeepCopy() *AdmissionPluginConfig {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in AdmissionPluginConfigList) DeepCopyInto(out *AdmissionPluginConfigList) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(AdmissionPluginConfigList, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(AdmissionPluginConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionPluginConfigList.
|
||||
func (in AdmissionPluginConfigList) DeepCopy() AdmissionPluginConfigList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AdmissionPluginConfigList)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in Base64Bytes) DeepCopyInto(out *Base64Bytes) {
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user