From 5981991dabf06bf5252194dd8777fd032e0517cb Mon Sep 17 00:00:00 2001 From: 0w0mewo <72908579+0w0mewo@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:34:28 +0000 Subject: [PATCH 1/2] fix: empty container ip while it's attach to another container When a container's networking stack is attached to another container, the IP address of the container is empty and resulting DockerManager keep triggering retry and restart. Note: The restart loop triggered even the `com.dnsdock.ignore` label has added. --- internal/core/docker.go | 47 +++++++++++++++++++++++++++++++++-- internal/servers/dnsserver.go | 19 +++++++++----- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/internal/core/docker.go b/internal/core/docker.go index eae3766..434e566 100644 --- a/internal/core/docker.go +++ b/internal/core/docker.go @@ -97,6 +97,11 @@ func (d *DockerManager) run(ctx context.Context) error { if _, ok := services[id]; !ok && srv.Provider == DockerProvider { err := d.list.RemoveService(id) if err != nil { + // The service id(in this case, container id) may not register + // during 'AddService' stage because it's ignored by label/env setting. + if err == servers.ErrSvrsNotExist { + continue + } return fmt.Errorf("error removing service: %w", err) } } @@ -172,6 +177,11 @@ func (d *DockerManager) stopHandler(m events.Message) error { if !d.config.All { err := d.list.RemoveService(m.ID) if err != nil { + // The service id(in this case, container id) may not register + // during 'AddService' stage because it's ignored by label/env setting. + if err == servers.ErrSvrsNotExist { + return nil + } return fmt.Errorf("error removing service: %w", err) } } else { @@ -184,6 +194,11 @@ func (d *DockerManager) renameHandler(m events.Message) error { logger.Debugf("Renamed container '%s'", m.ID) err := d.list.RemoveService(m.ID) if err != nil { + // The service id(in this case, container id) may not register + // during 'AddService' stage because it's ignored by label/env setting. + if err == servers.ErrSvrsNotExist { + return nil + } return fmt.Errorf("error removing service: %w", err) } service, err := d.getService(m.ID) @@ -202,6 +217,11 @@ func (d *DockerManager) destroyHandler(m events.Message) error { if d.config.All { err := d.list.RemoveService(m.ID) if err != nil { + // The service id(in this case, container id) may not register + // during 'AddService' stage because it's ignored by label/env setting. + if err == servers.ErrSvrsNotExist { + return nil + } return fmt.Errorf("error removing service: %w", err) } } @@ -213,6 +233,23 @@ func (d *DockerManager) Stop() { d.cancel() } +func (d *DockerManager) getContainerIPbyId(id string) (res []net.IP, err error) { + desc, e := d.client.ContainerInspect(context.Background(), id) + if e != nil { + err = e + return + + } + + for _, val := range desc.NetworkSettings.Networks { + if ip := net.ParseIP(val.IPAddress); ip != nil { + res = append(res, ip) + } + } + + return +} + func (d *DockerManager) getService(id string) (*servers.Service, error) { desc, err := d.client.ContainerInspect(context.Background(), id) if err != nil { @@ -232,6 +269,12 @@ func (d *DockerManager) getService(id string) (*servers.Service, error) { switch len(desc.NetworkSettings.Networks) { case 0: logger.Warningf("Warning, no IP address found for container '%s' ", desc.Name) + if networkmode := desc.HostConfig.NetworkMode; networkmode.IsContainer() { + logger.Debugf("%s is linked to container %s", desc.Name, networkmode.ConnectedContainer()) + ips, _ := d.getContainerIPbyId(networkmode.ConnectedContainer()) + service.IPs = append(service.IPs, ips...) + } + default: for _, value := range desc.NetworkSettings.Networks { ip := net.ParseIP(value.IPAddress) @@ -297,7 +340,7 @@ func overrideFromLabels(in *servers.Service, labels map[string]string) (out *ser var region string for k, v := range labels { if k == "com.dnsdock.ignore" { - return nil + in.IgnoredByUser = true } if k == "com.dnsdock.alias" { @@ -363,7 +406,7 @@ func overrideFromEnv(in *servers.Service, env map[string]string) (out *servers.S var region string for k, v := range env { if k == "DNSDOCK_IGNORE" || k == "SERVICE_IGNORE" { - return nil + in.IgnoredByUser = true } if k == "DNSDOCK_ALIAS" { diff --git a/internal/servers/dnsserver.go b/internal/servers/dnsserver.go index a7ba869..ff4b2b3 100644 --- a/internal/servers/dnsserver.go +++ b/internal/servers/dnsserver.go @@ -21,13 +21,16 @@ import ( "github.com/miekg/dns" ) +var ErrSvrsNotExist = errors.New("no such service") + // Service represents a container and an attached DNS record type Service struct { - Name string - Image string - IPs []net.IP - TTL int - Aliases []string + Name string + Image string + IPs []net.IP + TTL int + Aliases []string + IgnoredByUser bool // Provider tracks the creator of a service Provider string `json:"-"` @@ -96,6 +99,10 @@ func (s *DNSServer) Stop() error { // AddService adds a new container and thus new DNS records func (s *DNSServer) AddService(id string, service Service) (err error) { + if service.IgnoredByUser { + return nil + } + if len(service.IPs) > 0 { defer s.lock.Unlock() s.lock.Lock() @@ -131,7 +138,7 @@ func (s *DNSServer) RemoveService(id string) (err error) { return err } if _, ok := s.services[id]; !ok { - return errors.New("No such service: " + id) + return ErrSvrsNotExist } for _, alias := range s.services[id].Aliases { From 8eee9fe32f38c5fa5365f4f068e6372f80ec53c8 Mon Sep 17 00:00:00 2001 From: 0w0mewo <72908579+0w0mewo@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:37:59 +0000 Subject: [PATCH 2/2] fix false negative tests --- internal/core/docker_test.go | 4 ++-- internal/servers/dnsserver.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/core/docker_test.go b/internal/core/docker_test.go index c7f24bf..66bcec3 100644 --- a/internal/core/docker_test.go +++ b/internal/core/docker_test.go @@ -87,13 +87,13 @@ func TestOverrideFromEnv(t *testing.T) { s := getService() s = overrideFromEnv(s, map[string]string{"SERVICE_IGNORE": "1"}) - if s != nil { + if s != nil && !s.IgnoredByUser { t.Error("Skipping failed") } s = getService() s = overrideFromEnv(s, map[string]string{"DNSDOCK_IGNORE": "1"}) - if s != nil { + if s != nil && !s.IgnoredByUser { t.Error("Skipping failed(2)") } diff --git a/internal/servers/dnsserver.go b/internal/servers/dnsserver.go index ff4b2b3..dc35f4c 100644 --- a/internal/servers/dnsserver.go +++ b/internal/servers/dnsserver.go @@ -30,7 +30,7 @@ type Service struct { IPs []net.IP TTL int Aliases []string - IgnoredByUser bool + IgnoredByUser bool `json:"-"` // Provider tracks the creator of a service Provider string `json:"-"`