diff --git a/controllers/gce/backends/backends.go b/controllers/gce/backends/backends.go index 07f0b3fae..81edc32e3 100644 --- a/controllers/gce/backends/backends.go +++ b/controllers/gce/backends/backends.go @@ -119,7 +119,7 @@ func NewBackendPool( func(i interface{}) (string, error) { bs := i.(*compute.BackendService) if !namer.NameBelongsToCluster(bs.Name) { - return "", fmt.Errorf("Unrecognized name %v", bs.Name) + return "", fmt.Errorf("unrecognized name %v", bs.Name) } port, err := namer.BePort(bs.Name) if err != nil { diff --git a/controllers/gce/backends/fakes.go b/controllers/gce/backends/fakes.go index bb2b031f0..6ad7460f5 100644 --- a/controllers/gce/backends/fakes.go +++ b/controllers/gce/backends/fakes.go @@ -47,7 +47,7 @@ func (f *FakeBackendServices) GetBackendService(name string) (*compute.BackendSe f.calls = append(f.calls, utils.Get) obj, exists, err := f.backendServices.GetByKey(name) if !exists { - return nil, fmt.Errorf("Backend service %v not found", name) + return nil, fmt.Errorf("backend service %v not found", name) } if err != nil { return nil, err @@ -57,7 +57,7 @@ func (f *FakeBackendServices) GetBackendService(name string) (*compute.BackendSe if name == svc.Name { return svc, nil } - return nil, fmt.Errorf("Backend service %v not found", name) + return nil, fmt.Errorf("backend service %v not found", name) } // CreateBackendService fakes backend service creation. @@ -77,7 +77,7 @@ func (f *FakeBackendServices) DeleteBackendService(name string) error { f.calls = append(f.calls, utils.Delete) svc, exists, err := f.backendServices.GetByKey(name) if !exists { - return fmt.Errorf("Backend service %v not found", name) + return fmt.Errorf("backend service %v not found", name) } if err != nil { return err diff --git a/controllers/gce/controller/controller.go b/controllers/gce/controller/controller.go index 69f6a2533..3a039222b 100644 --- a/controllers/gce/controller/controller.go +++ b/controllers/gce/controller/controller.go @@ -290,7 +290,7 @@ func (lbc *LoadBalancerController) storesSynced() bool { func (lbc *LoadBalancerController) sync(key string) (err error) { if !lbc.hasSynced() { time.Sleep(storeSyncPollPeriod) - return fmt.Errorf("Waiting for stores to sync") + return fmt.Errorf("waiting for stores to sync") } glog.V(3).Infof("Syncing %v", key) @@ -326,7 +326,7 @@ func (lbc *LoadBalancerController) sync(key string) (err error) { defer func() { if deferErr := lbc.CloudClusterManager.GC(lbNames, nodePorts); deferErr != nil { - err = fmt.Errorf("Error during sync %v, error during GC %v", err, deferErr) + err = fmt.Errorf("error during sync %v, error during GC %v", err, deferErr) } glog.V(3).Infof("Finished syncing %v", key) }() @@ -343,7 +343,7 @@ func (lbc *LoadBalancerController) sync(key string) (err error) { if ingExists { lbc.recorder.Eventf(obj.(*extensions.Ingress), api.EventTypeWarning, eventMsg, err.Error()) } else { - err = fmt.Errorf("%v Error: %v", eventMsg, err) + err = fmt.Errorf("%v, error: %v", eventMsg, err) } syncError = err } diff --git a/controllers/gce/controller/tls.go b/controllers/gce/controller/tls.go index b8cb7a2e7..70bf7e00c 100644 --- a/controllers/gce/controller/tls.go +++ b/controllers/gce/controller/tls.go @@ -65,11 +65,11 @@ func (t *apiServerTLSLoader) load(ing *extensions.Ingress) (*loadbalancers.TLSCe } cert, ok := secret.Data[api.TLSCertKey] if !ok { - return nil, fmt.Errorf("Secret %v has no private key", secretName) + return nil, fmt.Errorf("secret %v has no private key", secretName) } key, ok := secret.Data[api.TLSPrivateKeyKey] if !ok { - return nil, fmt.Errorf("Secret %v has no cert", secretName) + return nil, fmt.Errorf("secret %v has no cert", secretName) } certs := &loadbalancers.TLSCerts{Key: string(key), Cert: string(cert)} if err := t.validate(certs); err != nil { @@ -95,5 +95,5 @@ func (f *fakeTLSSecretLoader) load(ing *extensions.Ingress) (*loadbalancers.TLSC return cert, nil } } - return nil, fmt.Errorf("Couldn't find secret for ingress %v", ing.Name) + return nil, fmt.Errorf("couldn't find secret for ingress %v", ing.Name) } diff --git a/controllers/gce/controller/utils.go b/controllers/gce/controller/utils.go index b57020cc3..7efc6cd56 100644 --- a/controllers/gce/controller/utils.go +++ b/controllers/gce/controller/utils.go @@ -233,7 +233,7 @@ func (s *StoreToIngressLister) GetServiceIngress(svc *api.Service) (ings []exten } } if len(ings) == 0 { - err = fmt.Errorf("No ingress for service %v", svc.Name) + err = fmt.Errorf("no ingress for service %v", svc.Name) } return } @@ -315,7 +315,7 @@ func (t *GCETranslator) toGCEBackend(be *extensions.IngressBackend, ns string) ( backend, err := t.CloudClusterManager.backendPool.Get(int64(port)) if err != nil { return nil, fmt.Errorf( - "No GCE backend exists for port %v, kube backend %+v", port, be) + "no GCE backend exists for port %v, kube backend %+v", port, be) } return backend, nil } @@ -332,7 +332,7 @@ func (t *GCETranslator) getServiceNodePort(be extensions.IngressBackend, namespa }) if !exists { return invalidPort, errorNodePortNotFound{be, fmt.Errorf( - "Service %v/%v not found in store", namespace, be.ServiceName)} + "service %v/%v not found in store", namespace, be.ServiceName)} } if err != nil { return invalidPort, errorNodePortNotFound{be, err} @@ -356,7 +356,7 @@ func (t *GCETranslator) getServiceNodePort(be extensions.IngressBackend, namespa return nodePort, nil } return invalidPort, errorNodePortNotFound{be, fmt.Errorf( - "Could not find matching nodeport from service.")} + "could not find matching nodeport from service")} } // toNodePorts converts a pathlist to a flat list of nodeports. @@ -374,7 +374,7 @@ func (t *GCETranslator) toNodePorts(ings *extensions.IngressList) []int64 { } for _, rule := range ing.Spec.Rules { if rule.HTTP == nil { - glog.Errorf("Ignoring non http Ingress rule.") + glog.Errorf("ignoring non http Ingress rule") continue } for _, path := range rule.HTTP.Paths { @@ -411,7 +411,7 @@ func (t *GCETranslator) GetZoneForNode(name string) (string, error) { return getZone(n), nil } } - return "", fmt.Errorf("Node not found %v", name) + return "", fmt.Errorf("node not found %v", name) } // ListZones returns a list of zones this Kubernetes cluster spans. diff --git a/controllers/gce/firewalls/fakes.go b/controllers/gce/firewalls/fakes.go index 3479d83d1..71c90c321 100644 --- a/controllers/gce/firewalls/fakes.go +++ b/controllers/gce/firewalls/fakes.go @@ -35,7 +35,7 @@ func (f *fakeFirewallRules) GetFirewall(name string) (*compute.Firewall, error) return rule, nil } } - return nil, fmt.Errorf("Firewall rule %v not found.", name) + return nil, fmt.Errorf("firewall rule %v not found", name) } func (f *fakeFirewallRules) CreateFirewall(name, msgTag string, srcRange netset.IPNet, ports []int64, hosts []string) error { @@ -66,7 +66,7 @@ func (f *fakeFirewallRules) DeleteFirewall(name string) error { firewalls = append(firewalls, rule) } if !exists { - return fmt.Errorf("Failed to find health check %v", name) + return fmt.Errorf("failed to find health check %v", name) } f.fw = firewalls return nil @@ -95,7 +95,7 @@ func (f *fakeFirewallRules) UpdateFirewall(name, msgTag string, srcRange netset. if exists { return nil } - return fmt.Errorf("Update failed for rule %v, srcRange %v ports %v, rule not found", name, srcRange, ports) + return fmt.Errorf("update failed for rule %v, srcRange %v ports %v, rule not found", name, srcRange, ports) } // NewFakeFirewallRules creates a fake for firewall rules. diff --git a/controllers/gce/healthchecks/fakes.go b/controllers/gce/healthchecks/fakes.go index 900b73023..18984d122 100644 --- a/controllers/gce/healthchecks/fakes.go +++ b/controllers/gce/healthchecks/fakes.go @@ -60,7 +60,7 @@ func (f *FakeHealthChecks) GetHttpHealthCheck(name string) (*compute.HttpHealthC return h, nil } } - return nil, fmt.Errorf("Health check %v not found.", name) + return nil, fmt.Errorf("health check %v not found", name) } // DeleteHttpHealthCheck fakes out deleting a http health check. @@ -75,7 +75,7 @@ func (f *FakeHealthChecks) DeleteHttpHealthCheck(name string) error { healthChecks = append(healthChecks, h) } if !exists { - return fmt.Errorf("Failed to find health check %v", name) + return fmt.Errorf("failed to find health check %v", name) } f.hc = healthChecks return nil @@ -94,7 +94,7 @@ func (f *FakeHealthChecks) UpdateHttpHealthCheck(hc *compute.HttpHealthCheck) er } } if !found { - return fmt.Errorf("Cannot update a non-existent health check %v", hc.Name) + return fmt.Errorf("cannot update a non-existent health check %v", hc.Name) } f.hc = healthChecks return nil diff --git a/controllers/gce/instances/fakes.go b/controllers/gce/instances/fakes.go index 94e22ced9..df2ee26fa 100644 --- a/controllers/gce/instances/fakes.go +++ b/controllers/gce/instances/fakes.go @@ -75,7 +75,7 @@ func (f *FakeInstanceGroups) GetInstanceGroup(name, zone string) (*compute.Insta } } // TODO: Return googleapi 404 error - return nil, fmt.Errorf("Instance group %v not found", name) + return nil, fmt.Errorf("instance group %v not found", name) } // CreateInstanceGroup fakes instance group creation. @@ -97,7 +97,7 @@ func (f *FakeInstanceGroups) DeleteInstanceGroup(name, zone string) error { newGroups = append(newGroups, ig) } if !found { - return fmt.Errorf("Instance Group %v not found", name) + return fmt.Errorf("instance group %v not found", name) } f.instanceGroups = newGroups return nil diff --git a/controllers/gce/loadbalancers/fakes.go b/controllers/gce/loadbalancers/fakes.go index b167a9ae1..6dfdcd941 100644 --- a/controllers/gce/loadbalancers/fakes.go +++ b/controllers/gce/loadbalancers/fakes.go @@ -109,7 +109,7 @@ func (f *FakeLoadBalancers) GetGlobalForwardingRule(name string) (*compute.Forwa return f.Fw[i], nil } } - return nil, fmt.Errorf("Forwarding rule %v not found", name) + return nil, fmt.Errorf("forwarding rule %v not found", name) } // CreateGlobalForwardingRule fakes forwarding rule creation. @@ -176,7 +176,7 @@ func (f *FakeLoadBalancers) GetUrlMap(name string) (*compute.UrlMap, error) { return f.Um[i], nil } } - return nil, fmt.Errorf("Url Map %v not found", name) + return nil, fmt.Errorf("url map %v not found", name) } // CreateUrlMap fakes url-map creation. @@ -226,7 +226,7 @@ func (f *FakeLoadBalancers) GetTargetHttpProxy(name string) (*compute.TargetHttp return f.Tp[i], nil } } - return nil, fmt.Errorf("Targetproxy %v not found", name) + return nil, fmt.Errorf("target http proxy %v not found", name) } // CreateTargetHttpProxy fakes creating a target http proxy. @@ -275,7 +275,7 @@ func (f *FakeLoadBalancers) GetTargetHttpsProxy(name string) (*compute.TargetHtt return f.Tps[i], nil } } - return nil, fmt.Errorf("Targetproxy %v not found", name) + return nil, fmt.Errorf("target https proxy %v not found", name) } // CreateTargetHttpsProxy fakes creating a target http proxy. @@ -326,7 +326,7 @@ func (f *FakeLoadBalancers) SetSslCertificateForTargetHttpsProxy(proxy *compute. } } if !found { - return fmt.Errorf("Failed to find proxy %v", proxy.Name) + return fmt.Errorf("failed to find proxy %v", proxy.Name) } return nil } @@ -415,7 +415,7 @@ func (f *FakeLoadBalancers) GetGlobalStaticIP(name string) (*compute.Address, er return f.IP[i], nil } } - return nil, fmt.Errorf("Static IP %v not found", name) + return nil, fmt.Errorf("static IP %v not found", name) } // DeleteGlobalStaticIP fakes out static IP deletion. @@ -441,7 +441,7 @@ func (f *FakeLoadBalancers) GetSslCertificate(name string) (*compute.SslCertific return f.Certs[i], nil } } - return nil, fmt.Errorf("Cert %v not found", name) + return nil, fmt.Errorf("cert %v not found", name) } // CreateSslCertificate fakes out certificate creation. diff --git a/controllers/gce/loadbalancers/loadbalancers.go b/controllers/gce/loadbalancers/loadbalancers.go index 9688a4cc0..7e04fb2b0 100644 --- a/controllers/gce/loadbalancers/loadbalancers.go +++ b/controllers/gce/loadbalancers/loadbalancers.go @@ -106,7 +106,7 @@ func (l *L7s) Get(name string) (*L7, error) { name = l.namer.LBName(name) lb, exists := l.snapshotter.Get(name) if !exists { - return nil, fmt.Errorf("Loadbalancer %v not in pool", name) + return nil, fmt.Errorf("loadbalancer %v not in pool", name) } return lb.(*L7), nil } @@ -292,7 +292,7 @@ type L7 struct { func (l *L7) checkUrlMap(backend *compute.BackendService) (err error) { if l.glbcDefaultBackend == nil { - return fmt.Errorf("Cannot create urlmap without default backend.") + return fmt.Errorf("cannot create urlmap without default backend") } urlMapName := l.namer.Truncate(fmt.Sprintf("%v-%v", urlMapPrefix, l.Name)) urlMap, _ := l.cloud.GetUrlMap(urlMapName) @@ -313,7 +313,7 @@ func (l *L7) checkUrlMap(backend *compute.BackendService) (err error) { func (l *L7) checkProxy() (err error) { if l.um == nil { - return fmt.Errorf("Cannot create proxy without urlmap.") + return fmt.Errorf("cannot create proxy without urlmap") } proxyName := l.namer.Truncate(fmt.Sprintf("%v-%v", targetProxyPrefix, l.Name)) proxy, _ := l.cloud.GetTargetHttpProxy(proxyName) @@ -362,7 +362,7 @@ func (l *L7) checkSSLCert() (err error) { return err } if cert == nil { - return fmt.Errorf("Cannot find existing sslCertificate %v for %v", certName, l.Name) + return fmt.Errorf("cannot find existing sslCertificate %v for %v", certName, l.Name) } glog.Infof("Using existing sslCertificate %v for %v", certName, l.Name) @@ -429,7 +429,7 @@ func (l *L7) checkHttpsProxy() (err error) { return nil } if l.um == nil { - return fmt.Errorf("No UrlMap for %v, will not create HTTPS proxy.", l.Name) + return fmt.Errorf("no UrlMap for %v, will not create HTTPS proxy", l.Name) } proxyName := l.namer.Truncate(fmt.Sprintf("%v-%v", targetHTTPSProxyPrefix, l.Name)) proxy, _ := l.cloud.GetTargetHttpsProxy(proxyName) @@ -535,7 +535,7 @@ func (l *L7) getEffectiveIP() (string, bool) { func (l *L7) checkHttpForwardingRule() (err error) { if l.tp == nil { - return fmt.Errorf("Cannot create forwarding rule without proxy.") + return fmt.Errorf("cannot create forwarding rule without proxy") } name := l.namer.Truncate(fmt.Sprintf("%v-%v", forwardingRulePrefix, l.Name)) address, _ := l.getEffectiveIP() @@ -565,7 +565,7 @@ func (l *L7) checkHttpsForwardingRule() (err error) { // checkStaticIP reserves a static IP allocated to the Forwarding Rule. func (l *L7) checkStaticIP() (err error) { if l.fw == nil || l.fw.IPAddress == "" { - return fmt.Errorf("Will not create static IP without a forwarding rule.") + return fmt.Errorf("will not create static IP without a forwarding rule") } // Don't manage staticIPs if the user has specified an IP. if address, manageStaticIP := l.getEffectiveIP(); !manageStaticIP { @@ -704,7 +704,7 @@ func getNameForPathMatcher(hostRule string) string { // pathmatcher of the host. func (l *L7) UpdateUrlMap(ingressRules utils.GCEURLMap) error { if l.um == nil { - return fmt.Errorf("Cannot add url without an urlmap.") + return fmt.Errorf("cannot add url without an urlmap") } glog.V(3).Infof("Updating urlmap for l7 %v", l.Name) diff --git a/controllers/gce/main.go b/controllers/gce/main.go index b8afbf9ab..a306956a2 100644 --- a/controllers/gce/main.go +++ b/controllers/gce/main.go @@ -316,7 +316,7 @@ func useDefaultOrLookupVault(cfgVault *storage.ConfigMapVault, cm_key, default_n // 2. No such key in config map - found=false, err=nil // 3. Apiserver flake - found=false, err!=nil // It is not safe to proceed in 3. - return "", fmt.Errorf("Failed to retrieve %v: %v, returning empty name", cm_key, err) + return "", fmt.Errorf("failed to retrieve %v: %v, returning empty name", cm_key, err) } else if !found { // Not found but safe to proceed. return "", nil diff --git a/controllers/gce/storage/configmaps.go b/controllers/gce/storage/configmaps.go index 6af08b65d..ace030b9f 100644 --- a/controllers/gce/storage/configmaps.go +++ b/controllers/gce/storage/configmaps.go @@ -95,12 +95,12 @@ func (c *ConfigMapVault) Put(key, val string) error { glog.Infof("Configmap %v will be updated with %v = %v", cfgMapKey, key, val) } if err := c.ConfigMapStore.Update(apiObj); err != nil { - return fmt.Errorf("Failed to update %v: %v", cfgMapKey, err) + return fmt.Errorf("failed to update %v: %v", cfgMapKey, err) } } else { apiObj.Data = map[string]string{key: val} if err := c.ConfigMapStore.Add(apiObj); err != nil { - return fmt.Errorf("Failed to add %v: %v", cfgMapKey, err) + return fmt.Errorf("failed to add %v: %v", cfgMapKey, err) } } glog.Infof("Successfully stored key %v = %v in config map %v", key, val, cfgMapKey) @@ -176,7 +176,7 @@ func (a *APIServerConfigMapStore) Delete(obj interface{}) error { func (a *APIServerConfigMapStore) GetByKey(key string) (item interface{}, exists bool, err error) { nsName := strings.Split(key, "/") if len(nsName) != 2 { - return nil, false, fmt.Errorf("Failed to get key %v, unexpecte format, expecting ns/name", key) + return nil, false, fmt.Errorf("failed to get key %v, unexpecte format, expecting ns/name", key) } ns, name := nsName[0], nsName[1] cfg, err := a.client.Core().ConfigMaps(ns).Get(name) diff --git a/controllers/gce/utils/utils.go b/controllers/gce/utils/utils.go index 9d5dbfad1..1ed36769f 100644 --- a/controllers/gce/utils/utils.go +++ b/controllers/gce/utils/utils.go @@ -223,11 +223,11 @@ func (n *Namer) BePort(beName string) (string, error) { } match := r.FindStringSubmatch(beName) if len(match) < 2 { - return "", fmt.Errorf("Unable to lookup port for %v", beName) + return "", fmt.Errorf("unable to lookup port for %v", beName) } _, err = strconv.Atoi(match[1]) if err != nil { - return "", fmt.Errorf("Unexpected regex match: %v", beName) + return "", fmt.Errorf("unexpected regex match: %v", beName) } return match[1], nil } diff --git a/controllers/nginx/Changelog.md b/controllers/nginx/Changelog.md index 761cda127..69eee1dff 100644 --- a/controllers/nginx/Changelog.md +++ b/controllers/nginx/Changelog.md @@ -1,5 +1,74 @@ Changelog +### 0.9-beta.3 + +**Image:** `gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3` + +*New Features:* + +- Custom log formats using `log-format-upstream` directive in the configuration configmap. +- Force redirect to SSL using the annotation `ingress.kubernetes.io/force-ssl-redirect` +- Prometheus metric for VTS status module (transparent, just enable vts stats) +- Improved external authentication adding `ingress.kubernetes.io/auth-signin` annotation. Please check this [example](https://github.com/kubernetes/ingress/tree/master/examples/external-auth/nginx) + + +*Breaking changes:* + +- `ssl-dh-param` configuration in configmap is now the name of a secret that contains the Diffie-Hellman key + +*Changes:* + +- [X] [#433](https://github.com/kubernetes/ingress/pull/433) close over the ingress variable or the last assignment will be used +- [X] [#424](https://github.com/kubernetes/ingress/pull/424) Manually sync secrets from certificate authentication annotations +- [X] [#423](https://github.com/kubernetes/ingress/pull/423) Scrap json metrics from nginx vts module when enabled +- [X] [#418](https://github.com/kubernetes/ingress/pull/418) Only update Ingress status for the configured class +- [X] [#415](https://github.com/kubernetes/ingress/pull/415) Improve external authentication docs +- [X] [#410](https://github.com/kubernetes/ingress/pull/410) Add support for "signin url" +- [X] [#409](https://github.com/kubernetes/ingress/pull/409) Allow custom http2 header sizes +- [X] [#408](https://github.com/kubernetes/ingress/pull/408) Review docs +- [X] [#406](https://github.com/kubernetes/ingress/pull/406) Add debug info and fix spelling +- [X] [#402](https://github.com/kubernetes/ingress/pull/402) allow specifying custom dh param +- [X] [#397](https://github.com/kubernetes/ingress/pull/397) Fix external auth +- [X] [#394](https://github.com/kubernetes/ingress/pull/394) Update README.md +- [X] [#392](https://github.com/kubernetes/ingress/pull/392) Fix http2 header size +- [X] [#391](https://github.com/kubernetes/ingress/pull/391) remove tmp nginx-diff files +- [X] [#390](https://github.com/kubernetes/ingress/pull/390) Fix RateLimit comment +- [X] [#385](https://github.com/kubernetes/ingress/pull/385) add Copyright +- [X] [#382](https://github.com/kubernetes/ingress/pull/382) Ingress Fake Certificate generation +- [X] [#380](https://github.com/kubernetes/ingress/pull/380) Fix custom log format +- [X] [#373](https://github.com/kubernetes/ingress/pull/373) Cleanup +- [X] [#371](https://github.com/kubernetes/ingress/pull/371) add configuration to disable listening on ipv6 +- [X] [#370](https://github.com/kubernetes/ingress/pull/270) Add documentation for ingress.kubernetes.io/force-ssl-redirect +- [X] [#369](https://github.com/kubernetes/ingress/pull/369) Minor text fix for "ApiServer" +- [X] [#367](https://github.com/kubernetes/ingress/pull/367) BuildLogFormatUpstream was always using the default log-format +- [X] [#366](https://github.com/kubernetes/ingress/pull/366) add_judgment +- [X] [#365](https://github.com/kubernetes/ingress/pull/365) add ForceSSLRedirect ingress annotation +- [X] [#364](https://github.com/kubernetes/ingress/pull/364) Fix error caused by increasing proxy_buffer_size (#363) +- [X] [#362](https://github.com/kubernetes/ingress/pull/362) Fix ingress class +- [X] [#360](https://github.com/kubernetes/ingress/pull/360) add example of 'run multiple nginx ingress controllers as a deployment' +- [X] [#358](https://github.com/kubernetes/ingress/pull/358) Checks if the TLS secret contains a valid keypair structure +- [X] [#356](https://github.com/kubernetes/ingress/pull/356) Disable listen only on ipv6 and fix proxy_protocol +- [X] [#354](https://github.com/kubernetes/ingress/pull/354) add judgment +- [X] [#352](https://github.com/kubernetes/ingress/pull/352) Add ability to customize upstream and stream log format +- [X] [#351](https://github.com/kubernetes/ingress/pull/351) Enable custom election id for status sync. +- [X] [#347](https://github.com/kubernetes/ingress/pull/347) Fix client source IP address +- [X] [#345](https://github.com/kubernetes/ingress/pull/345) Fix lint error +- [X] [#344](https://github.com/kubernetes/ingress/pull/344) Refactoring of TCP and UDP services +- [X] [#343](https://github.com/kubernetes/ingress/pull/343) Fix node lister when --watch-namespace is used +- [X] [#341](https://github.com/kubernetes/ingress/pull/341) Do not run coverage check in the default target. +- [X] [#340](https://github.com/kubernetes/ingress/pull/340) Add support for specify proxy cookie path/domain +- [X] [#337](https://github.com/kubernetes/ingress/pull/337) Fix for formatting error introduced in #304 +- [X] [#335](https://github.com/kubernetes/ingress/pull/335) Fix for vet complaints: +- [X] [#332](https://github.com/kubernetes/ingress/pull/332) Add annotation to customize nginx configuration +- [X] [#331](https://github.com/kubernetes/ingress/pull/331) Correct spelling mistake +- [X] [#328](https://github.com/kubernetes/ingress/pull/328) fix misspell "affinity" in main.go +- [X] [#326](https://github.com/kubernetes/ingress/pull/326) add nginx daemonset example +- [X] [#311](https://github.com/kubernetes/ingress/pull/311) Sort stream service ports to avoid extra reloads +- [X] [#307](https://github.com/kubernetes/ingress/pull/307) Add docs for body-size annotation +- [X] [#306](https://github.com/kubernetes/ingress/pull/306) modify nginx readme +- [X] [#304](https://github.com/kubernetes/ingress/pull/304) change 'buildSSPassthrouthUpstreams' to 'buildSSLPassthroughUpstreams' + + ### 0.9-beta.2 **Image:** `gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2` diff --git a/controllers/nginx/Makefile b/controllers/nginx/Makefile index bf22ee4ab..058760582 100644 --- a/controllers/nginx/Makefile +++ b/controllers/nginx/Makefile @@ -3,7 +3,7 @@ all: push BUILDTAGS= # Use the 0.0 tag for testing, it shouldn't clobber any release builds -RELEASE?=0.9.0-beta.2 +RELEASE?=0.9.0-beta.3 PREFIX?=gcr.io/google_containers/nginx-ingress-controller GOOS?=linux DOCKER?=gcloud docker -- @@ -21,7 +21,7 @@ build: clean -ldflags "-s -w -X ${PKG}/pkg/version.RELEASE=${RELEASE} -X ${PKG}/pkg/version.COMMIT=${COMMIT} -X ${PKG}/pkg/version.REPO=${REPO_INFO}" \ -o rootfs/nginx-ingress-controller ${PKG}/pkg/cmd/controller -container: +container: build $(DOCKER) build --pull -t $(PREFIX):$(RELEASE) rootfs push: container @@ -50,4 +50,4 @@ vet: @go vet $(shell go list ${PKG}/... | grep -v vendor) clean: - rm -f nginx-ingress-controller + rm -f rootfs/nginx-ingress-controller diff --git a/controllers/nginx/configuration.md b/controllers/nginx/configuration.md index e8ffd81ff..f27bde70a 100644 --- a/controllers/nginx/configuration.md +++ b/controllers/nginx/configuration.md @@ -40,6 +40,7 @@ The following annotations are supported: |Name |type| |---------------------------|------| |[ingress.kubernetes.io/add-base-url](#rewrite)|true or false| +|[ingress.kubernetes.io/app-root](#rewrite)|string| |[ingress.kubernetes.io/affinity](#session-affinity)|true or false| |[ingress.kubernetes.io/auth-realm](#authentication)|string| |[ingress.kubernetes.io/auth-secret](#authentication)|string| @@ -174,7 +175,9 @@ Set the annotation `ingress.kubernetes.io/rewrite-target` to the path expected b If the application contains relative links it is possible to add an additional annotation `ingress.kubernetes.io/add-base-url` that will prepend a [`base` tag](https://developer.mozilla.org/en/docs/Web/HTML/Element/base) in the header of the returned HTML from the backend. -Please check the [rewrite](examples/rewrite/README.md) example. +If the Application Root is exposed in a different path and needs to be redirected, the annotation `ingress.kubernetes.io/app-root` might be used. + +Please check the [rewrite](/examples/rewrite/README.md) example. ### Rate limiting diff --git a/controllers/nginx/pkg/cmd/controller/nginx.go b/controllers/nginx/pkg/cmd/controller/nginx.go index 1bd7ede60..8e6873c50 100644 --- a/controllers/nginx/pkg/cmd/controller/nginx.go +++ b/controllers/nginx/pkg/cmd/controller/nginx.go @@ -441,7 +441,7 @@ func (n NGINXController) Check(_ *http.Request) error { } defer res.Body.Close() if res.StatusCode != 200 { - return fmt.Errorf("Ingress controller is not healthy") + return fmt.Errorf("ingress controller is not healthy") } return nil } diff --git a/controllers/nginx/pkg/metric/collector/status.go b/controllers/nginx/pkg/metric/collector/status.go index 1a0fcaf0e..361838a31 100644 --- a/controllers/nginx/pkg/metric/collector/status.go +++ b/controllers/nginx/pkg/metric/collector/status.go @@ -138,7 +138,7 @@ func (bit BoolToFloat64) UnmarshalJSON(data []byte) error { } else if asString == "0" || asString == "false" { bit = 0 } else { - return fmt.Errorf(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString)) + return fmt.Errorf(fmt.Sprintf("boolean unmarshal error: invalid input %s", asString)) } return nil } diff --git a/controllers/nginx/pkg/template/template.go b/controllers/nginx/pkg/template/template.go index 234dd885b..90ae4fe59 100644 --- a/controllers/nginx/pkg/template/template.go +++ b/controllers/nginx/pkg/template/template.go @@ -205,7 +205,13 @@ func buildLocation(input interface{}) string { if path == slash { return fmt.Sprintf("~* %s", path) } - return fmt.Sprintf("~* ^%s", path) + // baseuri regex will parse basename from the given location + baseuri := `(?.*)` + if !strings.HasSuffix(path, slash) { + // Not treat the slash after "location path" as a part of baseuri + baseuri = fmt.Sprintf(`\/?%s`, baseuri) + } + return fmt.Sprintf(`~* ^%s%s`, path, baseuri) } return path @@ -273,13 +279,10 @@ func buildProxyPass(b interface{}, loc interface{}) string { if len(location.Redirect.Target) > 0 { abu := "" if location.Redirect.AddBaseURL { - bPath := location.Redirect.Target - if !strings.HasSuffix(bPath, slash) { - bPath = fmt.Sprintf("%s/", bPath) - } - - abu = fmt.Sprintf(`subs_filter '' '' r; - subs_filter '' '' r; + // path has a slash suffix, so that it can be connected with baseuri directly + bPath := fmt.Sprintf("%s%s", path, "$baseuri") + abu = fmt.Sprintf(`subs_filter '' '' r; + subs_filter '' '' r; `, bPath, bPath) } diff --git a/controllers/nginx/pkg/template/template_test.go b/controllers/nginx/pkg/template/template_test.go index 20e860c72..c6cbfbc14 100644 --- a/controllers/nginx/pkg/template/template_test.go +++ b/controllers/nginx/pkg/template/template_test.go @@ -45,33 +45,43 @@ var ( rewrite /(.*) /jenkins/$1 break; proxy_pass http://upstream-name; `, false}, - "redirect /something to /": {"/something", "/", "~* ^/something", ` + "redirect /something to /": {"/something", "/", `~* ^/something\/?(?.*)`, ` rewrite /something/(.*) /$1 break; rewrite /something / break; proxy_pass http://upstream-name; `, false}, - "redirect /something-complex to /not-root": {"/something-complex", "/not-root", "~* ^/something-complex", ` + "redirect /end-with-slash/ to /not-root": {"/end-with-slash/", "/not-root", "~* ^/end-with-slash/(?.*)", ` + rewrite /end-with-slash/(.*) /not-root/$1 break; + proxy_pass http://upstream-name; + `, false}, + "redirect /something-complex to /not-root": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?.*)`, ` rewrite /something-complex/(.*) /not-root/$1 break; proxy_pass http://upstream-name; `, false}, "redirect / to /jenkins and rewrite": {"/", "/jenkins", "~* /", ` rewrite /(.*) /jenkins/$1 break; proxy_pass http://upstream-name; - subs_filter '' '' r; - subs_filter '' '' r; + subs_filter '' '' r; + subs_filter '' '' r; `, true}, - "redirect /something to / and rewrite": {"/something", "/", "~* ^/something", ` + "redirect /something to / and rewrite": {"/something", "/", `~* ^/something\/?(?.*)`, ` rewrite /something/(.*) /$1 break; rewrite /something / break; proxy_pass http://upstream-name; - subs_filter '' '' r; - subs_filter '' '' r; + subs_filter '' '' r; + subs_filter '' '' r; `, true}, - "redirect /something-complex to /not-root and rewrite": {"/something-complex", "/not-root", "~* ^/something-complex", ` + "redirect /end-with-slash/ to /not-root and rewrite": {"/end-with-slash/", "/not-root", `~* ^/end-with-slash/(?.*)`, ` + rewrite /end-with-slash/(.*) /not-root/$1 break; + proxy_pass http://upstream-name; + subs_filter '' '' r; + subs_filter '' '' r; + `, true}, + "redirect /something-complex to /not-root and rewrite": {"/something-complex", "/not-root", `~* ^/something-complex\/?(?.*)`, ` rewrite /something-complex/(.*) /not-root/$1 break; proxy_pass http://upstream-name; - subs_filter '' '' r; - subs_filter '' '' r; + subs_filter '' '' r; + subs_filter '' '' r; `, true}, } ) diff --git a/controllers/nginx/rootfs/Dockerfile b/controllers/nginx/rootfs/Dockerfile index 6959d6bbc..dc114b925 100644 --- a/controllers/nginx/rootfs/Dockerfile +++ b/controllers/nginx/rootfs/Dockerfile @@ -16,10 +16,8 @@ FROM gcr.io/google_containers/nginx-slim:0.14 RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \ diffutils \ - ssl-cert \ --no-install-recommends \ - && rm -rf /var/lib/apt/lists/* \ - && make-ssl-cert generate-default-snakeoil --force-overwrite + && rm -rf /var/lib/apt/lists/* COPY . / diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index 07a7e7921..efe296422 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -236,7 +236,19 @@ http { ssl_verify_client on; ssl_verify_depth {{ $location.CertificateAuth.ValidationDepth }}; {{ end }} + + {{ if (or $location.Redirect.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Redirect.SSLRedirect)) }} + # enforce ssl on server side + if ($pass_access_scheme = http) { + return 301 https://$host$request_uri; + } + {{ end }} + {{ if not (empty $location.Redirect.AppRoot)}} + if ($uri = /) { + return 302 {{ $location.Redirect.AppRoot }}; + } + {{ end }} {{ if not (empty $authPath) }} location = {{ $authPath }} { internal; @@ -279,12 +291,7 @@ http { error_page 401 = {{ $location.ExternalAuth.SigninURL }}; {{ end }} - {{ if (or $location.Redirect.ForceSSLRedirect (and (not (empty $server.SSLCertificate)) $location.Redirect.SSLRedirect)) }} - # enforce ssl on server side - if ($pass_access_scheme = http) { - return 301 https://$host$request_uri; - } - {{ end }} + {{/* if the location contains a rate limit annotation, create one */}} {{ $limits := buildRateLimit $location }} {{ range $limit := $limits }} @@ -490,7 +497,7 @@ stream { # TCP services {{ range $i, $tcpServer := .TCPBackends }} - upstream {{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }} { + upstream tcp-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }} { {{ range $j, $endpoint := $tcpServer.Endpoints }} server {{ $endpoint.Address }}:{{ $endpoint.Port }}; {{ end }} @@ -498,22 +505,22 @@ stream { server { listen {{ $tcpServer.Port }}; - proxy_pass {{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }}; + proxy_pass tcp-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }}; } {{ end }} # UDP services {{ range $i, $udpServer := .UDPBackends }} - upstream {{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }} { + upstream udp-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }} { {{ range $j, $endpoint := $udpServer.Endpoints }} server {{ $endpoint.Address }}:{{ $endpoint.Port }}; {{ end }} } server { - listen {{ $udpServer.Port }}; + listen {{ $udpServer.Port }} udp; proxy_responses 1; - proxy_pass {{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }}; + proxy_pass udp-{{ $udpServer.Backend.Namespace }}-{{ $udpServer.Backend.Name }}-{{ $udpServer.Backend.Port }}; } {{ end }} } diff --git a/core/pkg/ingress/annotations/rewrite/main.go b/core/pkg/ingress/annotations/rewrite/main.go index 999ef7844..e522a275a 100644 --- a/core/pkg/ingress/annotations/rewrite/main.go +++ b/core/pkg/ingress/annotations/rewrite/main.go @@ -28,6 +28,7 @@ const ( addBaseURL = "ingress.kubernetes.io/add-base-url" sslRedirect = "ingress.kubernetes.io/ssl-redirect" forceSSLRedirect = "ingress.kubernetes.io/force-ssl-redirect" + appRoot = "ingress.kubernetes.io/app-root" ) // Redirect describes the per location redirect config @@ -41,6 +42,8 @@ type Redirect struct { SSLRedirect bool `json:"sslRedirect"` // ForceSSLRedirect indicates if the location section is accessible SSL only ForceSSLRedirect bool `json:"forceSSLRedirect"` + // AppRoot defines the Application Root that the Controller must redirect if it's not in '/' context + AppRoot string `json:"appRoot"` } type rewrite struct { @@ -65,10 +68,12 @@ func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) { fSslRe = a.backendResolver.GetDefaultBackend().ForceSSLRedirect } abu, _ := parser.GetBoolAnnotation(addBaseURL, ing) + ar, _ := parser.GetStringAnnotation(appRoot, ing) return &Redirect{ Target: rt, AddBaseURL: abu, SSLRedirect: sslRe, ForceSSLRedirect: fSslRe, + AppRoot: ar, }, nil } diff --git a/core/pkg/ingress/annotations/rewrite/main_test.go b/core/pkg/ingress/annotations/rewrite/main_test.go index 75daf01bc..2a3252184 100644 --- a/core/pkg/ingress/annotations/rewrite/main_test.go +++ b/core/pkg/ingress/annotations/rewrite/main_test.go @@ -158,3 +158,20 @@ func TestForceSSLRedirect(t *testing.T) { t.Errorf("Expected true but returned false") } } +func TestAppRoot(t *testing.T) { + ing := buildIngress() + + data := map[string]string{} + data[appRoot] = "/app1" + ing.SetAnnotations(data) + + i, _ := NewParser(mockBackend{true}).Parse(ing) + redirect, ok := i.(*Redirect) + if !ok { + t.Errorf("expected a App Context") + } + if redirect.AppRoot != "/app1" { + t.Errorf("Unexpected value got in AppRoot") + } + +} diff --git a/core/pkg/ingress/controller/backend_ssl.go b/core/pkg/ingress/controller/backend_ssl.go index e75d8ff0e..977484081 100644 --- a/core/pkg/ingress/controller/backend_ssl.go +++ b/core/pkg/ingress/controller/backend_ssl.go @@ -76,11 +76,11 @@ func (ic *GenericController) syncSecret(k interface{}) error { // no need to update return nil } - glog.V(3).Infof("updating secret %v/%v in the store", sec.Namespace, sec.Name) + glog.Infof("updating secret %v/%v in the local store", sec.Namespace, sec.Name) ic.sslCertTracker.Update(key, cert) return nil } - glog.V(3).Infof("adding secret %v/%v to the store", sec.Namespace, sec.Name) + glog.Infof("adding secret %v/%v to the local store", sec.Namespace, sec.Name) ic.sslCertTracker.Add(key, cert) return nil } @@ -106,10 +106,10 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC var s *ingress.SSLCert if okcert && okkey { - glog.V(3).Infof("found certificate and private key, configuring %v as a TLS Secret", secretName) + glog.Infof("found certificate and private key, configuring %v as a TLS Secret", secretName) s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca) } else if ca != nil { - glog.V(3).Infof("found only ca.crt, configuring %v as an Certificate Authentication secret", secretName) + glog.Infof("found only ca.crt, configuring %v as an Certificate Authentication secret", secretName) s, err = ssl.AddCertAuth(nsSecName, ca) } else { return nil, fmt.Errorf("ko keypair or CA cert could be found in %v", secretName) diff --git a/core/pkg/ingress/controller/controller.go b/core/pkg/ingress/controller/controller.go index bbb96df36..036e38d50 100644 --- a/core/pkg/ingress/controller/controller.go +++ b/core/pkg/ingress/controller/controller.go @@ -960,6 +960,12 @@ func (ic *GenericController) createServers(data []interface{}, } } + if tlsSecretName == "" { + glog.Warningf("ingress rule %v/%v for host %v does not contains a matching tls host", ing.Namespace, ing.Name, host) + glog.V(2).Infof("%v", ing.Spec.TLS) + continue + } + key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName) bc, exists := ic.sslCertTracker.Get(key) if exists { @@ -967,7 +973,11 @@ func (ic *GenericController) createServers(data []interface{}, if isHostValid(host, cert) { servers[host].SSLCertificate = cert.PemFileName servers[host].SSLPemChecksum = cert.PemSHA + } else { + glog.Warningf("ssl certificate %v does not contains a common name for host %v", key, host) } + } else { + glog.Warningf("ssl certificate \"%v\" does not exist in local store", key) } } } @@ -991,6 +1001,11 @@ func (ic *GenericController) getEndpoints( upsServers := []ingress.Endpoint{} + // avoid duplicated upstream servers when the service + // contains multiple port definitions sharing the same + // targetport. + adus := make(map[string]bool, 0) + for _, ss := range ep.Subsets { for _, epPort := range ss.Ports { @@ -1031,6 +1046,10 @@ func (ic *GenericController) getEndpoints( } for _, epAddress := range ss.Addresses { + ep := fmt.Sprintf("%v:%v", epAddress.IP, targetPort) + if _, exists := adus[ep]; exists { + continue + } ups := ingress.Endpoint{ Address: epAddress.IP, Port: fmt.Sprintf("%v", targetPort), @@ -1038,6 +1057,7 @@ func (ic *GenericController) getEndpoints( FailTimeout: hz.FailTimeout, } upsServers = append(upsServers, ups) + adus[ep] = true } } } diff --git a/core/pkg/ingress/controller/launch.go b/core/pkg/ingress/controller/launch.go index 144da3969..d532c0653 100644 --- a/core/pkg/ingress/controller/launch.go +++ b/core/pkg/ingress/controller/launch.go @@ -128,19 +128,6 @@ func NewIngressController(backend ingress.Controller) *GenericController { glog.Infof("service %v validated as source of Ingress status", *publishSvc) } - for _, configMap := range []string{*configMap, *tcpConfigMapName, *udpConfigMapName} { - - if configMap == "" { - continue - } - - _, err = k8s.IsValidConfigMap(kubeClient, configMap) - - if err != nil { - glog.Fatalf("%v", err) - } - } - if *watchNamespace != "" { _, err = k8s.IsValidNamespace(kubeClient, *watchNamespace) diff --git a/core/pkg/ingress/controller/util.go b/core/pkg/ingress/controller/util.go index 77b88ba0c..7f7db932e 100644 --- a/core/pkg/ingress/controller/util.go +++ b/core/pkg/ingress/controller/util.go @@ -46,7 +46,7 @@ func isHostValid(host string, cert *ingress.SSLCert) bool { return false } for _, cn := range cert.CN { - if matchHostnames(cn, host) { + if matchHostnames(cn, strings.ToLower(host)) { return true } } diff --git a/core/pkg/ingress/defaults/main.go b/core/pkg/ingress/defaults/main.go index d8420da04..92f5a72a2 100644 --- a/core/pkg/ingress/defaults/main.go +++ b/core/pkg/ingress/defaults/main.go @@ -6,6 +6,8 @@ import "net" // The reason of this requirements is the annotations are generic. If some implementation do not supports // one or more annotations it just can provides defaults type Backend struct { + // AppRoot contains the AppRoot for apps that doesn't exposes its content in the 'root' context + AppRoot string `json:"app-root"` // enables which HTTP codes should be passed for processing with the error_page directive // http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors diff --git a/core/pkg/net/ssl/ssl.go b/core/pkg/net/ssl/ssl.go index c758423fc..70ed50434 100644 --- a/core/pkg/net/ssl/ssl.go +++ b/core/pkg/net/ssl/ssl.go @@ -75,13 +75,13 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert, pemBlock, _ := pem.Decode(pemCerts) if pemBlock == nil { _ = os.Remove(tempPemFile.Name()) - return nil, fmt.Errorf("No valid PEM formatted block found") + return nil, fmt.Errorf("no valid PEM formatted block found") } // If the file does not start with 'BEGIN CERTIFICATE' it's invalid and must not be used. if pemBlock.Type != "CERTIFICATE" { _ = os.Remove(tempPemFile.Name()) - return nil, fmt.Errorf("Certificate %v contains invalid data, and must be created with 'kubectl create secret tls'", name) + return nil, fmt.Errorf("certificate %v contains invalid data, and must be created with 'kubectl create secret tls'", name) } pemCert, err := x509.ParseCertificate(pemBlock.Bytes) @@ -115,7 +115,7 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert, caFile, err := os.OpenFile(pemFileName, os.O_RDWR|os.O_APPEND, 0600) if err != nil { - return nil, fmt.Errorf("Could not open file %v for writing additional CA chains: %v", pemFileName, err) + return nil, fmt.Errorf("could not open file %v for writing additional CA chains: %v", pemFileName, err) } defer caFile.Close() @@ -150,11 +150,11 @@ func AddCertAuth(name string, ca []byte) (*ingress.SSLCert, error) { pemCABlock, _ := pem.Decode(ca) if pemCABlock == nil { - return nil, fmt.Errorf("No valid PEM formatted block found") + return nil, fmt.Errorf("no valid PEM formatted block found") } // If the first certificate does not start with 'BEGIN CERTIFICATE' it's invalid and must not be used. if pemCABlock.Type != "CERTIFICATE" { - return nil, fmt.Errorf("CA File %v contains invalid data, and must be created only with PEM formated certificates", name) + return nil, fmt.Errorf("CA file %v contains invalid data, and must be created only with PEM formated certificates", name) } _, err := x509.ParseCertificate(pemCABlock.Bytes) @@ -206,13 +206,13 @@ func AddOrUpdateDHParam(name string, dh []byte) (string, error) { pemBlock, _ := pem.Decode(pemCerts) if pemBlock == nil { _ = os.Remove(tempPemFile.Name()) - return "", fmt.Errorf("No valid PEM formatted block found") + return "", fmt.Errorf("no valid PEM formatted block found") } // If the file does not start with 'BEGIN DH PARAMETERS' it's invalid and must not be used. if pemBlock.Type != "DH PARAMETERS" { _ = os.Remove(tempPemFile.Name()) - return "", fmt.Errorf("Certificate %v contains invalid data", name) + return "", fmt.Errorf("certificate %v contains invalid data", name) } err = os.Rename(tempPemFile.Name(), pemFileName) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ab12588bd..877dc152b 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -255,7 +255,7 @@ spec: spec: terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: ingress-nginx imagePullPolicy: Always ports: diff --git a/examples/README.md b/examples/README.md index 69288dd45..997a64561 100644 --- a/examples/README.md +++ b/examples/README.md @@ -28,8 +28,8 @@ Re-encrypty | terminate, apply routing rules, re-encrypt | nginx | Advanced Name | Description | Platform | Complexity Level -----| ----------- | ---------- | ---------------- -Daemonset | run multiple controllers in a daemonset | nginx | Intermediate -Deployment | run multiple controllers as a deployment | nginx | Intermediate +Daemonset | run multiple controllers in a daemonset | nginx/haproxy | Intermediate +Deployment | run multiple controllers as a deployment | nginx/haproxy | Intermediate Multi-zone | bridge different zones in a single cluster | gce | Intermediate Static-ip | a single ingress gets a single static ip | * | Intermediate Geo-routing | route to geographically closest endpoint | nginx | Advanced diff --git a/examples/customization/configuration-snippets/nginx/nginx-ingress-controller.yaml b/examples/customization/configuration-snippets/nginx/nginx-ingress-controller.yaml index c4065804a..5786f03d9 100644 --- a/examples/customization/configuration-snippets/nginx/nginx-ingress-controller.yaml +++ b/examples/customization/configuration-snippets/nginx/nginx-ingress-controller.yaml @@ -19,7 +19,7 @@ spec: # hostNetwork: true terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/examples/customization/custom-errors/nginx/rc-custom-errors.yaml b/examples/customization/custom-errors/nginx/rc-custom-errors.yaml index d26dcbd5e..3dfbe540c 100644 --- a/examples/customization/custom-errors/nginx/rc-custom-errors.yaml +++ b/examples/customization/custom-errors/nginx/rc-custom-errors.yaml @@ -16,7 +16,7 @@ spec: spec: terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-lb imagePullPolicy: Always readinessProbe: diff --git a/examples/customization/custom-headers/nginx/nginx-ingress-controller.yaml b/examples/customization/custom-headers/nginx/nginx-ingress-controller.yaml index c4065804a..5786f03d9 100644 --- a/examples/customization/custom-headers/nginx/nginx-ingress-controller.yaml +++ b/examples/customization/custom-headers/nginx/nginx-ingress-controller.yaml @@ -19,7 +19,7 @@ spec: # hostNetwork: true terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/examples/customization/custom-template/custom-template.yaml b/examples/customization/custom-template/custom-template.yaml index 168b56b50..d3ca02cb1 100644 --- a/examples/customization/custom-template/custom-template.yaml +++ b/examples/customization/custom-template/custom-template.yaml @@ -16,7 +16,7 @@ spec: spec: terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-lb imagePullPolicy: Always readinessProbe: diff --git a/examples/daemonset/nginx/nginx-ingress-daemonset.yaml b/examples/daemonset/nginx/nginx-ingress-daemonset.yaml index 1b476d670..0db798c30 100644 --- a/examples/daemonset/nginx/nginx-ingress-daemonset.yaml +++ b/examples/daemonset/nginx/nginx-ingress-daemonset.yaml @@ -13,7 +13,7 @@ spec: spec: terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-lb readinessProbe: httpGet: diff --git a/examples/deployment/nginx/kubeadm/nginx-ingress-controller.yaml b/examples/deployment/nginx/kubeadm/nginx-ingress-controller.yaml index f2ca1072e..11f95e901 100644 --- a/examples/deployment/nginx/kubeadm/nginx-ingress-controller.yaml +++ b/examples/deployment/nginx/kubeadm/nginx-ingress-controller.yaml @@ -71,7 +71,7 @@ spec: hostNetwork: true terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/examples/deployment/nginx/nginx-ingress-controller.yaml b/examples/deployment/nginx/nginx-ingress-controller.yaml index b610d58f8..9ed25ad7f 100644 --- a/examples/deployment/nginx/nginx-ingress-controller.yaml +++ b/examples/deployment/nginx/nginx-ingress-controller.yaml @@ -19,7 +19,7 @@ spec: # hostNetwork: true terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/examples/rewrite/README.md b/examples/rewrite/README.md deleted file mode 100644 index a878d52ea..000000000 --- a/examples/rewrite/README.md +++ /dev/null @@ -1,66 +0,0 @@ -Create an Ingress rule with a rewrite annotation: -``` -$ echo " -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - annotations: - ingress.kubernetes.io/rewrite-target: / - name: rewrite - namespace: default -spec: - rules: - - host: rewrite.bar.com - http: - paths: - - backend: - serviceName: echoheaders - servicePort: 80 - path: /something -" | kubectl create -f - -``` - -Check the rewrite is working - -``` -$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' -* Trying 172.17.4.99... -* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) -> GET /something HTTP/1.1 -> Host: rewrite.bar.com -> User-Agent: curl/7.43.0 -> Accept: */* -> -< HTTP/1.1 200 OK -< Server: nginx/1.11.0 -< Date: Tue, 31 May 2016 16:07:31 GMT -< Content-Type: text/plain -< Transfer-Encoding: chunked -< Connection: keep-alive -< -CLIENT VALUES: -client_address=10.2.56.9 -command=GET -real path=/ -query=nil -request_version=1.1 -request_uri=http://rewrite.bar.com:8080/ - -SERVER VALUES: -server_version=nginx: 1.9.11 - lua: 10001 - -HEADERS RECEIVED: -accept=*/* -connection=close -host=rewrite.bar.com -user-agent=curl/7.43.0 -x-forwarded-for=10.2.56.1 -x-forwarded-host=rewrite.bar.com -x-forwarded-port=80 -x-forwarded-proto=http -x-real-ip=10.2.56.1 -BODY: -* Connection #0 to host 172.17.4.99 left intact --no body in request- -``` - diff --git a/examples/rewrite/nginx/README.md b/examples/rewrite/nginx/README.md new file mode 100644 index 000000000..f934eb616 --- /dev/null +++ b/examples/rewrite/nginx/README.md @@ -0,0 +1,127 @@ +# Rewrite + +This example demonstrates how to use the Rewrite annotations + +## Prerequisites + +You will need to make sure you Ingress targets exactly one Ingress +controller by specifying the [ingress.class annotation](/examples/PREREQUISITES.md#ingress-class), +and that you have an ingress controller [running](/examples/deployment) in your cluster. + +## Deployment + +Rewriting can be controlled using the following annotations: + +|Name|Description|Values| +| --- | --- | --- | +|ingress.kubernetes.io/rewrite-target|Target URI where the traffic must be redirected|string| +|ingress.kubernetes.io/add-base-url|indicates if is required to add a base tag in the head of the responses from the upstream servers|bool| +|ingress.kubernetes.io/ssl-redirect|Indicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate)|bool| +|ingress.kubernetes.io/force-ssl-redirect|Forces the redirection to HTTPS even if the Ingress is not TLS Enabled|bool| +|ingress.kubernetes.io/app-root|Defines the Application Root that the Controller must redirect if it's not in '/' context|string| + +## Validation + +### Rewrite Target +Create an Ingress rule with a rewrite annotation: +``` +$ echo " +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/rewrite-target: / + name: rewrite + namespace: default +spec: + rules: + - host: rewrite.bar.com + http: + paths: + - backend: + serviceName: echoheaders + servicePort: 80 + path: /something +" | kubectl create -f - +``` + +Check the rewrite is working + +``` +$ curl -v http://172.17.4.99/something -H 'Host: rewrite.bar.com' +* Trying 172.17.4.99... +* Connected to 172.17.4.99 (172.17.4.99) port 80 (#0) +> GET /something HTTP/1.1 +> Host: rewrite.bar.com +> User-Agent: curl/7.43.0 +> Accept: */* +> +< HTTP/1.1 200 OK +< Server: nginx/1.11.0 +< Date: Tue, 31 May 2016 16:07:31 GMT +< Content-Type: text/plain +< Transfer-Encoding: chunked +< Connection: keep-alive +< +CLIENT VALUES: +client_address=10.2.56.9 +command=GET +real path=/ +query=nil +request_version=1.1 +request_uri=http://rewrite.bar.com:8080/ + +SERVER VALUES: +server_version=nginx: 1.9.11 - lua: 10001 + +HEADERS RECEIVED: +accept=*/* +connection=close +host=rewrite.bar.com +user-agent=curl/7.43.0 +x-forwarded-for=10.2.56.1 +x-forwarded-host=rewrite.bar.com +x-forwarded-port=80 +x-forwarded-proto=http +x-real-ip=10.2.56.1 +BODY: +* Connection #0 to host 172.17.4.99 left intact +-no body in request- +``` + +### App Root + +Create an Ingress rule with a app-root annotation: +``` +$ echo " +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + annotations: + ingress.kubernetes.io/app-root: /app1 + name: approot + namespace: default +spec: + rules: + - host: approot.bar.com + http: + paths: + - backend: + serviceName: echoheaders + servicePort: 80 + path: / +" | kubectl create -f - +``` + +Check the rewrite is working + +``` +$ curl -I -k http://approot.bar.com/ +HTTP/1.1 302 Moved Temporarily +Server: nginx/1.11.10 +Date: Mon, 13 Mar 2017 14:57:15 GMT +Content-Type: text/html +Content-Length: 162 +Location: http://stickyingress.example.com/app1 +Connection: keep-alive +``` diff --git a/examples/scaling-deployment/haproxy/README.md b/examples/scaling-deployment/haproxy/README.md new file mode 100644 index 000000000..463550d72 --- /dev/null +++ b/examples/scaling-deployment/haproxy/README.md @@ -0,0 +1,65 @@ +# Deploying multi Haproxy Ingress Controllers + +This example aims to demonstrate the Deployment of multi haproxy ingress controllers. + +## Prerequisites + +This ingress controller doesn't yet have support for +[ingress classes](/examples/PREREQUISITES.md#ingress-class). You MUST turn +down any existing ingress controllers before running HAProxy Ingress controller or +they will fight for Ingresses. This includes any cloudprovider controller. + +This document has also the following prerequisites: + +* Create a [TLS secret](/examples/PREREQUISITES.md#tls-certificates) named `tls-secret` to be used as default TLS certificate + +Creating the TLS secret: + +```console +$ openssl req \ + -x509 -newkey rsa:2048 -nodes -days 365 \ + -keyout tls.key -out tls.crt -subj '/CN=localhost' +$ kubectl create secret tls tls-secret --cert=tls.crt --key=tls.key +$ rm -v tls.crt tls.key +``` + +## Default Backend + +The default backend is a service of handling all url paths and hosts the haproxy controller doesn't understand. Deploy the default-http-backend as follow: + +```console +$ kubectl create -f default-backend.yaml +deployment "default-http-backend" created +service "default-http-backend" created + +$ kubectl get svc +NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE +default-http-backend 192.168.3.4 80/TCP 30m + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +default-http-backend-q5sb6 1/1 Running 0 30m +``` + +## Ingress Deployment + +Deploy the Deployment of multi controllers as follows: + +```console +$ kubectl apply -f haproxy-ingress-deployment.yaml +deployment "haproxy-ingress" created +``` + +Check if the controller was successfully deployed: +```console +$ kubectl get deployment +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +default-http-backend 1 1 1 1 30m +haproxy-ingress 2 2 2 2 45s + +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +default-http-backend-q5sb6 1/1 Running 0 35m +haproxy-ingress-1779899633-k045t 1/1 Running 0 1m +haproxy-ingress-1779899633-mhthv 1/1 Running 0 1m +``` diff --git a/examples/scaling-deployment/haproxy/default-backend.yaml b/examples/scaling-deployment/haproxy/default-backend.yaml new file mode 100644 index 000000000..739ae2758 --- /dev/null +++ b/examples/scaling-deployment/haproxy/default-backend.yaml @@ -0,0 +1,49 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: default-http-backend + labels: + k8s-app: default-http-backend +spec: + replicas: 1 + template: + metadata: + labels: + k8s-app: default-http-backend + spec: + terminationGracePeriodSeconds: 60 + containers: + - name: default-http-backend + # Any image is permissable as long as: + # 1. It serves a 404 page at / + # 2. It serves 200 on a /healthz endpoint + image: gcr.io/google_containers/defaultbackend:1.0 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: 30 + timeoutSeconds: 5 + ports: + - containerPort: 8080 + resources: + limits: + cpu: 10m + memory: 20Mi + requests: + cpu: 10m + memory: 20Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: default-http-backend + labels: + k8s-app: default-http-backend +spec: + ports: + - port: 80 + targetPort: 8080 + selector: + k8s-app: default-http-backend diff --git a/examples/scaling-deployment/haproxy/haproxy-ingress-deployment.yaml b/examples/scaling-deployment/haproxy/haproxy-ingress-deployment.yaml new file mode 100644 index 000000000..357ed6387 --- /dev/null +++ b/examples/scaling-deployment/haproxy/haproxy-ingress-deployment.yaml @@ -0,0 +1,39 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + labels: + run: haproxy-ingress + name: haproxy-ingress +spec: + replicas: 2 + selector: + matchLabels: + run: haproxy-ingress + template: + metadata: + labels: + run: haproxy-ingress + spec: + containers: + - name: haproxy-ingress + image: quay.io/jcmoraisjr/haproxy-ingress + imagePullPolicy: IfNotPresent + args: + - --default-backend-service=default/default-http-backend + - --default-ssl-certificate=default/tls-secret + ports: + - name: http + containerPort: 80 + - name: https + containerPort: 443 + - name: stat + containerPort: 1936 + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace diff --git a/examples/scaling-deployment/nginx/nginx-ingress-deployment.yaml b/examples/scaling-deployment/nginx/nginx-ingress-deployment.yaml index f0ee65b31..d0948773f 100644 --- a/examples/scaling-deployment/nginx/nginx-ingress-deployment.yaml +++ b/examples/scaling-deployment/nginx/nginx-ingress-deployment.yaml @@ -14,7 +14,7 @@ spec: spec: terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/examples/static-ip/nginx/nginx-ingress-controller.yaml b/examples/static-ip/nginx/nginx-ingress-controller.yaml index d6eb1d512..1417a28eb 100644 --- a/examples/static-ip/nginx/nginx-ingress-controller.yaml +++ b/examples/static-ip/nginx/nginx-ingress-controller.yaml @@ -18,7 +18,7 @@ spec: # hostNetwork: true terminationGracePeriodSeconds: 60 containers: - - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.2 + - image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3 name: nginx-ingress-controller readinessProbe: httpGet: diff --git a/hack/e2e.go b/hack/e2e.go index 65dc71cd1..be9f2aa28 100644 --- a/hack/e2e.go +++ b/hack/e2e.go @@ -234,7 +234,7 @@ func getDeployer() (deployer, error) { case "bash": return bash{}, nil default: - return nil, fmt.Errorf("Unknown deployment strategy %q", *deployment) + return nil, fmt.Errorf("unknown deployment strategy %q", *deployment) } }