1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package options 18 19import ( 20 "strings" 21 "testing" 22 "time" 23 24 "k8s.io/apimachinery/pkg/runtime/schema" 25 utilerrors "k8s.io/apimachinery/pkg/util/errors" 26 "k8s.io/apiserver/pkg/server" 27 "k8s.io/apiserver/pkg/storage/storagebackend" 28) 29 30func TestEtcdOptionsValidate(t *testing.T) { 31 testCases := []struct { 32 name string 33 testOptions *EtcdOptions 34 expectErr string 35 }{ 36 { 37 name: "test when ServerList is not specified", 38 testOptions: &EtcdOptions{ 39 StorageConfig: storagebackend.Config{ 40 Type: "etcd3", 41 Prefix: "/registry", 42 Transport: storagebackend.TransportConfig{ 43 ServerList: nil, 44 KeyFile: "/var/run/kubernetes/etcd.key", 45 TrustedCAFile: "/var/run/kubernetes/etcdca.crt", 46 CertFile: "/var/run/kubernetes/etcdce.crt", 47 }, 48 CompactionInterval: storagebackend.DefaultCompactInterval, 49 CountMetricPollPeriod: time.Minute, 50 }, 51 DefaultStorageMediaType: "application/vnd.kubernetes.protobuf", 52 DeleteCollectionWorkers: 1, 53 EnableGarbageCollection: true, 54 EnableWatchCache: true, 55 DefaultWatchCacheSize: 100, 56 EtcdServersOverrides: []string{"/events#http://127.0.0.1:4002"}, 57 }, 58 expectErr: "--etcd-servers must be specified", 59 }, 60 { 61 name: "test when storage-backend is invalid", 62 testOptions: &EtcdOptions{ 63 StorageConfig: storagebackend.Config{ 64 Type: "etcd4", 65 Prefix: "/registry", 66 Transport: storagebackend.TransportConfig{ 67 ServerList: []string{"http://127.0.0.1"}, 68 KeyFile: "/var/run/kubernetes/etcd.key", 69 TrustedCAFile: "/var/run/kubernetes/etcdca.crt", 70 CertFile: "/var/run/kubernetes/etcdce.crt", 71 }, 72 CompactionInterval: storagebackend.DefaultCompactInterval, 73 CountMetricPollPeriod: time.Minute, 74 }, 75 DefaultStorageMediaType: "application/vnd.kubernetes.protobuf", 76 DeleteCollectionWorkers: 1, 77 EnableGarbageCollection: true, 78 EnableWatchCache: true, 79 DefaultWatchCacheSize: 100, 80 EtcdServersOverrides: []string{"/events#http://127.0.0.1:4002"}, 81 }, 82 expectErr: "--storage-backend invalid, allowed values: etcd3. If not specified, it will default to 'etcd3'", 83 }, 84 { 85 name: "test when etcd-servers-overrides is invalid", 86 testOptions: &EtcdOptions{ 87 StorageConfig: storagebackend.Config{ 88 Type: "etcd3", 89 Transport: storagebackend.TransportConfig{ 90 ServerList: []string{"http://127.0.0.1"}, 91 KeyFile: "/var/run/kubernetes/etcd.key", 92 TrustedCAFile: "/var/run/kubernetes/etcdca.crt", 93 CertFile: "/var/run/kubernetes/etcdce.crt", 94 }, 95 Prefix: "/registry", 96 CompactionInterval: storagebackend.DefaultCompactInterval, 97 CountMetricPollPeriod: time.Minute, 98 }, 99 DefaultStorageMediaType: "application/vnd.kubernetes.protobuf", 100 DeleteCollectionWorkers: 1, 101 EnableGarbageCollection: true, 102 EnableWatchCache: true, 103 DefaultWatchCacheSize: 100, 104 EtcdServersOverrides: []string{"/events/http://127.0.0.1:4002"}, 105 }, 106 expectErr: "--etcd-servers-overrides invalid, must be of format: group/resource#servers, where servers are URLs, semicolon separated", 107 }, 108 { 109 name: "test when EtcdOptions is valid", 110 testOptions: &EtcdOptions{ 111 StorageConfig: storagebackend.Config{ 112 Type: "etcd3", 113 Prefix: "/registry", 114 Transport: storagebackend.TransportConfig{ 115 ServerList: []string{"http://127.0.0.1"}, 116 KeyFile: "/var/run/kubernetes/etcd.key", 117 TrustedCAFile: "/var/run/kubernetes/etcdca.crt", 118 CertFile: "/var/run/kubernetes/etcdce.crt", 119 }, 120 CompactionInterval: storagebackend.DefaultCompactInterval, 121 CountMetricPollPeriod: time.Minute, 122 }, 123 DefaultStorageMediaType: "application/vnd.kubernetes.protobuf", 124 DeleteCollectionWorkers: 1, 125 EnableGarbageCollection: true, 126 EnableWatchCache: true, 127 DefaultWatchCacheSize: 100, 128 EtcdServersOverrides: []string{"/events#http://127.0.0.1:4002"}, 129 }, 130 }, 131 } 132 133 for _, testcase := range testCases { 134 t.Run(testcase.name, func(t *testing.T) { 135 errs := testcase.testOptions.Validate() 136 if len(testcase.expectErr) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), testcase.expectErr) { 137 t.Errorf("got err: %v, expected err: %s", errs, testcase.expectErr) 138 } 139 if len(testcase.expectErr) == 0 && len(errs) != 0 { 140 t.Errorf("got err: %s, expected err nil", errs) 141 } 142 }) 143 } 144} 145 146func TestParseWatchCacheSizes(t *testing.T) { 147 testCases := []struct { 148 name string 149 cacheSizes []string 150 expectWatchCacheSizes map[schema.GroupResource]int 151 expectErr string 152 }{ 153 { 154 name: "test when invalid value of watch cache size", 155 cacheSizes: []string{"deployments.apps#65536", "replicasets.extensions"}, 156 expectErr: "invalid value of watch cache size", 157 }, 158 { 159 name: "test when invalid size of watch cache size", 160 cacheSizes: []string{"deployments.apps#65536", "replicasets.extensions#655d1"}, 161 expectErr: "invalid size of watch cache size", 162 }, 163 { 164 name: "test when watch cache size is negative", 165 cacheSizes: []string{"deployments.apps#65536", "replicasets.extensions#-65536"}, 166 expectErr: "watch cache size cannot be negative", 167 }, 168 { 169 name: "test when parse watch cache size success", 170 cacheSizes: []string{"deployments.apps#65536", "replicasets.extensions#65536"}, 171 expectWatchCacheSizes: map[schema.GroupResource]int{ 172 {Group: "apps", Resource: "deployments"}: 65536, 173 {Group: "extensions", Resource: "replicasets"}: 65536, 174 }, 175 }, 176 } 177 178 for _, testcase := range testCases { 179 t.Run(testcase.name, func(t *testing.T) { 180 result, err := ParseWatchCacheSizes(testcase.cacheSizes) 181 if len(testcase.expectErr) != 0 && !strings.Contains(err.Error(), testcase.expectErr) { 182 t.Errorf("got err: %v, expected err: %s", err, testcase.expectErr) 183 } 184 if len(testcase.expectErr) == 0 { 185 if err != nil { 186 t.Errorf("got err: %v, expected err nil", err) 187 } else { 188 for key, expectValue := range testcase.expectWatchCacheSizes { 189 if resultValue, exist := result[key]; !exist || resultValue != expectValue { 190 t.Errorf("got watch cache size: %v, expected watch cache size %v", result, testcase.expectWatchCacheSizes) 191 } 192 } 193 } 194 } 195 }) 196 } 197} 198 199func TestKMSHealthzEndpoint(t *testing.T) { 200 testCases := []struct { 201 name string 202 encryptionConfigPath string 203 wantChecks []string 204 }{ 205 { 206 name: "single kms-provider, expect single kms healthz check", 207 encryptionConfigPath: "testdata/encryption-configs/single-kms-provider.yaml", 208 wantChecks: []string{"etcd", "kms-provider-0"}, 209 }, 210 { 211 name: "two kms-providers, expect two kms healthz checks", 212 encryptionConfigPath: "testdata/encryption-configs/multiple-kms-providers.yaml", 213 wantChecks: []string{"etcd", "kms-provider-0", "kms-provider-1"}, 214 }, 215 } 216 217 for _, tc := range testCases { 218 t.Run(tc.name, func(t *testing.T) { 219 serverConfig := &server.Config{} 220 etcdOptions := &EtcdOptions{ 221 EncryptionProviderConfigFilepath: tc.encryptionConfigPath, 222 } 223 if err := etcdOptions.addEtcdHealthEndpoint(serverConfig); err != nil { 224 t.Fatalf("Failed to add healthz error: %v", err) 225 } 226 227 for _, n := range tc.wantChecks { 228 found := false 229 for _, h := range serverConfig.HealthzChecks { 230 if n == h.Name() { 231 found = true 232 break 233 } 234 } 235 if !found { 236 t.Errorf("Missing HealthzChecker %s", n) 237 } 238 found = false 239 } 240 }) 241 } 242} 243