Skip to content

Commit

Permalink
Rip out the port cache
Browse files Browse the repository at this point in the history
For a while now (potentially since ever), ch-k8s-lbaas has been known
for losing floating IPs. We were so far unable to track it down---the
logs were always inconclusive and it wasn't fully clear where the issue
might come from.

As "cache invalidation" is one of the two hard problems in computer
science (next to naming things and off-by-one errors), it seems most
sensible to rip out the port cache.

With the typical cluster size, it should not be necessary to have a
cache. In addition, using a cache is in direct contradiction to acting
on the current state (even though API calls also always return stale
data, but at least it's less stale than your average cache), which we
normally want to do in the Kubernetes world.

So let's try this, for a change.
  • Loading branch information
horazont committed May 12, 2022
1 parent 931f009 commit 8179501
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 174 deletions.
164 changes: 0 additions & 164 deletions internal/openstack/cache.go

This file was deleted.

16 changes: 6 additions & 10 deletions internal/openstack/port_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package openstack

import (
"errors"
"time"

"github.com/gophercloud/gophercloud"
tags "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/attributestags"
Expand Down Expand Up @@ -75,7 +74,7 @@ type OpenStackL3PortManager struct {
client *gophercloud.ServiceClient
networkID string
cfg *NetworkingOpts
cache PortCache
ports PortClient
}

func (client *OpenStackClient) NewOpenStackL3PortManager(networkConfig *NetworkingOpts) (*OpenStackL3PortManager, error) {
Expand All @@ -95,9 +94,8 @@ func (client *OpenStackClient) NewOpenStackL3PortManager(networkConfig *Networki
client: networkingclient,
cfg: networkConfig,
networkID: networkID,
cache: NewPortCache(
ports: NewPortClient(
networkingclient,
30*time.Second,
TagLBManagedPort,
networkConfig.UseFloatingIPs,
),
Expand Down Expand Up @@ -194,7 +192,6 @@ func (pm *OpenStackL3PortManager) ProvisionPort() (string, error) {
}
}

pm.cache.Invalidate()
return port.ID, nil
}

Expand Down Expand Up @@ -238,7 +235,7 @@ func (pm *OpenStackL3PortManager) deleteUnusedFloatingIPs() error {
}

func (pm *OpenStackL3PortManager) CleanUnusedPorts(usedPorts []string) error {
ports, err := pm.cache.GetPorts()
ports, err := pm.ports.GetPorts()
klog.Infof("Used ports=%q", usedPorts)
if err != nil {
return err
Expand All @@ -265,14 +262,13 @@ func (pm *OpenStackL3PortManager) CleanUnusedPorts(usedPorts []string) error {
}

if anyDeleted {
pm.cache.Invalidate()
return pm.deleteUnusedFloatingIPs()
}
return nil
}

func (pm *OpenStackL3PortManager) GetAvailablePorts() ([]string, error) {
ports, err := pm.cache.GetPorts()
ports, err := pm.ports.GetPorts()
if err != nil {
return nil, err
}
Expand All @@ -287,7 +283,7 @@ func (pm *OpenStackL3PortManager) GetAvailablePorts() ([]string, error) {
}

func (pm *OpenStackL3PortManager) GetExternalAddress(portID string) (string, string, error) {
port, fip, err := pm.cache.GetPortByID(portID)
port, fip, err := pm.ports.GetPortByID(portID)
if err != nil {
return "", "", err
}
Expand All @@ -313,7 +309,7 @@ func (pm *OpenStackL3PortManager) GetExternalAddress(portID string) (string, str
}

func (pm *OpenStackL3PortManager) GetInternalAddress(portID string) (string, error) {
port, _, err := pm.cache.GetPortByID(portID)
port, _, err := pm.ports.GetPortByID(portID)
if err != nil {
return "", err
}
Expand Down
102 changes: 102 additions & 0 deletions internal/openstack/ports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* Copyright 2020 CLOUD&HEAT Technologies GmbH
*
* 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 openstack

import (
"github.com/gophercloud/gophercloud"
floatingipsv2 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
portsv2 "github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"github.com/gophercloud/gophercloud/pagination"

"k8s.io/klog"
)

type CachedPort struct {
Port portsv2.Port
FloatingIP *floatingipsv2.FloatingIP
}

type UncachedClient struct {
client *gophercloud.ServiceClient
tag string
useFloatingIPs bool
}

type PortClient interface {
GetPorts() ([]*portsv2.Port, error)
GetPortByID(ID string) (*portsv2.Port, *floatingipsv2.FloatingIP, error)
}

func NewPortClient(networkingclient *gophercloud.ServiceClient, tag string, useFloatingIPs bool) *UncachedClient {
return &UncachedClient{
client: networkingclient,
tag: tag,
useFloatingIPs: useFloatingIPs,
}
}

func (pc *UncachedClient) GetPorts() (ports []*portsv2.Port, err error) {
err = portsv2.List(
pc.client,
portsv2.ListOpts{Tags: pc.tag},
).EachPage(func(page pagination.Page) (bool, error) {
fetched_ports, err := portsv2.ExtractPorts(page)
if err != nil {
return false, err
}
for _, found_port := range fetched_ports {
ports = append(ports, &found_port)
}
return true, nil
})
if err != nil {
return nil, err
}
return ports, err
}

func (pc *UncachedClient) GetPortByID(ID string) (port *portsv2.Port, fip *floatingipsv2.FloatingIP, err error) {
port, err = portsv2.Get(
pc.client,
ID,
).Extract()
if err != nil {
return nil, nil, err
}

if pc.useFloatingIPs {
err = floatingipsv2.List(
pc.client,
floatingipsv2.ListOpts{Tags: pc.tag, PortID: ID},
).EachPage(func(page pagination.Page) (bool, error) {
fips, err := floatingipsv2.ExtractFloatingIPs(page)
if err != nil {
return false, err
}
for _, found_fip := range fips {
if fip != nil {
// TODO: warn here?!
klog.Warningf("Found multiple floating IPs for port %s (%s and %s at least)", ID, fip.ID, found_fip.ID)
}
fip = &found_fip
}
return true, nil
})
if err != nil {
return nil, nil, err
}
}
return port, fip, nil
}

0 comments on commit 8179501

Please sign in to comment.