mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 01:40:07 +00:00
Change CreateTCPLoadBalancer -> EnsureTCPLoadBalancer; implementations auto-delete if already exists
Previously the servicecontroller would do the delete, but by having the cloudprovider take that task on, we can later remove it from the servicecontroller, and the cloudprovider can do something more efficient.
This commit is contained in:
parent
1ab62e541b
commit
87df1d6fb6
@ -80,8 +80,8 @@ type TCPLoadBalancer interface {
|
|||||||
// GetTCPLoadBalancer returns whether the specified load balancer exists, and
|
// GetTCPLoadBalancer returns whether the specified load balancer exists, and
|
||||||
// if so, what its status is.
|
// if so, what its status is.
|
||||||
GetTCPLoadBalancer(name, region string) (status *api.LoadBalancerStatus, exists bool, err error)
|
GetTCPLoadBalancer(name, region string) (status *api.LoadBalancerStatus, exists bool, err error)
|
||||||
// CreateTCPLoadBalancer creates a new tcp load balancer. Returns the status of the balancer
|
// EnsureTCPLoadBalancer creates a new tcp load balancer, or updates an existing one. Returns the status of the balancer
|
||||||
CreateTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error)
|
EnsureTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error)
|
||||||
// UpdateTCPLoadBalancer updates hosts under the specified load balancer.
|
// UpdateTCPLoadBalancer updates hosts under the specified load balancer.
|
||||||
UpdateTCPLoadBalancer(name, region string, hosts []string) error
|
UpdateTCPLoadBalancer(name, region string, hosts []string) error
|
||||||
// EnsureTCPLoadBalancerDeleted deletes the specified load balancer if it
|
// EnsureTCPLoadBalancerDeleted deletes the specified load balancer if it
|
||||||
|
@ -1584,8 +1584,23 @@ func (s *AWSCloud) createTags(request *ec2.CreateTagsInput) (*ec2.CreateTagsOutp
|
|||||||
// CreateTCPLoadBalancer implements TCPLoadBalancer.CreateTCPLoadBalancer
|
// CreateTCPLoadBalancer implements TCPLoadBalancer.CreateTCPLoadBalancer
|
||||||
// TODO(justinsb): This must be idempotent
|
// TODO(justinsb): This must be idempotent
|
||||||
// TODO(justinsb) It is weird that these take a region. I suspect it won't work cross-region anwyay.
|
// TODO(justinsb) It is weird that these take a region. I suspect it won't work cross-region anwyay.
|
||||||
func (s *AWSCloud) CreateTCPLoadBalancer(name, region string, publicIP net.IP, ports []*api.ServicePort, hosts []string, affinity api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
func (s *AWSCloud) EnsureTCPLoadBalancer(name, region string, publicIP net.IP, ports []*api.ServicePort, hosts []string, affinity api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
||||||
glog.V(2).Infof("CreateTCPLoadBalancer(%v, %v, %v, %v, %v)", name, region, publicIP, ports, hosts)
|
glog.V(2).Infof("EnsureTCPLoadBalancer(%v, %v, %v, %v, %v)", name, region, publicIP, ports, hosts)
|
||||||
|
|
||||||
|
glog.V(2).Info("Checking if load balancer already exists: %s", name)
|
||||||
|
_, exists, err := s.GetTCPLoadBalancer(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error checking if AWS load balancer already exists: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement a more efficient update strategy for common changes than delete & create
|
||||||
|
// In particular, if we implement hosts update, we can get rid of UpdateHosts
|
||||||
|
if exists {
|
||||||
|
err := s.EnsureTCPLoadBalancerDeleted(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deleting existing AWS load balancer: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
elbClient, err := s.getELBClient(region)
|
elbClient, err := s.getELBClient(region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -56,7 +56,7 @@ type FakeCloud struct {
|
|||||||
ClusterList []string
|
ClusterList []string
|
||||||
MasterName string
|
MasterName string
|
||||||
ExternalIP net.IP
|
ExternalIP net.IP
|
||||||
Balancers []FakeBalancer
|
Balancers map[string]FakeBalancer
|
||||||
UpdateCalls []FakeUpdateBalancerCall
|
UpdateCalls []FakeUpdateBalancerCall
|
||||||
RouteMap map[string]*FakeRoute
|
RouteMap map[string]*FakeRoute
|
||||||
Lock sync.Mutex
|
Lock sync.Mutex
|
||||||
@ -123,11 +123,14 @@ func (f *FakeCloud) GetTCPLoadBalancer(name, region string) (*api.LoadBalancerSt
|
|||||||
return status, f.Exists, f.Err
|
return status, f.Exists, f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTCPLoadBalancer is a test-spy implementation of TCPLoadBalancer.CreateTCPLoadBalancer.
|
// EnsureTCPLoadBalancer is a test-spy implementation of TCPLoadBalancer.EnsureTCPLoadBalancer.
|
||||||
// It adds an entry "create" into the internal method call record.
|
// It adds an entry "create" into the internal method call record.
|
||||||
func (f *FakeCloud) CreateTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
func (f *FakeCloud) EnsureTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
||||||
f.addCall("create")
|
f.addCall("create")
|
||||||
f.Balancers = append(f.Balancers, FakeBalancer{name, region, externalIP, ports, hosts})
|
if f.Balancers == nil {
|
||||||
|
f.Balancers = make(map[string]FakeBalancer)
|
||||||
|
}
|
||||||
|
f.Balancers[name] = FakeBalancer{name, region, externalIP, ports, hosts}
|
||||||
|
|
||||||
status := &api.LoadBalancerStatus{}
|
status := &api.LoadBalancerStatus{}
|
||||||
status.Ingress = []api.LoadBalancerIngress{{IP: f.ExternalIP.String()}}
|
status.Ingress = []api.LoadBalancerIngress{{IP: f.ExternalIP.String()}}
|
||||||
|
@ -348,11 +348,26 @@ func makeFirewallName(name string) string {
|
|||||||
return fmt.Sprintf("k8s-fw-%s", name)
|
return fmt.Sprintf("k8s-fw-%s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTCPLoadBalancer is an implementation of TCPLoadBalancer.CreateTCPLoadBalancer.
|
// EnsureTCPLoadBalancer is an implementation of TCPLoadBalancer.EnsureTCPLoadBalancer.
|
||||||
// TODO(a-robinson): Don't just ignore specified IP addresses. Check if they're
|
// TODO(a-robinson): Don't just ignore specified IP addresses. Check if they're
|
||||||
// owned by the project and available to be used, and use them if they are.
|
// owned by the project and available to be used, and use them if they are.
|
||||||
func (gce *GCECloud) CreateTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
func (gce *GCECloud) EnsureTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinityType api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
||||||
err := gce.makeTargetPool(name, region, hosts, translateAffinityType(affinityType))
|
glog.V(2).Info("Checking if load balancer already exists: %s", name)
|
||||||
|
_, exists, err := gce.GetTCPLoadBalancer(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error checking if GCE load balancer already exists: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement a more efficient update strategy for common changes than delete & create
|
||||||
|
// In particular, if we implement hosts update, we can get rid of UpdateHosts
|
||||||
|
if exists {
|
||||||
|
err := gce.EnsureTCPLoadBalancerDeleted(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deleting existing GCE load balancer: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gce.makeTargetPool(name, region, hosts, translateAffinityType(affinityType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !isHTTPErrorCode(err, http.StatusConflict) {
|
if !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -521,8 +521,8 @@ func (lb *LoadBalancer) GetTCPLoadBalancer(name, region string) (*api.LoadBalanc
|
|||||||
// a list of regions (from config) and query/create loadbalancers in
|
// a list of regions (from config) and query/create loadbalancers in
|
||||||
// each region.
|
// each region.
|
||||||
|
|
||||||
func (lb *LoadBalancer) CreateTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinity api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
func (lb *LoadBalancer) EnsureTCPLoadBalancer(name, region string, externalIP net.IP, ports []*api.ServicePort, hosts []string, affinity api.ServiceAffinity) (*api.LoadBalancerStatus, error) {
|
||||||
glog.V(4).Infof("CreateTCPLoadBalancer(%v, %v, %v, %v, %v, %v)", name, region, externalIP, ports, hosts, affinity)
|
glog.V(4).Infof("EnsureTCPLoadBalancer(%v, %v, %v, %v, %v, %v)", name, region, externalIP, ports, hosts, affinity)
|
||||||
|
|
||||||
if len(ports) > 1 {
|
if len(ports) > 1 {
|
||||||
return nil, fmt.Errorf("multiple ports are not yet supported in openstack load balancers")
|
return nil, fmt.Errorf("multiple ports are not yet supported in openstack load balancers")
|
||||||
@ -538,6 +538,21 @@ func (lb *LoadBalancer) CreateTCPLoadBalancer(name, region string, externalIP ne
|
|||||||
return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity)
|
return nil, fmt.Errorf("unsupported load balancer affinity: %v", affinity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glog.V(2).Info("Checking if openstack load balancer already exists: %s", name)
|
||||||
|
_, exists, err := lb.GetTCPLoadBalancer(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error checking if openstack load balancer already exists: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement a more efficient update strategy for common changes than delete & create
|
||||||
|
// In particular, if we implement hosts update, we can get rid of UpdateHosts
|
||||||
|
if exists {
|
||||||
|
err := lb.EnsureTCPLoadBalancerDeleted(name, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deleting existing openstack load balancer: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lbmethod := lb.opts.LBMethod
|
lbmethod := lb.opts.LBMethod
|
||||||
if lbmethod == "" {
|
if lbmethod == "" {
|
||||||
lbmethod = pools.LBMethodRoundRobin
|
lbmethod = pools.LBMethodRoundRobin
|
||||||
|
@ -335,7 +335,7 @@ func (s *ServiceController) createLoadBalancerIfNeeded(namespacedName types.Name
|
|||||||
return fmt.Errorf("Failed to persist updated status to apiserver, even after retries. Giving up: %v", err), notRetryable
|
return fmt.Errorf("Failed to persist updated status to apiserver, even after retries. Giving up: %v", err), notRetryable
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glog.Infof("Not persisting unchanged LoadBalancerStatus to registry.")
|
glog.V(2).Infof("Not persisting unchanged LoadBalancerStatus to registry.")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, notRetryable
|
return nil, notRetryable
|
||||||
@ -383,7 +383,7 @@ func (s *ServiceController) createExternalLoadBalancer(service *api.Service) err
|
|||||||
for _, publicIP := range service.Spec.DeprecatedPublicIPs {
|
for _, publicIP := range service.Spec.DeprecatedPublicIPs {
|
||||||
// TODO: Make this actually work for multiple IPs by using different
|
// TODO: Make this actually work for multiple IPs by using different
|
||||||
// names for each. For now, we'll just create the first and break.
|
// names for each. For now, we'll just create the first and break.
|
||||||
status, err := s.balancer.CreateTCPLoadBalancer(name, s.zone.Region, net.ParseIP(publicIP),
|
status, err := s.balancer.EnsureTCPLoadBalancer(name, s.zone.Region, net.ParseIP(publicIP),
|
||||||
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -393,7 +393,7 @@ func (s *ServiceController) createExternalLoadBalancer(service *api.Service) err
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
status, err := s.balancer.CreateTCPLoadBalancer(name, s.zone.Region, nil,
|
status, err := s.balancer.EnsureTCPLoadBalancer(name, s.zone.Region, nil,
|
||||||
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -110,12 +110,22 @@ func TestCreateExternalLoadBalancer(t *testing.T) {
|
|||||||
t.Errorf("unexpected client actions: %v", actions)
|
t.Errorf("unexpected client actions: %v", actions)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if len(cloud.Balancers) != 1 {
|
var balancer *fake_cloud.FakeBalancer
|
||||||
t.Errorf("expected one load balancer to be created, got %v", cloud.Balancers)
|
for k := range cloud.Balancers {
|
||||||
} else if cloud.Balancers[0].Name != controller.loadBalancerName(item.service) ||
|
if balancer == nil {
|
||||||
cloud.Balancers[0].Region != region ||
|
b := cloud.Balancers[k]
|
||||||
cloud.Balancers[0].Ports[0].Port != item.service.Spec.Ports[0].Port {
|
balancer = &b
|
||||||
t.Errorf("created load balancer has incorrect parameters: %v", cloud.Balancers[0])
|
} else {
|
||||||
|
t.Errorf("expected one load balancer to be created, got %v", cloud.Balancers)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if balancer == nil {
|
||||||
|
t.Errorf("expected one load balancer to be created, got none")
|
||||||
|
} else if balancer.Name != controller.loadBalancerName(item.service) ||
|
||||||
|
balancer.Region != region ||
|
||||||
|
balancer.Ports[0].Port != item.service.Spec.Ports[0].Port {
|
||||||
|
t.Errorf("created load balancer has incorrect parameters: %v", balancer)
|
||||||
}
|
}
|
||||||
actionFound := false
|
actionFound := false
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
|
Loading…
Reference in New Issue
Block a user