Add Generic interface
This commit is contained in:
parent
f2b627486d
commit
5a8e090736
36 changed files with 58014 additions and 675 deletions
|
|
@ -23,10 +23,10 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -59,10 +59,10 @@ var (
|
|||
|
||||
// BasicDigest returns authentication configuration for an Ingress rule
|
||||
type BasicDigest struct {
|
||||
Type string
|
||||
Realm string
|
||||
File string
|
||||
Secured bool
|
||||
Type string `json:"type"`
|
||||
Realm string `json:"realm"`
|
||||
File string `json:"file"`
|
||||
Secured bool `json:"secured"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -34,9 +35,9 @@ const (
|
|||
|
||||
// External returns external authentication configuration for an Ingress rule
|
||||
type External struct {
|
||||
URL string
|
||||
Method string
|
||||
SendBody bool
|
||||
URL string `json:"url"`
|
||||
Method string `json:"method"`
|
||||
SendBody bool `json:"sendBody"`
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package authtls
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress/core/pkg/k8s"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -32,11 +32,11 @@ const (
|
|||
|
||||
// SSLCert returns external authentication configuration for an Ingress rule
|
||||
type SSLCert struct {
|
||||
Secret string
|
||||
CertFileName string
|
||||
KeyFileName string
|
||||
CAFileName string
|
||||
PemSHA string
|
||||
Secret string `json:"secret"`
|
||||
CertFileName string `json:"certFilename"`
|
||||
KeyFileName string `json:"keyFilename"`
|
||||
CAFileName string `json:"caFilename"`
|
||||
PemSHA string `json:"pemSha"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ limitations under the License.
|
|||
package cors
|
||||
|
||||
import (
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ const (
|
|||
// Upstream returns the URL and method to use check the status of
|
||||
// the upstream server/s
|
||||
type Upstream struct {
|
||||
MaxFails int
|
||||
FailTimeout int
|
||||
MaxFails int `json:"maxFails"`
|
||||
FailTimeout int `json:"failTimeout"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/util/net/sets"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -39,7 +39,7 @@ var (
|
|||
|
||||
// SourceRange returns the CIDR
|
||||
type SourceRange struct {
|
||||
CIDR []string
|
||||
CIDR []string `json:"cidr"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ const (
|
|||
|
||||
// Configuration returns the proxy timeout to use in the upstream server/s
|
||||
type Configuration struct {
|
||||
ConnectTimeout int
|
||||
SendTimeout int
|
||||
ReadTimeout int
|
||||
BufferSize string
|
||||
ConnectTimeout int `json:"conectTimeout"`
|
||||
SendTimeout int `json:"sendTimeout"`
|
||||
ReadTimeout int `json:"readTimeout"`
|
||||
BufferSize string `json:"bufferSize"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -48,19 +48,19 @@ var (
|
|||
// Note: Is possible to specify both limits
|
||||
type RateLimit struct {
|
||||
// Connections indicates a limit with the number of connections per IP address
|
||||
Connections Zone
|
||||
Connections Zone `json:"connections"`
|
||||
// RPS indicates a limit with the number of connections per second
|
||||
RPS Zone
|
||||
RPS Zone `json:"rps"`
|
||||
}
|
||||
|
||||
// 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
|
||||
type Zone struct {
|
||||
Name string
|
||||
Limit int
|
||||
Burst int
|
||||
Name string `json:"name"`
|
||||
Limit int `json:"limit"`
|
||||
Burst int `json:"burst"`
|
||||
// SharedSize amount of shared memory for the zone
|
||||
SharedSize int
|
||||
SharedSize int `json:"sharedSize"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package rewrite
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -34,12 +34,12 @@ const (
|
|||
// Redirect describes the per location redirect config
|
||||
type Redirect struct {
|
||||
// Target URI where the traffic must be redirected
|
||||
Target string
|
||||
Target string `json:"target"`
|
||||
// AddBaseURL indicates if is required to add a base tag in the head
|
||||
// of the responses from the upstream servers
|
||||
AddBaseURL bool
|
||||
AddBaseURL bool `json:"addBaseUrl"`
|
||||
// SSLRedirect indicates if the location section is accessible SSL only
|
||||
SSLRedirect bool
|
||||
SSLRedirect bool `json:"sslRedirect"`
|
||||
}
|
||||
|
||||
// ParseAnnotations parses the annotations contained in the ingress
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ limitations under the License.
|
|||
package secureupstream
|
||||
|
||||
import (
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package sslpassthrough
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
"k8s.io/ingress/core/pkg/ingress/defaults"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
ssl "k8s.io/ingress/core/pkg/net/ssl"
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ func (ic GenericController) Check(_ *http.Request) error {
|
|||
}
|
||||
|
||||
// Info returns information about the backend
|
||||
func (ic GenericController) Info() string {
|
||||
func (ic GenericController) Info() *ingress.BackendInfo {
|
||||
return ic.cfg.Backend.Info()
|
||||
}
|
||||
|
||||
|
|
@ -368,31 +368,25 @@ func (ic *GenericController) sync(key interface{}) error {
|
|||
continue
|
||||
}
|
||||
passUpstreams = append(passUpstreams, &ingress.SSLPassthroughBackend{
|
||||
Upstream: loc.Backend,
|
||||
Host: server.Name,
|
||||
Backend: loc.Backend,
|
||||
Hostname: server.Hostname,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
data, err := ic.cfg.Backend.OnUpdate(cfg, ingress.Configuration{
|
||||
HealthzURL: ic.cfg.DefaultHealthzURL,
|
||||
Upstreams: upstreams,
|
||||
Servers: servers,
|
||||
TCPEndpoints: ic.getTCPServices(),
|
||||
UPDEndpoints: ic.getUDPServices(),
|
||||
PassthroughUpstreams: passUpstreams,
|
||||
Backends: upstreams,
|
||||
Servers: servers,
|
||||
TCPEndpoints: ic.getTCPServices(),
|
||||
UPDEndpoints: ic.getUDPServices(),
|
||||
PassthroughBackends: passUpstreams,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ic.cfg.Backend.IsReloadRequired(data) {
|
||||
return nil
|
||||
}
|
||||
|
||||
glog.Infof("reloading ingress backend...")
|
||||
out, err := ic.cfg.Backend.Restart(data)
|
||||
out, err := ic.cfg.Backend.Reload(data)
|
||||
if err != nil {
|
||||
incReloadErrorCount()
|
||||
glog.Errorf("unexpected failure restarting the backend: \n%v", string(out))
|
||||
|
|
@ -517,11 +511,8 @@ func (ic *GenericController) getStreamServices(data map[string]string, proto api
|
|||
}
|
||||
|
||||
svcs = append(svcs, &ingress.Location{
|
||||
Path: k,
|
||||
Upstream: ingress.Backend{
|
||||
Name: fmt.Sprintf("%v-%v-%v", svcNs, svcName, port),
|
||||
Endpoints: endps,
|
||||
},
|
||||
Path: k,
|
||||
Backend: fmt.Sprintf("%v-%v-%v", svcNs, svcName, port),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -579,7 +570,7 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
|
|||
upstreams := ic.createUpstreams(ings)
|
||||
servers := ic.createServers(ings, upstreams)
|
||||
|
||||
upsDefaults := ic.cfg.Backend.UpstreamDefaults()
|
||||
upsDefaults := ic.cfg.Backend.BackendDefaults()
|
||||
|
||||
for _, ingIf := range ings {
|
||||
ing := ingIf.(*extensions.Ingress)
|
||||
|
|
@ -596,11 +587,6 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
|
|||
glog.V(5).Infof("error reading rate limit annotation in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
|
||||
}
|
||||
|
||||
secUpstream, err := secureupstream.ParseAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("error reading secure upstream in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
|
||||
}
|
||||
|
||||
locRew, err := rewrite.ParseAnnotations(upsDefaults, ing)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("error parsing rewrite annotations for Ingress rule %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
|
||||
|
|
@ -666,7 +652,7 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
|
|||
len(ing.Spec.TLS) == 0 &&
|
||||
host != defServerName {
|
||||
glog.V(3).Infof("ingress rule %v/%v does not contains HTTP or TLS rules. using default backend", ing.Namespace, ing.Name)
|
||||
server.Locations[0].Upstream = *defBackend
|
||||
server.Locations[0].Backend = defBackend.Name
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -690,19 +676,19 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
|
|||
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.Backend.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)
|
||||
break
|
||||
}
|
||||
|
||||
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
|
||||
glog.V(3).Infof("replacing ingress rule %v/%v location %v upstream %v (%v)", ing.Namespace, ing.Name, loc.Path, ups.Name, loc.Backend)
|
||||
loc.Backend = ups.Name
|
||||
loc.IsDefBackend = false
|
||||
loc.BasicDigestAuth = *nginxAuth
|
||||
loc.RateLimit = *rl
|
||||
loc.Redirect = *locRew
|
||||
loc.SecureUpstream = secUpstream
|
||||
//loc.SecureUpstream = secUpstream
|
||||
loc.Whitelist = *wl
|
||||
loc.Backend = *ups
|
||||
loc.Backend = ups.Name
|
||||
loc.EnableCORS = eCORS
|
||||
loc.ExternalAuth = ra
|
||||
loc.Proxy = *prx
|
||||
|
|
@ -712,15 +698,15 @@ func (ic *GenericController) getBackendServers() ([]*ingress.Backend, []*ingress
|
|||
}
|
||||
// is a new location
|
||||
if addLoc {
|
||||
glog.V(3).Infof("adding location %v in ingress rule %v/%v upstream", nginxPath, ing.Namespace, ing.Name, ups.Name)
|
||||
glog.V(3).Infof("adding location %v in ingress rule %v/%v upstream %v", nginxPath, ing.Namespace, ing.Name, ups.Name)
|
||||
server.Locations = append(server.Locations, &ingress.Location{
|
||||
Path: nginxPath,
|
||||
Upstream: *ups,
|
||||
Backend: ups.Name,
|
||||
IsDefBackend: false,
|
||||
BasicDigestAuth: *nginxAuth,
|
||||
RateLimit: *rl,
|
||||
Redirect: *locRew,
|
||||
SecureUpstream: secUpstream,
|
||||
//SecureUpstream: secUpstream,
|
||||
Whitelist: *wl,
|
||||
EnableCORS: eCORS,
|
||||
ExternalAuth: ra,
|
||||
|
|
@ -776,10 +762,15 @@ func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ing
|
|||
upstreams := make(map[string]*ingress.Backend)
|
||||
upstreams[defUpstreamName] = ic.getDefaultUpstream()
|
||||
|
||||
upsDefaults := ic.cfg.Backend.UpstreamDefaults()
|
||||
upsDefaults := ic.cfg.Backend.BackendDefaults()
|
||||
for _, ingIf := range data {
|
||||
ing := ingIf.(*extensions.Ingress)
|
||||
|
||||
secUpstream, err := secureupstream.ParseAnnotations(ing)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("error reading secure upstream in Ingress %v/%v: %v", ing.GetNamespace(), ing.GetName(), err)
|
||||
}
|
||||
|
||||
hz := healthcheck.ParseAnnotations(upsDefaults, ing)
|
||||
|
||||
var defBackend string
|
||||
|
|
@ -817,7 +808,9 @@ func (ic *GenericController) createUpstreams(data []interface{}) map[string]*ing
|
|||
|
||||
glog.V(3).Infof("creating upstream %v", name)
|
||||
upstreams[name] = newUpstream(name)
|
||||
|
||||
if !upstreams[name].Secure {
|
||||
upstreams[name].Secure = secUpstream
|
||||
}
|
||||
svcKey := fmt.Sprintf("%v/%v", ing.GetNamespace(), path.Backend.ServiceName)
|
||||
endp, err := ic.serviceEndpoints(svcKey, path.Backend.ServicePort.String(), hz)
|
||||
if err != nil {
|
||||
|
|
@ -871,18 +864,18 @@ func (ic *GenericController) serviceEndpoints(svcKey, backendPort string,
|
|||
|
||||
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)
|
||||
ngxProxy := *proxy.ParseAnnotations(ic.cfg.Backend.BackendDefaults(), nil)
|
||||
|
||||
upsDefaults := ic.cfg.Backend.UpstreamDefaults()
|
||||
upsDefaults := ic.cfg.Backend.BackendDefaults()
|
||||
|
||||
// default server
|
||||
servers[defServerName] = &ingress.Server{
|
||||
Name: defServerName,
|
||||
Hostname: defServerName,
|
||||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: rootLocation,
|
||||
IsDefBackend: true,
|
||||
Upstream: *ic.getDefaultUpstream(),
|
||||
Backend: ic.getDefaultUpstream().Name,
|
||||
Proxy: ngxProxy,
|
||||
},
|
||||
}}
|
||||
|
|
@ -906,12 +899,12 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str
|
|||
continue
|
||||
}
|
||||
servers[host] = &ingress.Server{
|
||||
Name: host,
|
||||
Hostname: host,
|
||||
Locations: []*ingress.Location{
|
||||
{
|
||||
Path: rootLocation,
|
||||
IsDefBackend: true,
|
||||
Upstream: *ic.getDefaultUpstream(),
|
||||
Backend: ic.getDefaultUpstream().Name,
|
||||
Proxy: ngxProxy,
|
||||
},
|
||||
}, SSLPassthrough: sslpt}
|
||||
|
|
@ -929,15 +922,13 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str
|
|||
}
|
||||
|
||||
// only add certificate if the server does not have one previously configured
|
||||
if len(ing.Spec.TLS) > 0 && !servers[host].SSL {
|
||||
if len(ing.Spec.TLS) > 0 && servers[host].SSLCertificate != "" {
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, ing.Spec.TLS[0].SecretName)
|
||||
bc, exists := ic.sslCertTracker.Get(key)
|
||||
if exists {
|
||||
cert := bc.(*ingress.SSLCert)
|
||||
if isHostValid(host, cert) {
|
||||
servers[host].SSL = true
|
||||
servers[host].SSLCertificate = cert.PemFileName
|
||||
//servers[host].SSLCertificateKey = cert.PemFileName
|
||||
servers[host].SSLPemChecksum = cert.PemSHA
|
||||
}
|
||||
}
|
||||
|
|
@ -950,7 +941,7 @@ func (ic *GenericController) createServers(data []interface{}, upstreams map[str
|
|||
ic.recorder.Eventf(ing, api.EventTypeWarning, "MAPPING", "error: rules with Spec.Backend are allowed only with hostnames")
|
||||
continue
|
||||
}
|
||||
servers[host].Locations[0].Upstream = *backendUpstream
|
||||
servers[host].Locations[0].Backend = backendUpstream.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1050,7 +1041,6 @@ func (ic GenericController) Stop() error {
|
|||
// Start starts the Ingress controller.
|
||||
func (ic GenericController) Start() {
|
||||
glog.Infof("starting Ingress controller")
|
||||
go ic.cfg.Backend.Start()
|
||||
|
||||
go ic.ingController.Run(ic.stopCh)
|
||||
go ic.endpController.Run(ic.stopCh)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
|
@ -12,15 +13,15 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/k8s"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/healthz"
|
||||
kubectl_util "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/k8s"
|
||||
)
|
||||
|
||||
// NewIngressController returns a configured Ingress controller
|
||||
|
|
@ -160,7 +161,8 @@ func registerHandlers(enableProfiling bool, port int, ic *GenericController) {
|
|||
|
||||
mux.HandleFunc("/build", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, ic.Info())
|
||||
b, _ := json.Marshal(ic.Info())
|
||||
w.Write(b)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ import (
|
|||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/service"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
podutil "k8s.io/kubernetes/pkg/api/pod"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/service"
|
||||
)
|
||||
|
||||
// checkSvcForUpdate verifies if one of the running pods for a service contains
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ package controller
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress"
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/parser"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
)
|
||||
|
||||
// newDefaultServer return an BackendServer to be use as default server that returns 503.
|
||||
|
|
@ -33,7 +33,7 @@ func newDefaultServer() ingress.Endpoint {
|
|||
// newUpstream creates an upstream without servers.
|
||||
func newUpstream(name string) *ingress.Backend {
|
||||
return &ingress.Backend{
|
||||
Name: name,
|
||||
Name: name,
|
||||
Endpoints: []ingress.Endpoint{},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
core/pkg/ingress/doc.go
Normal file
63
core/pkg/ingress/doc.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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
|
||||
|
||||
// This package contains the interface is required to implement to build an Ingress controller
|
||||
// A dummy implementation could be
|
||||
//
|
||||
// func main() {
|
||||
// dc := newDummyController()
|
||||
// controller.NewIngressController(dc)
|
||||
// glog.Infof("shutting down Ingress controller...")
|
||||
// }
|
||||
//
|
||||
//where newDummyController returns and implementation of the Controller interface:
|
||||
//
|
||||
// func newDummyController() ingress.Controller {
|
||||
// return &DummyController{}
|
||||
// }
|
||||
//
|
||||
// type DummyController struct {
|
||||
// }
|
||||
//
|
||||
// func (dc DummyController) Reload(data []byte) ([]byte, error) {
|
||||
// err := ioutil.WriteFile("/arbitrary-path", data, 0644)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return exec.Command("some command", "--reload").CombinedOutput()
|
||||
// }
|
||||
//
|
||||
// func (dc DummyController) Test(file string) *exec.Cmd {
|
||||
// return exec.Command("some command", "--config-file", file)
|
||||
// }
|
||||
//
|
||||
// func (dc DummyController) OnUpdate(*api.ConfigMap, Configuration) ([]byte, error) {
|
||||
// return []byte(`<string containing a configuration file>`)
|
||||
// }
|
||||
//
|
||||
// func (dc DummyController) BackendDefaults() defaults.Backend {
|
||||
// return ingress.NewStandardDefaults()
|
||||
// }
|
||||
//
|
||||
// func (dc DummyController) Info() *BackendInfo {
|
||||
// Name: "dummy",
|
||||
// Release: "0.0.0",
|
||||
// Build: "git-00000000",
|
||||
// Repository: "git://foo.bar.com",
|
||||
// }
|
||||
85
core/pkg/ingress/sort_ingress.go
Normal file
85
core/pkg/ingress/sort_ingress.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
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 (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// BackendByNameServers sorts upstreams by name
|
||||
type BackendByNameServers []*Backend
|
||||
|
||||
func (c BackendByNameServers) Len() int { return len(c) }
|
||||
func (c BackendByNameServers) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
func (c BackendByNameServers) Less(i, j int) bool {
|
||||
|
||||
return c[i].Name < c[j].Name
|
||||
}
|
||||
|
||||
// EndpointByAddrPort sorts endpoints by address and port
|
||||
type EndpointByAddrPort []Endpoint
|
||||
|
||||
func (c EndpointByAddrPort) Len() int { return len(c) }
|
||||
func (c EndpointByAddrPort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
func (c EndpointByAddrPort) 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 servers 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].Hostname < c[j].Hostname
|
||||
}
|
||||
|
||||
// LocationByPath sorts location by path in descending order
|
||||
// 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 `json:"metadata,omitempty"`
|
||||
// CAFileName contains the path to the file with the root certificate
|
||||
CAFileName string `json:"caFileName"`
|
||||
// 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 the certificates
|
||||
PemSHA string `json:"pemSha"`
|
||||
// CN contains all the common names defined in the SSL certificate
|
||||
CN []string `json:"cn"`
|
||||
}
|
||||
|
||||
// GetObjectKind implements the ObjectKind interface as a noop
|
||||
func (s SSLCert) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }
|
||||
|
|
@ -23,17 +23,17 @@ import (
|
|||
|
||||
"github.com/golang/glog"
|
||||
|
||||
cache_store "k8s.io/ingress/core/pkg/cache"
|
||||
"k8s.io/ingress/core/pkg/k8s"
|
||||
strings "k8s.io/ingress/core/pkg/strings"
|
||||
"k8s.io/ingress/core/pkg/task"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/leaderelection"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
cache_store "k8s.io/ingress/core/pkg/cache"
|
||||
"k8s.io/ingress/core/pkg/k8s"
|
||||
strings "k8s.io/ingress/core/pkg/strings"
|
||||
"k8s.io/ingress/core/pkg/task"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
|||
243
core/pkg/ingress/types.go
Normal file
243
core/pkg/ingress/types.go
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
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 (
|
||||
"os/exec"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
"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
|
||||
// This directory contains all the SSL certificates that are specified in Ingress rules.
|
||||
// The name of each file is <namespace>-<secret name>.pem. The content is the concatenated
|
||||
// certificate and key.
|
||||
DefaultSSLDirectory = "/ingress-controller/ssl"
|
||||
)
|
||||
|
||||
// Controller holds the methods to handle an Ingress backend
|
||||
// TODO (#18): Make sure this is sufficiently supportive of other backends.
|
||||
type Controller interface {
|
||||
// Reload takes a byte array representing the new loadbalancer configuration,
|
||||
// and returns a byte array containing any output/errors from the backend.
|
||||
// Before returning the backend must load the configuration in the given array
|
||||
// into the loadbalancer and restart it, or fail with an error and message string.
|
||||
// If reloading fails, there should be not change in the running configuration or
|
||||
// the given byte array.
|
||||
Reload(data []byte) ([]byte, error)
|
||||
// Tests returns the commands to execute that verifies 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#L387
|
||||
// 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
|
||||
// Any update to services, endpoints, secrets (only those referenced from Ingress)
|
||||
// and ingress trigger the execution.
|
||||
// Notifications of type Add, Update and Delete:
|
||||
// https://github.com/kubernetes/kubernetes/blob/master/pkg/client/cache/controller.go#L164
|
||||
//
|
||||
// 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#L83
|
||||
// The backend returns the contents of the configuration file or an error
|
||||
// with the reason why was not possible to generate the file.
|
||||
//
|
||||
// The returned configuration is then passed to test, and then to reload
|
||||
// if there is no errors.
|
||||
OnUpdate(*api.ConfigMap, Configuration) ([]byte, error)
|
||||
// BackendDefaults returns the minimum settings required to configure the
|
||||
// communication to endpoints
|
||||
BackendDefaults() defaults.Backend
|
||||
// Info returns information about the ingress controller
|
||||
Info() *BackendInfo
|
||||
}
|
||||
|
||||
// BackendInfo returns information about the backend.
|
||||
// This fields contains information that helps to track issues or to
|
||||
// map the running ingress controller to source code
|
||||
type BackendInfo struct {
|
||||
// Name returns the name of the backend implementation
|
||||
Name string `json:"name"`
|
||||
// Release returns the running version (semver)
|
||||
Release string `json:"release"`
|
||||
// Build returns information about the git commit
|
||||
Build string `json:"build"`
|
||||
// Repository return information about the git repository
|
||||
Repository string `json:"repository"`
|
||||
}
|
||||
|
||||
// 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:"namespace"`
|
||||
// Servers
|
||||
Servers []*Server `json:"servers"`
|
||||
// TCPEndpoints contain endpoints for tcp streams handled by this backend
|
||||
// +optional
|
||||
TCPEndpoints []*Location `json:"tcpEndpoints,omitempty"`
|
||||
// UPDEndpoints contain endpoints for udp streams handled by this backend
|
||||
// +optional
|
||||
UPDEndpoints []*Location `json:"udpEndpoints,omitempty"`
|
||||
// PassthroughBackend contains the backends used for SSL passthrough.
|
||||
// It contains information about the associated Server Name Indication (SNI).
|
||||
// +optional
|
||||
PassthroughBackends []*SSLPassthroughBackend `json:"passthroughBackends,omitempty"`
|
||||
}
|
||||
|
||||
// Backend describes one or more remote server/s (endpoints) associated with a service
|
||||
type Backend struct {
|
||||
// Name represents an unique api.Service name formatted as <namespace>-<name>-<port>
|
||||
Name string `json:"name"`
|
||||
// This indicates if the communication protocol between the backend and the endpoint is HTTP or HTTPS
|
||||
// Allowing the use of HTTPS
|
||||
// The endpoint/s must provide a TLS connection.
|
||||
// The certificate used in the endpoint cannot be a self signed certificate
|
||||
// TODO: add annotation to allow the load of ca certificate
|
||||
Secure bool `json:"secure"`
|
||||
// Endpoints contains the list of endpoints currently running
|
||||
Endpoints []Endpoint `json:"endpoints"`
|
||||
}
|
||||
|
||||
// Endpoint describes a kubernetes endpoint in an backend
|
||||
type Endpoint struct {
|
||||
// Address IP address of the endpoint
|
||||
Address string `json:"address"`
|
||||
// Port number of the TCP port
|
||||
Port string `json:"port"`
|
||||
// MaxFails returns the number of unsuccessful attempts to communicate
|
||||
// allowed before this should be considered dow.
|
||||
// Setting 0 indicates that the check is performed by a Kubernetes probe
|
||||
MaxFails int `json:"maxFails"`
|
||||
// FailTimeout returns the time in seconds during which the specified number
|
||||
// of unsuccessful attempts to communicate with the server should happen
|
||||
// to consider the endpoint unavailable
|
||||
FailTimeout int `json:"failTimeout"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
// SSLCertificate path to the SSL certificate on disk
|
||||
SSLCertificate string `json:"sslCertificate"`
|
||||
// SSLPemChecksum returns the checksum of the certificate file on disk.
|
||||
// There is no restriction in the hash generator. This checksim can be
|
||||
// used to determine if the secret changed without the use of file
|
||||
// system notifications
|
||||
SSLPemChecksum string `json:"sslPemChecksum"`
|
||||
// Locations list of URIs configured in the server.
|
||||
Locations []*Location `json:"locations,omitempty"`
|
||||
}
|
||||
|
||||
// Location describes an URI inside a server.
|
||||
// Also contains additional information about annotations in the Ingress.
|
||||
//
|
||||
// Important:
|
||||
// The implementation of annotations is optional
|
||||
//
|
||||
// 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:
|
||||
// - CertificateAuth
|
||||
// - 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"`
|
||||
// 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"`
|
||||
// Backend describes the name of the backend to use.
|
||||
Backend string `json:"backend"`
|
||||
// BasicDigestAuth returns authentication configuration for
|
||||
// an Ingress rule.
|
||||
// +optional
|
||||
BasicDigestAuth auth.BasicDigest `json:"basicDigestAuth,omitempty"`
|
||||
// EnableCORS indicates if path must support CORS
|
||||
// +optional
|
||||
EnableCORS bool `json:"enableCors,omitempty"`
|
||||
// ExternalAuth indicates the access to this location requires
|
||||
// authentication using an external provider
|
||||
// +optional
|
||||
ExternalAuth authreq.External `json:"externalAuth,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.RateLimit `json:"rateLimit,omitempty"`
|
||||
// Redirect describes the redirection this location.
|
||||
// +optional
|
||||
Redirect rewrite.Redirect `json:"redirect,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.Configuration `json:"proxy,omitempty"`
|
||||
// CertificateAuth indicates the access to this location requires
|
||||
// external authentication
|
||||
// +optional
|
||||
CertificateAuth authtls.SSLCert `json:"certificateAuth,omitempty"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// Backend describes the endpoints to use.
|
||||
Backend string `json:"namespace,omitempty"`
|
||||
// Hostname returns the FQDN of the server
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -92,7 +93,8 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
|||
|
||||
_, err := pemCert.Verify(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to verify certificate chain: \n\t%s\n", err)
|
||||
oe := fmt.Sprintf("failed to verify certificate chain: \n\t%s\n", err)
|
||||
return nil, errors.New(oe)
|
||||
}
|
||||
|
||||
caName := fmt.Sprintf("ca-%v.pem", name)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue