Prevent container veth name race condition

This commit is contained in:
Jack O'Sullivan 2021-06-08 21:48:24 +01:00
parent 0cc1fb82ec
commit 126dd55069
3 changed files with 49 additions and 8 deletions

View File

@ -17,6 +17,8 @@ import (
"github.com/devplayer0/docker-net-dhcp/pkg/util"
)
const pollTime = 100 * time.Millisecond
type dhcpManager struct {
docker *docker.Client
joinReq JoinRequest
@ -197,7 +199,7 @@ func (m *dhcpManager) setupClient(v6 bool) (chan error, error) {
func (m *dhcpManager) Start(ctx context.Context) error {
var err error
m.nsHandle, err = util.AwaitNetNS(ctx, m.joinReq.SandboxKey, 100*time.Millisecond)
m.nsHandle, err = util.AwaitNetNS(ctx, m.joinReq.SandboxKey, pollTime)
if err != nil {
return fmt.Errorf("failed to get sandbox network namespace: %w", err)
}
@ -209,7 +211,7 @@ func (m *dhcpManager) Start(ctx context.Context) error {
}
if err := func() error {
hostName, _ := vethPairNames(m.joinReq.EndpointID)
hostName, oldCtrName := vethPairNames(m.joinReq.EndpointID)
hostLink, err := netlink.LinkByName(hostName)
if err != nil {
return fmt.Errorf("failed to find host side of veth pair: %w", err)
@ -224,9 +226,15 @@ func (m *dhcpManager) Start(ctx context.Context) error {
return fmt.Errorf("failed to get container side of veth's index: %w", err)
}
m.ctrLink, err = util.AwaitLinkByIndex(ctx, m.netHandle, ctrIndex, 100*time.Millisecond)
if err != nil {
return fmt.Errorf("failed to get link for container side of veth pair: %w", err)
if err := util.AwaitCondition(ctx, func() (bool, error) {
m.ctrLink, err = util.AwaitLinkByIndex(ctx, m.netHandle, ctrIndex, pollTime)
if err != nil {
return false, fmt.Errorf("failed to get link for container side of veth pair: %w", err)
}
return m.ctrLink.Attrs().Name != oldCtrName, nil
}, pollTime); err != nil {
return err
}
dockerNet, err := m.docker.NetworkInspect(ctx, m.joinReq.NetworkID, dTypes.NetworkInspectOptions{})

33
pkg/util/general.go Normal file
View File

@ -0,0 +1,33 @@
package util
import (
"context"
"time"
)
func AwaitCondition(ctx context.Context, cond func() (bool, error), interval time.Duration) error {
errChan := make(chan error)
go func() {
for {
ok, err := cond()
if err != nil {
errChan <- err
return
}
if ok {
errChan <- nil
return
}
time.Sleep(interval)
}
}()
select {
case err := <-errChan:
return err
case <-ctx.Done():
return ctx.Err()
}
}

View File

@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
)
@ -31,7 +31,7 @@ func AwaitNetNS(ctx context.Context, path string, interval time.Duration) (netns
return ns, nil
case <-ctx.Done():
if err != nil {
logrus.WithError(err).WithField("path", path).Error("Failed to await network namespace")
log.WithError(err).WithField("path", path).Error("Failed to await network namespace")
}
return dummy, ctx.Err()
}
@ -59,7 +59,7 @@ func AwaitLinkByIndex(ctx context.Context, handle *netlink.Handle, index int, in
return link, nil
case <-ctx.Done():
if err != nil {
logrus.WithError(err).WithField("index", index).Error("Failed to await link by index")
log.WithError(err).WithField("index", index).Error("Failed to await link by index")
}
return dummy, ctx.Err()
}