returnfmt.Errorf("unable to refresh the service IP block: %v",err)
}
r:=ipallocator.NewCIDRRange(c.network)
rebuilt:=ipallocator.NewCIDRRange(c.network)
// Check every Service's ClusterIP, and rebuild the state as we think it should be.
for_,svc:=rangelist.Items{
if!api.IsServiceIPSet(&svc){
// didn't need a cluster IP
continue
}
ip:=net.ParseIP(svc.Spec.ClusterIP)
ifip==nil{
// cluster IP is broken, reallocate
// cluster IP is corrupt
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
}
switcherr:=r.Allocate(ip);err{
// mark it as in-use
switcherr:=rebuilt.Allocate(ip);err{
casenil:
ifstored.Has(ip){
// remove it from the old set, so we can find leaks
stored.Release(ip)
}else{
// 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))
}
delete(c.leaks,ip.String())// it is used, so it can't be leaked
caseipallocator.ErrAllocated:
// TODO: send event
// cluster IP is broken, reallocate
// cluster IP is duplicate
runtime.HandleError(fmt.Errorf("the cluster IP %s for service %s/%s was assigned to multiple services; please recreate",ip,svc.Name,svc.Namespace))
caseipallocator.ErrNotInRange:
// TODO: send event
// cluster IP is broken, reallocate
// cluster IP is out of range
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))
caseipallocator.ErrFull:
// TODO: send event
returnfmt.Errorf("the service CIDR %v is full; you must widen the CIDR in order to create new services",r)
// somehow we are out of IPs
returnfmt.Errorf("the service CIDR %v is full; you must widen the CIDR in order to create new services",rebuilt)
default:
returnfmt.Errorf("unable to allocate cluster IP %s for service %s/%s due to an unknown error, exiting: %v",ip,svc.Name,svc.Namespace,err)
}
}
iferr:=r.Snapshot(latest);err!=nil{
returnfmt.Errorf("unable to snapshot the updated service IP allocations: %v",err)
// Check for IPs that are left in the old set. They appear to have been leaked.
stored.ForEach(func(ipnet.IP){
count,found:=c.leaks[ip.String()]
switch{
case!found:
// flag it to be cleaned up after any races (hopefully) are gone
runtime.HandleError(fmt.Errorf("the cluster IP %s may have leaked: flagging for later clean up",ip))
count=numRepairsBeforeLeakCleanup-1
fallthrough
casecount>0:
// pretend it is still in use until count expires
c.leaks[ip.String()]=count-1
iferr:=rebuilt.Allocate(ip);err!=nil{
runtime.HandleError(fmt.Errorf("the cluster IP %s may have leaked, but can not be allocated: %v",ip,err))
}
default:
// do not add it to the rebuilt set, which means it will be available for reuse
runtime.HandleError(fmt.Errorf("the cluster IP %s appears to have leaked: cleaning up",ip))
}
})
iferr:=c.alloc.CreateOrUpdate(latest);err!=nil{
// Blast the rebuilt state into storage.
iferr:=rebuilt.Snapshot(snapshot);err!=nil{
returnfmt.Errorf("unable to snapshot the updated service IP allocations: %v",err)