Skip to content

Commit 9553e11

Browse files
authored
Merge pull request #83 from nginxinc/nginx-plus-controller
Add new features to the Plus controller
2 parents ea43f60 + 9cdebff commit 9553e11

File tree

9 files changed

+393
-32
lines changed

9 files changed

+393
-32
lines changed

nginx-plus-controller/Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
FROM ubuntu:14.04
1+
FROM ubuntu:16.04
22

33
MAINTAINER NGINX Docker Maintainers "[email protected]"
44

55
# Set the debconf front end to Noninteractive
66
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
77

8-
RUN apt-get update && apt-get install -y -q wget apt-transport-https
8+
RUN apt-get update && apt-get install -y -q wget lsb-release apt-transport-https
99

1010
# Download certificate and key from the customer portal (https://cs.nginx.com)
1111
# and copy to the build context
1212
ADD nginx-repo.crt /etc/ssl/nginx/
1313
ADD nginx-repo.key /etc/ssl/nginx/
1414

1515
# Get other files required for installation
16-
RUN wget -q -O /etc/ssl/nginx/CA.crt https://cs.nginx.com/static/files/CA.crt
1716
RUN wget -q -O - http://nginx.org/keys/nginx_signing.key | apt-key add -
1817
RUN wget -q -O /etc/apt/apt.conf.d/90nginx https://cs.nginx.com/static/files/90nginx
1918

nginx-plus-controller/controller/controller.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,65 @@ func (lbc *LoadBalancerController) syncCfgm(key string) {
324324
if serverNamesHashMaxSize, exists := cfgm.Data["server-names-hash-max-size"]; exists {
325325
cfg.MainServerNamesHashMaxSize = serverNamesHashMaxSize
326326
}
327+
if HTTP2, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "http2", cfgm); exists {
328+
if err != nil {
329+
glog.Error(err)
330+
} else {
331+
cfg.HTTP2 = HTTP2
332+
}
333+
}
334+
335+
// HSTS block
336+
if hsts, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "hsts", cfgm); exists {
337+
if err != nil {
338+
glog.Error(err)
339+
} else {
340+
parsingErrors := false
341+
342+
hstsMaxAge, existsMA, err := nginx.GetMapKeyAsInt(cfgm.Data, "hsts-max-age", cfgm)
343+
if existsMA && err != nil {
344+
glog.Error(err)
345+
parsingErrors = true
346+
}
347+
hstsIncludeSubdomains, existsIS, err := nginx.GetMapKeyAsBool(cfgm.Data, "hsts-include-subdomains", cfgm)
348+
if existsIS && err != nil {
349+
glog.Error(err)
350+
parsingErrors = true
351+
}
352+
353+
if parsingErrors {
354+
glog.Errorf("Configmap %s/%s: There are configuration issues with hsts annotations, skipping options for all hsts settings", cfgm.GetNamespace(), cfgm.GetName())
355+
} else {
356+
cfg.HSTS = hsts
357+
if existsMA {
358+
cfg.HSTSMaxAge = hstsMaxAge
359+
}
360+
if existsIS {
361+
cfg.HSTSIncludeSubdomains = hstsIncludeSubdomains
362+
}
363+
}
364+
}
365+
}
366+
367+
if logFormat, exists := cfgm.Data["log-format"]; exists {
368+
cfg.MainLogFormat = logFormat
369+
}
370+
if proxyBuffering, exists, err := nginx.GetMapKeyAsBool(cfgm.Data, "proxy-buffering", cfgm); exists {
371+
if err != nil {
372+
glog.Error(err)
373+
} else {
374+
cfg.ProxyBuffering = proxyBuffering
375+
}
376+
}
377+
if proxyBuffers, exists := cfgm.Data["proxy-buffers"]; exists {
378+
cfg.ProxyBuffers = proxyBuffers
379+
}
380+
if proxyBufferSize, exists := cfgm.Data["proxy-buffer-size"]; exists {
381+
cfg.ProxyBufferSize = proxyBufferSize
382+
}
383+
if proxyMaxTempFileSize, exists := cfgm.Data["proxy-max-temp-file-size"]; exists {
384+
cfg.ProxyMaxTempFileSize = proxyMaxTempFileSize
385+
}
327386
}
328387
lbc.cnf.UpdateConfig(cfg)
329388

