diff --git a/network-go/docker/docker.go b/network-go/docker/docker.go index b9c72ac..896314b 100644 --- a/network-go/docker/docker.go +++ b/network-go/docker/docker.go @@ -5,9 +5,11 @@ import ( "fmt" "net" "os/exec" + "strings" "time" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" @@ -26,6 +28,7 @@ type DockerAPI interface { WaitForContainerRunning(ctx context.Context, containerName string, timeout time.Duration) error GetContainerPID(ctx context.Context, containerName string) (int, error) AddRouteInContainer(ctx context.Context, containerName, network, gateway string) error + FindContainerName(ctx context.Context, name, selector string) (string, error) } // Client wraps the Docker SDK client @@ -197,4 +200,54 @@ func (c *Client) AddRouteInContainer(ctx context.Context, containerName, network return fmt.Errorf("failed to add route in container %s: %w\noutput: %s", containerName, err, string(output)) } return nil +} + +// FindContainerName attempts to find a running container by name or selector. +// First tries the exact name, then tries listing running containers whose name +// starts with the selector prefix (or the name prefix), matching the old shell +// script's grep $D"-" behavior. +func (c *Client) FindContainerName(ctx context.Context, name, selector string) (string, error) { + // First try the exact name + cont, err := c.cli.ContainerInspect(ctx, name) + if err == nil && cont.State != nil && cont.State.Running { + return name, nil + } + + // Try exact selector + if selector != "" && selector != name { + cont, err := c.cli.ContainerInspect(ctx, selector) + if err == nil && cont.State != nil && cont.State.Running { + return selector, nil + } + } + + // Try prefix matching with selector (old shell script behavior: grep $D"-") + candidates := []string{name, selector} + for _, candidate := range candidates { + if candidate == "" { + continue + } + // Extract prefix before first dash if present + prefix := candidate + if strings.Contains(candidate, "-") { + prefix = candidate[:strings.Index(candidate, "-")] + } + + containers, err := c.cli.ContainerList(ctx, container.ListOptions{}) + if err != nil { + continue + } + + for _, container := range containers { + // Remove leading / from container names + for _, cName := range container.Names { + cName = strings.TrimPrefix(cName, "/") + if strings.HasPrefix(cName, prefix+"-") && container.State == "running" { + return cName, nil + } + } + } + } + + return "", fmt.Errorf("no running container found matching name=%q selector=%q", name, selector) } \ No newline at end of file diff --git a/network-go/firewall/firewall.go b/network-go/firewall/firewall.go index a29831e..dbe28ad 100644 --- a/network-go/firewall/firewall.go +++ b/network-go/firewall/firewall.go @@ -76,16 +76,24 @@ func (o *Orchestrator) reconcileIPs(ctx context.Context, cfg *config.NetworksCon continue } - log.Printf("FIREWALL: connecting container %s to network %s with IP %s", ipCfg.ContainerName, networkName, ipStr) + // Resolve the actual container name, with fallback to fuzzy matching + // (old shell script behavior: docker ps | grep $D"-") + containerName, err := o.dockerClient.FindContainerName(ctx, ipCfg.ContainerName, ipCfg.Selector) + if err != nil { + log.Printf("FIREWALL: WARNING container %s (selector=%s) not found: %v, trying connection anyway", ipCfg.ContainerName, ipCfg.Selector, err) + containerName = ipCfg.ContainerName + } + + log.Printf("FIREWALL: connecting container %s to network %s with IP %s", containerName, networkName, ipStr) waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second) - if err := o.dockerClient.WaitForContainerRunning(waitCtx, ipCfg.ContainerName, 10*time.Second); err != nil { - log.Printf("FIREWALL: WARNING container %s not running yet: %v, connecting anyway", ipCfg.ContainerName, err) + if err := o.dockerClient.WaitForContainerRunning(waitCtx, containerName, 10*time.Second); err != nil { + log.Printf("FIREWALL: WARNING container %s not running yet: %v, connecting anyway", containerName, err) } cancel() - if err := o.dockerClient.ConnectContainer(ctx, ipCfg.ContainerName, networkName, ipStr); err != nil { - log.Printf("FIREWALL: ERROR connecting container %s to %s: %v", ipCfg.ContainerName, networkName, err) + if err := o.dockerClient.ConnectContainer(ctx, containerName, networkName, ipStr); err != nil { + log.Printf("FIREWALL: ERROR connecting container %s to %s: %v", containerName, networkName, err) } } } diff --git a/network-go/mock/mock.go b/network-go/mock/mock.go index dee35dc..ea05bae 100644 --- a/network-go/mock/mock.go +++ b/network-go/mock/mock.go @@ -41,6 +41,10 @@ type MockDockerClient struct { AddRouteGateway string AddRouteErr error + FindContainerNameCalled bool + FindContainerNameResult string + FindContainerNameErr error + InspectContainerErr error RemoveNetworkErr error DisconnectContainerErr error @@ -94,6 +98,14 @@ func (m *MockDockerClient) AddRouteInContainer(ctx context.Context, containerNam return m.AddRouteErr } +func (m *MockDockerClient) FindContainerName(ctx context.Context, name, selector string) (string, error) { + m.FindContainerNameCalled = true + if m.FindContainerNameResult != "" { + return m.FindContainerNameResult, m.FindContainerNameErr + } + return name, m.FindContainerNameErr +} + // MockIPTablesManager implements iptables.IPTablesAPI for testing type MockIPTablesManager struct { BinaryResult string