Skip to content

Commit

Permalink
fixed docker discovery issue where ip address was overwritten (#1201)
Browse files Browse the repository at this point in the history
* fixed docker discovery issue where ip address was overwritten

* cleanup
  • Loading branch information
cristianciutea authored Jun 8, 2022
1 parent 3152c41 commit efbbf04
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 7 deletions.
28 changes: 21 additions & 7 deletions pkg/databind/internal/discovery/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package docker

import (
"context"
"net"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -40,8 +41,6 @@ func Discoverer(d discovery.Container) (fetchDiscoveries func() (discoveries []d
}

func fetch(d discovery.Container, matcher *discovery.FieldsMatcher) ([]discovery.Discovery, error) {
var matches []discovery.Discovery

dc, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
Expand All @@ -53,6 +52,13 @@ func fetch(d discovery.Container, matcher *discovery.FieldsMatcher) ([]discovery
return nil, err
}

return getDiscoveries(containers, matcher), nil
}

// getDiscoveries will filter container list to only the ones that match the config and extract discovery variables from those.
func getDiscoveries(containers []types.Container, matcher *discovery.FieldsMatcher) []discovery.Discovery {
var matches []discovery.Discovery

for _, cont := range containers {
// discovery attributes that identify the container
labels := map[string]string{}
Expand Down Expand Up @@ -106,8 +112,7 @@ func fetch(d discovery.Container, matcher *discovery.FieldsMatcher) ([]discovery
})
}
}

return matches, nil
return matches
}

func addPorts(cont types.Container, labels map[string]string) {
Expand All @@ -123,20 +128,24 @@ func addPorts(cont types.Container, labels map[string]string) {
for index, port := range cont.Ports {
indexStr := "." + strconv.Itoa(index)
labels[data.IP+indexStr] = port.IP
labels[data.IP] = port.IP

tIdx := types.Count(port.Type)

publicPort := strconv.Itoa(int(port.PublicPort))
privatePort := strconv.Itoa(int(port.PrivatePort))
if firstPublic {

if firstPublic && port.PublicPort > 0 && isIPv4(port.IP) {
labels[data.IP] = port.IP
labels[data.Port] = publicPort
firstPublic = false
}

labels[data.Ports+indexStr] = publicPort

if firstPrivate {
labels[data.PrivatePort] = privatePort
firstPrivate = false
}

labels[data.PrivatePorts+indexStr] = privatePort

// label ports by type (e.g. discovery.port.tcp.1)
Expand All @@ -150,3 +159,8 @@ func addPorts(cont types.Container, labels map[string]string) {
}
}
}

// isIPv4 returns true if ip string has a IPv4 format.
func isIPv4(ip string) bool {
return net.ParseIP(ip).To4() != nil
}
150 changes: 150 additions & 0 deletions pkg/databind/internal/discovery/docker/docker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package docker

import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/newrelic/infrastructure-agent/pkg/databind/internal/discovery"
"github.com/newrelic/infrastructure-agent/pkg/databind/pkg/data"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)

func TestGetMatchingContainers(t *testing.T) {
givenContainerList := []types.Container{
{
ID: "484c2678906bed94a51fe12ec1fc8ac55f177453dba00c1b0ae0a22f4b655e41",
Names: []string{
"/sharp_beaver",
},
Image: "test-server",
ImageID: "sha256:8282995409c26b82d66243f169f6695115a06ce860966db549f8ca09dcbb9767",
Command: "/bin/bash -c 'java ${JAVA_OPTS} -jar /test-server.jar'",
Created: 1653916418,
Ports: []types.Port{
{
IP: "0.0.0.0",
PrivatePort: 7199,
PublicPort: 7199,
Type: "tcp",
},
{
IP: "",
PrivatePort: 4567,
PublicPort: 0,
Type: "tcp",
},
},
SizeRw: 0,
SizeRootFs: 0,
Labels: map[string]string{},
State: "running",
Status: "Up 8 minutes",
HostConfig: struct {
NetworkMode string "json:\",omitempty\""
}{
NetworkMode: "default",
},
NetworkSettings: &types.SummaryNetworkSettings{
Networks: map[string]*network.EndpointSettings{
"bridge": {
IPAMConfig: (*network.EndpointIPAMConfig)(nil),
Links: []string(nil),
Aliases: []string(nil),
NetworkID: "e0effada2c3eab26fb73188d0193952ef9a3c985e64cabd76c95196000405418",
EndpointID: "8e143f019bb8549a5594a31058c077eb774960b9b825f819f9593ab57a591f71",
Gateway: "172.17.0.1",
IPAddress: "172.17.0.2",
IPPrefixLen: 16,
IPv6Gateway: "",
GlobalIPv6Address: "",
GlobalIPv6PrefixLen: 0,
MacAddress: "02:42:ac:11:00:02",
DriverOpts: map[string]string(nil),
},
},
},

Mounts: []types.MountPoint{},
},
}

expectedDiscoveryData := []discovery.Discovery{
{
Variables: data.Map{
"discovery.containerId": "484c2678906bed94a51fe12ec1fc8ac55f177453dba00c1b0ae0a22f4b655e41",
"discovery.image": "test-server",
"discovery.ip": "0.0.0.0",
"discovery.ip.0": "",
"discovery.ip.1": "0.0.0.0",
"discovery.name": "sharp_beaver",
"discovery.port": "7199",
"discovery.ports.0": "0",
"discovery.ports.1": "7199",
"discovery.ports.tcp": "0",
"discovery.ports.tcp.0": "0",
"discovery.ports.tcp.1": "7199",
"discovery.private.ip": "172.17.0.2",
"discovery.private.ip.0": "172.17.0.2",
"discovery.private.port": "4567",
"discovery.private.ports.0": "4567",
"discovery.private.ports.1": "7199",
"discovery.private.ports.tcp": "4567",
"discovery.private.ports.tcp.0": "4567",
"discovery.private.ports.tcp.1": "7199",
},
MetricAnnotations: data.InterfaceMap{
"command": "/bin/bash -c 'java ${JAVA_OPTS} -jar /test-server.jar'",
"containerId": "484c2678906bed94a51fe12ec1fc8ac55f177453dba00c1b0ae0a22f4b655e41",
"containerName": "sharp_beaver",
"image": "test-server",
"imageId": "sha256:8282995409c26b82d66243f169f6695115a06ce860966db549f8ca09dcbb9767",
"label": map[string]string{}},
EntityRewrites: []data.EntityRewrite{
{
Action: "replace",
Match: "${ip}",
ReplaceField: "container:${containerId}",
},
},
},
}

matcher, err := discovery.NewMatcher(map[string]string{
"image": "/test-server/",
})
require.NoError(t, err)

actualDiscoveryData := getDiscoveries(givenContainerList, &matcher)
assert.Equal(t, expectedDiscoveryData, actualDiscoveryData)
}

func TestIsIPv4(t *testing.T) {
testCases := []struct {
name string
ip string
expected bool
}{
{
name: "ValidIpV4",
ip: "127.0.0.1",
expected: true,
},
{
name: "EmptyIp",
ip: "",
expected: false,
},
{
name: "IpV6",
ip: "0000:0000:0000:0000:0000:0000:0000:0001",
expected: false,
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, testCase.expected, isIPv4(testCase.ip))
})
}
}

0 comments on commit efbbf04

Please sign in to comment.