Free validator ports in the cloud on clear/cancel/delete
An address still being associated (assigning_fip) has no fip_id in the database, so "clear queue" did not detach it, and the association then finished after the row was gone, leaving the floating IP on the validator port for good. - After clear/cancel/delete, ask the cloud which floating IPs sit on the affected validator ports (new ListFloatingIPsByPort) and detach those that this system queued (known in ip_registry); foreign ones are left. - SetFIPAssociated applies only to a row still in assigning_fip; if the address was removed meanwhile, associateFIP detaches the floating IP. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c0e300f71c
commit
1ee5757004
8 files changed
+287
-5
No files matched your search
@@ -239,6 +239,27 @@ func (c *Client) ListFreeFloatingIPs(ctx context.Context, pageSize int, onPage f
|
||||
return paginate(ctx, pageSize, c.retry, c.fetchPage, onPage)
|
||||
}
|
||||
|
||||
// ListFloatingIPsByPort asks Neutron for the floating IPs attached to portID.
|
||||
func (c *Client) ListFloatingIPsByPort(ctx context.Context, portID string) ([]FloatingIP, error) {
|
||||
pages, err := floatingips.List(c.networking, floatingips.ListOpts{PortID: portID}).AllPages(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("openstack: list floating ips of port %s: %w", portID, err)
|
||||
}
|
||||
list, err := floatingips.ExtractFloatingIPs(pages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("openstack: extract floating ips: %w", err)
|
||||
}
|
||||
out := make([]FloatingIP, 0, len(list))
|
||||
for _, f := range list {
|
||||
proj := f.TenantID
|
||||
if proj == "" {
|
||||
proj = f.ProjectID
|
||||
}
|
||||
out = append(out, FloatingIP{ID: f.ID, Address: f.FloatingIP, PortID: f.PortID, ProjectID: proj})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListFloatingIPs(ctx context.Context) ([]FloatingIP, error) {
|
||||
return listAll(ctx, c)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ type FloatingIPClient interface {
|
||||
// onPage stops the walk and is returned as-is.
|
||||
ListFreeFloatingIPs(ctx context.Context, pageSize int, onPage func(page []FloatingIP) error) (pages int, err error)
|
||||
|
||||
// ListFloatingIPsByPort returns the floating IPs currently attached to
|
||||
// the given port — read from the cloud, not from our database, so it
|
||||
// also finds attachments we lost track of.
|
||||
ListFloatingIPsByPort(ctx context.Context, portID string) ([]FloatingIP, error)
|
||||
|
||||
// AssociateFloatingIP attaches the floating IP to the given Neutron
|
||||
// port (the validator's primary NIC port).
|
||||
AssociateFloatingIP(ctx context.Context, fipID, portID string) error
|
||||
|
||||
@@ -159,6 +159,18 @@ func (m *MockClient) ListFloatingIPs(ctx context.Context) ([]FloatingIP, error)
|
||||
return listAll(ctx, m)
|
||||
}
|
||||
|
||||
func (m *MockClient) ListFloatingIPsByPort(ctx context.Context, portID string) ([]FloatingIP, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
var out []FloatingIP
|
||||
for _, f := range m.fips {
|
||||
if f.PortID == portID {
|
||||
out = append(out, *f)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (m *MockClient) AssociateFloatingIP(ctx context.Context, fipID, portID string) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
Reference in new issue
Block a user