summaryrefslogtreecommitdiffstats
path: root/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImplTest.java
blob: 99b3fde4eb1f578bb931112dd079124e388f5781 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.node.admin.docker;

import com.google.common.net.InetAddresses;
import com.yahoo.collections.Pair;
import com.yahoo.system.ProcessExecuter;
import com.yahoo.vespa.hosted.dockerapi.Container;
import com.yahoo.vespa.hosted.dockerapi.ContainerName;
import com.yahoo.vespa.hosted.dockerapi.Docker;
import com.yahoo.vespa.hosted.dockerapi.DockerImage;
import com.yahoo.vespa.hosted.dockerapi.ProcessResult;
import com.yahoo.vespa.hosted.node.admin.nodeagent.ContainerData;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext;
import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextImpl;
import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddresses;
import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddressesMock;
import org.junit.Test;
import org.mockito.InOrder;

import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.OptionalLong;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class DockerOperationsImplTest {
    private final Docker docker = mock(Docker.class);
    private final ProcessExecuter processExecuter = mock(ProcessExecuter.class);
    private final IPAddresses ipAddresses = new IPAddressesMock();
    private final DockerOperationsImpl dockerOperations = new DockerOperationsImpl(
            docker, processExecuter, ipAddresses);

    @Test
    public void processResultFromNodeProgramWhenSuccess() {
        final NodeAgentContext context = new NodeAgentContextImpl.Builder("container-123.domain.tld").build();
        final ProcessResult actualResult = new ProcessResult(0, "output", "errors");

        when(docker.executeInContainerAsUser(any(), any(), any(), any()))
                .thenReturn(actualResult); // output from node program

        ProcessResult result = dockerOperations.executeNodeCtlInContainer(context, "start");

        final InOrder inOrder = inOrder(docker);
        inOrder.verify(docker, times(1)).executeInContainerAsUser(
                eq(context.containerName()),
                eq("root"),
                eq(OptionalLong.empty()),
                eq("/opt/vespa/bin/vespa-nodectl"),
                eq("start"));

        assertThat(result, is(actualResult));
    }

    @Test(expected = RuntimeException.class)
    public void processResultFromNodeProgramWhenNonZeroExitCode() {
        final NodeAgentContext context = new NodeAgentContextImpl.Builder("container-123.domain.tld").build();
        final ProcessResult actualResult = new ProcessResult(3, "output", "errors");

        when(docker.executeInContainerAsUser(any(), any(), any(), any()))
                .thenReturn(actualResult); // output from node program

        dockerOperations.executeNodeCtlInContainer(context, "start");
    }

    @Test
    public void runsCommandInNetworkNamespace() throws IOException {
        Container container = makeContainer("container-42", Container.State.RUNNING, 42);

        when(processExecuter.exec(aryEq(new String[]{"nsenter", "--net=/proc/42/ns/net", "--", "iptables", "-nvL"})))
                .thenReturn(new Pair<>(0, ""));

        dockerOperations.executeCommandInNetworkNamespace(container.name, "iptables", "-nvL");
    }

    private Container makeContainer(String name, Container.State state, int pid) {
        final Container container = new Container(name + ".fqdn", new DockerImage("mock"), null,
                new ContainerName(name), state, pid);
        when(docker.getContainer(eq(container.name))).thenReturn(Optional.of(container));
        return container;
    }

    @Test
    public void verifyEtcHosts() {
        ContainerData containerData = mock(ContainerData.class);
        String hostname = "hostname";
        InetAddress ipV6Local = InetAddresses.forString("::1");
        InetAddress ipV4Local = InetAddresses.forString("127.0.0.1");

        dockerOperations.addEtcHosts(containerData, hostname, Optional.empty(), ipV6Local);

        verify(containerData, times(1)).addFile(
                Paths.get("/etc/hosts"),
                "# This file was generated by com.yahoo.vespa.hosted.node.admin.docker.DockerOperationsImpl\n" +
                        "127.0.0.1	localhost\n" +
                        "::1	localhost ip6-localhost ip6-loopback\n" +
                        "fe00::0	ip6-localnet\n" +
                        "ff00::0	ip6-mcastprefix\n" +
                        "ff02::1	ip6-allnodes\n" +
                        "ff02::2	ip6-allrouters\n" +
                        "0:0:0:0:0:0:0:1	hostname\n");

        dockerOperations.addEtcHosts(containerData, hostname, Optional.of(ipV4Local), ipV6Local);

        verify(containerData, times(1)).addFile(
                Paths.get("/etc/hosts"),
                "# This file was generated by com.yahoo.vespa.hosted.node.admin.docker.DockerOperationsImpl\n" +
                        "127.0.0.1	localhost\n" +
                        "::1	localhost ip6-localhost ip6-loopback\n" +
                        "fe00::0	ip6-localnet\n" +
                        "ff00::0	ip6-mcastprefix\n" +
                        "ff02::1	ip6-allnodes\n" +
                        "ff02::2	ip6-allrouters\n" +
                        "0:0:0:0:0:0:0:1	hostname\n" +
                        "127.0.0.1	hostname\n");
    }
}