aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java
blob: ab8175cf98957de5fdaccef7a1f343d52652bd82 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.maintenance;

import com.yahoo.collections.Pair;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.Zone;
import com.yahoo.config.provisioning.FlavorsConfig;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
import com.yahoo.vespa.hosted.provision.autoscale.ClusterMetricSnapshot;
import com.yahoo.vespa.hosted.provision.autoscale.Load;
import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricSnapshot;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorConfigBuilder;
import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester;
import com.yahoo.vespa.hosted.provision.testutils.MockDeployer;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.function.IntFunction;

/**
 * @author bratseth
 */
public class AutoscalingMaintainerTester {

    private final ProvisioningTester provisioningTester;
    private final AutoscalingMaintainer maintainer;
    private final MockDeployer deployer;

    public AutoscalingMaintainerTester(MockDeployer.ApplicationContext ... appContexts) {
        this(new Zone(Environment.prod, RegionName.from("us-east3")), appContexts);
    }

    public AutoscalingMaintainerTester(Zone zone, MockDeployer.ApplicationContext ... appContexts) {
        provisioningTester = new ProvisioningTester.Builder().zone(zone).flavorsConfig(flavorsConfig()).build();
        provisioningTester.clock().setInstant(Instant.ofEpochMilli(0));
        deployer = new MockDeployer(provisioningTester.provisioner(), provisioningTester.clock(), List.of(appContexts));
        maintainer = new AutoscalingMaintainer(provisioningTester.nodeRepository(),
                                               deployer,
                                               new TestMetric(),
                                               Duration.ofMinutes(1));
        provisioningTester.makeReadyNodes(20, "flt", NodeType.host, 8);
        provisioningTester.activateTenantHosts();
    }

    public NodeRepository nodeRepository() { return provisioningTester.nodeRepository(); }
    public ManualClock clock() { return provisioningTester.clock(); }
    public MockDeployer deployer() { return deployer; }
    public AutoscalingMaintainer maintainer() { return maintainer; }

    public static ApplicationId makeApplicationId(String name) { return ProvisioningTester.applicationId(name); }
    public static ClusterSpec containerClusterSpec() { return ProvisioningTester.containerClusterSpec(); }

    public List<Node> deploy(ApplicationId application, ClusterSpec cluster, Capacity capacity) {
        return provisioningTester.deploy(application, cluster, capacity);
    }

    public Duration addMeasurements(float cpu, float mem, float disk, long generation, int count,
                                    ApplicationId applicationId, ClusterSpec.Id clusterId) {
        NodeList nodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId);
        Instant startTime = clock().instant();
        for (int i = 0; i < count; i++) {
            for (Node node : nodes)
                nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(),
                                                                               new NodeMetricSnapshot(clock().instant(),
                                                                                                      new Load(cpu, mem, disk),
                                                                                                      generation,
                                                                                                      true,
                                                                                                      true,
                                                                                                      0.0))));
            clock().advance(Duration.ofSeconds(150));
        }
        var totalDuration = Duration.between(startTime, clock().instant());
        clock().advance(totalDuration.negated());
        addQueryRateMeasurements(applicationId, clusterId, count, t -> 100.0);
        return totalDuration;
    }

    /** Creates the given number of measurements, spaced 5 minutes between, using the given function */
    public void addQueryRateMeasurements(ApplicationId application,
                                         ClusterSpec.Id cluster,
                                         int measurements,
                                         IntFunction<Double> queryRate) {
        for (int i = 0; i < measurements; i++) {
            nodeRepository().metricsDb().addClusterMetrics(application,
                                                           Map.of(cluster, new ClusterMetricSnapshot(clock().instant(), queryRate.apply(i), 0.0)));
            clock().advance(Duration.ofSeconds(150));
        }
    }

    public Cluster cluster(ApplicationId application, ClusterSpec cluster) {
        return nodeRepository().applications().get(application).get().cluster(cluster.id()).get();
    }

    private FlavorsConfig flavorsConfig() {
        FlavorConfigBuilder b = new FlavorConfigBuilder();
        b.addFlavor("flt", 30, 30, 50, 3, Flavor.Type.BARE_METAL);
        b.addFlavor("cpu", 40, 20, 40, 3, Flavor.Type.BARE_METAL);
        b.addFlavor("mem", 20, 40, 40, 3, Flavor.Type.BARE_METAL);
        return b.build();
    }

}