mirror of https://github.com/k3s-io/k3s
Send events on ip and port allocator repair controller errors
Signed-off-by: Ferran Rodenas <rodenasf@vmware.com>pull/6/head
parent
64ccd7665f
commit
8ed0bc1250
|
@ -48,6 +48,7 @@ const kubernetesServiceName = "kubernetes"
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
ServiceClient coreclient.ServicesGetter
|
ServiceClient coreclient.ServicesGetter
|
||||||
NamespaceClient coreclient.NamespacesGetter
|
NamespaceClient coreclient.NamespacesGetter
|
||||||
|
EventClient coreclient.EventsGetter
|
||||||
|
|
||||||
ServiceClusterIPRegistry rangeallocation.RangeRegistry
|
ServiceClusterIPRegistry rangeallocation.RangeRegistry
|
||||||
ServiceClusterIPInterval time.Duration
|
ServiceClusterIPInterval time.Duration
|
||||||
|
@ -77,10 +78,11 @@ type Controller struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBootstrapController returns a controller for watching the core capabilities of the master
|
// NewBootstrapController returns a controller for watching the core capabilities of the master
|
||||||
func (c *completedConfig) NewBootstrapController(legacyRESTStorage corerest.LegacyRESTStorage, serviceClient coreclient.ServicesGetter, nsClient coreclient.NamespacesGetter) *Controller {
|
func (c *completedConfig) NewBootstrapController(legacyRESTStorage corerest.LegacyRESTStorage, serviceClient coreclient.ServicesGetter, nsClient coreclient.NamespacesGetter, eventClient coreclient.EventsGetter) *Controller {
|
||||||
return &Controller{
|
return &Controller{
|
||||||
ServiceClient: serviceClient,
|
ServiceClient: serviceClient,
|
||||||
NamespaceClient: nsClient,
|
NamespaceClient: nsClient,
|
||||||
|
EventClient: eventClient,
|
||||||
|
|
||||||
EndpointReconciler: c.ExtraConfig.EndpointReconcilerConfig.Reconciler,
|
EndpointReconciler: c.ExtraConfig.EndpointReconcilerConfig.Reconciler,
|
||||||
EndpointInterval: c.ExtraConfig.EndpointReconcilerConfig.Interval,
|
EndpointInterval: c.ExtraConfig.EndpointReconcilerConfig.Interval,
|
||||||
|
@ -124,8 +126,8 @@ func (c *Controller) Start() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repairClusterIPs := servicecontroller.NewRepair(c.ServiceClusterIPInterval, c.ServiceClient, &c.ServiceClusterIPRange, c.ServiceClusterIPRegistry)
|
repairClusterIPs := servicecontroller.NewRepair(c.ServiceClusterIPInterval, c.ServiceClient, c.EventClient, &c.ServiceClusterIPRange, c.ServiceClusterIPRegistry)
|
||||||
repairNodePorts := portallocatorcontroller.NewRepair(c.ServiceNodePortInterval, c.ServiceClient, c.ServiceNodePortRange, c.ServiceNodePortRegistry)
|
repairNodePorts := portallocatorcontroller.NewRepair(c.ServiceNodePortInterval, c.ServiceClient, c.EventClient, c.ServiceNodePortRange, c.ServiceNodePortRegistry)
|
||||||
|
|
||||||
// run all of the controllers once prior to returning from Start.
|
// run all of the controllers once prior to returning from Start.
|
||||||
if err := repairClusterIPs.RunOnce(); err != nil {
|
if err := repairClusterIPs.RunOnce(); err != nil {
|
||||||
|
|
|
@ -374,7 +374,7 @@ func (m *Master) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.
|
||||||
if c.ExtraConfig.EnableCoreControllers {
|
if c.ExtraConfig.EnableCoreControllers {
|
||||||
controllerName := "bootstrap-controller"
|
controllerName := "bootstrap-controller"
|
||||||
coreClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
|
coreClient := coreclient.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
|
||||||
bootstrapController := c.NewBootstrapController(legacyRESTStorage, coreClient, coreClient)
|
bootstrapController := c.NewBootstrapController(legacyRESTStorage, coreClient, coreClient, coreClient)
|
||||||
m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)
|
m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)
|
||||||
m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)
|
m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,18 @@ go_library(
|
||||||
srcs = ["repair.go"],
|
srcs = ["repair.go"],
|
||||||
importpath = "k8s.io/kubernetes/pkg/registry/core/service/ipallocator/controller",
|
importpath = "k8s.io/kubernetes/pkg/registry/core/service/ipallocator/controller",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/helper:go_default_library",
|
"//pkg/apis/core/helper:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
"//pkg/registry/core/rangeallocation:go_default_library",
|
"//pkg/registry/core/rangeallocation:go_default_library",
|
||||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||||
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
|
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/util/retry:go_default_library",
|
"//vendor/k8s.io/client-go/util/retry:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,11 +21,14 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/runtime"
|
"k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||||
|
@ -54,6 +57,7 @@ type Repair struct {
|
||||||
network *net.IPNet
|
network *net.IPNet
|
||||||
alloc rangeallocation.RangeRegistry
|
alloc rangeallocation.RangeRegistry
|
||||||
leaks map[string]int // counter per leaked IP
|
leaks map[string]int // counter per leaked IP
|
||||||
|
recorder record.EventRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// How many times we need to detect a leak before we clean up. This is to
|
// How many times we need to detect a leak before we clean up. This is to
|
||||||
|
@ -62,13 +66,18 @@ const numRepairsBeforeLeakCleanup = 3
|
||||||
|
|
||||||
// NewRepair creates a controller that periodically ensures that all clusterIPs are uniquely allocated across the cluster
|
// NewRepair creates a controller that periodically ensures that all clusterIPs are uniquely allocated across the cluster
|
||||||
// and generates informational warnings for a cluster that is not in sync.
|
// and generates informational warnings for a cluster that is not in sync.
|
||||||
func NewRepair(interval time.Duration, serviceClient coreclient.ServicesGetter, network *net.IPNet, alloc rangeallocation.RangeRegistry) *Repair {
|
func NewRepair(interval time.Duration, serviceClient coreclient.ServicesGetter, eventClient coreclient.EventsGetter, network *net.IPNet, alloc rangeallocation.RangeRegistry) *Repair {
|
||||||
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
|
eventBroadcaster.StartRecordingToSink(&coreclient.EventSinkImpl{Interface: eventClient.Events("")})
|
||||||
|
recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: "ipallocator-repair-controller"})
|
||||||
|
|
||||||
return &Repair{
|
return &Repair{
|
||||||
interval: interval,
|
interval: interval,
|
||||||
serviceClient: serviceClient,
|
serviceClient: serviceClient,
|
||||||
network: network,
|
network: network,
|
||||||
alloc: alloc,
|
alloc: alloc,
|
||||||
leaks: map[string]int{},
|
leaks: map[string]int{},
|
||||||
|
recorder: recorder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +145,7 @@ func (c *Repair) runOnce() error {
|
||||||
ip := net.ParseIP(svc.Spec.ClusterIP)
|
ip := net.ParseIP(svc.Spec.ClusterIP)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
// cluster IP is corrupt
|
// cluster IP is corrupt
|
||||||
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "ClusterIPNotValid", "Cluster IP %s is not a valid IP; please recreate service", svc.Spec.ClusterIP)
|
||||||
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not a valid IP; please recreate", svc.Spec.ClusterIP, svc.Name, svc.Namespace))
|
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not a valid IP; please recreate", svc.Spec.ClusterIP, svc.Name, svc.Namespace))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -147,22 +157,24 @@ func (c *Repair) runOnce() error {
|
||||||
stored.Release(ip)
|
stored.Release(ip)
|
||||||
} else {
|
} else {
|
||||||
// cluster IP doesn't seem to be allocated
|
// cluster IP doesn't seem to be allocated
|
||||||
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not allocated; repairing", svc.Spec.ClusterIP, svc.Name, svc.Namespace))
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "ClusterIPNotAllocated", "Cluster IP %s is not allocated; repairing", ip)
|
||||||
|
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not allocated; repairing", ip, svc.Name, svc.Namespace))
|
||||||
}
|
}
|
||||||
delete(c.leaks, ip.String()) // it is used, so it can't be leaked
|
delete(c.leaks, ip.String()) // it is used, so it can't be leaked
|
||||||
case ipallocator.ErrAllocated:
|
case ipallocator.ErrAllocated:
|
||||||
// TODO: send event
|
|
||||||
// cluster IP is duplicate
|
// cluster IP is duplicate
|
||||||
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "ClusterIPAlreadyAllocated", "Cluster IP %s was assigned to multiple services; please recreate service", ip)
|
||||||
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s was assigned to multiple services; please recreate", ip, svc.Name, svc.Namespace))
|
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s was assigned to multiple services; please recreate", ip, svc.Name, svc.Namespace))
|
||||||
case err.(*ipallocator.ErrNotInRange):
|
case err.(*ipallocator.ErrNotInRange):
|
||||||
// TODO: send event
|
|
||||||
// cluster IP is out of range
|
// cluster IP is out of range
|
||||||
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "ClusterIPOutOfRange", "Cluster IP %s is not within the service CIDR %s; please recreate service", ip, c.network)
|
||||||
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not within the service CIDR %s; please recreate", ip, svc.Name, svc.Namespace, c.network))
|
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s is not within the service CIDR %s; please recreate", ip, svc.Name, svc.Namespace, c.network))
|
||||||
case ipallocator.ErrFull:
|
case ipallocator.ErrFull:
|
||||||
// TODO: send event
|
|
||||||
// somehow we are out of IPs
|
// somehow we are out of IPs
|
||||||
return fmt.Errorf("the service CIDR %v is full; you must widen the CIDR in order to create new services", rebuilt)
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "ServiceCIDRFull", "Service CIDR %s is full; you must widen the CIDR in order to create new services", c.network)
|
||||||
|
return fmt.Errorf("the service CIDR %s is full; you must widen the CIDR in order to create new services", c.network)
|
||||||
default:
|
default:
|
||||||
|
c.recorder.Eventf(&svc, v1.EventTypeWarning, "UnknownError", "Unable to allocate cluster IP %s due to an unknown error", ip)
|
||||||
return fmt.Errorf("unable to allocate cluster IP %s for service %s/%s due to an unknown error, exiting: %v", ip, svc.Name, svc.Namespace, err)
|
return fmt.Errorf("unable to allocate cluster IP %s for service %s/%s due to an unknown error, exiting: %v", ip, svc.Name, svc.Namespace, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestRepair(t *testing.T) {
|
||||||
item: &api.RangeAllocation{Range: "192.168.1.0/24"},
|
item: &api.RangeAllocation{Range: "192.168.1.0/24"},
|
||||||
}
|
}
|
||||||
_, cidr, _ := net.ParseCIDR(ipregistry.item.Range)
|
_, cidr, _ := net.ParseCIDR(ipregistry.item.Range)
|
||||||
r := NewRepair(0, fakeClient.Core(), cidr, ipregistry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), cidr, ipregistry)
|
||||||
|
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -68,7 +68,7 @@ func TestRepair(t *testing.T) {
|
||||||
item: &api.RangeAllocation{Range: "192.168.1.0/24"},
|
item: &api.RangeAllocation{Range: "192.168.1.0/24"},
|
||||||
updateErr: fmt.Errorf("test error"),
|
updateErr: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
r = NewRepair(0, fakeClient.Core(), cidr, ipregistry)
|
r = NewRepair(0, fakeClient.Core(), fakeClient.Core(), cidr, ipregistry)
|
||||||
if err := r.RunOnce(); !strings.Contains(err.Error(), ": test error") {
|
if err := r.RunOnce(); !strings.Contains(err.Error(), ": test error") {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func TestRepairLeak(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r := NewRepair(0, fakeClient.Core(), cidr, ipregistry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), cidr, ipregistry)
|
||||||
// Run through the "leak detection holdoff" loops.
|
// Run through the "leak detection holdoff" loops.
|
||||||
for i := 0; i < (numRepairsBeforeLeakCleanup - 1); i++ {
|
for i := 0; i < (numRepairsBeforeLeakCleanup - 1); i++ {
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
|
@ -169,7 +169,7 @@ func TestRepairWithExisting(t *testing.T) {
|
||||||
Data: dst.Data,
|
Data: dst.Data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
r := NewRepair(0, fakeClient.Core(), cidr, ipregistry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), cidr, ipregistry)
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,19 @@ go_library(
|
||||||
srcs = ["repair.go"],
|
srcs = ["repair.go"],
|
||||||
importpath = "k8s.io/kubernetes/pkg/registry/core/service/portallocator/controller",
|
importpath = "k8s.io/kubernetes/pkg/registry/core/service/portallocator/controller",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
"//pkg/registry/core/rangeallocation:go_default_library",
|
"//pkg/registry/core/rangeallocation:go_default_library",
|
||||||
"//pkg/registry/core/service:go_default_library",
|
"//pkg/registry/core/service:go_default_library",
|
||||||
"//pkg/registry/core/service/portallocator:go_default_library",
|
"//pkg/registry/core/service/portallocator:go_default_library",
|
||||||
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
|
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/util/retry:go_default_library",
|
"//vendor/k8s.io/client-go/util/retry:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,12 +20,15 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/net"
|
"k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/runtime"
|
"k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/registry/core/rangeallocation"
|
"k8s.io/kubernetes/pkg/registry/core/rangeallocation"
|
||||||
|
@ -40,6 +43,7 @@ type Repair struct {
|
||||||
portRange net.PortRange
|
portRange net.PortRange
|
||||||
alloc rangeallocation.RangeRegistry
|
alloc rangeallocation.RangeRegistry
|
||||||
leaks map[int]int // counter per leaked port
|
leaks map[int]int // counter per leaked port
|
||||||
|
recorder record.EventRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// How many times we need to detect a leak before we clean up. This is to
|
// How many times we need to detect a leak before we clean up. This is to
|
||||||
|
@ -48,13 +52,18 @@ const numRepairsBeforeLeakCleanup = 3
|
||||||
|
|
||||||
// NewRepair creates a controller that periodically ensures that all ports are uniquely allocated across the cluster
|
// NewRepair creates a controller that periodically ensures that all ports are uniquely allocated across the cluster
|
||||||
// and generates informational warnings for a cluster that is not in sync.
|
// and generates informational warnings for a cluster that is not in sync.
|
||||||
func NewRepair(interval time.Duration, serviceClient coreclient.ServicesGetter, portRange net.PortRange, alloc rangeallocation.RangeRegistry) *Repair {
|
func NewRepair(interval time.Duration, serviceClient coreclient.ServicesGetter, eventClient coreclient.EventsGetter, portRange net.PortRange, alloc rangeallocation.RangeRegistry) *Repair {
|
||||||
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
|
eventBroadcaster.StartRecordingToSink(&coreclient.EventSinkImpl{Interface: eventClient.Events("")})
|
||||||
|
recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: "portallocator-repair-controller"})
|
||||||
|
|
||||||
return &Repair{
|
return &Repair{
|
||||||
interval: interval,
|
interval: interval,
|
||||||
serviceClient: serviceClient,
|
serviceClient: serviceClient,
|
||||||
portRange: portRange,
|
portRange: portRange,
|
||||||
alloc: alloc,
|
alloc: alloc,
|
||||||
leaks: map[int]int{},
|
leaks: map[int]int{},
|
||||||
|
recorder: recorder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,22 +139,24 @@ func (c *Repair) runOnce() error {
|
||||||
stored.Release(port)
|
stored.Release(port)
|
||||||
} else {
|
} else {
|
||||||
// doesn't seem to be allocated
|
// doesn't seem to be allocated
|
||||||
|
c.recorder.Eventf(svc, v1.EventTypeWarning, "PortNotAllocated", "Port %d is not allocated; repairing", port)
|
||||||
runtime.HandleError(fmt.Errorf("the node port %d for service %s/%s is not allocated; repairing", port, svc.Name, svc.Namespace))
|
runtime.HandleError(fmt.Errorf("the node port %d for service %s/%s is not allocated; repairing", port, svc.Name, svc.Namespace))
|
||||||
}
|
}
|
||||||
delete(c.leaks, port) // it is used, so it can't be leaked
|
delete(c.leaks, port) // it is used, so it can't be leaked
|
||||||
case portallocator.ErrAllocated:
|
case portallocator.ErrAllocated:
|
||||||
// TODO: send event
|
|
||||||
// port is duplicate, reallocate
|
// port is duplicate, reallocate
|
||||||
|
c.recorder.Eventf(svc, v1.EventTypeWarning, "PortAlreadyAllocated", "Port %d was assigned to multiple services; please recreate service", port)
|
||||||
runtime.HandleError(fmt.Errorf("the node port %d for service %s/%s was assigned to multiple services; please recreate", port, svc.Name, svc.Namespace))
|
runtime.HandleError(fmt.Errorf("the node port %d for service %s/%s was assigned to multiple services; please recreate", port, svc.Name, svc.Namespace))
|
||||||
case err.(*portallocator.ErrNotInRange):
|
case err.(*portallocator.ErrNotInRange):
|
||||||
// TODO: send event
|
|
||||||
// port is out of range, reallocate
|
// port is out of range, reallocate
|
||||||
runtime.HandleError(fmt.Errorf("the port %d for service %s/%s is not within the port range %v; please recreate", port, svc.Name, svc.Namespace, c.portRange))
|
c.recorder.Eventf(svc, v1.EventTypeWarning, "PortOutOfRange", "Port %d is not within the port range %s; please recreate service", port, c.portRange)
|
||||||
|
runtime.HandleError(fmt.Errorf("the port %d for service %s/%s is not within the port range %s; please recreate", port, svc.Name, svc.Namespace, c.portRange))
|
||||||
case portallocator.ErrFull:
|
case portallocator.ErrFull:
|
||||||
// TODO: send event
|
|
||||||
// somehow we are out of ports
|
// somehow we are out of ports
|
||||||
return fmt.Errorf("the port range %v is full; you must widen the port range in order to create new services", c.portRange)
|
c.recorder.Eventf(svc, v1.EventTypeWarning, "PortRangeFull", "Port range %s is full; you must widen the port range in order to create new services", c.portRange)
|
||||||
|
return fmt.Errorf("the port range %s is full; you must widen the port range in order to create new services", c.portRange)
|
||||||
default:
|
default:
|
||||||
|
c.recorder.Eventf(svc, v1.EventTypeWarning, "UnknownError", "Unable to allocate port %d due to an unknown error", port)
|
||||||
return fmt.Errorf("unable to allocate port %d for service %s/%s due to an unknown error, exiting: %v", port, svc.Name, svc.Namespace, err)
|
return fmt.Errorf("unable to allocate port %d for service %s/%s due to an unknown error, exiting: %v", port, svc.Name, svc.Namespace, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestRepair(t *testing.T) {
|
||||||
item: &api.RangeAllocation{Range: "100-200"},
|
item: &api.RangeAllocation{Range: "100-200"},
|
||||||
}
|
}
|
||||||
pr, _ := net.ParsePortRange(registry.item.Range)
|
pr, _ := net.ParsePortRange(registry.item.Range)
|
||||||
r := NewRepair(0, fakeClient.Core(), *pr, registry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), *pr, registry)
|
||||||
|
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -68,7 +68,7 @@ func TestRepair(t *testing.T) {
|
||||||
item: &api.RangeAllocation{Range: "100-200"},
|
item: &api.RangeAllocation{Range: "100-200"},
|
||||||
updateErr: fmt.Errorf("test error"),
|
updateErr: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
r = NewRepair(0, fakeClient.Core(), *pr, registry)
|
r = NewRepair(0, fakeClient.Core(), fakeClient.Core(), *pr, registry)
|
||||||
if err := r.RunOnce(); !strings.Contains(err.Error(), ": test error") {
|
if err := r.RunOnce(); !strings.Contains(err.Error(), ": test error") {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ func TestRepairLeak(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
r := NewRepair(0, fakeClient.Core(), *pr, registry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), *pr, registry)
|
||||||
// Run through the "leak detection holdoff" loops.
|
// Run through the "leak detection holdoff" loops.
|
||||||
for i := 0; i < (numRepairsBeforeLeakCleanup - 1); i++ {
|
for i := 0; i < (numRepairsBeforeLeakCleanup - 1); i++ {
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
|
@ -175,7 +175,7 @@ func TestRepairWithExisting(t *testing.T) {
|
||||||
Data: dst.Data,
|
Data: dst.Data,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
r := NewRepair(0, fakeClient.Core(), *pr, registry)
|
r := NewRepair(0, fakeClient.Core(), fakeClient.Core(), *pr, registry)
|
||||||
if err := r.RunOnce(); err != nil {
|
if err := r.RunOnce(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue