From 7b6b17fc7de45ea4e91bfb5988080c6dc1eec323 Mon Sep 17 00:00:00 2001 From: Chris Telfer Date: Wed, 7 Mar 2018 16:47:16 -0500 Subject: [PATCH] Add test for ingress removal on service removal The commit https://github.com/moby/moby/pull/35422 had the result of accidentally causing the removal of the ingress network when the last member of a service left the network. This did not appear in swarm instances because the swarm manager would still maintain and return cluster state about the network even though it had removed its sandbox and endpoint. This test verifies that after a service gets added and removed that the ingress sandbox remains in a functional state. Signed-off-by: Chris Telfer Upstream-commit: 805b6a7f749a6c7cbb237e21ee7260d536621808 Component: engine --- .../integration/network/service_test.go | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/components/engine/integration/network/service_test.go b/components/engine/integration/network/service_test.go index 684b29c1c1..f1c0950988 100644 --- a/components/engine/integration/network/service_test.go +++ b/components/engine/integration/network/service_test.go @@ -36,6 +36,9 @@ func TestServiceWithPredefinedNetwork(t *testing.T) { if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" { config.Timeout = 50 * time.Second config.Delay = 100 * time.Millisecond + } else { + config.Timeout = 30 * time.Second + config.Delay = 100 * time.Millisecond } } @@ -53,6 +56,72 @@ func TestServiceWithPredefinedNetwork(t *testing.T) { } +const ingressNet = "ingress" + +func TestServiceWithIngressNetwork(t *testing.T) { + defer setupTest(t)() + d := newSwarm(t) + defer d.Stop(t) + + client, err := client.NewClientWithOpts(client.WithHost((d.Sock()))) + require.NoError(t, err) + + pollSettings := func(config *poll.Settings) { + if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" { + config.Timeout = 50 * time.Second + config.Delay = 100 * time.Millisecond + } else { + config.Timeout = 30 * time.Second + config.Delay = 100 * time.Millisecond + } + } + + poll.WaitOn(t, swarmIngressReady(client), pollSettings) + + var instances uint64 = 1 + serviceName := "TestIngressService" + serviceSpec := swarmServiceSpec(serviceName, instances) + serviceSpec.TaskTemplate.Networks = append(serviceSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{Target: ingressNet}) + serviceSpec.EndpointSpec = &swarm.EndpointSpec{ + Ports: []swarm.PortConfig{ + { + Protocol: swarm.PortConfigProtocolTCP, + TargetPort: 80, + PublishMode: swarm.PortConfigPublishModeIngress, + }, + }, + } + + serviceResp, err := client.ServiceCreate(context.Background(), serviceSpec, types.ServiceCreateOptions{ + QueryRegistry: false, + }) + require.NoError(t, err) + + serviceID := serviceResp.ID + poll.WaitOn(t, serviceRunningCount(client, serviceID, instances), pollSettings) + + _, _, err = client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{}) + require.NoError(t, err) + + err = client.ServiceRemove(context.Background(), serviceID) + require.NoError(t, err) + + poll.WaitOn(t, serviceIsRemoved(client, serviceID), pollSettings) + poll.WaitOn(t, noTasks(client), pollSettings) + + // Ensure that "ingress" is not removed or corrupted + time.Sleep(10 * time.Second) + netInfo, err := client.NetworkInspect(context.Background(), ingressNet, types.NetworkInspectOptions{ + Verbose: true, + Scope: "swarm", + }) + require.NoError(t, err, "Ingress network was removed after removing service!") + require.NotZero(t, len(netInfo.Containers), "No load balancing endpoints in ingress network") + require.NotZero(t, len(netInfo.Peers), "No peers (including self) in ingress network") + _, ok := netInfo.Containers["ingress-sbox"] + require.True(t, ok, "ingress-sbox not present in ingress network") +} + func serviceRunningCount(client client.ServiceAPIClient, serviceID string, instances uint64) func(log poll.LogT) poll.Result { return func(log poll.LogT) poll.Result { filter := filters.NewArgs() @@ -68,3 +137,25 @@ func serviceRunningCount(client client.ServiceAPIClient, serviceID string, insta return poll.Success() } } + +func swarmIngressReady(client client.NetworkAPIClient) func(log poll.LogT) poll.Result { + return func(log poll.LogT) poll.Result { + netInfo, err := client.NetworkInspect(context.Background(), ingressNet, types.NetworkInspectOptions{ + Verbose: true, + Scope: "swarm", + }) + if err != nil { + return poll.Error(err) + } + np := len(netInfo.Peers) + nc := len(netInfo.Containers) + if np == 0 || nc == 0 { + return poll.Continue("ingress not ready: %d peers and %d containers", nc, np) + } + _, ok := netInfo.Containers["ingress-sbox"] + if !ok { + return poll.Continue("ingress not ready: does not contain the ingress-sbox") + } + return poll.Success() + } +}