nginx-plus-controller/nginx/config.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,17 @@ type Config struct {
55
ProxyConnectTimeout string
66
ProxyReadTimeout string
77
ClientMaxBodySize string
8+
HTTP2 bool
89
MainServerNamesHashBucketSize string
910
MainServerNamesHashMaxSize string
11+
MainLogFormat string
12+
ProxyBuffering bool
13+
ProxyBuffers string
14+
ProxyBufferSize string
15+
ProxyMaxTempFileSize string
16+
HSTS bool
17+
HSTSMaxAge int64
18+
HSTSIncludeSubdomains bool
1019
}
1120

1221
// NewDefaultConfig creates a Config with default values
@@ -16,5 +25,7 @@ func NewDefaultConfig() *Config {
1625
ProxyReadTimeout: "60s",
1726
ClientMaxBodySize: "1m",
1827
MainServerNamesHashMaxSize: "512",
28+
ProxyBuffering: true,
29+
HSTSMaxAge: 2592000,
1930
}
2031
}

nginx-plus-controller/nginx/configurator.go

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,14 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri
111111
glog.Warningf("Host field of ingress rule in %v/%v is empty", ingEx.Ingress.Namespace, ingEx.Ingress.Name)
112112
}
113113

114-
server := Server{Name: serverName, StatusZone: statuzZone}
114+
server := Server{
115+
Name: serverName,
116+
HTTP2: ingCfg.HTTP2,
117+
HSTS: ingCfg.HSTS,
118+
HSTSMaxAge: ingCfg.HSTSMaxAge,
119+
HSTSIncludeSubdomains: ingCfg.HSTSIncludeSubdomains,
120+
StatusZone: statuzZone,
121+
}
115122

116123
if pemFile, ok := pems[serverName]; ok {
117124
server.SSL = true
@@ -153,7 +160,14 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri
153160
statuzZone := ingEx.Ingress.Namespace + "-" + ingEx.Ingress.Name
154161
glog.Warningf("Host field of ingress rule in %v/%v is empty", ingEx.Ingress.Namespace, ingEx.Ingress.Name)
155162

156-
server := Server{Name: serverName, StatusZone: statuzZone}
163+
server := Server{
164+
Name: serverName,
165+
HTTP2: ingCfg.HTTP2,
166+
HSTS: ingCfg.HSTS,
167+
HSTSMaxAge: ingCfg.HSTSMaxAge,
168+
HSTSIncludeSubdomains: ingCfg.HSTSIncludeSubdomains,
169+
StatusZone: statuzZone,
170+
}
157171

158172
if pemFile, ok := pems[emptyHost]; ok {
159173
server.SSL = true
@@ -186,7 +200,61 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
186200
if clientMaxBodySize, exists := ingEx.Ingress.Annotations["nginx.org/client-max-body-size"]; exists {
187201
ingCfg.ClientMaxBodySize = clientMaxBodySize
188202
}
203+
if HTTP2, exists, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/http2", ingEx.Ingress); exists {
204+
if err != nil {
205+
glog.Error(err)
206+
} else {
207+
ingCfg.HTTP2 = HTTP2
208+
}
209+
}
210+
if proxyBuffering, exists, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/proxy-buffering", ingEx.Ingress); exists {
211+
if err != nil {
212+
glog.Error(err)
213+
} else {
214+
ingCfg.ProxyBuffering = proxyBuffering
215+
}
216+
}
217+
218+
if hsts, exists, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/hsts", ingEx.Ingress); exists {
219+
if err != nil {
220+
glog.Error(err)
221+
} else {
222+
parsingErrors := false
223+
224+
hstsMaxAge, existsMA, err := GetMapKeyAsInt(ingEx.Ingress.Annotations, "nginx.org/hsts-max-age", ingEx.Ingress)
225+
if existsMA && err != nil {
226+
glog.Error(err)
227+
parsingErrors = true
228+
}
229+
hstsIncludeSubdomains, existsIS, err := GetMapKeyAsBool(ingEx.Ingress.Annotations, "nginx.org/hsts-include-subdomains", ingEx.Ingress)
230+
if existsIS && err != nil {
231+
glog.Error(err)
232+
parsingErrors = true
233+
}
234+
235+
if parsingErrors {
236+
glog.Errorf("Ingress %s/%s: There are configuration issues with hsts annotations, skipping annotions for all hsts settings", ingEx.Ingress.GetNamespace(), ingEx.Ingress.GetName())
237+
} else {
238+
ingCfg.HSTS = hsts
239+
if existsMA {
240+
ingCfg.HSTSMaxAge = hstsMaxAge
241+
}
242+
if existsIS {
243+
ingCfg.HSTSIncludeSubdomains = hstsIncludeSubdomains
244+
}
245+
}
246+
}
247+
}
189248

