Remove interface

This commit is contained in:
Manuel de Brito Fontes 2016-11-11 20:43:35 -03:00
parent ed9a416b01
commit f2b627486d
13 changed files with 72 additions and 872 deletions

View file

@ -31,8 +31,8 @@ import (
ssl "k8s.io/ingress/core/pkg/net/ssl"
)
// syncSecret keeps in sync Secrets used by Ingress rules with files to allow
// being used in controllers.
// syncSecret keeps in sync Secrets used by Ingress rules with the files on
// disk to allow being used in controllers.
func (ic *GenericController) syncSecret(k interface{}) error {
if ic.secretQueue.IsShuttingDown() {
return nil
@ -67,7 +67,6 @@ func (ic *GenericController) syncSecret(k interface{}) error {
key = k.(string)
// get secret
secObj, exists, err := ic.secrLister.Store.GetByKey(key)
if err != nil {
return fmt.Errorf("error getting secret %v: %v", key, err)
@ -128,7 +127,7 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC
return s, nil
}
// check if secret is referenced in this controller's config
// secrReferenced checks if a secret is referenced or not by one or more Ingress rules
func (ic *GenericController) secrReferenced(name, namespace string) bool {
for _, ingIf := range ic.ingLister.Store.List() {
ing := ingIf.(*extensions.Ingress)
@ -136,7 +135,6 @@ func (ic *GenericController) secrReferenced(name, namespace string) bool {
if err == nil && str == fmt.Sprintf("%v/%v", namespace, name) {
return true
}
if ing.Namespace != namespace {
continue
}
@ -149,7 +147,7 @@ func (ic *GenericController) secrReferenced(name, namespace string) bool {
return false
}
// sslCertTracker ...
// sslCertTracker holds a store of referenced Secrets in Ingress rules
type sslCertTracker struct {
cache.ThreadSafeStore
}

View file

@ -76,17 +76,7 @@ var (
reservedPorts = []string{"80", "443", "8181", "18080"}
)
// Interface holds the methods to handle an Ingress backend
type Interface interface {
Start()
Stop() error
Info() string
healthz.HealthzChecker
}
// GenericController watches the kubernetes api and adds/removes services from the loadbalancer
// GenericController holds the boilerplate code required to build an Ingress controlller.
type GenericController struct {
healthz.HealthzChecker
@ -143,12 +133,13 @@ type Configuration struct {
DefaultHealthzURL string
// optional
PublishService string
// Backend is the particular implementation to be used.
// (for instance NGINX)
Backend ingress.Controller
}
// newIngressController creates an Ingress controller
func newIngressController(config *Configuration) Interface {
func newIngressController(config *Configuration) *GenericController {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof)
@ -280,7 +271,7 @@ func newIngressController(config *Configuration) Interface {
IngressLister: ic.ingLister,
})
return ic
return &ic
}
func (ic *GenericController) controllersInSync() bool {
@ -365,8 +356,8 @@ func (ic *GenericController) sync(key interface{}) error {
}
}
upstreams, servers := ic.getUpstreamServers()
var passUpstreams []*ingress.SSLPassthroughUpstreams
upstreams, servers := ic.getBackendServers()
var passUpstreams []*ingress.SSLPassthroughBackend
for _, server := range servers {
if !server.SSLPassthrough {
continue
@ -376,8 +367,8 @@ func (ic *GenericController) sync(key interface{}) error {
if loc.Path != rootLocation {
continue
}
passUpstreams = append(passUpstreams, &ingress.SSLPassthroughUpstreams{
Upstream: loc.Upstream,
passUpstreams = append(passUpstreams, &ingress.SSLPassthroughBackend{
Upstream: loc.Backend,
Host: server.Name,
})
break
@ -388,8 +379,8 @@ func (ic *GenericController) sync(key interface{}) error {
HealthzURL: ic.cfg.DefaultHealthzURL,
Upstreams: upstreams,
Servers: servers,
TCPUpstreams: ic.getTCPServices(),
UDPUpstreams: ic.getUDPServices(),
TCPEndpoints: ic.getTCPServices(),
UPDEndpoints: ic.getUDPServices(),
PassthroughUpstreams: passUpstreams,
})
if err != nil {
@ -497,7 +488,7 @@ func (ic *GenericController) getStreamServices(data map[string]string, proto api
svc := svcObj.(*api.Service)
var endps []ingress.UpstreamServer
var endps []ingress.Endpoint
targetPort, err := strconv.Atoi(svcPort)
if err != nil {
for _, sp := range svc.Spec.Ports {
@ -516,7 +507,7 @@ func (ic *GenericController) getStreamServices(data map[string]string, proto api
}
}
sort.Sort(ingress.UpstreamServerByAddrPort(endps))
sort.Sort(ingress.EndpointByAddrPort(endps))
// tcp upstreams cannot contain empty upstreams and there is no
// default backend equivalent for TCP
@ -527,9 +518,9 @@ func (ic *GenericController) getStreamServices(data map[string]string, proto api
svcs = append(svcs, &ingress.Location{
Path: k,
Upstream: ingress.Upstream{
Upstream: ingress.Backend{
Name: fmt.Sprintf("%v-%v-%v", svcNs, svcName, port),
Backends: endps,
Endpoints: endps,
},
})
}
@ -540,21 +531,21 @@ func (ic *GenericController) getStreamServices(data map[string]string, proto api
// getDefaultUpstream returns an upstream associated with the
// default backend service. In case of error retrieving information
// configure the upstream to return http code 503.
func (ic *GenericController) getDefaultUpstream() *ingress.Upstream {
upstream := &ingress.Upstream{
func (ic *GenericController) getDefaultUpstream() *ingress.Backend {
upstream := &ingress.Backend{
Name: defUpstreamName,
}
svcKey := ic.cfg.DefaultService
svcObj, svcExists, err := ic.svcLister.Indexer.GetByKey(svcKey)
if err != nil {
glog.Warningf("unexpected error searching the default backend %v: %v", ic.cfg.DefaultService, err)
upstream.Backends = append(upstream.Backends, newDefaultServer())
upstream.Endpoints = append(upstream.Endpoints, newDefaultServer())
return upstream
}
if !svcExists {
glog.Warningf("service %v does not exists", svcKey)
upstream.Backends = append(upstream.Backends, newDefaultServer())
upstream.Endpoints = append(upstream.Endpoints, newDefaultServer())
return upstream
}
@ -562,10 +553,10 @@ func (ic *GenericController) getDefaultUpstream() *ingress.Upstream {
endps := ic.getEndpoints(svc, svc.Spec.Ports[0].TargetPort, api.ProtocolTCP, &healthcheck.Upstream{})
if len(endps) == 0 {
glog.Warningf("service %v does not have any active endpoints", svcKey)
endps = []ingress.UpstreamServer{newDefaultServer()}
endps = []ingress.Endpoint{newDefaultServer()}
}
upstream.Backends = append(upstream.Backends, endps...)
upstream.Endpoints = append(upstream.Endpoints, endps...)
return upstream
}
@ -579,9 +570,9 @@ func (c ingressByRevision) Less(i, j int) bool {
return ir < jr
}
// getUpstreamServers returns a list of Upstream and Server to be used by the backend
// getBackendServers returns a list of Upstream and Server to be used by the backend
// An upstream can be used in multiple servers if the namespace, service name and port are the same
func (ic *GenericController) getUpstreamServers() ([]*ingress.Upstream, []*ingress.Server) {
func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress.Server) {
ings := ic.ingLister.Store.List()
sort.Sort(ingressByRevision(ings))
@ -699,19 +690,19 @@ func (ic *GenericController) getUpstreamServers() ([]*ingress.Upstream, []*ingre
addLoc = false
if !loc.IsDefBackend {
glog.V(3).Infof("avoiding replacement of ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Upstream.Name)
glog.V(3).Infof("avoiding replacement of ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Backend.Name)
break
}
glog.V(3).Infof("replacing ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Upstream.Name)
loc.Upstream = *ups
glog.V(3).Infof("replacing ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Backend.Name)
loc.Backend = *ups
loc.IsDefBackend = false
loc.BasicDigestAuth = *nginxAuth
loc.RateLimit = *rl
loc.Redirect = *locRew
loc.SecureUpstream = secUpstream
loc.Whitelist = *wl
loc.Upstream = *ups
loc.Backend = *ups
loc.EnableCORS = eCORS
loc.ExternalAuth = ra
loc.Proxy = *prx
@ -744,16 +735,16 @@ func (ic *GenericController) getUpstreamServers() ([]*ingress.Upstream, []*ingre
// 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.Upstream, 0, len(upstreams))
aUpstreams := make([]*ingress.Backend, 0, len(upstreams))
for _, value := range upstreams {
if len(value.Backends) == 0 {
if len(value.Endpoints) == 0 {
glog.V(3).Infof("upstream %v does not have any active endpoints. Using default backend", value.Name)
value.Backends = append(value.Backends, newDefaultServer())
value.Endpoints = append(value.Endpoints, newDefaultServer())
}
sort.Sort(ingress.UpstreamServerByAddrPort(value.Backends))
sort.Sort(ingress.EndpointByAddrPort(value.Endpoints))
aUpstreams = append(aUpstreams, value)
}
sort.Sort(ingress.UpstreamByNameServers(aUpstreams))
sort.Sort(ingress.BackendByNameServers(aUpstreams))
aServers := make([]*ingress.Server, 0, len(servers))
for _, value := range servers {
@ -781,8 +772,8 @@ func (ic *GenericController) getAuthCertificate(secretName string) (*authtls.SSL
// createUpstreams creates the NGINX upstreams for each service referenced in
// Ingress rules. The servers inside the upstream are endpoints.
func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ingress.Upstream {
upstreams := make(map[string]*ingress.Upstream)
func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ingress.Backend {
upstreams := make(map[string]*ingress.Backend)
upstreams[defUpstreamName] = ic.getDefaultUpstream()
upsDefaults := ic.cfg.Backend.UpstreamDefaults()
@ -803,7 +794,7 @@ func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ing
svcKey := fmt.Sprintf("%v/%v", ing.GetNamespace(), ing.Spec.Backend.ServiceName)
endps, err := ic.serviceEndpoints(svcKey, ing.Spec.Backend.ServicePort.String(), hz)
upstreams[defBackend].Backends = append(upstreams[defBackend].Backends, endps...)
upstreams[defBackend].Endpoints = append(upstreams[defBackend].Endpoints, endps...)
if err != nil {
glog.Warningf("error creating upstream %v: %v", defBackend, err)
}
@ -833,7 +824,7 @@ func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ing
glog.Warningf("error obtaining service endpoints: %v", err)
continue
}
upstreams[name].Backends = endp
upstreams[name].Endpoints = endp
}
}
}
@ -844,10 +835,10 @@ func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ing
// serviceEndpoints returns the upstream servers (endpoints) associated
// to a service.
func (ic *GenericController) serviceEndpoints(svcKey, backendPort string,
hz *healthcheck.Upstream) ([]ingress.UpstreamServer, error) {
hz *healthcheck.Upstream) ([]ingress.Endpoint, error) {
svcObj, svcExists, err := ic.svcLister.Indexer.GetByKey(svcKey)
var upstreams []ingress.UpstreamServer
var upstreams []ingress.Endpoint
if err != nil {
return upstreams, fmt.Errorf("error getting service %v from the cache: %v", svcKey, err)
}
@ -878,7 +869,7 @@ func (ic *GenericController) serviceEndpoints(svcKey, backendPort string,
return upstreams, nil
}
func (ic *GenericController) createServers(data []interface{}, upstreams map[string]*ingress.Upstream) map[string]*ingress.Server {
func (ic *GenericController) createServers(data []interface{}, upstreams map[string]*ingress.Backend) map[string]*ingress.Server {
servers := make(map[string]*ingress.Server)
ngxProxy := *proxy.ParseAnnotations(ic.cfg.Backend.UpstreamDefaults(), nil)
@ -973,15 +964,15 @@ func (ic *GenericController) getEndpoints(
s *api.Service,
servicePort intstr.IntOrString,
proto api.Protocol,
hz *healthcheck.Upstream) []ingress.UpstreamServer {
hz *healthcheck.Upstream) []ingress.Endpoint {
glog.V(3).Infof("getting endpoints for service %v/%v and port %v", s.Namespace, s.Name, servicePort.String())
ep, err := ic.endpLister.GetServiceEndpoints(s)
if err != nil {
glog.Warningf("unexpected error obtaining service endpoints: %v", err)
return []ingress.UpstreamServer{}
return []ingress.Endpoint{}
}
upsServers := []ingress.UpstreamServer{}
upsServers := []ingress.Endpoint{}
for _, ss := range ep.Subsets {
for _, epPort := range ss.Ports {
@ -1023,7 +1014,7 @@ func (ic *GenericController) getEndpoints(
}
for _, epAddress := range ss.Addresses {
ups := ingress.UpstreamServer{
ups := ingress.Endpoint{
Address: epAddress.IP,
Port: fmt.Sprintf("%v", targetPort),
MaxFails: hz.MaxFails,

View file

@ -23,8 +23,8 @@ import (
kubectl_util "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)
// NewIngressController returns a configured Ingress controller ready to start
func NewIngressController(backend ingress.Controller) Interface {
// NewIngressController returns a configured Ingress controller
func NewIngressController(backend ingress.Controller) *GenericController {
var (
flags = pflag.NewFlagSet("", pflag.ExitOnError)
@ -33,7 +33,7 @@ func NewIngressController(backend ingress.Controller) Interface {
namespace/name. The controller uses the first node port of this Service for
the default backend.`)
ingressClass = flags.String("ingress-class", "nginx",
ingressClass = flags.String("ingress-class", "",
`Name of the ingress class to route through this controller.`)
configMap = flags.String("configmap", "",
@ -49,7 +49,7 @@ func NewIngressController(backend ingress.Controller) Interface {
The key in the map indicates the external port to be used. The value is the name of the
service with the format namespace/serviceName and the port of the service could be a
number of the name of the port.
The ports 80 and 443 are not allowed as external ports. This ports are reserved for nginx`)
The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend`)
udpConfigMapName = flags.String("udp-services-configmap", "",
`Name of the ConfigMap that contains the definition of the UDP services to expose.
@ -152,7 +152,7 @@ func NewIngressController(backend ingress.Controller) Interface {
return ic
}
func registerHandlers(enableProfiling bool, port int, ic Interface) {
func registerHandlers(enableProfiling bool, port int, ic *GenericController) {
mux := http.NewServeMux()
healthz.InstallHandler(mux, ic)

View file

@ -25,16 +25,16 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions"
)
// newDefaultServer return an UpstreamServer to be use as default server that returns 503.
func newDefaultServer() ingress.UpstreamServer {
return ingress.UpstreamServer{Address: "127.0.0.1", Port: "8181"}
// newDefaultServer return an BackendServer to be use as default server that returns 503.
func newDefaultServer() ingress.Endpoint {
return ingress.Endpoint{Address: "127.0.0.1", Port: "8181"}
}
// newUpstream creates an upstream without servers.
func newUpstream(name string) *ingress.Upstream {
return &ingress.Upstream{
func newUpstream(name string) *ingress.Backend {
return &ingress.Backend{
Name: name,
Backends: []ingress.UpstreamServer{},
Endpoints: []ingress.Endpoint{},
}
}

View file

@ -1,214 +0,0 @@
/*
Copyright 2015 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 (
"os/exec"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/ingress/core/pkg/ingress/annotations/auth"
"k8s.io/ingress/core/pkg/ingress/annotations/authreq"
"k8s.io/ingress/core/pkg/ingress/annotations/authtls"
"k8s.io/ingress/core/pkg/ingress/annotations/ipwhitelist"
"k8s.io/ingress/core/pkg/ingress/annotations/proxy"
"k8s.io/ingress/core/pkg/ingress/annotations/ratelimit"
"k8s.io/ingress/core/pkg/ingress/annotations/rewrite"
"k8s.io/ingress/core/pkg/ingress/defaults"
)
var (
// DefaultSSLDirectory defines the location where the SSL certificates will be generated
DefaultSSLDirectory = "/ingress-controller/ssl"
)
// Controller ...
type Controller interface {
// Start returns the command is executed to start the backend.
// The command must run in foreground.
Start()
// Stop stops the backend
Stop() error
// Restart reload the backend with the a configuration file returning
// the combined output of Stdout and Stderr
Restart(data []byte) ([]byte, error)
// Tests returns a commands that checks if the configuration file is valid
// Example: nginx -t -c <file>
Test(file string) *exec.Cmd
// OnUpdate callback invoked from the sync queue https://k8s.io/ingress/core/blob/master/pkg/ingress/controller/controller.go#L355
// when an update occurs. This is executed frequently because Ingress
// controllers watches changes in:
// - Ingresses: main work
// - Secrets: referenced from Ingress rules with TLS configured
// - ConfigMaps: where the controller reads custom configuration
// - Services: referenced from Ingress rules and required to obtain
// information about ports and annotations
// - Endpoints: referenced from Services and what the backend uses
// to route traffic
//
// ConfigMap content of --configmap
// Configuration returns the translation from Ingress rules containing
// information about all the upstreams (service endpoints ) "virtual"
// servers (FQDN)
// and all the locations inside each server. Each location contains
// information about all the annotations were configured
// https://k8s.io/ingress/core/blob/master/pkg/ingress/types.go#L48
OnUpdate(*api.ConfigMap, Configuration) ([]byte, error)
// UpstreamDefaults returns the minimum settings required to configure the
// communication to upstream servers (endpoints)
UpstreamDefaults() defaults.Backend
// IsReloadRequired checks if the backend must be reloaded or not.
// The parameter contains the new rendered template
IsReloadRequired([]byte) bool
// Info returns information about the ingress controller
// This can include build version, repository, etc.
Info() string
}
// Configuration describes
type Configuration struct {
HealthzURL string
Upstreams []*Upstream
Servers []*Server
TCPUpstreams []*Location
UDPUpstreams []*Location
PassthroughUpstreams []*SSLPassthroughUpstreams
}
// Upstream describes an upstream server (endpoint)
type Upstream struct {
// Secure indicates if the communication with the en
Secure bool
// Name represents an unique api.Service name formatted
// as <namespace>-<name>-<port>
Name string
// Backends
Backends []UpstreamServer
}
// SSLPassthroughUpstreams describes an SSL upstream server configured
// as passthrough (no TLS termination)
type SSLPassthroughUpstreams struct {
Upstream
Host string
}
// UpstreamByNameServers sorts upstreams by name
type UpstreamByNameServers []*Upstream
func (c UpstreamByNameServers) Len() int { return len(c) }
func (c UpstreamByNameServers) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c UpstreamByNameServers) Less(i, j int) bool {
return c[i].Name < c[j].Name
}
// UpstreamServer describes a server in an upstream
type UpstreamServer struct {
// Address IP address of the endpoint
Address string
Port string
// MaxFails returns the maximum number of check failures
// allowed before this should be considered dow.
// Setting 0 indicates that the check is performed by a Kubernetes probe
MaxFails int
FailTimeout int
}
// Server describes a virtual server
type Server struct {
Name string
SSL bool
SSLPassthrough bool
SSLCertificate string
//SSLCertificateKey string
SSLPemChecksum string
Locations []*Location
}
// Location describes a server location
type Location struct {
IsDefBackend bool
SecureUpstream bool
EnableCORS bool
Path string
Upstream Upstream
BasicDigestAuth auth.BasicDigest
RateLimit ratelimit.RateLimit
Redirect rewrite.Redirect
Whitelist ipwhitelist.SourceRange
ExternalAuth authreq.External
Proxy proxy.Configuration
CertificateAuth authtls.SSLCert
}
// UpstreamServerByAddrPort sorts upstream servers by address and port
type UpstreamServerByAddrPort []UpstreamServer
func (c UpstreamServerByAddrPort) Len() int { return len(c) }
func (c UpstreamServerByAddrPort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c UpstreamServerByAddrPort) Less(i, j int) bool {
iName := c[i].Address
jName := c[j].Address
if iName != jName {
return iName < jName
}
iU := c[i].Port
jU := c[j].Port
return iU < jU
}
// ServerByName sorts server by name
type ServerByName []*Server
func (c ServerByName) Len() int { return len(c) }
func (c ServerByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServerByName) Less(i, j int) bool {
return c[i].Name < c[j].Name
}
// LocationByPath sorts location by path
// Location / is the last one
type LocationByPath []*Location
func (c LocationByPath) Len() int { return len(c) }
func (c LocationByPath) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c LocationByPath) Less(i, j int) bool {
return c[i].Path > c[j].Path
}
// SSLCert describes a SSL certificate to be used in a server
type SSLCert struct {
api.ObjectMeta
//CertFileName string
//KeyFileName string
CAFileName string
// PemFileName contains the path to the file with the certificate and key concatenated
PemFileName string
// PemSHA contains the sha1 of the pem file.
// This is used to detect changes in the secret that contains the certificates
PemSHA string
// CN contains all the common names defined in the SSL certificate
CN []string
}
// GetObjectKind implements the ObjectKind interface as a noop
func (s SSLCert) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }