aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/NodeList.java
blob: a3aefa55f4e7a73759efbaaab39768e9c623b99a (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;

import com.yahoo.collections.AbstractFilteringList;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ServiceConvergence;

import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jonmv
 */
public class NodeList extends AbstractFilteringList<NodeWithServices, NodeList> {

    private final long wantedConfigGeneration;

    private NodeList(Collection<? extends NodeWithServices> items, boolean negate, long wantedConfigGeneration) {
        super(items, negate, (i, n) -> new NodeList(i, n, wantedConfigGeneration));
        this.wantedConfigGeneration = wantedConfigGeneration;
    }

    public static NodeList of(List<Node> nodes, List<Node> parents, ServiceConvergence services) {
        var servicesByHostName = services.services().stream()
                                         .collect(Collectors.groupingBy(service -> service.host()));
        var parentsByHostName = parents.stream()
                                       .collect(Collectors.toMap(node -> node.hostname(), node -> node));
        return new NodeList(nodes.stream()
                                 .map(node -> new NodeWithServices(node,
                                                                   parentsByHostName.get(node.parentHostname().get()),
                                                                   services.wantedGeneration(),
                                                                   servicesByHostName.getOrDefault(node.hostname(), List.of())))
                                 .toList(),
                            false,
                            services.wantedGeneration());
    }

    /** The nodes on an outdated OS. */
    public NodeList needsOsUpgrade() {
        return matching(NodeWithServices::needsOsUpgrade);
    }

    /** The nodes with outdated firmware. */
    public NodeList needsFirmwareUpgrade() {
        return matching(NodeWithServices::needsFirmwareUpgrade);
    }

    /** The nodes whose parent is down. */
    public NodeList withParentDown() {
        return matching(NodeWithServices::hasParentDown);
    }

    /** The nodes on an outdated platform. */
    public NodeList needsPlatformUpgrade() {
        return matching(NodeWithServices::needsPlatformUpgrade);
    }

    /** The nodes in need of a reboot. */
    public NodeList needsReboot() {
        return matching(NodeWithServices::needsReboot);
    }

    /** The nodes in need of a restart. */
    public NodeList needsRestart() {
        return matching(NodeWithServices::needsRestart);
    }

    /** The nodes currently allowed to be down. */
    public NodeList allowedDown() {
        return matching(node -> node.isAllowedDown());
    }

    /** The nodes currently expected to be down. */
    public NodeList expectedDown() {
        return matching(node -> node.isAllowedDown() || node.isNewlyProvisioned());
    }

    /** The nodes which have been suspended since before the given instant. */
    public NodeList suspendedSince(Instant instant) {
        return matching(node -> node.isSuspendedSince(instant));
    }

    /** The nodes with services on outdated config generation. */
    public NodeList needsNewConfig() {
        return matching(NodeWithServices::needsNewConfig);
    }

    public NodeList isStateful() {
        return matching(NodeWithServices::isStateful);
    }

    /** The nodes that are retiring. */
    public NodeList retiring() {
        return matching(node -> node.node().retired());
    }


    /** Returns a summary of the convergence status of the nodes in this list. */
    public ConvergenceSummary summary() {
        NodeList allowedDown = expectedDown();
        return new ConvergenceSummary(size(),
                                      allowedDown.size(),
                                      withParentDown().needsOsUpgrade().size(),
                                      withParentDown().needsFirmwareUpgrade().size(),
                                      needsPlatformUpgrade().size(),
                                      allowedDown.needsPlatformUpgrade().size(),
                                      needsReboot().size(),
                                      allowedDown.needsReboot().size(),
                                      needsRestart().size(),
                                      allowedDown.needsRestart().size(),
                                      asList().stream().mapToLong(node -> node.services().size()).sum(),
                                      asList().stream().mapToLong(node -> node.services().stream().filter(service -> wantedConfigGeneration > service.currentGeneration()).count()).sum(),
                                      retiring().size());
    }

}