...

Source file src/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver_test.go

Documentation: sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane

     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  }
   296  

View as plain text