Update Ingress status information in nginx controller
This commit is contained in:
parent
7abc7a77f6
commit
2632fe566b
3 changed files with 148 additions and 5 deletions
|
@ -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,6 +65,8 @@ type loadBalancerController struct {
|
||||||
tcpConfigMap string
|
tcpConfigMap string
|
||||||
udpConfigMap string
|
udpConfigMap string
|
||||||
|
|
||||||
|
recorder record.EventRecorder
|
||||||
|
|
||||||
syncQueue *taskQueue
|
syncQueue *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.
|
||||||
|
@ -77,6 +80,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,10 +94,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)
|
||||||
|
|
||||||
|
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.updateIngressStatus(addIng)
|
||||||
|
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.updateIngressStatus(upIng)
|
||||||
|
lbc.syncQueue.enqueue(cur)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
eventHandler := framework.ResourceEventHandlerFuncs{
|
eventHandler := framework.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
lbc.syncQueue.enqueue(obj)
|
lbc.syncQueue.enqueue(obj)
|
||||||
|
@ -109,7 +140,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 +237,39 @@ func (lbc *loadBalancerController) sync(key string) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lbc *loadBalancerController) updateIngressStatus(ing *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 len(lbIPs) > 0 && !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
|
||||||
|
@ -571,17 +635,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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue