aboutsummaryrefslogtreecommitdiffstats
path: root/service-monitor/src/main/java/com/yahoo/vespa/service/duper/InfraApplication.java
blob: e4181f7cb108bccacc62c6198c5a44ea96bf9817 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.duper;

import ai.vespa.http.DomainName;
import com.yahoo.component.Version;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.HostInfo;
import com.yahoo.config.model.api.PortInfo;
import com.yahoo.config.model.api.ServiceInfo;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.InfrastructureApplication;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.applicationmodel.TenantId;
import com.yahoo.vespa.service.health.StateV1HealthModel;
import com.yahoo.vespa.service.model.ApplicationInstanceGenerator;
import com.yahoo.vespa.service.model.ModelGenerator;
import com.yahoo.vespa.service.monitor.InfraApplicationApi;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author freva
 */
public abstract class InfraApplication implements InfraApplicationApi {

    private final InfrastructureApplication application;
    private final Capacity capacity;
    private final ClusterSpec.Type clusterSpecType;
    private final ClusterSpec.Id clusterSpecId;
    private final ServiceType serviceType;
    private final int healthPort;

    protected InfraApplication(InfrastructureApplication application,
                               ClusterSpec.Type clusterSpecType,
                               ClusterSpec.Id clusterSpecId,
                               ServiceType serviceType,
                               int healthPort) {
        this.application = application;
        this.capacity = Capacity.fromRequiredNodeType(application.nodeType());
        this.clusterSpecType = clusterSpecType;
        this.clusterSpecId = clusterSpecId;
        this.serviceType = serviceType;
        this.healthPort = healthPort;
    }

    @Override
    public ApplicationId getApplicationId() {
        return application.id();
    }

    @Override
    public Capacity getCapacity() {
        return capacity;
    }

    @Override
    public ClusterSpec getClusterSpecWithVersion(Version version) {
        return ClusterSpec.request(clusterSpecType, clusterSpecId).exclusive(true).vespaVersion(version).build();
    }

    public ClusterSpec.Type getClusterSpecType() {
        return clusterSpecType;
    }

    public ClusterSpec.Id getClusterSpecId() {
        return clusterSpecId;
    }

    public ClusterId getClusterId() {
        return new ClusterId(clusterSpecId.value());
    }

    public ServiceType getServiceType() {
        return serviceType;
    }

    public ApplicationInstanceId getApplicationInstanceId(Zone zone) {
        return ApplicationInstanceGenerator.toApplicationInstanceId(application.id(), zone);
    }

    public TenantId getTenantId() {
        return new TenantId(application.id().tenant().value());
    }

    public ApplicationInfo makeApplicationInfo(List<DomainName> hostnames) {
        List<HostInfo> hostInfos = hostnames.stream().map(this::makeHostInfo).toList();
        return new ApplicationInfo(application.id(), 0, new HostsModel(hostInfos));
    }

    private HostInfo makeHostInfo(DomainName hostname) {
        PortInfo portInfo = new PortInfo(healthPort, StateV1HealthModel.HTTP_HEALTH_PORT_TAGS);

        Map<String, String> properties = new HashMap<>();
        properties.put(ModelGenerator.CLUSTER_ID_PROPERTY_NAME, getClusterId().s());

        ServiceInfo serviceInfo = new ServiceInfo(
                // service name == service type for the first service of each type on each host
                serviceType.s(),
                serviceType.s(),
                Collections.singletonList(portInfo),
                properties,
                configIdFor(hostname).s(),
                hostname.value());

        return new HostInfo(hostname.value(), Collections.singletonList(serviceInfo));
    }

    public ConfigId configIdFor(DomainName hostname) {
        // Not necessarily unique, but service monitor doesn't require it to be unique.
        return new ConfigId(String.format("%s/%s", clusterSpecId.value(), prefixTo(hostname.value(), '.')));
    }

    private static String prefixTo(String string, char sentinel) {
        int offset = string.indexOf(sentinel);
        if (offset == -1) {
            return string;
        } else {
            return string.substring(0, offset);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        InfraApplication that = (InfraApplication) o;
        return healthPort == that.healthPort &&
                Objects.equals(application, that.application) &&
                Objects.equals(capacity, that.capacity) &&
                clusterSpecType == that.clusterSpecType &&
                Objects.equals(clusterSpecId, that.clusterSpecId) &&
                Objects.equals(serviceType, that.serviceType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(application, capacity, clusterSpecType, clusterSpecId, serviceType, healthPort);
    }

    @Override
    public String toString() {
        return "InfraApplication{" +
                "application=" + application +
                ", capacity=" + capacity +
                ", clusterSpecType=" + clusterSpecType +
                ", clusterSpecId=" + clusterSpecId +
                ", serviceType=" + serviceType +
                ", healthPort=" + healthPort +
                '}';
    }

}