sigs.k8s.io/controller-runtime@v0.18.2/pkg/internal/testing/controlplane/apiserver_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controlplane_test 18 19 import ( 20 "errors" 21 "net/url" 22 23 . "github.com/onsi/ginkgo/v2" 24 . "github.com/onsi/gomega" 25 "k8s.io/client-go/rest" 26 27 . "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane" 28 "sigs.k8s.io/controller-runtime/pkg/internal/testing/process" 29 ) 30 31 var _ = Describe("APIServer", func() { 32 var server *APIServer 33 BeforeEach(func() { 34 server = &APIServer{ 35 EtcdURL: &url.URL{}, 36 } 37 }) 38 JustBeforeEach(func() { 39 Expect(PrepareAPIServer(server)).To(Succeed()) 40 }) 41 Describe("setting up serving hosts & ports", func() { 42 Context("when URL is set", func() { 43 BeforeEach(func() { 44 server.URL = &url.URL{Scheme: "http", Host: "localhost:8675", Path: "/some-path"} 45 }) 46 47 Context("when insecure serving is also set", func() { 48 BeforeEach(func() { 49 server.InsecureServing = &process.ListenAddr{ 50 Address: "localhost", 51 Port: "1234", 52 } 53 }) 54 55 It("should override the existing insecure serving", func() { 56 Expect(server.InsecureServing).To(Equal(&process.ListenAddr{ 57 Address: "localhost", 58 Port: "8675", 59 })) 60 }) 61 }) 62 63 It("should set insecure serving off of that", func() { 64 Expect(server.InsecureServing).To(Equal(&process.ListenAddr{ 65 Address: "localhost", 66 Port: "8675", 67 })) 68 }) 69 70 It("should keep URL as-is", func() { 71 Expect(server.URL.String()).To(Equal("http://localhost:8675/some-path")) 72 }) 73 }) 74 75 Context("when URL is not set but InsecureServing is set", func() { 76 BeforeEach(func() { 77 server.InsecureServing = &process.ListenAddr{} 78 }) 79 80 Context("when host and port are set", func() { 81 BeforeEach(func() { 82 server.InsecureServing.Address = "localhost" 83 server.InsecureServing.Port = "8675" 84 }) 85 It("should set URL from InsecureServing", func() { 86 Expect(server.URL.String()).To(Equal("http://localhost:8675")) 87 }) 88 89 It("should leave InsecureServing as-is if address and port are filled out", func() { 90 Expect(server.InsecureServing).To(Equal(&process.ListenAddr{ 91 Address: "localhost", 92 Port: "8675", 93 })) 94 }) 95 }) 96 97 Context("when address and port are not filled out", func() { 98 BeforeEach(func() { 99 server.InsecureServing = &process.ListenAddr{} 100 }) 101 It("should default an insecure port", func() { 102 Expect(server.InsecureServing.Port).NotTo(BeEmpty()) 103 }) 104 It("should set URL from InsecureServing", func() { 105 Expect(server.URL.String()).To(Equal("http://" + server.InsecureServing.Address + ":" + server.InsecureServing.Port)) 106 }) 107 }) 108 }) 109 110 Context("when neither URL or InsecureServing are set", func() { 111 It("should not default either of them", func() { 112 Expect(server.URL).To(BeNil(), "no URL should be set") 113 Expect(server.InsecureServing).To(BeNil(), "no insecure serving details should be set") 114 }) 115 }) 116 117 Context("when SecureServing host & port are set", func() { 118 BeforeEach(func() { 119 server.Address = "localhost" 120 server.Port = "8675" 121 }) 122 123 It("should leave SecureServing as-is", func() { 124 Expect(server.SecureServing.Address).To(Equal("localhost")) 125 Expect(server.SecureServing.Port).To(Equal("8675")) 126 }) 127 }) 128 129 Context("when SecureServing is not set", func() { 130 It("should be defaulted with a random port", func() { 131 Expect(server.Port).NotTo(BeEquivalentTo(0)) 132 }) 133 }) 134 }) 135 136 It("should default authn if not set", func() { 137 Expect(server.Authn).NotTo(BeNil()) 138 }) 139 140 Describe("argument defaulting", func() { 141 // NB(directxman12): most of the templating vs configure logic is tested 142 // in arguments/arguments_test.go, so just test secure vs insecure port logic here 143 144 Context("when insecure serving is set, on a binary that supports it", func() { 145 BeforeEach(func() { 146 server.InsecureServing = &process.ListenAddr{ 147 Address: "localhost", 148 Port: "8675", 149 } 150 server.Path = "./testdata/fake-1.19-apiserver.sh" 151 }) 152 It("should set the insecure-port and insecure-bind-address fields from insecureserving", func() { 153 Expect(APIServerArguments(server)).To(ContainElements( 154 "--insecure-port=8675", 155 "--insecure-bind-address=localhost", 156 )) 157 }) 158 }) 159 160 Context("when insecureserving is disabled, on binaries with no insecure-port flag", func() { 161 BeforeEach(func() { 162 server.Path = "./testdata/fake-1.20-apiserver.sh" 163 }) 164 It("should not try to explicitly disable the insecure port", func() { 165 Expect(APIServerArguments(server)).NotTo(ContainElement(HavePrefix("--insecure-port"))) 166 }) 167 }) 168 169 Context("when insecureserving is disabled, on binaries with an insecure-port flag", func() { 170 BeforeEach(func() { 171 server.Path = "./testdata/fake-1.19-apiserver.sh" 172 }) 173 It("should explicitly disable the insecure port", func() { 174 Expect(APIServerArguments(server)).To(ContainElement("--insecure-port=0")) 175 }) 176 }) 177 178 Context("when given legacy-style template arguments", func() { 179 BeforeEach(func() { 180 server.Args = []string{"--foo=bar", "--baz={{ .Port }}"} 181 }) 182 It("should use the passed in args with the minimal required defaults", func() { 183 Expect(APIServerArguments(server)).To(ConsistOf( 184 "--foo=bar", 185 MatchRegexp(`--baz=\d+`), 186 "--service-cluster-ip-range=10.0.0.0/24", 187 MatchRegexp("--client-ca-file=.+"), 188 "--authorization-mode=RBAC", 189 )) 190 }) 191 }) 192 }) 193 194 Describe("setting up auth", func() { 195 var auth *fakeAuthn 196 BeforeEach(func() { 197 auth = &fakeAuthn{ 198 setFlag: true, 199 } 200 server.Authn = auth 201 }) 202 It("should configure with the cert dir", func() { 203 Expect(auth.workDir).To(Equal(server.CertDir)) 204 }) 205 It("should pass its args to be configured", func() { 206 Expect(server.Configure().Get("configure-called").Get(nil)).To(ConsistOf("true")) 207 }) 208 209 Context("when configuring auth errors out", func() { 210 It("should fail to configure", func() { 211 server := &APIServer{ 212 EtcdURL: &url.URL{}, 213 SecureServing: SecureServing{ 214 Authn: auth, 215 }, 216 } 217 auth.configureErr = errors.New("Oh no") 218 Expect(PrepareAPIServer(server)).NotTo(Succeed()) 219 }) 220 }) 221 }) 222 223 Describe("managing", func() { 224 // some of these tests are combined for speed reasons -- starting the apiserver 225 // takes a while, relatively speaking 226 227 var ( 228 auth *fakeAuthn 229 etcd *Etcd 230 ) 231 BeforeEach(func() { 232 etcd = &Etcd{} 233 Expect(etcd.Start()).To(Succeed()) 234 server.EtcdURL = etcd.URL 235 236 auth = &fakeAuthn{} 237 server.Authn = auth 238 }) 239 AfterEach(func() { 240 Expect(etcd.Stop()).To(Succeed()) 241 }) 242 243 Context("after starting", func() { 244 BeforeEach(func() { 245 Expect(server.Start()).To(Succeed()) 246 }) 247 248 It("should stop successfully, and stop auth", func() { 249 Expect(server.Stop()).To(Succeed()) 250 Expect(auth.stopCalled).To(BeTrue()) 251 }) 252 }) 253 254 It("should fail to start when auth fails to start", func() { 255 auth.startErr = errors.New("Oh no") 256 Expect(server.Start()).NotTo(Succeed()) 257 }) 258 259 It("should start successfully & start auth", func() { 260 Expect(server.Start()).To(Succeed()) 261 defer func() { Expect(server.Stop()).To(Succeed()) }() 262 Expect(auth.startCalled).To(BeTrue()) 263 }) 264 }) 265 }) 266 267 type fakeAuthn struct { 268 workDir string 269 270 startCalled bool 271 stopCalled bool 272 setFlag bool 273 274 configureErr error 275 startErr error 276 } 277 278 func (f *fakeAuthn) Configure(workDir string, args *process.Arguments) error { 279 f.workDir = workDir 280 if f.setFlag { 281 args.Set("configure-called", "true") 282 } 283 return f.configureErr 284 } 285 func (f *fakeAuthn) Start() error { 286 f.startCalled = true 287 return f.startErr 288 } 289 func (f *fakeAuthn) AddUser(user User, baseCfg *rest.Config) (*rest.Config, error) { 290 return nil, nil 291 } 292 func (f *fakeAuthn) Stop() error { 293 f.stopCalled = true 294 return nil 295 }