Move APIs to be used by both controller and configurer (#8854)
This commit is contained in:
parent
4391474bf1
commit
c86d50ecef
30 changed files with 30 additions and 35 deletions
91
pkg/apis/ingress/sslcert.go
Normal file
91
pkg/apis/ingress/sslcert.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright 2016 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 (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// SSLCert describes a SSL certificate to be used in a server
|
||||
type SSLCert struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
|
||||
Certificate *x509.Certificate `json:"-"`
|
||||
|
||||
CACertificate []*x509.Certificate `json:"-"`
|
||||
|
||||
// CAFileName contains the path to the file with the root certificate
|
||||
CAFileName string `json:"caFileName"`
|
||||
|
||||
// CASHA contains the sha1 of the ca file.
|
||||
// This is used to detect changes in the secret that contains certificates
|
||||
CASHA string `json:"caSha"`
|
||||
|
||||
// CRLFileName contains the path to the file with the Certificate Revocation List
|
||||
CRLFileName string `json:"crlFileName"`
|
||||
// CRLSHA contains the sha1 of the pem file.
|
||||
CRLSHA string `json:"crlSha"`
|
||||
|
||||
// PemFileName contains the path to the file with the certificate and key concatenated
|
||||
PemFileName string `json:"pemFileName"`
|
||||
|
||||
// PemSHA contains the sha1 of the pem file.
|
||||
// This is used to detect changes in the secret that contains certificates
|
||||
PemSHA string `json:"pemSha"`
|
||||
|
||||
// CN contains all the common names defined in the SSL certificate
|
||||
CN []string `json:"cn"`
|
||||
|
||||
// ExpiresTime contains the expiration of this SSL certificate in timestamp format
|
||||
ExpireTime time.Time `json:"expires"`
|
||||
|
||||
// Pem encoded certificate and key concatenated
|
||||
PemCertKey string `json:"pemCertKey,omitempty"`
|
||||
|
||||
// UID unique identifier of the Kubernetes Secret
|
||||
UID string `json:"uid"`
|
||||
}
|
||||
|
||||
// GetObjectKind implements the ObjectKind interface as a noop
|
||||
func (s SSLCert) GetObjectKind() schema.ObjectKind {
|
||||
return schema.EmptyObjectKind
|
||||
}
|
||||
|
||||
// Identifier returns a the couple issuer / serial number if they both exist, an empty string otherwise
|
||||
func (s SSLCert) Identifier() string {
|
||||
if s.Certificate != nil {
|
||||
if s.Certificate.SerialNumber != nil {
|
||||
return fmt.Sprintf("%s-%s", s.Certificate.Issuer.SerialNumber, s.Certificate.SerialNumber.String())
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// HashInclude defines if a field should be used or not to calculate the hash
|
||||
func (s SSLCert) HashInclude(field string, v interface{}) (bool, error) {
|
||||
switch field {
|
||||
case "PemSHA", "CASHA", "ExpireTime":
|
||||
return true, nil
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
407
pkg/apis/ingress/types.go
Normal file
407
pkg/apis/ingress/types.go
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
Copyright 2016 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 (
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/auth"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/authtls"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/connection"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/cors"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/fastcgi"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/globalratelimit"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ipwhitelist"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/log"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/mirror"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/modsecurity"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/opentracing"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/proxyssl"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/redirect"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
|
||||
)
|
||||
|
||||
// TODO: The API shouldn't be importing structs from annotation code. Instead we probably want a conversion from internal
|
||||
// to API object, or see how much effort is to move the structs of annotations to become an "API'ish" as well
|
||||
|
||||
// Configuration holds the definition of all the parts required to describe all
|
||||
// ingresses reachable by the ingress controller (using a filter by namespace)
|
||||
type Configuration struct {
|
||||
// Backends are a list of backends used by all the Ingress rules in the
|
||||
// ingress controller. This list includes the default backend
|
||||
Backends []*Backend `json:"backends,omitempty"`
|
||||
// Servers save the website config
|
||||
Servers []*Server `json:"servers,omitempty"`
|
||||
// TCPEndpoints contain endpoints for tcp streams handled by this backend
|
||||
// +optional
|
||||
TCPEndpoints []L4Service `json:"tcpEndpoints,omitempty"`
|
||||
// UDPEndpoints contain endpoints for udp streams handled by this backend
|
||||
// +optional
|
||||
UDPEndpoints []L4Service `json:"udpEndpoints,omitempty"`
|
||||
// PassthroughBackends contains the backends used for SSL passthrough.
|
||||
// It contains information about the associated Server Name Indication (SNI).
|
||||
// +optional
|
||||
PassthroughBackends []*SSLPassthroughBackend `json:"passthroughBackends,omitempty"`
|
||||
|
||||
// BackendConfigChecksum contains the particular checksum of a Configuration object
|
||||
BackendConfigChecksum string `json:"BackendConfigChecksum,omitempty"`
|
||||
|
||||
// ConfigurationChecksum contains the particular checksum of a Configuration object
|
||||
ConfigurationChecksum string `json:"configurationChecksum,omitempty"`
|
||||
|
||||
DefaultSSLCertificate *SSLCert `json:"-"`
|
||||
|
||||
StreamSnippets []string
|
||||
}
|
||||
|
||||
// Backend describes one or more remote server/s (endpoints) associated with a service
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Backend struct {
|
||||
// Name represents an unique apiv1.Service name formatted as <namespace>-<name>-<port>
|
||||
Name string `json:"name"`
|
||||
Service *apiv1.Service `json:"service,omitempty"`
|
||||
Port intstr.IntOrString `json:"port"`
|
||||
// SSLPassthrough indicates that Ingress controller will delegate TLS termination to the endpoints.
|
||||
SSLPassthrough bool `json:"sslPassthrough"`
|
||||
// Endpoints contains the list of endpoints currently running
|
||||
Endpoints []Endpoint `json:"endpoints,omitempty"`
|
||||
// StickySessionAffinitySession contains the StickyConfig object with stickiness configuration
|
||||
SessionAffinity SessionAffinityConfig `json:"sessionAffinityConfig"`
|
||||
// Consistent hashing by NGINX variable
|
||||
UpstreamHashBy UpstreamHashByConfig `json:"upstreamHashByConfig,omitempty"`
|
||||
// LB algorithm configuration per ingress
|
||||
LoadBalancing string `json:"load-balance,omitempty"`
|
||||
// Denotes if a backend has no server. The backend instead shares a server with another backend and acts as an
|
||||
// alternative backend.
|
||||
// This can be used to share multiple upstreams in the sam nginx server block.
|
||||
NoServer bool `json:"noServer"`
|
||||
// Policies to describe the characteristics of an alternative backend.
|
||||
// +optional
|
||||
TrafficShapingPolicy TrafficShapingPolicy `json:"trafficShapingPolicy,omitempty"`
|
||||
// Contains a list of backends without servers that are associated with this backend.
|
||||
// +optional
|
||||
AlternativeBackends []string `json:"alternativeBackends,omitempty"`
|
||||
}
|
||||
|
||||
// TrafficShapingPolicy describes the policies to put in place when a backend has no server and is used as an
|
||||
// alternative backend
|
||||
// +k8s:deepcopy-gen=true
|
||||
type TrafficShapingPolicy struct {
|
||||
// Weight (0-<WeightTotal>) of traffic to redirect to the backend.
|
||||
// e.g. <WeightTotal> defaults to 100, weight 20 means 20% of traffic will be
|
||||
// redirected to the backend and 80% will remain with the other backend. If
|
||||
// <WeightTotal> is set to 1000, weight 2 means 0.2% of traffic will be
|
||||
// redirected to the backend and 99.8% will remain with the other backend.
|
||||
// 0 weight will not send any traffic to this backend
|
||||
Weight int `json:"weight"`
|
||||
// The total weight of traffic (>= 100). If unspecified, it defaults to 100.
|
||||
WeightTotal int `json:"weightTotal"`
|
||||
// Header on which to redirect requests to this backend
|
||||
Header string `json:"header"`
|
||||
// HeaderValue on which to redirect requests to this backend
|
||||
HeaderValue string `json:"headerValue"`
|
||||
// HeaderPattern the header value match pattern, support exact, regex.
|
||||
HeaderPattern string `json:"headerPattern"`
|
||||
// Cookie on which to redirect requests to this backend
|
||||
Cookie string `json:"cookie"`
|
||||
}
|
||||
|
||||
// HashInclude defines if a field should be used or not to calculate the hash
|
||||
func (s Backend) HashInclude(field string, v interface{}) (bool, error) {
|
||||
switch field {
|
||||
case "Endpoints":
|
||||
return false, nil
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SessionAffinityConfig describes different affinity configurations for new sessions.
|
||||
// Once a session is mapped to a backend based on some affinity setting, it
|
||||
// retains that mapping till the backend goes down, or the ingress controller
|
||||
// restarts. Exactly one of these values will be set on the upstream, since multiple
|
||||
// affinity values are incompatible. Once set, the backend makes no guarantees
|
||||
// about honoring updates.
|
||||
// +k8s:deepcopy-gen=true
|
||||
type SessionAffinityConfig struct {
|
||||
AffinityType string `json:"name"`
|
||||
AffinityMode string `json:"mode"`
|
||||
CookieSessionAffinity CookieSessionAffinity `json:"cookieSessionAffinity"`
|
||||
}
|
||||
|
||||
// CookieSessionAffinity defines the structure used in Affinity configured by Cookies.
|
||||
// +k8s:deepcopy-gen=true
|
||||
type CookieSessionAffinity struct {
|
||||
Name string `json:"name"`
|
||||
Expires string `json:"expires,omitempty"`
|
||||
MaxAge string `json:"maxage,omitempty"`
|
||||
Locations map[string][]string `json:"locations,omitempty"`
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
SameSite string `json:"samesite,omitempty"`
|
||||
ConditionalSameSiteNone bool `json:"conditional_samesite_none,omitempty"`
|
||||
ChangeOnFailure bool `json:"change_on_failure,omitempty"`
|
||||
}
|
||||
|
||||
// UpstreamHashByConfig described setting from the upstream-hash-by* annotations.
|
||||
type UpstreamHashByConfig struct {
|
||||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
||||
UpstreamHashBySubset bool `json:"upstream-hash-by-subset,omitempty"`
|
||||
UpstreamHashBySubsetSize int `json:"upstream-hash-by-subset-size,omitempty"`
|
||||
}
|
||||
|
||||
// Endpoint describes a kubernetes endpoint in a backend
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Endpoint struct {
|
||||
// Address IP address of the endpoint
|
||||
Address string `json:"address"`
|
||||
// Port number of the TCP port
|
||||
Port string `json:"port"`
|
||||
// Target returns a reference to the object providing the endpoint
|
||||
Target *apiv1.ObjectReference `json:"target,omitempty"`
|
||||
}
|
||||
|
||||
// Server describes a website
|
||||
type Server struct {
|
||||
// Hostname returns the FQDN of the server
|
||||
Hostname string `json:"hostname"`
|
||||
// SSLPassthrough indicates if the TLS termination is realized in
|
||||
// the server or in the remote endpoint
|
||||
SSLPassthrough bool `json:"sslPassthrough"`
|
||||
// SSLCert describes the certificate that will be used on the server
|
||||
SSLCert *SSLCert `json:"sslCert"`
|
||||
// Locations list of URIs configured in the server.
|
||||
Locations []*Location `json:"locations,omitempty"`
|
||||
// Aliases return the alias of the server name
|
||||
Aliases []string `json:"aliases,omitempty"`
|
||||
// RedirectFromToWWW returns if a redirect to/from prefix www is required
|
||||
RedirectFromToWWW bool `json:"redirectFromToWWW,omitempty"`
|
||||
// CertificateAuth indicates the this server requires mutual authentication
|
||||
// +optional
|
||||
CertificateAuth authtls.Config `json:"certificateAuth"`
|
||||
// ProxySSL indicates the this server uses client certificate to access backends
|
||||
// +optional
|
||||
ProxySSL proxyssl.Config `json:"proxySSL"`
|
||||
// ServerSnippet returns the snippet of server
|
||||
// +optional
|
||||
ServerSnippet string `json:"serverSnippet"`
|
||||
// SSLCiphers returns list of ciphers to be enabled
|
||||
SSLCiphers string `json:"sslCiphers,omitempty"`
|
||||
// SSLPreferServerCiphers indicates that server ciphers should be preferred
|
||||
// over client ciphers when using the SSLv3 and TLS protocols.
|
||||
SSLPreferServerCiphers string `json:"sslPreferServerCiphers,omitempty"`
|
||||
// AuthTLSError contains the reason why the access to a server should be denied
|
||||
AuthTLSError string `json:"authTLSError,omitempty"`
|
||||
}
|
||||
|
||||
// Location describes an URI inside a server.
|
||||
// Also contains additional information about annotations in the Ingress.
|
||||
//
|
||||
// In some cases when more than one annotations is defined a particular order in the execution
|
||||
// is required.
|
||||
// The chain in the execution order of annotations should be:
|
||||
// - Whitelist
|
||||
// - RateLimit
|
||||
// - BasicDigestAuth
|
||||
// - ExternalAuth
|
||||
// - Redirect
|
||||
type Location struct {
|
||||
// Path is an extended POSIX regex as defined by IEEE Std 1003.1,
|
||||
// (i.e this follows the egrep/unix syntax, not the perl syntax)
|
||||
// matched against the path of an incoming request. Currently it can
|
||||
// contain characters disallowed from the conventional "path"
|
||||
// part of a URL as defined by RFC 3986. Paths must begin with
|
||||
// a '/'. If unspecified, the path defaults to a catch all sending
|
||||
// traffic to the backend.
|
||||
Path string `json:"path"`
|
||||
// PathType represents the type of path referred to by a HTTPIngressPath.
|
||||
PathType *networking.PathType `json:"pathType"`
|
||||
// IsDefBackend indicates if service specified in the Ingress
|
||||
// contains active endpoints or not. Returning true means the location
|
||||
// uses the default backend.
|
||||
IsDefBackend bool `json:"isDefBackend"`
|
||||
// Ingress returns the ingress from which this location was generated
|
||||
Ingress *Ingress `json:"ingress"`
|
||||
// IngressPath original path defined in the ingress rule
|
||||
IngressPath string `json:"ingressPath"`
|
||||
// Backend describes the name of the backend to use.
|
||||
Backend string `json:"backend"`
|
||||
// Service describes the referenced services from the ingress
|
||||
Service *apiv1.Service `json:"-"`
|
||||
// Port describes to which port from the service
|
||||
Port intstr.IntOrString `json:"port"`
|
||||
// Overwrite the Host header passed into the backend. Defaults to
|
||||
// vhost of the incoming request.
|
||||
// +optional
|
||||
UpstreamVhost string `json:"upstream-vhost"`
|
||||
// BasicDigestAuth returns authentication configuration for
|
||||
// an Ingress rule.
|
||||
// +optional
|
||||
BasicDigestAuth auth.Config `json:"basicDigestAuth,omitempty"`
|
||||
// Denied returns an error when this location cannot not be allowed
|
||||
// Requesting a denied location should return HTTP code 403.
|
||||
Denied *string `json:"denied,omitempty"`
|
||||
// CorsConfig returns the Cors Configuration for the ingress rule
|
||||
// +optional
|
||||
CorsConfig cors.Config `json:"corsConfig,omitempty"`
|
||||
// ExternalAuth indicates the access to this location requires
|
||||
// authentication using an external provider
|
||||
// +optional
|
||||
ExternalAuth authreq.Config `json:"externalAuth,omitempty"`
|
||||
// EnableGlobalAuth indicates if the access to this location requires
|
||||
// authentication using an external provider defined in controller's config
|
||||
EnableGlobalAuth bool `json:"enableGlobalAuth"`
|
||||
// HTTP2PushPreload allows to configure the HTTP2 Push Preload from backend
|
||||
// original location.
|
||||
// +optional
|
||||
HTTP2PushPreload bool `json:"http2PushPreload,omitempty"`
|
||||
// RateLimit describes a limit in the number of connections per IP
|
||||
// address or connections per second.
|
||||
// The Redirect annotation precedes RateLimit
|
||||
// +optional
|
||||
RateLimit ratelimit.Config `json:"rateLimit,omitempty"`
|
||||
// GlobalRateLimit similar to RateLimit
|
||||
// but this is applied globally across multiple replicas.
|
||||
// +optional
|
||||
GlobalRateLimit globalratelimit.Config `json:"globalRateLimit,omitempty"`
|
||||
// Redirect describes a temporal o permanent redirection this location.
|
||||
// +optional
|
||||
Redirect redirect.Config `json:"redirect,omitempty"`
|
||||
// Rewrite describes the redirection this location.
|
||||
// +optional
|
||||
Rewrite rewrite.Config `json:"rewrite,omitempty"`
|
||||
// Whitelist indicates only connections from certain client
|
||||
// addresses or networks are allowed.
|
||||
// +optional
|
||||
Whitelist ipwhitelist.SourceRange `json:"whitelist,omitempty"`
|
||||
// Proxy contains information about timeouts and buffer sizes
|
||||
// to be used in connections against endpoints
|
||||
// +optional
|
||||
Proxy proxy.Config `json:"proxy,omitempty"`
|
||||
// ProxySSL contains information about SSL configuration parameters
|
||||
// to be used in connections against endpoints
|
||||
// +optional
|
||||
ProxySSL proxyssl.Config `json:"proxySSL,omitempty"`
|
||||
// UsePortInRedirects indicates if redirects must specify the port
|
||||
// +optional
|
||||
UsePortInRedirects bool `json:"usePortInRedirects"`
|
||||
// ConfigurationSnippet contains additional configuration for the backend
|
||||
// to be considered in the configuration of the location
|
||||
ConfigurationSnippet string `json:"configurationSnippet"`
|
||||
// Connection contains connection header to override the default Connection header
|
||||
// to the request.
|
||||
// +optional
|
||||
Connection connection.Config `json:"connection"`
|
||||
// ClientBodyBufferSize allows for the configuration of the client body
|
||||
// buffer size for a specific location.
|
||||
// +optional
|
||||
ClientBodyBufferSize string `json:"clientBodyBufferSize,omitempty"`
|
||||
// DefaultBackend allows the use of a custom default backend for this location.
|
||||
// +optional
|
||||
DefaultBackend *apiv1.Service `json:"-"`
|
||||
// DefaultBackendUpstreamName is the upstream-formatted string for the name of
|
||||
// this location's custom default backend
|
||||
DefaultBackendUpstreamName string `json:"defaultBackendUpstreamName,omitempty"`
|
||||
// XForwardedPrefix allows to add a header X-Forwarded-Prefix to the request with the
|
||||
// original location.
|
||||
// +optional
|
||||
XForwardedPrefix string `json:"xForwardedPrefix,omitempty"`
|
||||
// Logs allows to enable or disable the nginx logs
|
||||
// By default access logs are enabled and rewrite logs are disabled
|
||||
Logs log.Config `json:"logs,omitempty"`
|
||||
// InfluxDB allows to monitor the incoming request by sending them to an influxdb database
|
||||
// +optional
|
||||
InfluxDB influxdb.Config `json:"influxDB,omitempty"`
|
||||
// BackendProtocol indicates which protocol should be used to communicate with the service
|
||||
// By default this is HTTP
|
||||
BackendProtocol string `json:"backend-protocol"`
|
||||
// FastCGI allows the ingress to act as a FastCGI client for a given location.
|
||||
// +optional
|
||||
FastCGI fastcgi.Config `json:"fastcgi,omitempty"`
|
||||
// CustomHTTPErrors specifies the error codes that should be intercepted.
|
||||
// +optional
|
||||
CustomHTTPErrors []int `json:"custom-http-errors"`
|
||||
// ModSecurity allows to enable and configure modsecurity
|
||||
// +optional
|
||||
ModSecurity modsecurity.Config `json:"modsecurity"`
|
||||
// Satisfy dictates allow access if any or all is set
|
||||
Satisfy string `json:"satisfy"`
|
||||
// Mirror allows you to mirror traffic to a "test" backend
|
||||
// +optional
|
||||
Mirror mirror.Config `json:"mirror,omitempty"`
|
||||
// Opentracing allows the global opentracing setting to be overridden for a location
|
||||
// +optional
|
||||
Opentracing opentracing.Config `json:"opentracing"`
|
||||
}
|
||||
|
||||
// SSLPassthroughBackend describes a SSL upstream server configured
|
||||
// as passthrough (no TLS termination in the ingress controller)
|
||||
// The endpoints must provide the TLS termination exposing the required SSL certificate.
|
||||
// The ingress controller only pipes the underlying TCP connection
|
||||
type SSLPassthroughBackend struct {
|
||||
Service *apiv1.Service `json:"-"`
|
||||
Port intstr.IntOrString `json:"port"`
|
||||
// Backend describes the endpoints to use.
|
||||
Backend string `json:"namespace,omitempty"`
|
||||
// Hostname returns the FQDN of the server
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
// L4Service describes a L4 Ingress service.
|
||||
type L4Service struct {
|
||||
// Port external port to expose
|
||||
Port int `json:"port"`
|
||||
// Backend of the service
|
||||
Backend L4Backend `json:"backend"`
|
||||
// Endpoints active endpoints of the service
|
||||
Endpoints []Endpoint `json:"endpoints,omitempty"`
|
||||
// k8s Service
|
||||
Service *apiv1.Service `json:"-"`
|
||||
}
|
||||
|
||||
// L4Backend describes the kubernetes service behind L4 Ingress service
|
||||
type L4Backend struct {
|
||||
Port intstr.IntOrString `json:"port"`
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Protocol apiv1.Protocol `json:"protocol"`
|
||||
// +optional
|
||||
ProxyProtocol ProxyProtocol `json:"proxyProtocol"`
|
||||
}
|
||||
|
||||
// ProxyProtocol describes the proxy protocol configuration
|
||||
type ProxyProtocol struct {
|
||||
Decode bool `json:"decode"`
|
||||
Encode bool `json:"encode"`
|
||||
}
|
||||
|
||||
// Ingress holds the definition of an Ingress plus its annotations
|
||||
type Ingress struct {
|
||||
networking.Ingress `json:"-"`
|
||||
ParsedAnnotations *annotations.Ingress `json:"parsedAnnotations"`
|
||||
}
|
||||
|
||||
// GeneralConfig holds the definition of lua general configuration data
|
||||
type GeneralConfig struct {
|
||||
}
|
||||
656
pkg/apis/ingress/types_equals.go
Normal file
656
pkg/apis/ingress/types_equals.go
Normal file
|
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
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 (
|
||||
"k8s.io/ingress-nginx/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Equal tests for equality between two Configuration types
|
||||
func (c1 *Configuration) Equal(c2 *Configuration) bool {
|
||||
if c1 == c2 {
|
||||
return true
|
||||
}
|
||||
if c1 == nil || c2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if !c1.DefaultSSLCertificate.Equal(c2.DefaultSSLCertificate) {
|
||||
return false
|
||||
}
|
||||
|
||||
match := compareBackends(c1.Backends, c2.Backends)
|
||||
if !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(c1.Servers) != len(c2.Servers) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Servers are sorted
|
||||
for idx, c1s := range c1.Servers {
|
||||
if !c1s.Equal(c2.Servers[idx]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
match = compareL4Service(c1.TCPEndpoints, c2.TCPEndpoints)
|
||||
if !match {
|
||||
return false
|
||||
}
|
||||
|
||||
match = compareL4Service(c1.UDPEndpoints, c2.UDPEndpoints)
|
||||
if !match {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if c1.BackendConfigChecksum != c2.BackendConfigChecksum {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Backend types
|
||||
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.NoServer != b2.NoServer {
|
||||
return false
|
||||
}
|
||||
|
||||
if b1.Service != b2.Service {
|
||||
if b1.Service == nil || b2.Service == nil {
|
||||
return false
|
||||
}
|
||||
if b1.Service.GetNamespace() != b2.Service.GetNamespace() {
|
||||
return false
|
||||
}
|
||||
if b1.Service.GetName() != b2.Service.GetName() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if b1.Port != b2.Port {
|
||||
return false
|
||||
}
|
||||
if b1.SSLPassthrough != b2.SSLPassthrough {
|
||||
return false
|
||||
}
|
||||
if !(&b1.SessionAffinity).Equal(&b2.SessionAffinity) {
|
||||
return false
|
||||
}
|
||||
if b1.UpstreamHashBy != b2.UpstreamHashBy {
|
||||
return false
|
||||
}
|
||||
if b1.LoadBalancing != b2.LoadBalancing {
|
||||
return false
|
||||
}
|
||||
|
||||
match := compareEndpoints(b1.Endpoints, b2.Endpoints)
|
||||
if !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if !b1.TrafficShapingPolicy.Equal(b2.TrafficShapingPolicy) {
|
||||
return false
|
||||
}
|
||||
|
||||
return sets.StringElementsMatch(b1.AlternativeBackends, b2.AlternativeBackends)
|
||||
}
|
||||
|
||||
// Equal tests for equality between two SessionAffinityConfig types
|
||||
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.AffinityMode != sac2.AffinityMode {
|
||||
return false
|
||||
}
|
||||
if !(&sac1.CookieSessionAffinity).Equal(&sac2.CookieSessionAffinity) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two CookieSessionAffinity types
|
||||
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.Path != csa2.Path {
|
||||
return false
|
||||
}
|
||||
if csa1.Expires != csa2.Expires {
|
||||
return false
|
||||
}
|
||||
if csa1.MaxAge != csa2.MaxAge {
|
||||
return false
|
||||
}
|
||||
if csa1.SameSite != csa2.SameSite {
|
||||
return false
|
||||
}
|
||||
if csa1.Secure != csa2.Secure {
|
||||
return false
|
||||
}
|
||||
if csa1.ConditionalSameSiteNone != csa2.ConditionalSameSiteNone {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//Equal checks the equality between UpstreamByConfig types
|
||||
func (u1 *UpstreamHashByConfig) Equal(u2 *UpstreamHashByConfig) bool {
|
||||
if u1 == u2 {
|
||||
return true
|
||||
}
|
||||
if u1 == nil || u2 == nil {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBy != u2.UpstreamHashBy {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBySubset != u2.UpstreamHashBySubset {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBySubsetSize != u2.UpstreamHashBySubsetSize {
|
||||
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.Target != e2.Target {
|
||||
if e1.Target == nil || e2.Target == nil {
|
||||
return false
|
||||
}
|
||||
if e1.Target.UID != e2.Target.UID {
|
||||
return false
|
||||
}
|
||||
if e1.Target.ResourceVersion != e2.Target.ResourceVersion {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal checks for equality between two TrafficShapingPolicies
|
||||
func (tsp1 TrafficShapingPolicy) Equal(tsp2 TrafficShapingPolicy) bool {
|
||||
if tsp1.Weight != tsp2.Weight {
|
||||
return false
|
||||
}
|
||||
if tsp1.Header != tsp2.Header {
|
||||
return false
|
||||
}
|
||||
if tsp1.HeaderValue != tsp2.HeaderValue {
|
||||
return false
|
||||
}
|
||||
if tsp1.HeaderPattern != tsp2.HeaderPattern {
|
||||
return false
|
||||
}
|
||||
if tsp1.Cookie != tsp2.Cookie {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Server types
|
||||
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.SSLCert.Equal(s2.SSLCert) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(s1.Aliases) != len(s2.Aliases) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, a1 := range s1.Aliases {
|
||||
found := false
|
||||
for _, a2 := range s2.Aliases {
|
||||
if a1 == a2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if s1.RedirectFromToWWW != s2.RedirectFromToWWW {
|
||||
return false
|
||||
}
|
||||
if !(&s1.CertificateAuth).Equal(&s2.CertificateAuth) {
|
||||
return false
|
||||
}
|
||||
if s1.ServerSnippet != s2.ServerSnippet {
|
||||
return false
|
||||
}
|
||||
if s1.SSLCiphers != s2.SSLCiphers {
|
||||
return false
|
||||
}
|
||||
if s1.SSLPreferServerCiphers != s2.SSLPreferServerCiphers {
|
||||
return false
|
||||
}
|
||||
if s1.AuthTLSError != s2.AuthTLSError {
|
||||
return false
|
||||
}
|
||||
if !(&s1.ProxySSL).Equal(&s2.ProxySSL) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(s1.Locations) != len(s2.Locations) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Location are sorted
|
||||
for idx, s1l := range s1.Locations {
|
||||
if !s1l.Equal(s2.Locations[idx]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two Location types
|
||||
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 != l2.Service {
|
||||
if l1.Service == nil || l2.Service == nil {
|
||||
return false
|
||||
}
|
||||
if l1.Service.GetNamespace() != l2.Service.GetNamespace() {
|
||||
return false
|
||||
}
|
||||
if l1.Service.GetName() != l2.Service.GetName() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if l1.Port.String() != l2.Port.String() {
|
||||
return false
|
||||
}
|
||||
if !(&l1.BasicDigestAuth).Equal(&l2.BasicDigestAuth) {
|
||||
return false
|
||||
}
|
||||
if l1.Denied != l2.Denied {
|
||||
return false
|
||||
}
|
||||
if !(&l1.CorsConfig).Equal(&l2.CorsConfig) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.ExternalAuth).Equal(&l2.ExternalAuth) {
|
||||
return false
|
||||
}
|
||||
if l1.EnableGlobalAuth != l2.EnableGlobalAuth {
|
||||
return false
|
||||
}
|
||||
if l1.HTTP2PushPreload != l2.HTTP2PushPreload {
|
||||
return false
|
||||
}
|
||||
if !(&l1.RateLimit).Equal(&l2.RateLimit) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.GlobalRateLimit).Equal(&l2.GlobalRateLimit) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Redirect).Equal(&l2.Redirect) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Rewrite).Equal(&l2.Rewrite) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Whitelist).Equal(&l2.Whitelist) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Proxy).Equal(&l2.Proxy) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.ProxySSL).Equal(&l2.ProxySSL) {
|
||||
return false
|
||||
}
|
||||
if l1.UsePortInRedirects != l2.UsePortInRedirects {
|
||||
return false
|
||||
}
|
||||
if l1.ConfigurationSnippet != l2.ConfigurationSnippet {
|
||||
return false
|
||||
}
|
||||
if l1.ClientBodyBufferSize != l2.ClientBodyBufferSize {
|
||||
return false
|
||||
}
|
||||
if l1.UpstreamVhost != l2.UpstreamVhost {
|
||||
return false
|
||||
}
|
||||
if l1.XForwardedPrefix != l2.XForwardedPrefix {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Connection).Equal(&l2.Connection) {
|
||||
return false
|
||||
}
|
||||
if !(&l1.Logs).Equal(&l2.Logs) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !(&l1.InfluxDB).Equal(&l2.InfluxDB) {
|
||||
return false
|
||||
}
|
||||
|
||||
if l1.BackendProtocol != l2.BackendProtocol {
|
||||
return false
|
||||
}
|
||||
|
||||
if !(&l1.FastCGI).Equal(&l2.FastCGI) {
|
||||
return false
|
||||
}
|
||||
|
||||
match := compareInts(l1.CustomHTTPErrors, l2.CustomHTTPErrors)
|
||||
if !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if !(&l1.ModSecurity).Equal(&l2.ModSecurity) {
|
||||
return false
|
||||
}
|
||||
|
||||
if l1.Satisfy != l2.Satisfy {
|
||||
return false
|
||||
}
|
||||
|
||||
if l1.DefaultBackendUpstreamName != l2.DefaultBackendUpstreamName {
|
||||
return false
|
||||
}
|
||||
|
||||
if !l1.Opentracing.Equal(&l2.Opentracing) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !l1.Mirror.Equal(&l2.Mirror) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two SSLPassthroughBackend types
|
||||
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 != ptb2.Service {
|
||||
if ptb1.Service == nil || ptb2.Service == nil {
|
||||
return false
|
||||
}
|
||||
if ptb1.Service.GetNamespace() != ptb2.Service.GetNamespace() {
|
||||
return false
|
||||
}
|
||||
if ptb1.Service.GetName() != ptb2.Service.GetName() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two L4Service types
|
||||
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
|
||||
}
|
||||
|
||||
return compareEndpoints(e1.Endpoints, e2.Endpoints)
|
||||
}
|
||||
|
||||
// Equal tests for equality between two L4Backend types
|
||||
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
|
||||
}
|
||||
if l4b1.ProxyProtocol != l4b2.ProxyProtocol {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal tests for equality between two SSLCert types
|
||||
func (s1 *SSLCert) Equal(s2 *SSLCert) bool {
|
||||
if s1 == s2 {
|
||||
return true
|
||||
}
|
||||
if s1 == nil || s2 == nil {
|
||||
return false
|
||||
}
|
||||
if s1.CASHA != s2.CASHA {
|
||||
return false
|
||||
}
|
||||
if s1.CRLSHA != s2.CRLSHA {
|
||||
return false
|
||||
}
|
||||
if s1.PemSHA != s2.PemSHA {
|
||||
return false
|
||||
}
|
||||
if s1.CAFileName != s2.CAFileName {
|
||||
return false
|
||||
}
|
||||
if s1.CRLFileName != s2.CRLFileName {
|
||||
return false
|
||||
}
|
||||
if !s1.ExpireTime.Equal(s2.ExpireTime) {
|
||||
return false
|
||||
}
|
||||
if s1.PemCertKey != s2.PemCertKey {
|
||||
return false
|
||||
}
|
||||
if s1.UID != s2.UID {
|
||||
return false
|
||||
}
|
||||
|
||||
return sets.StringElementsMatch(s1.CN, s2.CN)
|
||||
}
|
||||
|
||||
var compareEndpointsFunc = func(e1, e2 interface{}) bool {
|
||||
ep1, ok := e1.(Endpoint)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
ep2, ok := e2.(Endpoint)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return (&ep1).Equal(&ep2)
|
||||
}
|
||||
|
||||
func compareEndpoints(a, b []Endpoint) bool {
|
||||
return sets.Compare(a, b, compareEndpointsFunc)
|
||||
}
|
||||
|
||||
var compareBackendsFunc = func(e1, e2 interface{}) bool {
|
||||
b1, ok := e1.(*Backend)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
b2, ok := e2.(*Backend)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return b1.Equal(b2)
|
||||
}
|
||||
|
||||
func compareBackends(a, b []*Backend) bool {
|
||||
return sets.Compare(a, b, compareBackendsFunc)
|
||||
}
|
||||
|
||||
var compareIntsFunc = func(e1, e2 interface{}) bool {
|
||||
b1, ok := e1.(int)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
b2, ok := e2.(int)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return b1 == b2
|
||||
}
|
||||
|
||||
func compareInts(a, b []int) bool {
|
||||
return sets.Compare(a, b, compareIntsFunc)
|
||||
}
|
||||
|
||||
var compareL4ServiceFunc = func(e1, e2 interface{}) bool {
|
||||
b1, ok := e1.(L4Service)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
b2, ok := e2.(L4Service)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return (&b1).Equal(&b2)
|
||||
}
|
||||
|
||||
func compareL4Service(a, b []L4Service) bool {
|
||||
return sets.Compare(a, b, compareL4ServiceFunc)
|
||||
}
|
||||
295
pkg/apis/ingress/types_equals_test.go
Normal file
295
pkg/apis/ingress/types_equals_test.go
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
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"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestEqualConfiguration(t *testing.T) {
|
||||
ap, _ := filepath.Abs("../../../test/manifests/configuration-a.json")
|
||||
a, err := readJSON(ap)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error reading JSON file: %v", err)
|
||||
}
|
||||
|
||||
bp, _ := filepath.Abs("../../../test/manifests/configuration-b.json")
|
||||
b, err := readJSON(bp)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error reading JSON file: %v", err)
|
||||
}
|
||||
|
||||
cp, _ := filepath.Abs("../../../test/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-b.json and configuration-a.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
|
||||
}
|
||||
|
||||
func TestL4ServiceElementsMatch(t *testing.T) {
|
||||
testCases := []struct {
|
||||
listA []L4Service
|
||||
listB []L4Service
|
||||
expected bool
|
||||
}{
|
||||
{nil, nil, true},
|
||||
{[]L4Service{{Port: 80}}, nil, false},
|
||||
{[]L4Service{{Port: 80}}, []L4Service{{Port: 80}}, true},
|
||||
{
|
||||
[]L4Service{
|
||||
{Port: 80, Endpoints: []Endpoint{{Address: "1.1.1.1"}}}},
|
||||
[]L4Service{{Port: 80}},
|
||||
false,
|
||||
},
|
||||
{
|
||||
[]L4Service{
|
||||
{Port: 80, Endpoints: []Endpoint{{Address: "1.1.1.1"}, {Address: "1.1.1.2"}}}},
|
||||
[]L4Service{
|
||||
{Port: 80, Endpoints: []Endpoint{{Address: "1.1.1.2"}, {Address: "1.1.1.1"}}}},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]L4Service{
|
||||
{Port: 80, Backend: L4Backend{Name: "test", Namespace: "default", Protocol: "TCP", ProxyProtocol: ProxyProtocol{Decode: false, Encode: false}}},
|
||||
},
|
||||
[]L4Service{
|
||||
{Port: 80, Backend: L4Backend{Name: "test", Namespace: "default", Protocol: "TCP", ProxyProtocol: ProxyProtocol{Decode: false, Encode: false}}},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]L4Service{
|
||||
{Port: 80, Backend: L4Backend{Name: "test", Namespace: "default", Protocol: "TCP", ProxyProtocol: ProxyProtocol{Decode: false, Encode: false}}},
|
||||
},
|
||||
[]L4Service{
|
||||
{Port: 80, Backend: L4Backend{Name: "test", Namespace: "default", Protocol: "TCP", ProxyProtocol: ProxyProtocol{Decode: false, Encode: true}}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
result := compareL4Service(testCase.listA, testCase.listB)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v (%v - %v)", testCase.expected, result, testCase.listA, testCase.listB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntElementsMatch(t *testing.T) {
|
||||
testCases := []struct {
|
||||
listA []int
|
||||
listB []int
|
||||
expected bool
|
||||
}{
|
||||
{nil, nil, true},
|
||||
{[]int{}, nil, false},
|
||||
{[]int{}, []int{1}, false},
|
||||
{[]int{1}, []int{1}, true},
|
||||
{[]int{1, 2, 3}, []int{3, 2, 1}, true},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
result := compareInts(testCase.listA, testCase.listB)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v (%v - %v)", testCase.expected, result, testCase.listA, testCase.listB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSLCertMatch(t *testing.T) {
|
||||
now := time.Now()
|
||||
cert := &SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
sslCertA *SSLCert
|
||||
sslCertB *SSLCert
|
||||
expected bool
|
||||
}{
|
||||
{cert, cert, true},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_New",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_NEW",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_New",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameNew"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now.Add(time.Minute),
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "1",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyNew",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
cert,
|
||||
&SSLCert{
|
||||
UID: "2",
|
||||
Name: "nameA",
|
||||
Namespace: "namespaceA",
|
||||
CASHA: "CASHA_A",
|
||||
CN: []string{"CommonNameA"},
|
||||
CRLSHA: "CRLSHA_A",
|
||||
PemSHA: "PemSHA_A",
|
||||
PemCertKey: "PemKeyA",
|
||||
ExpireTime: now,
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
result := testCase.sslCertA.Equal(testCase.sslCertB)
|
||||
if result != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v (%v - %v)", testCase.expected, result, testCase.sslCertA, testCase.sslCertB)
|
||||
}
|
||||
}
|
||||
}
|
||||
148
pkg/apis/ingress/zz_generated.deepcopy.go
Normal file
148
pkg/apis/ingress/zz_generated.deepcopy.go
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2021 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package ingress
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Backend) DeepCopyInto(out *Backend) {
|
||||
*out = *in
|
||||
if in.Service != nil {
|
||||
in, out := &in.Service, &out.Service
|
||||
*out = new(v1.Service)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.Port = in.Port
|
||||
if in.Endpoints != nil {
|
||||
in, out := &in.Endpoints, &out.Endpoints
|
||||
*out = make([]Endpoint, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.SessionAffinity.DeepCopyInto(&out.SessionAffinity)
|
||||
out.UpstreamHashBy = in.UpstreamHashBy
|
||||
out.TrafficShapingPolicy = in.TrafficShapingPolicy
|
||||
if in.AlternativeBackends != nil {
|
||||
in, out := &in.AlternativeBackends, &out.AlternativeBackends
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backend.
|
||||
func (in *Backend) DeepCopy() *Backend {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Backend)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CookieSessionAffinity) DeepCopyInto(out *CookieSessionAffinity) {
|
||||
*out = *in
|
||||
if in.Locations != nil {
|
||||
in, out := &in.Locations, &out.Locations
|
||||
*out = make(map[string][]string, len(*in))
|
||||
for key, val := range *in {
|
||||
var outVal []string
|
||||
if val == nil {
|
||||
(*out)[key] = nil
|
||||
} else {
|
||||
in, out := &val, &outVal
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
(*out)[key] = outVal
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CookieSessionAffinity.
|
||||
func (in *CookieSessionAffinity) DeepCopy() *CookieSessionAffinity {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CookieSessionAffinity)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Endpoint) DeepCopyInto(out *Endpoint) {
|
||||
*out = *in
|
||||
if in.Target != nil {
|
||||
in, out := &in.Target, &out.Target
|
||||
*out = new(v1.ObjectReference)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint.
|
||||
func (in *Endpoint) DeepCopy() *Endpoint {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Endpoint)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SessionAffinityConfig) DeepCopyInto(out *SessionAffinityConfig) {
|
||||
*out = *in
|
||||
in.CookieSessionAffinity.DeepCopyInto(&out.CookieSessionAffinity)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionAffinityConfig.
|
||||
func (in *SessionAffinityConfig) DeepCopy() *SessionAffinityConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SessionAffinityConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TrafficShapingPolicy) DeepCopyInto(out *TrafficShapingPolicy) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficShapingPolicy.
|
||||
func (in *TrafficShapingPolicy) DeepCopy() *TrafficShapingPolicy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TrafficShapingPolicy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue