1
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
142
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
225
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 }
296
View as plain text