Merge pull request #681 from aledbf/add-lb-status

Update Ingress status information in nginx controller
This commit is contained in:
Prashanth B 2016-04-01 12:00:42 -07:00
commit f22e6d2690
15 changed files with 269 additions and 21 deletions

View file

@ -230,4 +230,4 @@ The previous behavior can be restored using `retry-non-idempotent=true` in the c
## Limitations ## Limitations
TODO - Ingress rules for TLS require the definition of the field `host`

View file

@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/record"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/controller/framework" "k8s.io/kubernetes/pkg/controller/framework"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
@ -64,8 +65,14 @@ type loadBalancerController struct {
tcpConfigMap string tcpConfigMap string
udpConfigMap string udpConfigMap string
recorder record.EventRecorder
syncQueue *taskQueue syncQueue *taskQueue
// taskQueue used to update the status of the Ingress rules.
// this avoids a sync execution in the ResourceEventHandlerFuncs
ingQueue *taskQueue
// stopLock is used to enforce only a single call to Stop is active. // stopLock is used to enforce only a single call to Stop is active.
// Needed because we allow stopping through an http endpoint and // Needed because we allow stopping through an http endpoint and
// allowing concurrent stoppers leads to stack traces. // allowing concurrent stoppers leads to stack traces.
@ -77,6 +84,11 @@ type loadBalancerController struct {
// newLoadBalancerController creates a controller for nginx loadbalancer // newLoadBalancerController creates a controller for nginx loadbalancer
func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Duration, defaultSvc, func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Duration, defaultSvc,
namespace, nxgConfigMapName, tcpConfigMapName, udpConfigMapName string, lbRuntimeInfo *lbInfo) (*loadBalancerController, error) { namespace, nxgConfigMapName, tcpConfigMapName, udpConfigMapName string, lbRuntimeInfo *lbInfo) (*loadBalancerController, error) {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof)
eventBroadcaster.StartRecordingToSink(kubeClient.Events(""))
lbc := loadBalancerController{ lbc := loadBalancerController{
client: kubeClient, client: kubeClient,
stopCh: make(chan struct{}), stopCh: make(chan struct{}),
@ -86,9 +98,33 @@ func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Dura
tcpConfigMap: tcpConfigMapName, tcpConfigMap: tcpConfigMapName,
udpConfigMap: udpConfigMapName, udpConfigMap: udpConfigMapName,
defaultSvc: defaultSvc, defaultSvc: defaultSvc,
recorder: eventBroadcaster.NewRecorder(api.EventSource{Component: "loadbalancer-controller"}),
} }
lbc.syncQueue = NewTaskQueue(lbc.sync) lbc.syncQueue = NewTaskQueue(lbc.sync)
lbc.ingQueue = NewTaskQueue(lbc.updateIngressStatus)
ingEventHandler := framework.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
addIng := obj.(*extensions.Ingress)
lbc.recorder.Eventf(addIng, api.EventTypeNormal, "CREATE", fmt.Sprintf("%s/%s", addIng.Namespace, addIng.Name))
lbc.ingQueue.enqueue(obj)
lbc.syncQueue.enqueue(obj)
},
DeleteFunc: func(obj interface{}) {
upIng := obj.(*extensions.Ingress)
lbc.recorder.Eventf(upIng, api.EventTypeNormal, "DELETE", fmt.Sprintf("%s/%s", upIng.Namespace, upIng.Name))
lbc.syncQueue.enqueue(obj)
},
UpdateFunc: func(old, cur interface{}) {
if !reflect.DeepEqual(old, cur) {
upIng := cur.(*extensions.Ingress)
lbc.recorder.Eventf(upIng, api.EventTypeNormal, "UPDATE", fmt.Sprintf("%s/%s", upIng.Namespace, upIng.Name))
lbc.ingQueue.enqueue(cur)
lbc.syncQueue.enqueue(cur)
}
},
}
eventHandler := framework.ResourceEventHandlerFuncs{ eventHandler := framework.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { AddFunc: func(obj interface{}) {
@ -109,7 +145,7 @@ func newLoadBalancerController(kubeClient *client.Client, resyncPeriod time.Dura
ListFunc: ingressListFunc(lbc.client, namespace), ListFunc: ingressListFunc(lbc.client, namespace),
WatchFunc: ingressWatchFunc(lbc.client, namespace), WatchFunc: ingressWatchFunc(lbc.client, namespace),
}, },
&extensions.Ingress{}, resyncPeriod, eventHandler) &extensions.Ingress{}, resyncPeriod, ingEventHandler)
lbc.endpLister.Store, lbc.endpController = framework.NewInformer( lbc.endpLister.Store, lbc.endpController = framework.NewInformer(
&cache.ListWatch{ &cache.ListWatch{
@ -206,6 +242,57 @@ func (lbc *loadBalancerController) sync(key string) {
}) })
} }
func (lbc *loadBalancerController) updateIngressStatus(key string) {
if !lbc.controllersInSync() {
lbc.ingQueue.requeue(key, fmt.Errorf("deferring sync till endpoints controller has synced"))
return
}
obj, ingExists, err := lbc.ingLister.Store.GetByKey(key)
if err != nil {
lbc.ingQueue.requeue(key, err)
return
}
if !ingExists {
return
}
ing := obj.(*extensions.Ingress)
ingClient := lbc.client.Extensions().Ingress(ing.Namespace)
currIng, err := ingClient.Get(ing.Name)
if err != nil {
glog.Errorf("unexpected error searching Ingress %v/%v: %v", ing.Namespace, ing.Name, err)
return
}
lbIPs := ing.Status.LoadBalancer.Ingress
if !lbc.isStatusIPDefined(lbIPs) {
glog.Infof("Updating loadbalancer %v/%v with IP %v", ing.Namespace, ing.Name, lbc.lbInfo.Address)
currIng.Status.LoadBalancer.Ingress = append(currIng.Status.LoadBalancer.Ingress, api.LoadBalancerIngress{
IP: lbc.lbInfo.Address,
})
if _, err := ingClient.UpdateStatus(currIng); err != nil {
lbc.recorder.Eventf(currIng, api.EventTypeWarning, "UPDATE", "error: %v", err)
return
}
lbc.recorder.Eventf(currIng, api.EventTypeNormal, "CREATE", "ip: %v", lbc.lbInfo.Address)
}
}
func (lbc *loadBalancerController) isStatusIPDefined(lbings []api.LoadBalancerIngress) bool {
for _, lbing := range lbings {
if lbing.IP == lbc.lbInfo.Address {
return true
}
}
return false
}
func (lbc *loadBalancerController) getTCPServices() []*nginx.Location { func (lbc *loadBalancerController) getTCPServices() []*nginx.Location {
if lbc.tcpConfigMap == "" { if lbc.tcpConfigMap == "" {
// no configmap for TCP services // no configmap for TCP services
@ -505,10 +592,14 @@ func (lbc *loadBalancerController) getPemsFromIngress(data []interface{}) map[st
continue continue
} }
pemFileName := lbc.nginx.AddOrUpdateCertAndKey(secretName, string(cert), string(key)) pemFileName, err := lbc.nginx.AddOrUpdateCertAndKey(fmt.Sprintf("%v-%v", ing.Namespace, secretName), string(cert), string(key))
if err != nil {
glog.Errorf("No valid SSL certificate found in secret %v: %v", secretName, err)
continue
}
cn, err := lbc.nginx.CheckSSLCertificate(pemFileName) cn, err := lbc.nginx.CheckSSLCertificate(pemFileName)
if err != nil { if err != nil {
glog.Warningf("No valid SSL certificate found in secret %v", secretName) glog.Errorf("No valid SSL certificate found in secret %v: %v", secretName, err)
continue continue
} }
@ -571,17 +662,59 @@ func (lbc *loadBalancerController) getEndpoints(s *api.Service, servicePort ints
} }
// Stop stops the loadbalancer controller. // Stop stops the loadbalancer controller.
func (lbc *loadBalancerController) Stop() { func (lbc *loadBalancerController) Stop() error {
// Stop is invoked from the http endpoint. // Stop is invoked from the http endpoint.
lbc.stopLock.Lock() lbc.stopLock.Lock()
defer lbc.stopLock.Unlock() defer lbc.stopLock.Unlock()
// Only try draining the workqueue if we haven't already. // Only try draining the workqueue if we haven't already.
if !lbc.shutdown { if !lbc.shutdown {
lbc.removeFromIngress()
close(lbc.stopCh) close(lbc.stopCh)
glog.Infof("shutting down controller queues") glog.Infof("shutting down controller queues")
lbc.shutdown = true lbc.shutdown = true
lbc.syncQueue.shutdown() lbc.syncQueue.shutdown()
return nil
}
return fmt.Errorf("shutdown already in progress")
}
func (lbc *loadBalancerController) removeFromIngress() {
ings := lbc.ingLister.Store.List()
glog.Infof("updating %v Ingress rule/s", len(ings))
for _, cur := range ings {
ing := cur.(*extensions.Ingress)
ingClient := lbc.client.Extensions().Ingress(ing.Namespace)
currIng, err := ingClient.Get(ing.Name)
if err != nil {
glog.Errorf("unexpected error searching Ingress %v/%v: %v", ing.Namespace, ing.Name, err)
continue
}
lbIPs := ing.Status.LoadBalancer.Ingress
if len(lbIPs) > 0 && lbc.isStatusIPDefined(lbIPs) {
glog.Infof("Updating loadbalancer %v/%v. Removing IP %v", ing.Namespace, ing.Name, lbc.lbInfo.Address)
for idx, lbStatus := range currIng.Status.LoadBalancer.Ingress {
if lbStatus.IP == lbc.lbInfo.Address {
currIng.Status.LoadBalancer.Ingress = append(currIng.Status.LoadBalancer.Ingress[:idx],
currIng.Status.LoadBalancer.Ingress[idx+1:]...)
break
}
}
if _, err := ingClient.UpdateStatus(currIng); err != nil {
lbc.recorder.Eventf(currIng, api.EventTypeWarning, "UPDATE", "error: %v", err)
continue
}
lbc.recorder.Eventf(currIng, api.EventTypeNormal, "DELETE", "ip: %v", lbc.lbInfo.Address)
}
} }
} }
@ -595,6 +728,7 @@ func (lbc *loadBalancerController) Run() {
go lbc.svcController.Run(lbc.stopCh) go lbc.svcController.Run(lbc.stopCh)
go lbc.syncQueue.run(time.Second, lbc.stopCh) go lbc.syncQueue.run(time.Second, lbc.stopCh)
go lbc.ingQueue.run(time.Second, lbc.stopCh)
<-lbc.stopCh <-lbc.stopCh
glog.Infof("shutting down NGINX loadbalancer controller") glog.Infof("shutting down NGINX loadbalancer controller")

View file

@ -14,8 +14,9 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -8,8 +8,9 @@ spec:
labels: labels:
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -11,7 +11,7 @@ spec:
labels: labels:
app: default-http-backend app: default-http-backend
spec: spec:
terminationGracePeriodSeconds: 600 terminationGracePeriodSeconds: 60
containers: containers:
- name: default-http-backend - name: default-http-backend
# Any image is permissable as long as: # Any image is permissable as long as:

View file

@ -14,8 +14,9 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -15,12 +15,13 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
volumes: volumes:
- name: dhparam-example - name: dhparam-example
secret: secret:
secretName: dhparam-example secretName: dhparam-example
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -14,8 +14,9 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -14,8 +14,9 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: gcr.io/google_containers/nginx-ingress-controller:0.4 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -14,8 +14,9 @@ spec:
k8s-app: nginx-ingress-lb k8s-app: nginx-ingress-lb
name: nginx-ingress-lb name: nginx-ingress-lb
spec: spec:
terminationGracePeriodSeconds: 60
containers: containers:
- image: aledbf/nginx-third-party:0.9 - image: gcr.io/google_containers/nginx-ingress-controller:0.5
name: nginx-ingress-lb name: nginx-ingress-lb
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:

View file

@ -22,6 +22,8 @@ import (
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
"os" "os"
"os/signal"
"syscall"
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
@ -32,7 +34,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/healthz" "k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/runtime"
) )
const ( const (
@ -111,6 +112,7 @@ func main() {
} }
go registerHandlers(lbc) go registerHandlers(lbc)
go handleSigterm(lbc)
lbc.Run() lbc.Run()
@ -122,11 +124,10 @@ func main() {
// lbInfo contains runtime information about the pod // lbInfo contains runtime information about the pod
type lbInfo struct { type lbInfo struct {
ObjectName string
DeployType runtime.Object
Podname string Podname string
PodIP string PodIP string
PodNamespace string PodNamespace string
Address string
} }
func registerHandlers(lbc *loadBalancerController) { func registerHandlers(lbc *loadBalancerController) {
@ -149,3 +150,18 @@ func registerHandlers(lbc *loadBalancerController) {
} }
glog.Fatal(server.ListenAndServe()) glog.Fatal(server.ListenAndServe())
} }
func handleSigterm(lbc *loadBalancerController) {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM)
<-signalChan
glog.Infof("Received SIGTERM, shutting down")
exitCode := 0
if err := lbc.Stop(); err != nil {
glog.Infof("Error during shutdown %v", err)
exitCode = 1
}
glog.Infof("Exiting with %v", exitCode)
os.Exit(exitCode)
}

View file

@ -77,7 +77,9 @@ const (
// Size of the SSL shared cache between all worker processes. // Size of the SSL shared cache between all worker processes.
// http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache // http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache
sslSessionCacheSize = "10m" sslSessionCacheSize = "10m"
)
var (
// Base directory that contains the mounted secrets with SSL certificates, keys and // Base directory that contains the mounted secrets with SSL certificates, keys and
sslDirectory = "/etc/nginx-ssl" sslDirectory = "/etc/nginx-ssl"
) )

View file

@ -27,21 +27,21 @@ import (
) )
// AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name // AddOrUpdateCertAndKey creates a .pem file wth the cert and the key with the specified name
func (nginx *Manager) AddOrUpdateCertAndKey(name string, cert string, key string) string { func (nginx *Manager) AddOrUpdateCertAndKey(name string, cert string, key string) (string, error) {
pemFileName := sslDirectory + "/" + name + ".pem" pemFileName := sslDirectory + "/" + name + ".pem"
pem, err := os.Create(pemFileName) pem, err := os.Create(pemFileName)
if err != nil { if err != nil {
glog.Fatalf("Couldn't create pem file %v: %v", pemFileName, err) return "", fmt.Errorf("Couldn't create pem file %v: %v", pemFileName, err)
} }
defer pem.Close() defer pem.Close()
_, err = pem.WriteString(fmt.Sprintf("%v\n%v", key, cert)) _, err = pem.WriteString(fmt.Sprintf("%v\n%v", cert, key))
if err != nil { if err != nil {
glog.Fatalf("Couldn't write to pem file %v: %v", pemFileName, err) return "", fmt.Errorf("Couldn't write to pem file %v: %v", pemFileName, err)
} }
return pemFileName return pemFileName, nil
} }
// CheckSSLCertificate checks if the certificate and key file are valid // CheckSSLCertificate checks if the certificate and key file are valid

