From d3d383d1cc1d6419329c0dda272c36fe9fe4e20b Mon Sep 17 00:00:00 2001 From: Andrew Louis Date: Thu, 5 Apr 2018 11:00:37 -0400 Subject: [PATCH] Endpoint Awareness: Read backends data from tmp file as well Actually read from the file Logs probably shouldn't assume knowledge of implementation detail Typos Added integration test, and dynamic update config refactor Don't force the 8k default Minimal test case to make the configuration/backends request body write to temp file Leverage new safe config updating methods, and use 2 replicas instead of 4 Small refactor Better integration test, addresses other feedback Update bindata --- internal/file/bindata.go | 2 +- rootfs/etc/nginx/lua/configuration.lua | 31 ++++++++++++++++++++--- test/e2e/lua/dynamic_configuration.go | 35 ++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/internal/file/bindata.go b/internal/file/bindata.go index 4ff966a4f..f358870e1 100644 --- a/internal/file/bindata.go +++ b/internal/file/bindata.go @@ -116,7 +116,7 @@ func etcNginxLuaBalancerLua() (*asset, error) { return a, nil } -var _etcNginxLuaConfigurationLua = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x93\xcd\x6e\xdb\x30\x10\x84\xef\x7a\x8a\xad\x4e\x32\xe0\xc8\xf7\x00\x3e\xa4\xb1\x9a\x02\xad\xed\xd4\x51\xce\x04\x23\xae\x25\xa2\xec\xd2\x59\x2e\x93\x1a\x45\xfb\xec\x85\x7e\x62\x44\x89\xd0\x26\x27\x03\x34\x67\xbf\x99\xd1\xf2\xec\x0c\xa4\xb1\x01\x6c\x00\x69\x10\xbe\x46\x0d\x8c\x07\xc6\x80\x24\x5a\xac\x27\xf0\x7b\xb8\xf4\xb4\xb7\x75\xe4\xfe\x20\x08\xc7\x4a\xc0\x12\x58\x12\x64\xd2\x6e\x61\xa9\x66\x0c\x61\x21\xc7\x03\x86\xbc\xf6\x89\xf3\x95\x76\x50\x3d\xd7\x29\xa3\x45\xc3\x12\xa8\xfe\x99\x87\x46\x33\x9a\xfc\xf5\xff\xc9\xa0\x54\x6b\x58\xc2\xaf\xdf\x49\xb2\x8f\x54\x75\x54\xb5\xce\x6b\x14\x75\xa7\xab\xef\x48\x26\x74\xb7\xb3\x59\x02\xc0\x28\x91\x69\x82\x75\x5e\xa3\x64\xe9\x93\x20\x9d\x25\x48\x66\x3c\xb0\xd2\xce\x75\x33\xec\xbe\xb3\xf5\xa0\x39\x67\xbc\x8f\x18\x44\xfd\x40\x69\xbc\x81\x3f\x4b\x48\xaf\xb7\x37\x65\x0a\x9a\xcc\xbf\x2e\x5d\x15\x65\xda\x56\x48\x09\x00\xf4\x21\x45\x4b\x0c\x43\xe2\xcf\x65\x79\xad\x3e\x5e\xac\xd4\xae\xf8\x76\x5b\xdc\x94\xa7\x5b\x07\xb6\x24\x59\xba\x25\x77\x84\x16\xd4\x71\xae\x8a\x12\x06\x46\x00\xcd\x08\xda\x39\xff\x88\xe6\x43\x3a\xeb\x84\x7d\xe6\x04\xa0\x8b\x34\xe9\x3f\xb2\xed\x7c\x2d\x46\xc5\x2c\x4e\x75\xfc\xcf\xeb\x66\x5b\xaa\x4f\xdb\xdb\xcd\xea\xa5\xd3\x8d\x17\xd8\xfb\x48\xef\x31\x33\xf4\xb4\x7c\x63\x4f\xdb\x2f\x2f\xa0\xd3\x1f\x7f\x1a\xdf\xaa\x18\xef\x73\x46\x6d\xd4\x9d\x37\xc7\x6c\xd6\x1e\xf7\x7b\x15\x62\x55\x61\x08\x73\x40\x66\x58\x4e\x2d\x4d\x18\x2d\xcd\xfc\x34\xae\xe3\x7b\x73\x7c\xc6\x6e\x83\x7a\x79\x9a\x39\x0e\xe5\x7c\x9d\xb5\xbf\xc5\x6e\x37\x87\x14\x99\x3d\xc3\x63\x63\x1d\x42\xd0\x0f\x96\xea\x31\xfa\x1c\x52\xc8\x73\x10\x1f\x84\x2d\xd5\x19\x32\x0f\xe9\xde\xb6\x48\x53\x1d\xbc\x56\x5d\xee\x8a\x8b\xb2\x58\xf5\xef\x60\x78\x36\x6a\x9d\xfc\x0d\x00\x00\xff\xff\x7b\xd0\x2f\xb3\x03\x04\x00\x00") +var _etcNginxLuaConfigurationLua = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x54\xd1\x6e\xdb\x3a\x0c\x7d\xf7\x57\xf0\xfa\xe5\xba\x17\x89\xf3\x5e\x20\x17\xe8\x5a\xaf\x03\xb6\x36\x5d\xea\x3e\x1b\x8a\x4d\xdb\xc2\x14\x2a\x95\xe8\xb6\xd9\xb0\x7d\xfb\x20\x59\x76\x93\xce\xd8\xba\xed\x29\xb1\x74\x48\x9e\x73\x48\x6a\x3e\x07\x6e\xa5\x05\x69\x81\x5b\x84\x0f\x9d\x00\x83\x3b\x83\x16\x89\x05\x4b\x4d\xa0\x6b\x38\xd7\x54\xcb\xa6\x33\xfd\x81\x65\xd3\x95\x0c\x92\x40\x12\xa3\x21\xa1\x16\x92\x1a\x83\xd6\x2e\x78\xbf\x43\x9b\x36\x3a\x52\xba\x14\x0a\xca\xc3\xb8\xa2\x12\x2c\x60\x09\xd4\x3c\xa5\xb6\x15\x06\xab\xf4\xc7\xfb\x28\x44\x16\x57\xb0\x84\x2f\x5f\xa3\xa8\xee\xa8\xf4\x55\x8b\xab\xb4\x41\x2e\x36\xa2\xfc\x84\x54\x59\x8f\x4e\x4e\x22\x00\x83\xdc\x19\x9a\xa8\x75\xda\x20\x27\xf1\x10\x10\x9f\x44\x48\xd5\x90\x7f\x4c\x5b\x23\x97\x6d\x61\xf0\xbe\x43\xcb\xc5\x46\x57\x7b\x9f\xd4\x91\x34\x78\x9f\x1a\x14\xd5\xf3\x69\x1f\xeb\x3e\x83\x0e\x07\xf1\xac\x74\xb5\x1f\x18\x45\x00\xb2\x06\xd2\xdc\x03\xb9\x45\x8a\x00\x00\xe6\x73\x08\x65\xfa\x8b\xad\x6c\x5a\xfe\xf7\x01\x61\x83\x48\xf0\x68\x24\x33\x12\xb0\x06\xde\xee\xa0\x96\x0a\x5d\x1a\x8f\xfc\x1f\x4a\x25\x91\x42\x99\x4d\x57\xd7\x68\x0a\x2b\x3f\xa3\xcf\x1b\x04\x49\x85\x05\x89\x2d\x4e\x31\x73\x97\x5e\xc0\x21\x1a\x96\x20\x75\xaa\x77\x48\xc9\x18\x3c\x83\xd8\x6c\x62\xaf\x61\x54\xe1\xb1\xa3\x8a\xd1\x6f\x92\xca\x1f\x78\x53\xdd\x9f\x60\x8b\x83\x9f\x3a\xdb\x92\xf8\x3f\xa1\x54\xdc\x97\xf5\xa7\xa5\xd2\xb6\xe7\x11\x82\x42\x2a\x17\xd9\x37\xe7\xb0\xdb\xa5\x50\xca\x83\x1d\x8f\xe6\x29\x7d\x10\x26\x1d\xfa\xb4\x45\x6e\x75\x05\xdf\x96\x10\xdf\xac\x6e\xf3\x18\x04\x55\x3f\x03\x5d\x66\x79\xfc\xac\xc1\x4f\x20\x0b\xee\x6c\x30\xeb\x5d\x9e\xdf\x14\x6f\xce\x2e\x8a\x75\xf6\xf1\x2e\xbb\xcd\x47\xd4\xce\x48\xe2\x24\x5e\x91\xda\x83\x2b\xe4\xeb\x5c\x66\xf9\xd0\x49\x0b\xc2\x20\x08\xa5\xf4\x23\x56\xff\x04\xad\xbd\xaa\x67\x95\x13\xfc\x3b\x23\x3d\xaf\xc5\xd1\xd4\x2e\xc6\x59\xfd\x15\xd7\xeb\x55\x5e\xbc\x5d\xdd\x5d\x5f\xbc\x64\x7a\xed\x1a\xa6\x3b\xfa\x1d\x32\xc1\xa7\xe5\x2b\x7d\x5a\xbd\x7f\x51\x74\x7a\x33\xa7\xcb\x87\x0d\x0a\x50\x37\x2e\xd3\xfb\x37\x6c\xd0\x00\x3c\xe2\xa4\x74\x93\xb8\xdf\x6c\xbd\x9e\x41\x5c\xed\x49\x6c\x65\x39\x3f\xb2\xf2\x14\x3a\x12\x1b\x37\xb8\x1a\xdc\x30\xc2\x83\x50\xb2\x3a\x5a\xc0\x60\xd0\xeb\x86\x61\x5a\x87\xed\xca\x12\xad\x9d\x01\x1a\x03\xcb\xa9\x27\xc8\x1e\x3d\x41\xb3\x51\xd0\x81\xc6\x90\xe4\x0f\x24\xa2\x31\xda\x40\xb7\xab\x04\x4b\x6a\xe0\xc5\x6d\x0c\x69\x0a\xac\x2d\x1b\x49\x4d\x82\xc6\x9c\xfc\x8d\xe0\xe9\xa8\xf3\x75\x76\x96\x67\x17\xfd\xf2\x86\x6d\x2e\xae\xa2\xef\x01\x00\x00\xff\xff\x63\xb9\xf8\x38\x55\x06\x00\x00") func etcNginxLuaConfigurationLuaBytes() ([]byte, error) { return bindataRead( diff --git a/rootfs/etc/nginx/lua/configuration.lua b/rootfs/etc/nginx/lua/configuration.lua index 500772246..a7872cb68 100644 --- a/rootfs/etc/nginx/lua/configuration.lua +++ b/rootfs/etc/nginx/lua/configuration.lua @@ -7,6 +7,26 @@ function _M.get_backends_data() return configuration_data:get("backends") end +local function fetch_request_body() + ngx.req.read_body() + local body = ngx.req.get_body_data() + + if not body then + -- request body might've been written to tmp file if body > client_body_buffer_size + local file_name = ngx.req.get_body_file() + local file = io.open(file_name, "rb") + + if not file then + return nil + end + + body = file:read("*all") + file:close() + end + + return body +end + function _M.call() if ngx.var.request_method ~= "POST" and ngx.var.request_method ~= "GET" then ngx.status = ngx.HTTP_BAD_REQUEST @@ -26,11 +46,16 @@ function _M.call() return end - ngx.req.read_body() + local backends = fetch_request_body() + if not backends then + ngx.log(ngx.ERR, "dynamic-configuration: unable to read valid request body") + ngx.status = ngx.HTTP_BAD_REQUEST + return + end - local success, err = configuration_data:set("backends", ngx.req.get_body_data()) + local success, err = configuration_data:set("backends", backends) if not success then - ngx.log(ngx.ERR, "error while saving configuration: " .. tostring(err)) + ngx.log(ngx.ERR, "dynamic-configuration: error updating configuration: " .. tostring(err)) ngx.status = ngx.HTTP_BAD_REQUEST return end diff --git a/test/e2e/lua/dynamic_configuration.go b/test/e2e/lua/dynamic_configuration.go index 038365389..4a3c76cc1 100644 --- a/test/e2e/lua/dynamic_configuration.go +++ b/test/e2e/lua/dynamic_configuration.go @@ -104,6 +104,41 @@ var _ = framework.IngressNginxDescribe("Dynamic Configuration", func() { Expect(restOfLogs).ToNot(ContainSubstring("first sync of Nginx configuration")) }) + It("should be able to update endpoints even when the update POST size(request body) > size(client_body_buffer_size)", func() { + // Update client-body-buffer-size to 1 byte + err := f.UpdateNginxConfigMapData("client-body-buffer-size", "1") + Expect(err).NotTo(HaveOccurred()) + + replicas := 0 + err = framework.UpdateDeployment(f.KubeClientSet, f.IngressController.Namespace, "http-svc", replicas, nil) + Expect(err).NotTo(HaveOccurred()) + + replicas = 4 + err = framework.UpdateDeployment(f.KubeClientSet, f.IngressController.Namespace, "http-svc", replicas, nil) + Expect(err).NotTo(HaveOccurred()) + time.Sleep(5 * time.Second) + + resp, _, errs := gorequest.New(). + Get(f.IngressController.HTTPURL). + Set("Host", "foo.com"). + End() + Expect(len(errs)).Should(BeNumerically("==", 0)) + Expect(resp.StatusCode).Should(Equal(http.StatusOK)) + + log, err := f.NginxLogs() + Expect(err).ToNot(HaveOccurred()) + Expect(log).ToNot(BeEmpty()) + index := strings.Index(log, "POST /configuration/backends HTTP/1.1") + restOfLogs := log[index:] + + Expect(err).ToNot(HaveOccurred()) + Expect(log).ToNot(BeEmpty()) + + By("POSTing new backends to Lua endpoint") + Expect(restOfLogs).To(ContainSubstring("a client request body is buffered to a temporary file")) + Expect(restOfLogs).ToNot(ContainSubstring("dynamic-configuration: unable to read valid request body")) + }) + It("should handle annotation changes", func() { ingress, err := f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.IngressController.Namespace).Get("foo.com", metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred())