Fix support for macvlan driver in docker provider
This commit is contained in:
parent
38a4c80995
commit
dd873fbeee
4 changed files with 225 additions and 101 deletions
|
@ -95,6 +95,25 @@ func taskSlot(slot int) func(*swarm.Task) {
|
|||
}
|
||||
}
|
||||
|
||||
func taskNetworkAttachment(id string, name string, driver string, addresses []string) func(*swarm.Task) {
|
||||
return func(task *swarm.Task) {
|
||||
task.NetworksAttachments = append(task.NetworksAttachments, swarm.NetworkAttachment{
|
||||
Network: swarm.Network{
|
||||
ID: id,
|
||||
Spec: swarm.NetworkSpec{
|
||||
Annotations: swarm.Annotations{
|
||||
Name: name,
|
||||
},
|
||||
DriverConfiguration: &swarm.Driver{
|
||||
Name: driver,
|
||||
},
|
||||
},
|
||||
},
|
||||
Addresses: addresses,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func taskStatus(ops ...func(*swarm.TaskStatus)) func(*swarm.Task) {
|
||||
return func(task *swarm.Task) {
|
||||
status := &swarm.TaskStatus{}
|
||||
|
@ -113,6 +132,14 @@ func taskState(state swarm.TaskState) func(*swarm.TaskStatus) {
|
|||
}
|
||||
}
|
||||
|
||||
func taskContainerStatus(id string) func(*swarm.TaskStatus) {
|
||||
return func(status *swarm.TaskStatus) {
|
||||
status.ContainerStatus = swarm.ContainerStatus{
|
||||
ContainerID: id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func swarmService(ops ...func(*swarm.Service)) swarm.Service {
|
||||
service := &swarm.Service{
|
||||
ID: "serviceID",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -473,70 +472,6 @@ func TestSwarmTraefikFilter(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSwarmTaskParsing(t *testing.T) {
|
||||
testCases := []struct {
|
||||
service swarm.Service
|
||||
tasks []swarm.Task
|
||||
isGlobalSVC bool
|
||||
expectedNames map[string]string
|
||||
networks map[string]*docker.NetworkResource
|
||||
}{
|
||||
{
|
||||
service: swarmService(serviceName("container")),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1", taskSlot(1)),
|
||||
swarmTask("id2", taskSlot(2)),
|
||||
swarmTask("id3", taskSlot(3)),
|
||||
},
|
||||
isGlobalSVC: false,
|
||||
expectedNames: map[string]string{
|
||||
"id1": "container.1",
|
||||
"id2": "container.2",
|
||||
"id3": "container.3",
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
service: swarmService(serviceName("container")),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1"),
|
||||
swarmTask("id2"),
|
||||
swarmTask("id3"),
|
||||
},
|
||||
isGlobalSVC: true,
|
||||
expectedNames: map[string]string{
|
||||
"id1": "container.id1",
|
||||
"id2": "container.id2",
|
||||
"id3": "container.id3",
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for caseID, test := range testCases {
|
||||
test := test
|
||||
t.Run(strconv.Itoa(caseID), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dData := parseService(test.service, test.networks)
|
||||
|
||||
for _, task := range test.tasks {
|
||||
taskDockerData := parseTasks(task, dData, map[string]*docker.NetworkResource{}, test.isGlobalSVC)
|
||||
if !reflect.DeepEqual(taskDockerData.Name, test.expectedNames[task.ID]) {
|
||||
t.Errorf("expect %v, got %v", test.expectedNames[task.ID], taskDockerData.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwarmGetFuncStringLabel(t *testing.T) {
|
||||
testCases := []struct {
|
||||
service swarm.Service
|
||||
|
|
|
@ -260,19 +260,27 @@ func listContainers(ctx context.Context, dockerClient client.ContainerAPIClient)
|
|||
var containersInspected []dockerData
|
||||
// get inspect containers
|
||||
for _, container := range containerList {
|
||||
containerInspected, err := dockerClient.ContainerInspect(ctx, container.ID)
|
||||
dData := inspectContainers(ctx, dockerClient, container.ID)
|
||||
if len(dData.Name) > 0 {
|
||||
containersInspected = append(containersInspected, dData)
|
||||
}
|
||||
}
|
||||
return containersInspected, nil
|
||||
}
|
||||
|
||||
func inspectContainers(ctx context.Context, dockerClient client.ContainerAPIClient, containerID string) dockerData {
|
||||
dData := dockerData{}
|
||||
containerInspected, err := dockerClient.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to inspect container %s, error: %s", container.ID, err)
|
||||
log.Warnf("Failed to inspect container %s, error: %s", containerID, err)
|
||||
} else {
|
||||
// This condition is here to avoid to have empty IP https://github.com/containous/traefik/issues/2459
|
||||
// We register only container which are running
|
||||
if containerInspected.ContainerJSONBase != nil && containerInspected.ContainerJSONBase.State != nil && containerInspected.ContainerJSONBase.State.Running {
|
||||
dData := parseContainer(containerInspected)
|
||||
containersInspected = append(containersInspected, dData)
|
||||
dData = parseContainer(containerInspected)
|
||||
}
|
||||
}
|
||||
}
|
||||
return containersInspected, nil
|
||||
return dData
|
||||
}
|
||||
|
||||
func parseContainer(container dockertypes.ContainerJSON) dockerData {
|
||||
|
@ -388,6 +396,7 @@ func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes
|
|||
for _, virtualIP := range service.Endpoint.VirtualIPs {
|
||||
networkService := networkMap[virtualIP.NetworkID]
|
||||
if networkService != nil {
|
||||
if len(virtualIP.Addr) > 0 {
|
||||
ip, _, _ := net.ParseCIDR(virtualIP.Addr)
|
||||
network := &networkData{
|
||||
Name: networkService.Name,
|
||||
|
@ -395,6 +404,9 @@ func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes
|
|||
Addr: ip.String(),
|
||||
}
|
||||
dData.NetworkSettings.Networks[network.Name] = network
|
||||
} else {
|
||||
log.Debugf("No virtual IPs found in network %s", virtualIP.NetworkID)
|
||||
}
|
||||
} else {
|
||||
log.Debugf("Network not found, id: %s", virtualIP.NetworkID)
|
||||
}
|
||||
|
@ -421,12 +433,15 @@ func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID str
|
|||
continue
|
||||
}
|
||||
dData := parseTasks(task, serviceDockerData, networkMap, isGlobalSvc)
|
||||
if len(dData.NetworkSettings.Networks) > 0 {
|
||||
dockerDataList = append(dockerDataList, dData)
|
||||
}
|
||||
}
|
||||
return dockerDataList, err
|
||||
}
|
||||
|
||||
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) dockerData {
|
||||
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData,
|
||||
networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) dockerData {
|
||||
dData := dockerData{
|
||||
ServiceName: serviceDockerData.Name,
|
||||
Name: serviceDockerData.Name + "." + strconv.Itoa(task.Slot),
|
||||
|
@ -442,6 +457,7 @@ func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap m
|
|||
dData.NetworkSettings.Networks = make(map[string]*networkData)
|
||||
for _, virtualIP := range task.NetworksAttachments {
|
||||
if networkService, present := networkMap[virtualIP.Network.ID]; present {
|
||||
if len(virtualIP.Addresses) > 0 {
|
||||
// Not sure about this next loop - when would a task have multiple IP's for the same network?
|
||||
for _, addr := range virtualIP.Addresses {
|
||||
ip, _, _ := net.ParseCIDR(addr)
|
||||
|
@ -452,6 +468,9 @@ func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap m
|
|||
}
|
||||
dData.NetworkSettings.Networks[network.Name] = network
|
||||
}
|
||||
} else {
|
||||
log.Debugf("No IP addresses found for network %s", virtualIP.Network.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
type fakeTasksClient struct {
|
||||
dockerclient.APIClient
|
||||
tasks []swarm.Task
|
||||
container dockertypes.ContainerJSON
|
||||
err error
|
||||
}
|
||||
|
||||
|
@ -24,6 +25,10 @@ func (c *fakeTasksClient) TaskList(ctx context.Context, options dockertypes.Task
|
|||
return c.tasks, c.err
|
||||
}
|
||||
|
||||
func (c *fakeTasksClient) ContainerInspect(ctx context.Context, container string) (dockertypes.ContainerJSON, error) {
|
||||
return c.container, c.err
|
||||
}
|
||||
|
||||
func TestListTasks(t *testing.T) {
|
||||
testCases := []struct {
|
||||
service swarm.Service
|
||||
|
@ -35,11 +40,30 @@ func TestListTasks(t *testing.T) {
|
|||
{
|
||||
service: swarmService(serviceName("container")),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1", taskSlot(1), taskStatus(taskState(swarm.TaskStateRunning))),
|
||||
swarmTask("id2", taskSlot(2), taskStatus(taskState(swarm.TaskStatePending))),
|
||||
swarmTask("id3", taskSlot(3)),
|
||||
swarmTask("id4", taskSlot(4), taskStatus(taskState(swarm.TaskStateRunning))),
|
||||
swarmTask("id5", taskSlot(5), taskStatus(taskState(swarm.TaskStateFailed))),
|
||||
swarmTask("id1",
|
||||
taskSlot(1),
|
||||
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.1"}),
|
||||
taskStatus(taskState(swarm.TaskStateRunning)),
|
||||
),
|
||||
swarmTask("id2",
|
||||
taskSlot(2),
|
||||
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.2"}),
|
||||
taskStatus(taskState(swarm.TaskStatePending)),
|
||||
),
|
||||
swarmTask("id3",
|
||||
taskSlot(3),
|
||||
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.3"}),
|
||||
),
|
||||
swarmTask("id4",
|
||||
taskSlot(4),
|
||||
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.4"}),
|
||||
taskStatus(taskState(swarm.TaskStateRunning)),
|
||||
),
|
||||
swarmTask("id5",
|
||||
taskSlot(5),
|
||||
taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.5"}),
|
||||
taskStatus(taskState(swarm.TaskStateFailed)),
|
||||
),
|
||||
},
|
||||
isGlobalSVC: false,
|
||||
expectedTasks: []string{
|
||||
|
@ -60,7 +84,7 @@ func TestListTasks(t *testing.T) {
|
|||
t.Parallel()
|
||||
dockerData := parseService(test.service, test.networks)
|
||||
dockerClient := &fakeTasksClient{tasks: test.tasks}
|
||||
taskDockerData, _ := listTasks(context.Background(), dockerClient, test.service.ID, dockerData, map[string]*docker.NetworkResource{}, test.isGlobalSVC)
|
||||
taskDockerData, _ := listTasks(context.Background(), dockerClient, test.service.ID, dockerData, test.networks, test.isGlobalSVC)
|
||||
|
||||
if len(test.expectedTasks) != len(taskDockerData) {
|
||||
t.Errorf("expected tasks %v, got %v", spew.Sdump(test.expectedTasks), spew.Sdump(taskDockerData))
|
||||
|
@ -203,8 +227,14 @@ func TestListServices(t *testing.T) {
|
|||
withEndpointSpec(modeDNSSR)),
|
||||
},
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1", taskStatus(taskState(swarm.TaskStateRunning))),
|
||||
swarmTask("id2", taskStatus(taskState(swarm.TaskStateRunning))),
|
||||
swarmTask("id1",
|
||||
taskNetworkAttachment("yk6l57rfwizjzxxzftn4amaot", "network_name", "overlay", []string{"127.0.0.1"}),
|
||||
taskStatus(taskState(swarm.TaskStateRunning)),
|
||||
),
|
||||
swarmTask("id2",
|
||||
taskNetworkAttachment("yk6l57rfwizjzxxzftn4amaot", "network_name", "overlay", []string{"127.0.0.1"}),
|
||||
taskStatus(taskState(swarm.TaskStateRunning)),
|
||||
),
|
||||
},
|
||||
dockerVersion: "1.30",
|
||||
networks: []dockertypes.NetworkResource{
|
||||
|
@ -252,3 +282,116 @@ func TestListServices(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwarmTaskParsing(t *testing.T) {
|
||||
testCases := []struct {
|
||||
service swarm.Service
|
||||
tasks []swarm.Task
|
||||
isGlobalSVC bool
|
||||
expected map[string]dockerData
|
||||
networks map[string]*docker.NetworkResource
|
||||
}{
|
||||
{
|
||||
service: swarmService(serviceName("container")),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1", taskSlot(1)),
|
||||
swarmTask("id2", taskSlot(2)),
|
||||
swarmTask("id3", taskSlot(3)),
|
||||
},
|
||||
isGlobalSVC: false,
|
||||
expected: map[string]dockerData{
|
||||
"id1": {
|
||||
Name: "container.1",
|
||||
},
|
||||
"id2": {
|
||||
Name: "container.2",
|
||||
},
|
||||
"id3": {
|
||||
Name: "container.3",
|
||||
},
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
service: swarmService(serviceName("container")),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask("id1"),
|
||||
swarmTask("id2"),
|
||||
swarmTask("id3"),
|
||||
},
|
||||
isGlobalSVC: true,
|
||||
expected: map[string]dockerData{
|
||||
"id1": {
|
||||
Name: "container.id1",
|
||||
},
|
||||
"id2": {
|
||||
Name: "container.id2",
|
||||
},
|
||||
"id3": {
|
||||
Name: "container.id3",
|
||||
},
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
service: swarmService(
|
||||
serviceName("container"),
|
||||
withEndpointSpec(modeVIP),
|
||||
withEndpoint(
|
||||
virtualIP("1", ""),
|
||||
),
|
||||
),
|
||||
tasks: []swarm.Task{
|
||||
swarmTask(
|
||||
"id1",
|
||||
taskNetworkAttachment("1", "vlan", "macvlan", []string{"127.0.0.1"}),
|
||||
taskStatus(
|
||||
taskState(swarm.TaskStateRunning),
|
||||
taskContainerStatus("c1"),
|
||||
),
|
||||
),
|
||||
},
|
||||
isGlobalSVC: true,
|
||||
expected: map[string]dockerData{
|
||||
"id1": {
|
||||
Name: "container.id1",
|
||||
NetworkSettings: networkSettings{
|
||||
Networks: map[string]*networkData{
|
||||
"vlan": {
|
||||
Name: "vlan",
|
||||
Addr: "10.11.12.13",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
networks: map[string]*docker.NetworkResource{
|
||||
"1": {
|
||||
Name: "vlan",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for caseID, test := range testCases {
|
||||
test := test
|
||||
t.Run(strconv.Itoa(caseID), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dData := parseService(test.service, test.networks)
|
||||
|
||||
for _, task := range test.tasks {
|
||||
taskDockerData := parseTasks(task, dData, test.networks, test.isGlobalSVC)
|
||||
expected := test.expected[task.ID]
|
||||
assert.Equal(t, expected.Name, taskDockerData.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue