Merge branch 'upstream' into nginx/extauth_headers
This commit is contained in:
commit
6d07d32003
63 changed files with 1075 additions and 218 deletions
|
|
@ -28,6 +28,7 @@ const (
|
|||
addBaseURL = "ingress.kubernetes.io/add-base-url"
|
||||
sslRedirect = "ingress.kubernetes.io/ssl-redirect"
|
||||
forceSSLRedirect = "ingress.kubernetes.io/force-ssl-redirect"
|
||||
appRoot = "ingress.kubernetes.io/app-root"
|
||||
)
|
||||
|
||||
// Redirect describes the per location redirect config
|
||||
|
|
@ -41,6 +42,8 @@ type Redirect struct {
|
|||
SSLRedirect bool `json:"sslRedirect"`
|
||||
// ForceSSLRedirect indicates if the location section is accessible SSL only
|
||||
ForceSSLRedirect bool `json:"forceSSLRedirect"`
|
||||
// AppRoot defines the Application Root that the Controller must redirect if it's not in '/' context
|
||||
AppRoot string `json:"appRoot"`
|
||||
}
|
||||
|
||||
type rewrite struct {
|
||||
|
|
@ -65,10 +68,12 @@ func (a rewrite) Parse(ing *extensions.Ingress) (interface{}, error) {
|
|||
fSslRe = a.backendResolver.GetDefaultBackend().ForceSSLRedirect
|
||||
}
|
||||
abu, _ := parser.GetBoolAnnotation(addBaseURL, ing)
|
||||
ar, _ := parser.GetStringAnnotation(appRoot, ing)
|
||||
return &Redirect{
|
||||
Target: rt,
|
||||
AddBaseURL: abu,
|
||||
SSLRedirect: sslRe,
|
||||
ForceSSLRedirect: fSslRe,
|
||||
AppRoot: ar,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,3 +158,20 @@ func TestForceSSLRedirect(t *testing.T) {
|
|||
t.Errorf("Expected true but returned false")
|
||||
}
|
||||
}
|
||||
func TestAppRoot(t *testing.T) {
|
||||
ing := buildIngress()
|
||||
|
||||
data := map[string]string{}
|
||||
data[appRoot] = "/app1"
|
||||
ing.SetAnnotations(data)
|
||||
|
||||
i, _ := NewParser(mockBackend{true}).Parse(ing)
|
||||
redirect, ok := i.(*Redirect)
|
||||
if !ok {
|
||||
t.Errorf("expected a App Context")
|
||||
}
|
||||
if redirect.AppRoot != "/app1" {
|
||||
t.Errorf("Unexpected value got in AppRoot")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@ limitations under the License.
|
|||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/auth"
|
||||
|
|
@ -47,11 +50,13 @@ type extractorConfig interface {
|
|||
}
|
||||
|
||||
type annotationExtractor struct {
|
||||
annotations map[string]parser.IngressAnnotation
|
||||
secretResolver resolver.Secret
|
||||
annotations map[string]parser.IngressAnnotation
|
||||
}
|
||||
|
||||
func newAnnotationExtractor(cfg extractorConfig) annotationExtractor {
|
||||
return annotationExtractor{
|
||||
cfg,
|
||||
map[string]parser.IngressAnnotation{
|
||||
"BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg),
|
||||
"ExternalAuth": authreq.NewParser(),
|
||||
|
|
@ -104,6 +109,7 @@ const (
|
|||
healthCheck = "HealthCheck"
|
||||
sslPassthrough = "SSLPassthrough"
|
||||
sessionAffinity = "SessionAffinity"
|
||||
certificateAuth = "CertificateAuth"
|
||||
)
|
||||
|
||||
func (e *annotationExtractor) SecureUpstream(ing *extensions.Ingress) bool {
|
||||
|
|
@ -125,3 +131,17 @@ func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessiona
|
|||
val, _ := e.annotations[sessionAffinity].Parse(ing)
|
||||
return val.(*sessionaffinity.AffinityConfig)
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) ContainsCertificateAuth(ing *extensions.Ingress) bool {
|
||||
val, _ := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing)
|
||||
return val != ""
|
||||
}
|
||||
|
||||
func (e *annotationExtractor) CertificateAuthSecret(ing *extensions.Ingress) (*api.Secret, error) {
|
||||
val, _ := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing)
|
||||
if val == "" {
|
||||
return nil, fmt.Errorf("ingress rule %v/%v does not contains the auth-tls-secret annotation", ing.Namespace, ing.Name)
|
||||
}
|
||||
|
||||
return e.secretResolver.GetSecret(val)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package controller
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -68,13 +69,18 @@ func (ic *GenericController) syncSecret(k interface{}) error {
|
|||
}
|
||||
|
||||
// create certificates and add or update the item in the store
|
||||
_, exists = ic.sslCertTracker.Get(key)
|
||||
cur, exists := ic.sslCertTracker.Get(key)
|
||||
if exists {
|
||||
glog.V(3).Infof("updating secret %v/%v in the store ", sec.Namespace, sec.Name)
|
||||
s := cur.(*ingress.SSLCert)
|
||||
if reflect.DeepEqual(s, cert) {
|
||||
// no need to update
|
||||
return nil
|
||||
}
|
||||
glog.Infof("updating secret %v/%v in the local store", sec.Namespace, sec.Name)
|
||||
ic.sslCertTracker.Update(key, cert)
|
||||
return nil
|
||||
}
|
||||
glog.V(3).Infof("adding secret %v/%v to the store ", sec.Namespace, sec.Name)
|
||||
glog.Infof("adding secret %v/%v to the local store", sec.Namespace, sec.Name)
|
||||
ic.sslCertTracker.Add(key, cert)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -84,10 +90,10 @@ func (ic *GenericController) syncSecret(k interface{}) error {
|
|||
func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLCert, error) {
|
||||
secretInterface, exists, err := ic.secrLister.Store.GetByKey(secretName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error retriveing secret %v: %v", secretName, err)
|
||||
return nil, fmt.Errorf("error retrieving secret %v: %v", secretName, err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("secret named %v does not exists", secretName)
|
||||
return nil, fmt.Errorf("secret named %v does not exist", secretName)
|
||||
}
|
||||
|
||||
secret := secretInterface.(*api.Secret)
|
||||
|
|
@ -100,13 +106,13 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC
|
|||
|
||||
var s *ingress.SSLCert
|
||||
if okcert && okkey {
|
||||
glog.V(3).Infof("Found certificate and private key, configuring %v as a TLS Secret", secretName)
|
||||
glog.Infof("found certificate and private key, configuring %v as a TLS Secret", secretName)
|
||||
s, err = ssl.AddOrUpdateCertAndKey(nsSecName, cert, key, ca)
|
||||
} else if ca != nil {
|
||||
glog.V(3).Infof("Found only ca.crt, configuring %v as an Certificate Authentication secret", secretName)
|
||||
glog.Infof("found only ca.crt, configuring %v as an Certificate Authentication secret", secretName)
|
||||
s, err = ssl.AddCertAuth(nsSecName, ca)
|
||||
} else {
|
||||
return nil, fmt.Errorf("No keypair or CA cert could be found in %v", secretName)
|
||||
return nil, fmt.Errorf("ko keypair or CA cert could be found in %v", secretName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -122,10 +128,14 @@ func (ic *GenericController) getPemCertificate(secretName string) (*ingress.SSLC
|
|||
func (ic *GenericController) secrReferenced(name, namespace string) bool {
|
||||
for _, ingIf := range ic.ingLister.Store.List() {
|
||||
ing := ingIf.(*extensions.Ingress)
|
||||
str, err := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing)
|
||||
if err == nil && str == fmt.Sprintf("%v/%v", namespace, name) {
|
||||
return true
|
||||
|
||||
if ic.annotations.ContainsCertificateAuth(ing) {
|
||||
str, _ := parser.GetStringAnnotation("ingress.kubernetes.io/auth-tls-secret", ing)
|
||||
if str == fmt.Sprintf("%v/%v", namespace, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if ing.Namespace != namespace {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ type GenericController struct {
|
|||
|
||||
// Configuration contains all the settings required by an Ingress controller
|
||||
type Configuration struct {
|
||||
Client *clientset.Clientset
|
||||
Client clientset.Interface
|
||||
|
||||
ResyncPeriod time.Duration
|
||||
DefaultService string
|
||||
|
|
@ -170,6 +170,12 @@ func newIngressController(config *Configuration) *GenericController {
|
|||
}
|
||||
ic.recorder.Eventf(addIng, api.EventTypeNormal, "CREATE", fmt.Sprintf("Ingress %s/%s", addIng.Namespace, addIng.Name))
|
||||
ic.syncQueue.Enqueue(obj)
|
||||
if ic.annotations.ContainsCertificateAuth(addIng) {
|
||||
s, err := ic.annotations.CertificateAuthSecret(addIng)
|
||||
if err == nil {
|
||||
ic.syncSecret(fmt.Sprintf("%v/%v", s.Namespace, s.Name))
|
||||
}
|
||||
}
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
delIng := obj.(*extensions.Ingress)
|
||||
|
|
@ -209,6 +215,13 @@ func newIngressController(config *Configuration) *GenericController {
|
|||
}()
|
||||
}
|
||||
}
|
||||
if ic.annotations.ContainsCertificateAuth(upIng) {
|
||||
s, err := ic.annotations.CertificateAuthSecret(upIng)
|
||||
if err == nil {
|
||||
ic.syncSecret(fmt.Sprintf("%v/%v", s.Namespace, s.Name))
|
||||
}
|
||||
}
|
||||
|
||||
ic.syncQueue.Enqueue(cur)
|
||||
}
|
||||
},
|
||||
|
|
@ -280,11 +293,11 @@ func newIngressController(config *Configuration) *GenericController {
|
|||
&api.Endpoints{}, ic.cfg.ResyncPeriod, eventHandler)
|
||||
|
||||
ic.secrLister.Store, ic.secrController = cache.NewInformer(
|
||||
cache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), "secrets", ic.cfg.Namespace, fields.Everything()),
|
||||
cache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), "secrets", api.NamespaceAll, fields.Everything()),
|
||||
&api.Secret{}, ic.cfg.ResyncPeriod, secrEventHandler)
|
||||
|
||||
ic.mapLister.Store, ic.mapController = cache.NewInformer(
|
||||
cache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), "configmaps", ic.cfg.Namespace, fields.Everything()),
|
||||
cache.NewListWatchFromClient(ic.cfg.Client.Core().RESTClient(), "configmaps", api.NamespaceAll, fields.Everything()),
|
||||
&api.ConfigMap{}, ic.cfg.ResyncPeriod, mapEventHandler)
|
||||
|
||||
ic.svcLister.Indexer, ic.svcController = cache.NewIndexerInformer(
|
||||
|
|
@ -551,7 +564,7 @@ func (ic *GenericController) getDefaultUpstream() *ingress.Backend {
|
|||
}
|
||||
|
||||
if !svcExists {
|
||||
glog.Warningf("service %v does not exists", svcKey)
|
||||
glog.Warningf("service %v does not exist", svcKey)
|
||||
upstream.Endpoints = append(upstream.Endpoints, newDefaultServer())
|
||||
return upstream
|
||||
}
|
||||
|
|
@ -693,7 +706,7 @@ func (ic GenericController) GetAuthCertificate(secretName string) (*resolver.Aut
|
|||
|
||||
bc, exists := ic.sslCertTracker.Get(secretName)
|
||||
if !exists {
|
||||
return &resolver.AuthSSLCert{}, fmt.Errorf("secret %v does not exists", secretName)
|
||||
return &resolver.AuthSSLCert{}, fmt.Errorf("secret %v does not exist", secretName)
|
||||
}
|
||||
cert := bc.(*ingress.SSLCert)
|
||||
return &resolver.AuthSSLCert{
|
||||
|
|
@ -792,7 +805,7 @@ func (ic *GenericController) serviceEndpoints(svcKey, backendPort string,
|
|||
}
|
||||
|
||||
if !svcExists {
|
||||
err = fmt.Errorf("service %v does not exists", svcKey)
|
||||
err = fmt.Errorf("service %v does not exist", svcKey)
|
||||
return upstreams, err
|
||||
}
|
||||
|
||||
|
|
@ -947,6 +960,12 @@ func (ic *GenericController) createServers(data []interface{},
|
|||
}
|
||||
}
|
||||
|
||||
if tlsSecretName == "" {
|
||||
glog.Warningf("ingress rule %v/%v for host %v does not contains a matching tls host", ing.Namespace, ing.Name, host)
|
||||
glog.V(2).Infof("%v", ing.Spec.TLS)
|
||||
continue
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%v/%v", ing.Namespace, tlsSecretName)
|
||||
bc, exists := ic.sslCertTracker.Get(key)
|
||||
if exists {
|
||||
|
|
@ -954,7 +973,11 @@ func (ic *GenericController) createServers(data []interface{},
|
|||
if isHostValid(host, cert) {
|
||||
servers[host].SSLCertificate = cert.PemFileName
|
||||
servers[host].SSLPemChecksum = cert.PemSHA
|
||||
} else {
|
||||
glog.Warningf("ssl certificate %v does not contains a common name for host %v", key, host)
|
||||
}
|
||||
} else {
|
||||
glog.Warningf("ssl certificate \"%v\" does not exist in local store", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -978,6 +1001,11 @@ func (ic *GenericController) getEndpoints(
|
|||
|
||||
upsServers := []ingress.Endpoint{}
|
||||
|
||||
// avoid duplicated upstream servers when the service
|
||||
// contains multiple port definitions sharing the same
|
||||
// targetport.
|
||||
adus := make(map[string]bool, 0)
|
||||
|
||||
for _, ss := range ep.Subsets {
|
||||
for _, epPort := range ss.Ports {
|
||||
|
||||
|
|
@ -1018,6 +1046,10 @@ func (ic *GenericController) getEndpoints(
|
|||
}
|
||||
|
||||
for _, epAddress := range ss.Addresses {
|
||||
ep := fmt.Sprintf("%v:%v", epAddress.IP, targetPort)
|
||||
if _, exists := adus[ep]; exists {
|
||||
continue
|
||||
}
|
||||
ups := ingress.Endpoint{
|
||||
Address: epAddress.IP,
|
||||
Port: fmt.Sprintf("%v", targetPort),
|
||||
|
|
@ -1025,6 +1057,7 @@ func (ic *GenericController) getEndpoints(
|
|||
FailTimeout: hz.FailTimeout,
|
||||
}
|
||||
upsServers = append(upsServers, ups)
|
||||
adus[ep] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,10 +128,12 @@ func NewIngressController(backend ingress.Controller) *GenericController {
|
|||
glog.Infof("service %v validated as source of Ingress status", *publishSvc)
|
||||
}
|
||||
|
||||
if *configMap != "" {
|
||||
_, _, err = k8s.ParseNameNS(*configMap)
|
||||
if *watchNamespace != "" {
|
||||
|
||||
_, err = k8s.IsValidNamespace(kubeClient, *watchNamespace)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalf("configmap error: %v", err)
|
||||
glog.Fatalf("no watchNamespace with name %v found: %v", *watchNamespace, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ import (
|
|||
)
|
||||
|
||||
// checkSvcForUpdate verifies if one of the running pods for a service contains
|
||||
// named port. If the annotation in the service does not exists or is not equals
|
||||
// named port. If the annotation in the service does not exist or is not equals
|
||||
// to the port mapping obtained from the pod the service must be updated to reflect
|
||||
// the current state
|
||||
func (ic *GenericController) checkSvcForUpdate(svc *api.Service) error {
|
||||
// get the pods associated with the service
|
||||
// TODO: switch this to a watch
|
||||
pods, err := ic.cfg.Client.Pods(svc.Namespace).List(api.ListOptions{
|
||||
pods, err := ic.cfg.Client.Core().Pods(svc.Namespace).List(api.ListOptions{
|
||||
LabelSelector: labels.Set(svc.Spec.Selector).AsSelector(),
|
||||
})
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ func (ic *GenericController) checkSvcForUpdate(svc *api.Service) error {
|
|||
if len(namedPorts) > 0 && !reflect.DeepEqual(curNamedPort, namedPorts) {
|
||||
data, _ := json.Marshal(namedPorts)
|
||||
|
||||
newSvc, err := ic.cfg.Client.Services(svc.Namespace).Get(svc.Name)
|
||||
newSvc, err := ic.cfg.Client.Core().Services(svc.Namespace).Get(svc.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting service %v/%v: %v", svc.Namespace, svc.Name, err)
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ func (ic *GenericController) checkSvcForUpdate(svc *api.Service) error {
|
|||
|
||||
newSvc.ObjectMeta.Annotations[service.NamedPortAnnotation] = string(data)
|
||||
glog.Infof("updating service %v with new named port mappings", svc.Name)
|
||||
_, err = ic.cfg.Client.Services(svc.Namespace).Update(newSvc)
|
||||
_, err = ic.cfg.Client.Core().Services(svc.Namespace).Update(newSvc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error syncing service %v/%v: %v", svc.Namespace, svc.Name, err)
|
||||
}
|
||||
|
|
|
|||
191
core/pkg/ingress/controller/named_port_test.go
Normal file
191
core/pkg/ingress/controller/named_port_test.go
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/ingress/core/pkg/ingress/annotations/service"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
testclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func buildSimpleClientSet() *testclient.Clientset {
|
||||
return testclient.NewSimpleClientset(
|
||||
&api.PodList{Items: []api.Pod{
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo1",
|
||||
Namespace: api.NamespaceDefault,
|
||||
Labels: map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "foo_node_1",
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Ports: []api.ContainerPort{
|
||||
{
|
||||
Name: "foo1_named_port_c1",
|
||||
Protocol: api.ProtocolTCP,
|
||||
ContainerPort: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo1",
|
||||
Namespace: api.NamespaceSystem,
|
||||
Labels: map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
&api.ServiceList{Items: []api.Service{
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Namespace: api.NamespaceDefault,
|
||||
Name: "named_port_test_service",
|
||||
},
|
||||
},
|
||||
}},
|
||||
)
|
||||
}
|
||||
|
||||
func buildGenericController() *GenericController {
|
||||
return &GenericController{
|
||||
cfg: &Configuration{
|
||||
Client: buildSimpleClientSet(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildService() *api.Service {
|
||||
return &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Namespace: api.NamespaceSystem,
|
||||
Name: "named_port_test_service",
|
||||
},
|
||||
|
||||
Spec: api.ServiceSpec{
|
||||
ClusterIP: "10.10.10.10",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckSvcForUpdate(t *testing.T) {
|
||||
foos := []struct {
|
||||
n string
|
||||
ns string
|
||||
sps []api.ServicePort
|
||||
sl map[string]string
|
||||
er string
|
||||
}{
|
||||
{
|
||||
"pods_have_not_been_found_in_this_namespace",
|
||||
api.NamespaceSystem,
|
||||
[]api.ServicePort{
|
||||
{Name: "foo_port_1", Port: 8080, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("foo1_named_port_c1")},
|
||||
{Name: "foo_port_2", Port: 8181, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(81)},
|
||||
{Name: "foo_port_3", Port: 8282, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("")},
|
||||
},
|
||||
map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"ports_have_not_been_found_in_this_pod",
|
||||
api.NamespaceDefault,
|
||||
[]api.ServicePort{
|
||||
{Name: "foo_port_1", Port: 8080, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("foo1_named_port_cXX")},
|
||||
{Name: "foo_port_2", Port: 8181, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(81)},
|
||||
{Name: "foo_port_3", Port: 8282, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("")},
|
||||
},
|
||||
map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
"",
|
||||
},
|
||||
|
||||
{
|
||||
"ports_fixed",
|
||||
api.NamespaceDefault,
|
||||
[]api.ServicePort{
|
||||
{Name: "foo_port_1", Port: 8080, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(80)},
|
||||
{Name: "foo_port_2", Port: 8181, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(81)},
|
||||
{Name: "foo_port_3", Port: 8282, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("")},
|
||||
},
|
||||
map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"nil_selector",
|
||||
api.NamespaceDefault,
|
||||
[]api.ServicePort{
|
||||
{Name: "foo_port_1", Port: 8080, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("foo1_named_port_c1")},
|
||||
{Name: "foo_port_2", Port: 8181, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(81)},
|
||||
{Name: "foo_port_3", Port: 8282, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("")},
|
||||
},
|
||||
nil,
|
||||
"{\"foo1_named_port_c1\":\"80\"}",
|
||||
},
|
||||
{
|
||||
"normal_update",
|
||||
api.NamespaceDefault,
|
||||
[]api.ServicePort{
|
||||
{Name: "foo_port_1", Port: 8080, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("foo1_named_port_c1")},
|
||||
{Name: "foo_port_2", Port: 8181, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(81)},
|
||||
{Name: "foo_port_3", Port: 8282, Protocol: api.ProtocolTCP, TargetPort: intstr.FromString("")},
|
||||
},
|
||||
map[string]string{
|
||||
"lable_sig": "foo_pod",
|
||||
},
|
||||
"{\"foo1_named_port_c1\":\"80\"}",
|
||||
},
|
||||
}
|
||||
|
||||
for _, foo := range foos {
|
||||
t.Run(foo.n, func(t *testing.T) {
|
||||
gc := buildGenericController()
|
||||
s := buildService()
|
||||
s.SetNamespace(foo.ns)
|
||||
s.Spec.Ports = foo.sps
|
||||
s.Spec.Selector = foo.sl
|
||||
|
||||
err := gc.checkSvcForUpdate(s)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
rs, _ := gc.cfg.Client.Core().Services(api.NamespaceDefault).Get("named_port_test_service")
|
||||
rr := rs.ObjectMeta.Annotations[service.NamedPortAnnotation]
|
||||
if !reflect.DeepEqual(rr, foo.er) {
|
||||
t.Errorf("Returned %s, but expected %s for %s", rr, foo.er, foo.n)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ func isHostValid(host string, cert *ingress.SSLCert) bool {
|
|||
return false
|
||||
}
|
||||
for _, cn := range cert.CN {
|
||||
if matchHostnames(cn, host) {
|
||||
if matchHostnames(cn, strings.ToLower(host)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import "net"
|
|||
// The reason of this requirements is the annotations are generic. If some implementation do not supports
|
||||
// one or more annotations it just can provides defaults
|
||||
type Backend struct {
|
||||
// AppRoot contains the AppRoot for apps that doesn't exposes its content in the 'root' context
|
||||
AppRoot string `json:"app-root"`
|
||||
|
||||
// enables which HTTP codes should be passed for processing with the error_page directive
|
||||
// http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ func (s *statusSync) updateStatus(newIPs []api.LoadBalancerIngress) {
|
|||
continue
|
||||
}
|
||||
|
||||
go func(wg *sync.WaitGroup) {
|
||||
go func(wg *sync.WaitGroup, ing *extensions.Ingress) {
|
||||
defer wg.Done()
|
||||
ingClient := s.Client.Extensions().Ingresses(ing.Namespace)
|
||||
currIng, err := ingClient.Get(ing.Name)
|
||||
|
|
@ -274,7 +274,7 @@ func (s *statusSync) updateStatus(newIPs []api.LoadBalancerIngress) {
|
|||
if err != nil {
|
||||
glog.Warningf("error updating ingress rule: %v", err)
|
||||
}
|
||||
}(&wg)
|
||||
}(&wg, ing)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,30 @@ func IsValidService(kubeClient clientset.Interface, name string) (*api.Service,
|
|||
return kubeClient.Core().Services(ns).Get(name)
|
||||
}
|
||||
|
||||
// isValidConfigMap check if exists a configmap with the specified name
|
||||
func IsValidConfigMap(kubeClient clientset.Interface, fullName string) (*api.ConfigMap, error) {
|
||||
|
||||
ns, name, err := ParseNameNS(fullName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configMap, err := kubeClient.Core().ConfigMaps(ns).Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("configmap not found: %v", err)
|
||||
}
|
||||
|
||||
return configMap, nil
|
||||
|
||||
}
|
||||
|
||||
// isValidNamespace chck if exists a namespace with the specified name
|
||||
func IsValidNamespace(kubeClient clientset.Interface, name string) (*api.Namespace, error) {
|
||||
return kubeClient.Core().Namespaces().Get(name)
|
||||
}
|
||||
|
||||
// IsValidSecret checks if exists a secret with the specified name
|
||||
func IsValidSecret(kubeClient clientset.Interface, name string) (*api.Secret, error) {
|
||||
ns, name, err := ParseNameNS(name)
|
||||
|
|
|
|||
|
|
@ -85,6 +85,64 @@ func TestIsValidService(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsValidNamespace(t *testing.T) {
|
||||
|
||||
fk := testclient.NewSimpleClientset(&api.Namespace{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "default",
|
||||
},
|
||||
})
|
||||
|
||||
_, err := IsValidNamespace(fk, "empty")
|
||||
if err == nil {
|
||||
t.Errorf("expected error but return nill")
|
||||
}
|
||||
|
||||
ns, err := IsValidNamespace(fk, "default")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if ns == nil {
|
||||
t.Errorf("expected a configmap but returned nil")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIsValidConfigMap(t *testing.T) {
|
||||
|
||||
fk := testclient.NewSimpleClientset(&api.ConfigMap{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Namespace: api.NamespaceDefault,
|
||||
Name: "demo",
|
||||
},
|
||||
})
|
||||
|
||||
_, err := IsValidConfigMap(fk, "")
|
||||
if err == nil {
|
||||
t.Errorf("expected error but return nill")
|
||||
}
|
||||
|
||||
s, err := IsValidConfigMap(fk, "default/demo")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if s == nil {
|
||||
t.Errorf("expected a configmap but returned nil")
|
||||
}
|
||||
|
||||
fk = testclient.NewSimpleClientset()
|
||||
s, err = IsValidConfigMap(fk, "default/demo")
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but returned nil")
|
||||
}
|
||||
if s != nil {
|
||||
t.Errorf("unexpected Configmap returned: %v", s)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIsValidSecret(t *testing.T) {
|
||||
fk := testclient.NewSimpleClientset(&api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
|||
|
||||
tempPemFile, err := ioutil.TempFile(ingress.DefaultSSLDirectory, pemName)
|
||||
|
||||
glog.V(3).Infof("Creating temp file %v for Keypair: %v", tempPemFile.Name(), pemName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create temp pem file %v: %v", pemFileName, err)
|
||||
}
|
||||
glog.V(3).Infof("Creating temp file %v for Keypair: %v", tempPemFile.Name(), pemName)
|
||||
|
||||
_, err = tempPemFile.Write(cert)
|
||||
if err != nil {
|
||||
|
|
@ -75,13 +75,13 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
|||
pemBlock, _ := pem.Decode(pemCerts)
|
||||
if pemBlock == nil {
|
||||
_ = os.Remove(tempPemFile.Name())
|
||||
return nil, fmt.Errorf("No valid PEM formatted block found")
|
||||
return nil, fmt.Errorf("no valid PEM formatted block found")
|
||||
}
|
||||
|
||||
// If the file does not start with 'BEGIN CERTIFICATE' it's invalid and must not be used.
|
||||
if pemBlock.Type != "CERTIFICATE" {
|
||||
_ = os.Remove(tempPemFile.Name())
|
||||
return nil, fmt.Errorf("Certificate %v contains invalid data, and must be created with 'kubectl create secret tls'", name)
|
||||
return nil, fmt.Errorf("certificate %v contains invalid data, and must be created with 'kubectl create secret tls'", name)
|
||||
}
|
||||
|
||||
pemCert, err := x509.ParseCertificate(pemBlock.Bytes)
|
||||
|
|
@ -115,7 +115,7 @@ func AddOrUpdateCertAndKey(name string, cert, key, ca []byte) (*ingress.SSLCert,
|
|||
|
||||
caFile, err := os.OpenFile(pemFileName, os.O_RDWR|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not open file %v for writing additional CA chains: %v", pemFileName, err)
|
||||
return nil, fmt.Errorf("could not open file %v for writing additional CA chains: %v", pemFileName, err)
|
||||
}
|
||||
|
||||
defer caFile.Close()
|
||||
|
|
@ -150,11 +150,11 @@ func AddCertAuth(name string, ca []byte) (*ingress.SSLCert, error) {
|
|||
|
||||
pemCABlock, _ := pem.Decode(ca)
|
||||
if pemCABlock == nil {
|
||||
return nil, fmt.Errorf("No valid PEM formatted block found")
|
||||
return nil, fmt.Errorf("no valid PEM formatted block found")
|
||||
}
|
||||
// If the first certificate does not start with 'BEGIN CERTIFICATE' it's invalid and must not be used.
|
||||
if pemCABlock.Type != "CERTIFICATE" {
|
||||
return nil, fmt.Errorf("CA File %v contains invalid data, and must be created only with PEM formated certificates", name)
|
||||
return nil, fmt.Errorf("CA file %v contains invalid data, and must be created only with PEM formated certificates", name)
|
||||
}
|
||||
|
||||
_, err := x509.ParseCertificate(pemCABlock.Bytes)
|
||||
|
|
@ -206,13 +206,13 @@ func AddOrUpdateDHParam(name string, dh []byte) (string, error) {
|
|||
pemBlock, _ := pem.Decode(pemCerts)
|
||||
if pemBlock == nil {
|
||||
_ = os.Remove(tempPemFile.Name())
|
||||
return "", fmt.Errorf("No valid PEM formatted block found")
|
||||
return "", fmt.Errorf("no valid PEM formatted block found")
|
||||
}
|
||||
|
||||
// If the file does not start with 'BEGIN DH PARAMETERS' it's invalid and must not be used.
|
||||
if pemBlock.Type != "DH PARAMETERS" {
|
||||
_ = os.Remove(tempPemFile.Name())
|
||||
return "", fmt.Errorf("Certificate %v contains invalid data", name)
|
||||
return "", fmt.Errorf("certificate %v contains invalid data", name)
|
||||
}
|
||||
|
||||
err = os.Rename(tempPemFile.Name(), pemFileName)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue