This commit is contained in:
Manuel Alejandro de Brito Fontes 2017-06-11 18:12:18 +00:00 committed by GitHub
commit 973bfb0d8d
13 changed files with 740 additions and 51 deletions

View file

@ -30,10 +30,9 @@ import (
"syscall" "syscall"
"time" "time"
proxyproto "github.com/armon/go-proxyproto"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/spf13/pflag" "github.com/spf13/pflag"
proxyproto "github.com/armon/go-proxyproto"
api_v1 "k8s.io/client-go/pkg/api/v1" api_v1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/ingress/controllers/nginx/pkg/config" "k8s.io/ingress/controllers/nginx/pkg/config"
@ -237,19 +236,22 @@ func (n *NGINXController) start(cmd *exec.Cmd, done chan error) {
// Reload checks if the running configuration file is different // Reload checks if the running configuration file is different
// to the specified and reload nginx if required // to the specified and reload nginx if required
func (n NGINXController) Reload(data []byte) ([]byte, bool, error) { func (n NGINXController) Reload(cfg ingress.Configuration) error {
if !n.isReloadRequired(data) { ncfg, err := n.newConfFile(cfg)
return []byte("Reload not required"), false, nil
}
err := ioutil.WriteFile(cfgPath, data, 0644) n.printDiff(ncfg)
err = ioutil.WriteFile(cfgPath, ncfg, 0644)
if err != nil { if err != nil {
return nil, false, err return err
} }
o, e := exec.Command(n.binary, "-s", "reload", "-c", cfgPath).CombinedOutput() out, err := exec.Command(n.binary, "-s", "reload", "-c", cfgPath).CombinedOutput()
if err != nil {
return fmt.Errorf("%v\n%v", err, string(out))
}
return o, true, e return nil
} }
// BackendDefaults returns the nginx defaults // BackendDefaults returns the nginx defaults
@ -262,36 +264,35 @@ func (n NGINXController) BackendDefaults() defaults.Backend {
return ngx_template.ReadConfig(n.configmap.Data).Backend return ngx_template.ReadConfig(n.configmap.Data).Backend
} }
// isReloadRequired check if the new configuration file is different // printDiff prints the difference between the current configuration
// from the current one. // and the new one.
func (n NGINXController) isReloadRequired(data []byte) bool { func (n NGINXController) printDiff(data []byte) {
in, err := os.Open(cfgPath) in, err := os.Open(cfgPath)
if err != nil { if err != nil {
return false return
} }
src, err := ioutil.ReadAll(in) src, err := ioutil.ReadAll(in)
in.Close() in.Close()
if err != nil { if err != nil {
return false return
} }
if !bytes.Equal(src, data) { if !bytes.Equal(src, data) {
tmpfile, err := ioutil.TempFile("", "nginx-cfg-diff") tmpfile, err := ioutil.TempFile("", "nginx-cfg-diff")
if err != nil { if err != nil {
glog.Errorf("error creating temporal file: %s", err) glog.Errorf("error creating temporal file: %s", err)
return false return
} }
defer tmpfile.Close() defer tmpfile.Close()
err = ioutil.WriteFile(tmpfile.Name(), data, 0644) err = ioutil.WriteFile(tmpfile.Name(), data, 0644)
if err != nil { if err != nil {
return false return
} }
diffOutput, err := diff(src, data) diffOutput, err := diff(src, data)
if err != nil { if err != nil {
glog.Errorf("error computing diff: %s", err) glog.Errorf("error computing diff: %s", err)
return true return
} }
if glog.V(2) { if glog.V(2) {
@ -299,9 +300,7 @@ func (n NGINXController) isReloadRequired(data []byte) bool {
glog.Infof("%v", string(diffOutput)) glog.Infof("%v", string(diffOutput))
} }
os.Remove(tmpfile.Name()) os.Remove(tmpfile.Name())
return len(diffOutput) > 0
} }
return false
} }
// Info return build information // Info return build information
@ -404,7 +403,12 @@ func (n *NGINXController) SetListers(lister ingress.StoreLister) {
// write the configuration file // write the configuration file
// returning nill implies the backend will be reloaded. // returning nill implies the backend will be reloaded.
// if an error is returned means requeue the update // if an error is returned means requeue the update
func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) ([]byte, error) { func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error {
_, err := n.newConfFile(ingressCfg)
return err
}
func (n *NGINXController) newConfFile(ingressCfg ingress.Configuration) ([]byte, error) {
var longestName int var longestName int
var serverNameBytes int var serverNameBytes int
for _, srv := range ingressCfg.Servers { for _, srv := range ingressCfg.Servers {
@ -540,11 +544,8 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) ([]byte, er
Cfg: cfg, Cfg: cfg,
IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6, IsIPV6Enabled: n.isIPV6Enabled && !cfg.DisableIpv6,
}) })
if err != nil {
return nil, err
}
if err := n.testTemplate(content); err != nil { if err != nil {
return nil, err return nil, err
} }

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

@ -47,6 +47,48 @@ type External struct {
ResponseHeaders []string `json:"responseHeaders"` ResponseHeaders []string `json:"responseHeaders"`
} }
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 (
methods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "CONNECT", "OPTIONS", "TRACE"} methods = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "CONNECT", "OPTIONS", "TRACE"}
headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`) headerRegexp = regexp.MustCompile(`^[a-zA-Z\d\-_]+$`)

View file

@ -40,6 +40,23 @@ type AuthSSLConfig struct {
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

@ -39,6 +39,30 @@ type SourceRange struct {
CIDR []string `json:"cidr"` CIDR []string `json:"cidr"`
} }
func (sr1 *SourceRange) Equal(sr2 *SourceRange) bool {
if sr1 == sr2 {
return true
}
if sr1 == nil || sr2 == nil {
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 {
backendResolver resolver.DefaultBackend backendResolver resolver.DefaultBackend
} }

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 controller
import ( import (
"fmt" "fmt"
"math/rand"
"os" "os"
"reflect" "reflect"
"sort" "sort"
@ -109,6 +110,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
@ -153,7 +156,7 @@ func newIngressController(config *Configuration) *GenericController {
cfg: config, cfg: config,
stopLock: &sync.Mutex{}, stopLock: &sync.Mutex{},
stopCh: make(chan struct{}), stopCh: make(chan struct{}),
syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.5, 1), syncRateLimiter: flowcontrol.NewTokenBucketRateLimiter(0.6, 1),
recorder: eventBroadcaster.NewRecorder(scheme.Scheme, api.EventSource{ recorder: eventBroadcaster.NewRecorder(scheme.Scheme, api.EventSource{
Component: "ingress-controller", Component: "ingress-controller",
}), }),
@ -400,27 +403,38 @@ func (ic *GenericController) syncIngress(key interface{}) error {
} }
} }
data, 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.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 {
return err return err
} }
out, reloaded, err := ic.cfg.Backend.Reload(data) err = ic.cfg.Backend.Reload(pcfg)
if err != nil { if err != nil {
incReloadErrorCount() incReloadErrorCount()
glog.Errorf("unexpected failure restarting the backend: \n%v", string(out)) glog.Errorf("unexpected failure restarting the backend: \n%v", err)
return err return err
} }
if reloaded {
glog.Infof("ingress backend successfully reloaded...") glog.Infof("ingress backend successfully reloaded...")
incReloadCount() incReloadCount()
}
ic.runningConfig = &pcfg
return nil return nil
} }
@ -693,7 +707,7 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
} }
aUpstreams = append(aUpstreams, value) aUpstreams = append(aUpstreams, value)
} }
sort.Sort(ingress.BackendByNameServers(aUpstreams)) //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 {
@ -850,12 +864,16 @@ 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

@ -50,14 +50,11 @@ type Controller interface {
// controller status // controller status
healthz.HealthzChecker healthz.HealthzChecker
// Reload takes a byte array representing the new loadbalancer configuration, // Reload takes the new loadbalancer configuration,
// and returns a byte array containing any output/errors from the backend and // Before returning the backend must load the configuration into the loadbalancer
// if a reload was required. // and update the running configuration.
// Before returning the backend must load the configuration in the given array // If reloading fails, there should be not change in the running configuration
// into the loadbalancer and restart it, or fail with an error and message string. Reload(Configuration) error
// If reloading fails, there should be not change in the running configuration or
// the given byte array.
Reload(data []byte) ([]byte, bool, error)
// OnUpdate callback invoked from the sync queue https://k8s.io/ingress/core/blob/master/pkg/ingress/controller/controller.go#L387 // OnUpdate callback invoked from the sync queue https://k8s.io/ingress/core/blob/master/pkg/ingress/controller/controller.go#L387
// when an update occurs. This is executed frequently because Ingress // when an update occurs. This is executed frequently because Ingress
// controllers watches changes in: // controllers watches changes in:
@ -78,12 +75,9 @@ type Controller interface {
// servers (FQDN) and all the locations inside each server. Each // servers (FQDN) and all the locations inside each server. Each
// location contains information about all the annotations were configured // location contains information about all the annotations were configured
// 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 the contents of the configuration file or an error // The backend returns an error if was not possible to update the configuration.
// with the reason why was not possible to generate the file.
// //
// The returned configuration is then passed to test, and then to reload OnUpdate(Configuration) error
// if there is no errors.
OnUpdate(Configuration) ([]byte, error)
// ConfigMap content of --configmap // ConfigMap content of --configmap
SetConfig(*api.ConfigMap) SetConfig(*api.ConfigMap)
// SetListers allows the access of store listers present in the generic controller // SetListers allows the access of store listers present in the generic controller

View file

@ -0,0 +1,458 @@
/*
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 != l2.Port {
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

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
TAG ?= 0.10 TAG ?= 0.11
REGISTRY = gcr.io/google_containers REGISTRY = gcr.io/google_containers
ARCH ?= $(shell go env GOARCH) ARCH ?= $(shell go env GOARCH)
ALL_ARCH = amd64 arm arm64 ppc64le ALL_ARCH = amd64 arm arm64 ppc64le