Merge pull request #862 from aledbf/equals

Avoid reloads implementing Equaler interface
This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-06-16 18:02:40 -04:00 committed by GitHub
commit e1bdce0aa2
17 changed files with 1246 additions and 27 deletions

View file

@ -53,6 +53,29 @@ type BasicDigest struct {
Secured bool `json:"secured"` Secured bool `json:"secured"`
} }
func (bd1 *BasicDigest) Equal(bd2 *BasicDigest) bool {
if bd1 == bd2 {
return true
}
if bd1 == nil || bd2 == nil {
return false
}
if bd1.Type != bd2.Type {
return false
}
if bd1.Realm != bd2.Realm {
return false
}
if bd1.File != bd2.File {
return false
}
if bd1.Secured != bd2.Secured {
return false
}
return true
}
type auth struct { type auth struct {
secretResolver resolver.Secret secretResolver resolver.Secret
authDirectory string authDirectory string

View file

@ -44,7 +44,49 @@ type External struct {
SigninURL string `json:"signinUrl"` SigninURL string `json:"signinUrl"`
Method string `json:"method"` Method string `json:"method"`
SendBody bool `json:"sendBody"` SendBody bool `json:"sendBody"`
ResponseHeaders []string `json:"responseHeaders"` ResponseHeaders []string `json:"responseHeaders,omitEmpty"`
}
func (e1 *External) Equal(e2 *External) bool {
if e1 == e2 {
return true
}
if e1 == nil || e2 == nil {
return false
}
if e1.URL != e2.URL {
return false
}
if e1.Host != e2.Host {
return false
}
if e1.SigninURL != e2.SigninURL {
return false
}
if e1.Method != e2.Method {
return false
}
if e1.SendBody != e2.SendBody {
return false
}
if e1.Method != e2.Method {
return false
}
for _, ep1 := range e1.ResponseHeaders {
found := false
for _, ep2 := range e2.ResponseHeaders {
if ep1 == ep2 {
found = true
break
}
}
if !found {
return false
}
}
return true
} }
var ( var (

View file

@ -36,10 +36,27 @@ const (
// AuthSSLConfig contains the AuthSSLCert used for muthual autentication // AuthSSLConfig contains the AuthSSLCert used for muthual autentication
// and the configured ValidationDepth // and the configured ValidationDepth
type AuthSSLConfig struct { type AuthSSLConfig struct {
AuthSSLCert resolver.AuthSSLCert AuthSSLCert resolver.AuthSSLCert `json:"authSSLCert"`
ValidationDepth int `json:"validationDepth"` ValidationDepth int `json:"validationDepth"`
} }
func (assl1 *AuthSSLConfig) Equal(assl2 *AuthSSLConfig) bool {
if assl1 == assl2 {
return true
}
if assl1 == nil || assl2 == nil {
return false
}
if !(&assl1.AuthSSLCert).Equal(&assl2.AuthSSLCert) {
return false
}
if assl1.ValidationDepth != assl2.ValidationDepth {
return false
}
return true
}
// NewParser creates a new TLS authentication annotation parser // NewParser creates a new TLS authentication annotation parser
func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation { func NewParser(resolver resolver.AuthCertificate) parser.IngressAnnotation {
return authTLS{resolver} return authTLS{resolver}

View file

@ -36,7 +36,35 @@ const (
// SourceRange returns the CIDR // SourceRange returns the CIDR
type SourceRange struct { type SourceRange struct {
CIDR []string `json:"cidr"` CIDR []string `json:"cidr,omitEmpty"`
}
func (sr1 *SourceRange) Equal(sr2 *SourceRange) bool {
if sr1 == sr2 {
return true
}
if sr1 == nil || sr2 == nil {
return false
}
if len(sr1.CIDR) != len(sr2.CIDR) {
return false
}
for _, s1l := range sr1.CIDR {
found := false
for _, sl2 := range sr2.CIDR {
if s1l == sl2 {
found = true
break
}
}
if !found {
return false
}
}
return true
} }
type ipwhitelist struct { type ipwhitelist struct {

View file

@ -44,6 +44,38 @@ type Configuration struct {
CookiePath string `json:"cookiePath"` CookiePath string `json:"cookiePath"`
} }
func (l1 *Configuration) Equal(l2 *Configuration) bool {
if l1 == l2 {
return true
}
if l1 == nil || l2 == nil {
return false
}
if l1.BodySize != l2.BodySize {
return false
}
if l1.ConnectTimeout != l2.ConnectTimeout {
return false
}
if l1.SendTimeout != l2.SendTimeout {
return false
}
if l1.ReadTimeout != l2.ReadTimeout {
return false
}
if l1.BufferSize != l2.BufferSize {
return false
}
if l1.CookieDomain != l2.CookieDomain {
return false
}
if l1.CookiePath != l2.CookiePath {
return false
}
return true
}
type proxy struct { type proxy struct {
backendResolver resolver.DefaultBackend backendResolver resolver.DefaultBackend
} }

View file

@ -47,6 +47,23 @@ type RateLimit struct {
RPS Zone `json:"rps"` RPS Zone `json:"rps"`
} }
func (rt1 *RateLimit) Equal(rt2 *RateLimit) bool {
if rt1 == rt2 {
return true
}
if rt1 == nil || rt2 == nil {
return false
}
if !(&rt1.Connections).Equal(&rt2.Connections) {
return false
}
if !(&rt1.RPS).Equal(&rt2.RPS) {
return false
}
return true
}
// Zone returns information about the NGINX rate limit (limit_req_zone) // Zone returns information about the NGINX rate limit (limit_req_zone)
// http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone // http://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone
type Zone struct { type Zone struct {
@ -57,6 +74,29 @@ type Zone struct {
SharedSize int `json:"sharedSize"` SharedSize int `json:"sharedSize"`
} }
func (z1 *Zone) Equal(z2 *Zone) bool {
if z1 == z2 {
return true
}
if z1 == nil || z2 == nil {
return false
}
if z1.Name != z2.Name {
return false
}
if z1.Limit != z2.Limit {
return false
}
if z1.Burst != z2.Burst {
return false
}
if z1.SharedSize != z2.SharedSize {
return false
}
return true
}
type ratelimit struct { type ratelimit struct {
} }

View file

@ -46,6 +46,32 @@ type Redirect struct {
AppRoot string `json:"appRoot"` AppRoot string `json:"appRoot"`
} }
func (r1 *Redirect) Equal(r2 *Redirect) bool {
if r1 == r2 {
return true
}
if r1 == nil || r2 == nil {
return false
}
if r1.Target != r2.Target {
return false
}
if r1.AddBaseURL != r2.AddBaseURL {
return false
}
if r1.SSLRedirect != r2.SSLRedirect {
return false
}
if r1.ForceSSLRedirect != r2.ForceSSLRedirect {
return false
}
if r1.AppRoot != r2.AppRoot {
return false
}
return true
}
type rewrite struct { type rewrite struct {
backendResolver resolver.DefaultBackend backendResolver resolver.DefaultBackend
} }

View file

@ -18,6 +18,7 @@ package secureupstream
import ( import (
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1" extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
@ -32,8 +33,8 @@ const (
// Secure describes SSL backend configuration // Secure describes SSL backend configuration
type Secure struct { type Secure struct {
Secure bool Secure bool `json:"secure"`
CACert resolver.AuthSSLCert CACert resolver.AuthSSLCert `json:"caCert"`
} }
type su struct { type su struct {

View file

@ -18,6 +18,7 @@ package controller
import ( import (
"fmt" "fmt"
"math/rand"
"os" "os"
"reflect" "reflect"
"sort" "sort"
@ -108,6 +109,8 @@ type GenericController struct {
stopLock *sync.Mutex stopLock *sync.Mutex
stopCh chan struct{} stopCh chan struct{}
runningConfig *ingress.Configuration
} }
// Configuration contains all the settings required by an Ingress controller // Configuration contains all the settings required by an Ingress controller
@ -400,14 +403,22 @@ func (ic *GenericController) syncIngress(key interface{}) error {
} }
} }
err := ic.cfg.Backend.OnUpdate(ingress.Configuration{ pcfg := ingress.Configuration{
Backends: upstreams, Backends: upstreams,
Servers: servers, Servers: servers,
TCPEndpoints: ic.getStreamServices(ic.cfg.TCPConfigMapName, api.ProtocolTCP), TCPEndpoints: ic.getStreamServices(ic.cfg.TCPConfigMapName, api.ProtocolTCP),
UDPEndpoints: ic.getStreamServices(ic.cfg.UDPConfigMapName, api.ProtocolUDP), UDPEndpoints: ic.getStreamServices(ic.cfg.UDPConfigMapName, api.ProtocolUDP),
PassthroughBackends: passUpstreams, PassthroughBackends: passUpstreams,
}) }
if ic.runningConfig != nil && ic.runningConfig.Equal(&pcfg) {
glog.V(3).Infof("skipping backend reload (no changes detected)")
return nil
}
glog.Infof("backend reload required")
err := ic.cfg.Backend.OnUpdate(pcfg)
if err != nil { if err != nil {
incReloadErrorCount() incReloadErrorCount()
glog.Errorf("unexpected failure restarting the backend: \n%v", err) glog.Errorf("unexpected failure restarting the backend: \n%v", err)
@ -418,6 +429,8 @@ func (ic *GenericController) syncIngress(key interface{}) error {
incReloadCount() incReloadCount()
setSSLExpireTime(servers) setSSLExpireTime(servers)
ic.runningConfig = &pcfg
return nil return nil
} }
@ -679,9 +692,6 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
} }
} }
// TODO: find a way to make this more readable
// The structs must be ordered to always generate the same file
// if the content does not change.
aUpstreams := make([]*ingress.Backend, 0, len(upstreams)) aUpstreams := make([]*ingress.Backend, 0, len(upstreams))
for _, value := range upstreams { for _, value := range upstreams {
if len(value.Endpoints) == 0 { if len(value.Endpoints) == 0 {
@ -690,7 +700,6 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
} }
aUpstreams = append(aUpstreams, value) aUpstreams = append(aUpstreams, value)
} }
sort.Sort(ingress.BackendByNameServers(aUpstreams))
aServers := make([]*ingress.Server, 0, len(servers)) aServers := make([]*ingress.Server, 0, len(servers))
for _, value := range servers { for _, value := range servers {
@ -847,12 +856,17 @@ func (ic *GenericController) serviceEndpoints(svcKey, backendPort string,
glog.Warningf("service %v does not have any active endpoints", svcKey) glog.Warningf("service %v does not have any active endpoints", svcKey)
} }
sort.Sort(ingress.EndpointByAddrPort(endps))
upstreams = append(upstreams, endps...) upstreams = append(upstreams, endps...)
break break
} }
} }
rand.Seed(time.Now().UnixNano())
for i := range upstreams {
j := rand.Intn(i + 1)
upstreams[i], upstreams[j] = upstreams[j], upstreams[i]
}
return upstreams, nil return upstreams, nil
} }

View file

@ -51,3 +51,17 @@ type AuthSSLCert struct {
// PemSHA contains the SHA1 hash of the 'tls.crt' value // PemSHA contains the SHA1 hash of the 'tls.crt' value
PemSHA string `json:"pemSha"` PemSHA string `json:"pemSha"`
} }
func (asslc1 *AuthSSLCert) Equal(assl2 *AuthSSLCert) bool {
if asslc1.Secret != assl2.Secret {
return false
}
if asslc1.CAFileName != assl2.CAFileName {
return false
}
if asslc1.PemSHA != assl2.PemSHA {
return false
}
return true
}

View file

@ -17,9 +17,10 @@ limitations under the License.
package ingress package ingress
import ( import (
"time"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"time"
) )
// BackendByNameServers sorts upstreams by name // BackendByNameServers sorts upstreams by name

View file

@ -0,0 +1,74 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ingress
import (
"encoding/json"
"os"
"path/filepath"
"testing"
)
func TestEqualConfiguration(t *testing.T) {
ap, _ := filepath.Abs("../../../tests/manifests/configuration-a.json")
a, err := readJSON(ap)
if err != nil {
t.Errorf("unexpected error reading JSON file: %v", err)
}
bp, _ := filepath.Abs("../../../tests/manifests/configuration-b.json")
b, err := readJSON(bp)
if err != nil {
t.Errorf("unexpected error reading JSON file: %v", err)
}
cp, _ := filepath.Abs("../../../tests/manifests/configuration-c.json")
c, err := readJSON(cp)
if err != nil {
t.Errorf("unexpected error reading JSON file: %v", err)
}
if !a.Equal(b) {
t.Errorf("expected equal configurations (configuration-a.json and configuration-b.json)")
}
if !b.Equal(a) {
t.Errorf("expected equal configurations (configuration-a.json and configuration-b.json)")
}
if a.Equal(c) {
t.Errorf("expected equal configurations (configuration-a.json and configuration-c.json)")
}
}
func readJSON(p string) (*Configuration, error) {
f, err := os.Open(p)
if err != nil {
return nil, err
}
var c Configuration
d := json.NewDecoder(f)
err = d.Decode(&c)
if err != nil {
return nil, err
}
return &c, nil
}

View file

@ -17,6 +17,8 @@ limitations under the License.
package ingress package ingress
import ( import (
"time"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
@ -33,7 +35,6 @@ import (
"k8s.io/ingress/core/pkg/ingress/defaults" "k8s.io/ingress/core/pkg/ingress/defaults"
"k8s.io/ingress/core/pkg/ingress/resolver" "k8s.io/ingress/core/pkg/ingress/resolver"
"k8s.io/ingress/core/pkg/ingress/store" "k8s.io/ingress/core/pkg/ingress/store"
"time"
) )
var ( var (
@ -73,8 +74,6 @@ type Controller interface {
// https://k8s.io/ingress/core/blob/master/pkg/ingress/types.go#L83 // https://k8s.io/ingress/core/blob/master/pkg/ingress/types.go#L83
// The backend returns an error if was not possible to update the configuration. // The backend returns an error if was not possible to update the configuration.
// //
// The returned configuration is then passed to test, and then to reload
// if there is no errors.
OnUpdate(Configuration) error OnUpdate(Configuration) error
// ConfigMap content of --configmap // ConfigMap content of --configmap
SetConfig(*api.ConfigMap) SetConfig(*api.ConfigMap)
@ -125,9 +124,9 @@ type BackendInfo struct {
type Configuration struct { type Configuration struct {
// Backends are a list of backends used by all the Ingress rules in the // Backends are a list of backends used by all the Ingress rules in the
// ingress controller. This list includes the default backend // ingress controller. This list includes the default backend
Backends []*Backend `json:"namespace"` Backends []*Backend `json:"backends,omitEmpty"`
// Servers // Servers
Servers []*Server `json:"servers"` Servers []*Server `json:"servers,omitEmpty"`
// TCPEndpoints contain endpoints for tcp streams handled by this backend // TCPEndpoints contain endpoints for tcp streams handled by this backend
// +optional // +optional
TCPEndpoints []L4Service `json:"tcpEndpoints,omitempty"` TCPEndpoints []L4Service `json:"tcpEndpoints,omitempty"`
@ -144,7 +143,7 @@ type Configuration struct {
type Backend struct { type Backend struct {
// Name represents an unique api.Service name formatted as <namespace>-<name>-<port> // Name represents an unique api.Service name formatted as <namespace>-<name>-<port>
Name string `json:"name"` Name string `json:"name"`
Service *api.Service `json:"service"` Service *api.Service `json:"service,omitempty"`
Port intstr.IntOrString `json:"port"` Port intstr.IntOrString `json:"port"`
// This indicates if the communication protocol between the backend and the endpoint is HTTP or HTTPS // This indicates if the communication protocol between the backend and the endpoint is HTTP or HTTPS
// Allowing the use of HTTPS // Allowing the use of HTTPS
@ -157,9 +156,9 @@ type Backend struct {
// SSLPassthrough indicates that Ingress controller will delegate TLS termination to the endpoints. // SSLPassthrough indicates that Ingress controller will delegate TLS termination to the endpoints.
SSLPassthrough bool `json:"sslPassthrough"` SSLPassthrough bool `json:"sslPassthrough"`
// Endpoints contains the list of endpoints currently running // Endpoints contains the list of endpoints currently running
Endpoints []Endpoint `json:"endpoints"` Endpoints []Endpoint `json:"endpoints,omitempty"`
// StickySessionAffinitySession contains the StickyConfig object with stickness configuration // StickySessionAffinitySession contains the StickyConfig object with stickness configuration
SessionAffinity SessionAffinityConfig SessionAffinity SessionAffinityConfig `json:"sessionAffinityConfig"`
} }
// SessionAffinityConfig describes different affinity configurations for new sessions. // SessionAffinityConfig describes different affinity configurations for new sessions.
@ -170,7 +169,7 @@ type Backend struct {
// about honoring updates. // about honoring updates.
type SessionAffinityConfig struct { type SessionAffinityConfig struct {
AffinityType string `json:"name"` AffinityType string `json:"name"`
CookieSessionAffinity CookieSessionAffinity CookieSessionAffinity CookieSessionAffinity `json:"cookieSessionAffinity"`
} }
// CookieSessionAffinity defines the structure used in Affinity configured by Cookies. // CookieSessionAffinity defines the structure used in Affinity configured by Cookies.
@ -254,7 +253,7 @@ type Location struct {
BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"` BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"`
// Denied returns an error when this location cannot not be allowed // Denied returns an error when this location cannot not be allowed
// Requesting a denied location should return HTTP code 403. // Requesting a denied location should return HTTP code 403.
Denied error Denied error `json:"denied,omitempty"`
// EnableCORS indicates if path must support CORS // EnableCORS indicates if path must support CORS
// +optional // +optional
EnableCORS bool `json:"enableCors,omitempty"` EnableCORS bool `json:"enableCors,omitempty"`
@ -295,7 +294,7 @@ type Location struct {
// The endpoints must provide the TLS termination exposing the required SSL certificate. // The endpoints must provide the TLS termination exposing the required SSL certificate.
// The ingress controller only pipes the underlying TCP connection // The ingress controller only pipes the underlying TCP connection
type SSLPassthroughBackend struct { type SSLPassthroughBackend struct {
Service *api.Service `json:"service"` Service *api.Service `json:"service,omitEmpty"`
Port intstr.IntOrString `json:"port"` Port intstr.IntOrString `json:"port"`
// Backend describes the endpoints to use. // Backend describes the endpoints to use.
Backend string `json:"namespace,omitempty"` Backend string `json:"namespace,omitempty"`
@ -310,7 +309,7 @@ type L4Service struct {
// Backend of the service // Backend of the service
Backend L4Backend `json:"backend"` Backend L4Backend `json:"backend"`
// Endpoints active endpoints of the service // Endpoints active endpoints of the service
Endpoints []Endpoint `json:"endpoins"` Endpoints []Endpoint `json:"endpoins,omitEmpty"`
} }
// L4Backend describes the kubernetes service behind L4 Ingress service // L4Backend describes the kubernetes service behind L4 Ingress service

View file

@ -0,0 +1,460 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package ingress
func (bi1 *BackendInfo) Equal(bi2 *BackendInfo) bool {
if bi1 == bi2 {
return true
}
if bi1 == nil || bi2 == nil {
return false
}
if bi1.Name != bi2.Name {
return false
}
if bi1.Release != bi2.Release {
return false
}
if bi1.Build != bi2.Build {
return false
}
if bi1.Repository != bi2.Repository {
return false
}
return true
}
func (c1 *Configuration) Equal(c2 *Configuration) bool {
if c1 == c2 {
return true
}
if c1 == nil || c2 == nil {
return false
}
if len(c1.Backends) != len(c2.Backends) {
return false
}
for _, c1b := range c1.Backends {
found := false
for _, c2b := range c2.Backends {
if c1b.Equal(c2b) {
found = true
break
}
}
if !found {
return false
}
}
for _, c1s := range c1.Servers {
found := false
for _, c2s := range c2.Servers {
if c1s.Equal(c2s) {
found = true
break
}
}
if !found {
return false
}
}
if len(c1.TCPEndpoints) != len(c2.TCPEndpoints) {
return false
}
for _, tcp1 := range c1.TCPEndpoints {
found := false
for _, tcp2 := range c2.TCPEndpoints {
if (&tcp1).Equal(&tcp2) {
found = true
break
}
}
if !found {
return false
}
}
if len(c1.UDPEndpoints) != len(c2.UDPEndpoints) {
return false
}
for _, udp1 := range c1.UDPEndpoints {
found := false
for _, udp2 := range c2.UDPEndpoints {
if (&udp1).Equal(&udp2) {
found = true
break
}
}
if !found {
return false
}
}
if len(c1.PassthroughBackends) != len(c2.PassthroughBackends) {
return false
}
for _, ptb1 := range c1.PassthroughBackends {
found := false
for _, ptb2 := range c2.PassthroughBackends {
if ptb1.Equal(ptb2) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
func (b1 *Backend) Equal(b2 *Backend) bool {
if b1 == b2 {
return true
}
if b1 == nil || b2 == nil {
return false
}
if b1.Name != b2.Name {
return false
}
if (b1.Service == nil && b2.Service != nil) ||
(b1.Service != nil && b2.Service == nil) {
return false
}
if b1.Service != nil && b2.Service != nil {
if b1.Service.GetNamespace() != b2.Service.GetNamespace() {
return false
}
if b1.Service.GetName() != b2.Service.GetName() {
return false
}
if b1.Service.GetResourceVersion() != b2.Service.GetResourceVersion() {
return false
}
}
if b1.Port != b2.Port {
return false
}
if b1.Secure != b2.Secure {
return false
}
if !(&b1.SecureCACert).Equal(&b2.SecureCACert) {
return false
}
if b1.SSLPassthrough != b2.SSLPassthrough {
return false
}
if !(&b1.SessionAffinity).Equal(&b2.SessionAffinity) {
return false
}
if len(b1.Endpoints) != len(b2.Endpoints) {
return false
}
for _, udp1 := range b1.Endpoints {
found := false
for _, udp2 := range b2.Endpoints {
if (&udp1).Equal(&udp2) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
func (sac1 *SessionAffinityConfig) Equal(sac2 *SessionAffinityConfig) bool {
if sac1 == sac2 {
return true
}
if sac1 == nil || sac2 == nil {
return false
}
if sac1.AffinityType != sac2.AffinityType {
return false
}
if !(&sac1.CookieSessionAffinity).Equal(&sac2.CookieSessionAffinity) {
return false
}
return true
}
func (csa1 *CookieSessionAffinity) Equal(csa2 *CookieSessionAffinity) bool {
if csa1 == csa2 {
return true
}
if csa1 == nil || csa2 == nil {
return false
}
if csa1.Name != csa2.Name {
return false
}
if csa1.Hash != csa2.Hash {
return false
}
return true
}
// Equal checks the equality against an Endpoint
func (e1 *Endpoint) Equal(e2 *Endpoint) bool {
if e1 == e2 {
return true
}
if e1 == nil || e2 == nil {
return false
}
if e1.Address != e2.Address {
return false
}
if e1.Port != e2.Port {
return false
}
if e1.MaxFails != e2.MaxFails {
return false
}
if e1.FailTimeout != e2.FailTimeout {
return false
}
return true
}
func (s1 *Server) Equal(s2 *Server) bool {
if s1 == s2 {
return true
}
if s1 == nil || s2 == nil {
return false
}
if s1.Hostname != s2.Hostname {
return false
}
if s1.SSLPassthrough != s2.SSLPassthrough {
return false
}
if s1.SSLCertificate != s2.SSLCertificate {
return false
}
if s1.SSLPemChecksum != s2.SSLPemChecksum {
return false
}
if len(s1.Locations) != len(s2.Locations) {
return false
}
for _, s1l := range s1.Locations {
found := false
for _, sl2 := range s2.Locations {
if s1l.Equal(sl2) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
func (l1 *Location) Equal(l2 *Location) bool {
if l1 == l2 {
return true
}
if l1 == nil || l2 == nil {
return false
}
if l1.Path != l2.Path {
return false
}
if l1.IsDefBackend != l2.IsDefBackend {
return false
}
if l1.Backend != l2.Backend {
return false
}
if (l1.Service == nil && l2.Service != nil) ||
(l1.Service != nil && l2.Service == nil) {
return false
}
if l1.Service != nil && l2.Service != nil {
if l1.Service.GetNamespace() != l2.Service.GetNamespace() {
return false
}
if l1.Service.GetName() != l2.Service.GetName() {
return false
}
if l1.Service.GetResourceVersion() != l2.Service.GetResourceVersion() {
return false
}
}
if l1.Port.StrVal != l2.Port.StrVal {
return false
}
if !(&l1.BasicDigestAuth).Equal(&l2.BasicDigestAuth) {
return false
}
if l1.Denied != l2.Denied {
return false
}
if l1.EnableCORS != l2.EnableCORS {
return false
}
if !(&l1.ExternalAuth).Equal(&l2.ExternalAuth) {
return false
}
if !(&l1.RateLimit).Equal(&l2.RateLimit) {
return false
}
if !(&l1.Redirect).Equal(&l2.Redirect) {
return false
}
if !(&l1.Whitelist).Equal(&l2.Whitelist) {
return false
}
if !(&l1.Proxy).Equal(&l2.Proxy) {
return false
}
if !(&l1.CertificateAuth).Equal(&l2.CertificateAuth) {
return false
}
if l1.UsePortInRedirects != l2.UsePortInRedirects {
return false
}
if l1.ConfigurationSnippet != l2.ConfigurationSnippet {
return false
}
return true
}
func (ptb1 *SSLPassthroughBackend) Equal(ptb2 *SSLPassthroughBackend) bool {
if ptb1 == ptb2 {
return true
}
if ptb1 == nil || ptb2 == nil {
return false
}
if ptb1.Backend != ptb2.Backend {
return false
}
if ptb1.Hostname != ptb2.Hostname {
return false
}
if ptb1.Port != ptb2.Port {
return false
}
if (ptb1.Service == nil && ptb2.Service != nil) ||
(ptb1.Service != nil && ptb2.Service == nil) {
return false
}
if ptb1.Service != nil && ptb2.Service != nil {
if ptb1.Service.GetNamespace() != ptb2.Service.GetNamespace() {
return false
}
if ptb1.Service.GetName() != ptb2.Service.GetName() {
return false
}
if ptb1.Service.GetResourceVersion() != ptb2.Service.GetResourceVersion() {
return false
}
}
return true
}
func (e1 *L4Service) Equal(e2 *L4Service) bool {
if e1 == e2 {
return true
}
if e1 == nil || e2 == nil {
return false
}
if e1.Port != e2.Port {
return false
}
if !(&e1.Backend).Equal(&e2.Backend) {
return false
}
if len(e1.Endpoints) != len(e2.Endpoints) {
return false
}
for _, ep1 := range e1.Endpoints {
found := false
for _, ep2 := range e2.Endpoints {
if (&ep1).Equal(&ep2) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
func (l4b1 *L4Backend) Equal(l4b2 *L4Backend) bool {
if l4b1 == l4b2 {
return true
}
if l4b1 == nil || l4b2 == nil {
return false
}
if l4b1.Port != l4b2.Port {
return false
}
if l4b1.Name != l4b2.Name {
return false
}
if l4b1.Namespace != l4b2.Namespace {
return false
}
if l4b1.Protocol != l4b2.Protocol {
return false
}
return true
}

View file

@ -0,0 +1,97 @@
{
"backends": [{
"name": "upstream-default-backend",
"port": 0,
"secure": false,
"secureCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"sslPassthrough": false,
"endpoints": [{
"address": "172.17.0.5",
"port": "8080",
"maxFails": 0,
"failTimeout": 0
}],
"sessionAffinityConfig": {
"name": "",
"cookieSessionAffinity": {
"name": "",
"hash": ""
}
}
}],
"servers": [{
"hostname": "_",
"sslPassthrough": false,
"sslCertificate": "/ingress-controller/ssl/default-fake-certificate.pem",
"sslExpireTime": "0001-01-01T00:00:00Z",
"sslPemChecksum": "4302f26460e2c49c9a69229449efefb30dc42a9a",
"locations": [{
"path": "/",
"isDefBackend": true,
"backend": "upstream-default-backend",
"service": null,
"port": 0,
"basicDigestAuth": {
"type": "",
"realm": "",
"file": "",
"secured": false
},
"externalAuth": {
"url": "",
"host": "",
"signinUrl": "",
"method": "",
"sendBody": false,
"responseHeaders": null
},
"rateLimit": {
"connections": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
},
"rps": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
}
},
"redirect": {
"target": "",
"addBaseUrl": false,
"sslRedirect": false,
"forceSSLRedirect": false,
"appRoot": ""
},
"whitelist": {
"cidr": null
},
"proxy": {
"bodySize": "1m",
"conectTimeout": 5,
"sendTimeout": 60,
"readTimeout": 60,
"bufferSize": "4k",
"cookieDomain": "off",
"cookiePath": "off"
},
"certificateAuth": {
"authSSLCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"validationDepth": 0
},
"use-port-in-redirects": false,
"configuration-snippet": ""
}]
}]
}

View file

@ -0,0 +1,97 @@
{
"backends": [{
"name": "upstream-default-backend",
"port": 0,
"secure": false,
"secureCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"sslPassthrough": false,
"endpoints": [{
"address": "172.17.0.5",
"port": "8080",
"maxFails": 0,
"failTimeout": 0
}],
"sessionAffinityConfig": {
"name": "",
"cookieSessionAffinity": {
"name": "",
"hash": ""
}
}
}],
"servers": [{
"hostname": "_",
"sslPassthrough": false,
"sslCertificate": "/ingress-controller/ssl/default-fake-certificate.pem",
"sslExpireTime": "0001-01-01T00:00:00Z",
"sslPemChecksum": "4302f26460e2c49c9a69229449efefb30dc42a9a",
"locations": [{
"path": "/",
"isDefBackend": true,
"backend": "upstream-default-backend",
"service": null,
"port": 0,
"basicDigestAuth": {
"type": "",
"realm": "",
"file": "",
"secured": false
},
"externalAuth": {
"url": "",
"host": "",
"signinUrl": "",
"method": "",
"sendBody": false,
"responseHeaders": null
},
"rateLimit": {
"connections": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
},
"rps": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
}
},
"redirect": {
"target": "",
"addBaseUrl": false,
"sslRedirect": false,
"forceSSLRedirect": false,
"appRoot": ""
},
"whitelist": {
"cidr": null
},
"proxy": {
"bodySize": "1m",
"conectTimeout": 5,
"sendTimeout": 60,
"readTimeout": 60,
"bufferSize": "4k",
"cookieDomain": "off",
"cookiePath": "off"
},
"certificateAuth": {
"authSSLCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"validationDepth": 0
},
"use-port-in-redirects": false,
"configuration-snippet": ""
}]
}]
}

View file

@ -0,0 +1,254 @@
{
"backends": [{
"name": "upstream-default-backend",
"service": null,
"port": 0,
"secure": false,
"secureCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"sslPassthrough": false,
"endpoints": [{
"address": "172.17.0.8",
"port": "8080",
"maxFails": 0,
"failTimeout": 0
}],
"SessionAffinity": {
"name": "",
"CookieSessionAffinity": {
"name": "",
"hash": ""
}
}
}, {
"name": "deis-deis-controller-8000",
"service": {
"metadata": {
"name": "deis-controller",
"namespace": "deis",
"selfLink": "/api/v1/namespaces/deis/services/deis-controller",
"uid": "1cba01a8-50b0-11e7-a384-0800270f5693",
"resourceVersion": "532",
"creationTimestamp": "2017-06-14T03:18:18Z",
"labels": {
"heritage": "deis"
}
},
"spec": {
"ports": [{
"name": "http",
"protocol": "TCP",
"port": 8000,
"targetPort": 8000,
"nodePort": 30171
}],
"selector": {
"app": "deis-controller"
},
"clusterIP": "10.0.0.198",
"type": "NodePort",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
},
"port": 8000,
"secure": false,
"secureCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"sslPassthrough": false,
"endpoints": [{
"address": "172.17.0.7",
"port": "8000",
"maxFails": 0,
"failTimeout": 0
}],
"SessionAffinity": {
"name": "",
"CookieSessionAffinity": {
"name": "",
"hash": ""
}
}
}],
"servers": [{
"hostname": "_",
"sslPassthrough": false,
"sslCertificate": "/ingress-controller/ssl/default-fake-certificate.pem",
"sslExpireTime": "0001-01-01T00:00:00Z",
"sslPemChecksum": "123b44425920a2e4825ae779fba0e6e07fbac03d",
"locations": [{
"path": "/",
"isDefBackend": true,
"backend": "upstream-default-backend",
"service": null,
"port": 0,
"basicDigestAuth": {
"type": "",
"realm": "",
"file": "",
"secured": false
},
"Denied": null,
"externalAuth": {
"url": "",
"host": "",
"signinUrl": "",
"method": "",
"sendBody": false,
"responseHeaders": null
},
"rateLimit": {
"connections": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
},
"rps": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
}
},
"redirect": {
"target": "",
"addBaseUrl": false,
"sslRedirect": false,
"forceSSLRedirect": false,
"appRoot": ""
},
"whitelist": {
"cidr": null
},
"proxy": {
"bodySize": "1g",
"conectTimeout": 5,
"sendTimeout": 60,
"readTimeout": 60,
"bufferSize": "4k",
"cookieDomain": "off",
"cookiePath": "off"
},
"certificateAuth": {
"AuthSSLCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"validationDepth": 0
},
"use-port-in-redirects": false,
"configuration-snippet": ""
}]
}, {
"hostname": "deis.minikube",
"sslPassthrough": false,
"sslCertificate": "",
"sslExpireTime": "0001-01-01T00:00:00Z",
"sslPemChecksum": "",
"locations": [{
"path": "/",
"isDefBackend": false,
"backend": "deis-deis-controller-8000",
"service": {
"metadata": {
"name": "deis-controller",
"namespace": "deis",
"selfLink": "/api/v1/namespaces/deis/services/deis-controller",
"uid": "1cba01a8-50b0-11e7-a384-0800270f5693",
"resourceVersion": "532",
"creationTimestamp": "2017-06-14T03:18:18Z",
"labels": {
"heritage": "deis"
}
},
"spec": {
"ports": [{
"name": "http",
"protocol": "TCP",
"port": 8000,
"targetPort": 8000,
"nodePort": 30171
}],
"selector": {
"app": "deis-controller"
},
"clusterIP": "10.0.0.198",
"type": "NodePort",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
},
"port": 8000,
"basicDigestAuth": {
"type": "",
"realm": "",
"file": "",
"secured": false
},
"Denied": null,
"externalAuth": {
"url": "",
"host": "",
"signinUrl": "",
"method": "",
"sendBody": false,
"responseHeaders": null
},
"rateLimit": {
"connections": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
},
"rps": {
"name": "",
"limit": 0,
"burst": 0,
"sharedSize": 0
}
},
"redirect": {
"target": "",
"addBaseUrl": false,
"sslRedirect": true,
"forceSSLRedirect": false,
"appRoot": ""
},
"whitelist": {
"cidr": null
},
"proxy": {
"bodySize": "1g",
"conectTimeout": 5,
"sendTimeout": 60,
"readTimeout": 60,
"bufferSize": "4k",
"cookieDomain": "off",
"cookiePath": "off"
},
"certificateAuth": {
"AuthSSLCert": {
"secret": "",
"caFilename": "",
"pemSha": ""
},
"validationDepth": 0
},
"use-port-in-redirects": false,
"configuration-snippet": ""
}]
}]
}