249+
if proxyBuffers, exists := ingEx.Ingress.Annotations["nginx.org/proxy-buffers"]; exists {
250+
ingCfg.ProxyBuffers = proxyBuffers
251+
}
252+
if proxyBufferSize, exists := ingEx.Ingress.Annotations["nginx.org/proxy-buffer-size"]; exists {
253+
ingCfg.ProxyBufferSize = proxyBufferSize
254+
}
255+
if proxyMaxTempFileSize, exists := ingEx.Ingress.Annotations["nginx.org/proxy-max-temp-file-size"]; exists {
256+
ingCfg.ProxyMaxTempFileSize = proxyMaxTempFileSize
257+
}
190258
return ingCfg
191259
}
192260

@@ -283,14 +351,18 @@ func parseStickyService(service string) (serviceName string, stickyCookie string
283351

284352
func createLocation(path string, upstream Upstream, cfg *Config, websocket bool, rewrite string, ssl bool) Location {
285353
loc := Location{
286-
Path: path,
287-
Upstream: upstream,
288-
ProxyConnectTimeout: cfg.ProxyConnectTimeout,
289-
ProxyReadTimeout: cfg.ProxyReadTimeout,
290-
ClientMaxBodySize: cfg.ClientMaxBodySize,
291-
Websocket: websocket,
292-
Rewrite: rewrite,
293-
SSL: ssl,
354+
Path: path,
355+
Upstream: upstream,
356+
ProxyConnectTimeout: cfg.ProxyConnectTimeout,
357+
ProxyReadTimeout: cfg.ProxyReadTimeout,
358+
ClientMaxBodySize: cfg.ClientMaxBodySize,
359+
Websocket: websocket,
360+
Rewrite: rewrite,
361+
SSL: ssl,
362+
ProxyBuffering: cfg.ProxyBuffering,
363+
ProxyBuffers: cfg.ProxyBuffers,
364+
ProxyBufferSize: cfg.ProxyBufferSize,
365+
ProxyMaxTempFileSize: cfg.ProxyMaxTempFileSize,
294366
}
295367

296368
return loc
@@ -377,6 +449,7 @@ func (cnf *Configurator) UpdateConfig(config *Config) {
377449
mainCfg := &NginxMainConfig{
378450
ServerNamesHashBucketSize: config.MainServerNamesHashBucketSize,
379451
ServerNamesHashMaxSize: config.MainServerNamesHashMaxSize,
452+
LogFormat: config.MainLogFormat,
380453
}
381454

382455
cnf.nginx.UpdateMainConfigFile(mainCfg)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package nginx
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
7+
"k8s.io/kubernetes/pkg/api/meta"
8+
"k8s.io/kubernetes/pkg/runtime"
9+
)
10+
11+
// There seems to be no composite interface in the kubernetes api package,
12+
// so we have to declare our own.
13+
type apiObject interface {
14+
meta.Object
15+
runtime.Object
16+
}
17+
18+
// GetMapKeyAsBool searches the map for the given key and parses the key as bool
19+
func GetMapKeyAsBool(m map[string]string, key string, context apiObject) (bool, bool, error) {
20+
if str, exists := m[key]; exists {
21+
b, err := strconv.ParseBool(str)
22+
if err != nil {
23+
return false, exists, fmt.Errorf("%s %v/%v '%s' contains invalid bool: %v, ignoring", context.GetObjectKind().GroupVersionKind().Kind, context.GetNamespace(), context.GetName(), key, err)
24+
}
25+
return b, exists, nil
26+
}
27+
return false, false, nil
28+
}
29+
30+
// GetMapKeyAsInt tries to find and parse a key in a map as int64
31+
func GetMapKeyAsInt(m map[string]string, key string, context apiObject) (int64, bool, error) {
32+
if str, exists := m[key]; exists {
33+
i, err := strconv.ParseInt(str, 10, 64)
34+
if err != nil {
35+
return 0, exists, fmt.Errorf("%s %v/%v '%s' contains invalid integer: %v, ignoring", context.GetObjectKind().GroupVersionKind().Kind, context.GetNamespace(), context.GetName(), key, err)
36+
}
37+
return i, exists, nil
38+
}
39+
return 0, false, nil
40+
}

0 commit comments

Comments
 (0)