View file

@ -0,0 +1,68 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 nginx
import (
"encoding/base64"
"fmt"
"os"
"testing"
"time"
)
func TestAddOrUpdateCertAndKey(t *testing.T) {
sslDirectory = os.TempDir()
// openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=echoheaders/O=echoheaders"
tlsCrt := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURhakNDQWxLZ0F3SUJBZ0lKQUxHUXR5VVBKTFhYTUEwR0NTcUdTSWIzRFFFQkJRVUFNQ3d4RkRBU0JnTlYKQkFNVEMyVmphRzlvWldGa1pYSnpNUlF3RWdZRFZRUUtFd3RsWTJodmFHVmhaR1Z5Y3pBZUZ3MHhOakF6TXpFeQpNekU1TkRoYUZ3MHhOekF6TXpFeU16RTVORGhhTUN3eEZEQVNCZ05WQkFNVEMyVmphRzlvWldGa1pYSnpNUlF3CkVnWURWUVFLRXd0bFkyaHZhR1ZoWkdWeWN6Q0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0MKZ2dFQkFONzVmS0N5RWwxanFpMjUxTlNabDYzeGQweG5HMHZTVjdYL0xxTHJveVNraW5nbnI0NDZZWlE4UEJWOAo5TUZzdW5RRGt1QVoyZzA3NHM1YWhLSm9BRGJOMzhld053RXNsVDJkRzhRTUw0TktrTUNxL1hWbzRQMDFlWG1PCmkxR2txZFA1ZUExUHlPZCtHM3gzZmxPN2xOdmtJdHVHYXFyc0tvMEhtMHhqTDVtRUpwWUlOa0tGSVhsWWVLZS8KeHRDR25CU2tLVHFMTG0yeExKSGFFcnJpaDZRdkx4NXF5U2gzZTU2QVpEcTlkTERvcWdmVHV3Z2IzekhQekc2NwppZ0E0dkYrc2FRNHpZUE1NMHQyU1NiVkx1M2pScWNvL3lxZysrOVJBTTV4bjRubnorL0hUWFhHKzZ0RDBaeGI1CmVVRDNQakVhTnlXaUV2dTN6UFJmdysyNURMY0NBd0VBQWFPQmpqQ0JpekFkQmdOVkhRNEVGZ1FVcktMZFhHeUUKNUlEOGRvd2lZNkdzK3dNMHFKc3dYQVlEVlIwakJGVXdVNEFVcktMZFhHeUU1SUQ4ZG93aVk2R3Mrd00wcUp1aApNS1F1TUN3eEZEQVNCZ05WQkFNVEMyVmphRzlvWldGa1pYSnpNUlF3RWdZRFZRUUtFd3RsWTJodmFHVmhaR1Z5CmM0SUpBTEdRdHlVUEpMWFhNQXdHQTFVZEV3UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUZCUUFEZ2dFQkFNZVMKMHFia3VZa3Z1enlSWmtBeE1PdUFaSDJCK0Evb3N4ODhFRHB1ckV0ZWN5RXVxdnRvMmpCSVdCZ2RkR3VBYU5jVQorUUZDRm9NakJOUDVWVUxIWVhTQ3VaczN2Y25WRDU4N3NHNlBaLzhzbXJuYUhTUjg1ZVpZVS80bmFyNUErdWErClIvMHJrSkZnOTlQSmNJd3JmcWlYOHdRcWdJVVlLNE9nWEJZcUJRL0VZS2YvdXl6UFN3UVZYRnVJTTZTeDBXcTYKTUNML3d2RlhLS0FaWDBqb3J4cHRjcldkUXNCcmYzWVRnYmx4TE1sN20zL2VuR1drcEhDUHdYeVRCOC9rRkw3SApLL2ZHTU1NWGswUkVSbGFPM1hTSUhrZUQ2SXJiRnRNV3R1RlJwZms2ZFA2TXlMOHRmTmZ6a3VvUHVEWUFaWllWCnR1NnZ0c0FRS0xWb0pGaGV0b1k9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
tlsKey := "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBM3ZsOG9MSVNYV09xTGJuVTFKbVhyZkYzVEdjYlM5Slh0Zjh1b3V1akpLU0tlQ2V2CmpqcGhsRHc4Rlh6MHdXeTZkQU9TNEJuYURUdml6bHFFb21nQU5zM2Z4N0EzQVN5VlBaMGJ4QXd2ZzBxUXdLcjkKZFdqZy9UVjVlWTZMVWFTcDAvbDREVS9JNTM0YmZIZCtVN3VVMitRaTI0WnFxdXdxalFlYlRHTXZtWVFtbGdnMgpRb1VoZVZoNHA3L0cwSWFjRktRcE9vc3ViYkVza2RvU3V1S0hwQzh2SG1ySktIZDdub0JrT3IxMHNPaXFCOU83CkNCdmZNYy9NYnJ1S0FEaThYNnhwRGpOZzh3elMzWkpKdFV1N2VOR3B5ai9LcUQ3NzFFQXpuR2ZpZWZQNzhkTmQKY2I3cTBQUm5Gdmw1UVBjK01SbzNKYUlTKzdmTTlGL0Q3YmtNdHdJREFRQUJBb0lCQUViNmFEL0hMNjFtMG45bgp6bVkyMWwvYW83MUFmU0h2dlZnRCtWYUhhQkY4QjFBa1lmQUdpWlZrYjBQdjJRSFJtTERoaWxtb0lROWhadHVGCldQOVIxKythTFlnbGdmenZzanBBenR2amZTUndFaEFpM2pnSHdNY1p4S2Q3UnNJZ2hxY2huS093S0NYNHNNczQKUnBCbEFBZlhZWGs4R3F4NkxUbGptSDRDZk42QzZHM1EwTTlLMUxBN2lsck1Na3hwcngxMnBlVTNkczZMVmNpOQptOFdBL21YZ2I0c3pEbVNaWVpYRmNZMEhYNTgyS3JKRHpQWEVJdGQwZk5wd3I0eFIybzdzMEwvK2RnZCtqWERjCkh2SDBKZ3NqODJJaTIxWGZGM2tST3FxR3BKNmhVcncxTUZzVWRyZ29GL3pFck0vNWZKMDdVNEhodGFlalVzWTIKMFJuNXdpRUNnWUVBKzVUTVRiV084Wkg5K2pIdVQwc0NhZFBYcW50WTZYdTZmYU04Tm5CZWNoeTFoWGdlQVN5agpSWERlZGFWM1c0SjU5eWxIQ3FoOVdseVh4cDVTWWtyQU41RnQ3elFGYi91YmorUFIyWWhMTWZpYlBSYlYvZW1MCm5YaGF6MmtlNUUxT1JLY0x6QUVwSmpuZGQwZlZMZjdmQzFHeStnS2YyK3hTY1hjMHJqRE5iNGtDZ1lFQTR1UVEKQk91TlJQS3FKcDZUZS9zUzZrZitHbEpjQSs3RmVOMVlxM0E2WEVZVm9ydXhnZXQ4a2E2ZEo1QjZDOWtITGtNcQpwdnFwMzkxeTN3YW5uWC9ONC9KQlU2M2RxZEcyd1BWRUQ0REduaE54Qm1oaWZpQ1I0R0c2ZnE4MUV6ZE1vcTZ4CklTNHA2RVJaQnZkb1RqNk9pTHl6aUJMckpxeUhIMWR6c0hGRlNqOENnWUVBOWlSSEgyQ2JVazU4SnVYak8wRXcKUTBvNG4xdS9TZkQ4TFNBZ01VTVBwS1hpRTR2S0Qyd1U4a1BUNDFiWXlIZUh6UUpkdDFmU0RTNjZjR0ZHU1ZUSgphNVNsOG5yN051ejg3bkwvUmMzTGhFQ3Y0YjBOOFRjbW1oSy9CbDdiRXBOd0dFczNoNGs3TVdNOEF4QU15c3VxCmZmQ1pJM0tkNVJYNk0zbGwyV2QyRjhFQ2dZQlQ5RU9oTG0vVmhWMUVjUVR0cVZlMGJQTXZWaTVLSGozZm5UZkUKS0FEUVIvYVZncElLR3RLN0xUdGxlbVpPbi8yeU5wUS91UnpHZ3pDUUtldzNzU1RFSmMzYVlzbFVudzdhazJhZAp2ZTdBYXowMU84YkdHTk1oamNmdVBIS05LN2Nsc3pKRHJzcys4SnRvb245c0JHWEZYdDJuaWlpTTVPWVN5TTg4CkNJMjFEUUtCZ0hEQVRZbE84UWlDVWFBQlVqOFBsb1BtMDhwa3cyc1VmQW0xMzJCY00wQk9BN1hqYjhtNm1ManQKOUlteU5kZ2ZiM080UjlKVUxTb1pZSTc1dUxIL3k2SDhQOVlpWHZOdzMrTXl6VFU2b2d1YU8xSTNya2pna29NeAo5cU5pYlJFeGswS1A5MVZkckVLSEdHZEFwT05ES1N4VzF3ektvbUxHdmtYSTVKV05KRXFkCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg=="
dCrt, err := base64.StdEncoding.DecodeString(tlsCrt)
if err != nil {
t.Fatalf("Unexpected error: %+v", err)
return
}
dKey, err := base64.StdEncoding.DecodeString(tlsKey)
if err != nil {
t.Fatalf("Unexpected error: %+v", err)
}
ngx := &Manager{}
name := fmt.Sprintf("test-%v", time.Now().UnixNano())
pemPath, err := ngx.AddOrUpdateCertAndKey(name, string(dCrt), string(dKey))
if err != nil {
t.Fatalf("unexpected error checking SSL certificate: %v", err)
}
if pemPath == "" {
t.Fatalf("expected path to pem file but returned empty")
}
cnames, err := ngx.CheckSSLCertificate(pemPath)
if err != nil {
t.Fatalf("unexpected error checking SSL certificate: %v", err)
}
if len(cnames) == 0 {
t.Fatalf("expected at least one cname but none returned")
}
if cnames[0] != "echoheaders" {
t.Fatalf("expected cname echoheaders but %v returned", cnames[0])
}
}

View file

@ -24,6 +24,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/cache" "k8s.io/kubernetes/pkg/client/cache"
"k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
@ -108,10 +109,30 @@ func getLBDetails(kubeClient *unversioned.Client) (*lbInfo, error) {
return nil, fmt.Errorf("Unable to get POD information") return nil, fmt.Errorf("Unable to get POD information")
} }
node, err := kubeClient.Nodes().Get(pod.Spec.NodeName)
if err != nil {
return nil, err
}
var externalIP string
for _, address := range node.Status.Addresses {
if address.Type == api.NodeExternalIP {
if address.Address != "" {
externalIP = address.Address
break
}
}
if externalIP == "" && address.Type == api.NodeLegacyHostIP {
externalIP = address.Address
}
}
return &lbInfo{ return &lbInfo{
PodIP: podIP, PodIP: podIP,
Podname: podName, Podname: podName,
PodNamespace: podNs, PodNamespace: podNs,
Address: externalIP,
}, nil }, nil
} }