diff options
author | Harald Musum <musum@oath.com> | 2018-05-31 18:17:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-31 18:17:07 +0200 |
commit | 8bb145d2102fa5055c1860facda92ca0d9e108cd (patch) | |
tree | 7afc103f3021cfa5c4728d245991e570221f0ffc /service-monitor/src | |
parent | f5002a3fb979c72c0ee44f03204d1f233d13c6fa (diff) |
Revert "Make health client wo using it"
Diffstat (limited to 'service-monitor/src')
33 files changed, 399 insertions, 1272 deletions
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java index 75e61eef772..35003313775 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java @@ -11,13 +11,7 @@ import com.yahoo.vespa.applicationmodel.ServiceType; * @author hakon */ public interface ServiceStatusProvider { - /** - * Get the {@link ServiceStatus} of a particular service. - * - * <p>{@link ServiceStatus#NOT_CHECKED NOT_CHECKED} must be returned if the - * service status provider does does not monitor the service status for - * the particular application, cluster, service type, and config id. - */ + /** Get the {@link ServiceStatus} of a particular service. */ ServiceStatus getStatus(ApplicationId applicationId, ClusterId clusterId, ServiceType serviceType, diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java index cbdcce125cc..ec2702bcfaf 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java @@ -1,148 +1,13 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.application; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.model.api.HostInfo; -import com.yahoo.config.model.api.ServiceInfo; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.Zone; import com.yahoo.vespa.applicationmodel.ApplicationInstance; -import com.yahoo.vespa.applicationmodel.ApplicationInstanceId; -import com.yahoo.vespa.applicationmodel.ClusterId; -import com.yahoo.vespa.applicationmodel.ConfigId; -import com.yahoo.vespa.applicationmodel.HostName; -import com.yahoo.vespa.applicationmodel.ServiceCluster; -import com.yahoo.vespa.applicationmodel.ServiceClusterKey; -import com.yahoo.vespa.applicationmodel.ServiceInstance; -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.applicationmodel.ServiceType; -import com.yahoo.vespa.applicationmodel.TenantId; import com.yahoo.vespa.service.monitor.ServiceStatusProvider; -import com.yahoo.vespa.service.monitor.internal.ServiceId; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION; /** - * Class to generate an ApplicationInstance given service status for a standard (deployed) application. - * * @author hakon */ -public class ApplicationInstanceGenerator { - public static final String CLUSTER_ID_PROPERTY_NAME = "clustername"; - - private final ApplicationInfo applicationInfo; - private final Zone zone; - - public ApplicationInstanceGenerator(ApplicationInfo applicationInfo, Zone zone) { - this.applicationInfo = applicationInfo; - this.zone = zone; - } - - public ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider) { - Map<ServiceClusterKey, Set<ServiceInstance>> groupedServiceInstances = new HashMap<>(); - - for (HostInfo host : applicationInfo.getModel().getHosts()) { - HostName hostName = new HostName(host.getHostname()); - for (ServiceInfo serviceInfo : host.getServices()) { - ServiceClusterKey serviceClusterKey = toServiceClusterKey(serviceInfo); - ServiceInstance serviceInstance = - toServiceInstance( - applicationInfo.getApplicationId(), - serviceClusterKey.clusterId(), - serviceInfo, - hostName, - serviceStatusProvider); - - if (!groupedServiceInstances.containsKey(serviceClusterKey)) { - groupedServiceInstances.put(serviceClusterKey, new HashSet<>()); - } - groupedServiceInstances.get(serviceClusterKey).add(serviceInstance); - } - } - - Set<ServiceCluster> serviceClusters = groupedServiceInstances.entrySet().stream() - .map(entry -> new ServiceCluster( - entry.getKey().clusterId(), - entry.getKey().serviceType(), - entry.getValue())) - .collect(Collectors.toSet()); - - ApplicationInstance applicationInstance = new ApplicationInstance( - new TenantId(applicationInfo.getApplicationId().tenant().toString()), - toApplicationInstanceId(applicationInfo, zone), - serviceClusters); - - // Fill back-references - for (ServiceCluster serviceCluster : applicationInstance.serviceClusters()) { - serviceCluster.setApplicationInstance(applicationInstance); - for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) { - serviceInstance.setServiceCluster(serviceCluster); - } - } - - return applicationInstance; - } - - private ServiceInstance toServiceInstance( - ApplicationId applicationId, - ClusterId clusterId, - ServiceInfo serviceInfo, - HostName hostName, - ServiceStatusProvider serviceStatusProvider) { - ConfigId configId = toConfigId(serviceInfo); - - ServiceStatus status = serviceStatusProvider.getStatus( - applicationId, - clusterId, - toServiceType(serviceInfo), configId); - - return new ServiceInstance(configId, hostName, status); - } - - private ApplicationInstanceId toApplicationInstanceId(ApplicationInfo applicationInfo, Zone zone) { - if (applicationInfo.getApplicationId().equals(CONFIG_SERVER_APPLICATION.getApplicationId())) { - // Removing this historical discrepancy would break orchestration during rollout. - // An alternative may be to use a feature flag and flip it between releases, - // once that's available. - return new ApplicationInstanceId(applicationInfo.getApplicationId().application().value()); - } else { - return new ApplicationInstanceId(String.format("%s:%s:%s:%s", - applicationInfo.getApplicationId().application().value(), - zone.environment().value(), - zone.region().value(), - applicationInfo.getApplicationId().instance().value())); - } - } - - public static ServiceId getServiceId(ApplicationInfo applicationInfo, ServiceInfo serviceInfo) { - return new ServiceId( - applicationInfo.getApplicationId(), - getClusterId(serviceInfo), - toServiceType(serviceInfo), - toConfigId(serviceInfo)); - } - - private static ClusterId getClusterId(ServiceInfo serviceInfo) { - return new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse("")); - } - - private static ServiceClusterKey toServiceClusterKey(ServiceInfo serviceInfo) { - ClusterId clusterId = getClusterId(serviceInfo); - ServiceType serviceType = toServiceType(serviceInfo); - return new ServiceClusterKey(clusterId, serviceType); - } - - private static ServiceType toServiceType(ServiceInfo serviceInfo) { - return new ServiceType(serviceInfo.getServiceType()); - } - - private static ConfigId toConfigId(ServiceInfo serviceInfo) { - return new ConfigId(serviceInfo.getConfigId()); - } +public interface ApplicationInstanceGenerator { + /** Make an ApplicationInstance based on current service status. */ + ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider); } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java new file mode 100644 index 00000000000..76ca59cf583 --- /dev/null +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java @@ -0,0 +1,67 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.service.monitor.application; + +import com.yahoo.vespa.applicationmodel.ApplicationInstance; +import com.yahoo.vespa.applicationmodel.ConfigId; +import com.yahoo.vespa.applicationmodel.HostName; +import com.yahoo.vespa.applicationmodel.ServiceCluster; +import com.yahoo.vespa.applicationmodel.ServiceInstance; +import com.yahoo.vespa.applicationmodel.ServiceStatus; +import com.yahoo.vespa.service.monitor.ServiceStatusProvider; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Class for generating an ApplicationInstance for the synthesized config server application. + * + * @author hakon + */ +public class ConfigServerAppGenerator implements ApplicationInstanceGenerator { + private final List<String> hostnames; + + public ConfigServerAppGenerator(List<String> hostnames) { + this.hostnames = hostnames; + } + + @Override + public ApplicationInstance makeApplicationInstance(ServiceStatusProvider statusProvider) { + Set<ServiceInstance> serviceInstances = hostnames.stream() + .map(hostname -> makeServiceInstance(hostname, statusProvider)) + .collect(Collectors.toSet()); + + ServiceCluster serviceCluster = new ServiceCluster( + ConfigServerApplication.CLUSTER_ID, + ConfigServerApplication.SERVICE_TYPE, + serviceInstances); + + Set<ServiceCluster> serviceClusters = new HashSet<>(); + serviceClusters.add(serviceCluster); + + ApplicationInstance applicationInstance = new ApplicationInstance( + ConfigServerApplication.TENANT_ID, + ConfigServerApplication.APPLICATION_INSTANCE_ID, + serviceClusters); + + // Fill back-references + serviceCluster.setApplicationInstance(applicationInstance); + for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) { + serviceInstance.setServiceCluster(serviceCluster); + } + + return applicationInstance; + } + + private ServiceInstance makeServiceInstance(String hostname, ServiceStatusProvider statusProvider) { + ConfigId configId = new ConfigId(ConfigServerApplication.CONFIG_ID_PREFIX + hostname); + ServiceStatus status = statusProvider.getStatus( + ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(), + ConfigServerApplication.CLUSTER_ID, + ConfigServerApplication.SERVICE_TYPE, + configId); + + return new ServiceInstance(configId, new HostName(hostname), status); + } +} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java index ff51b40e4dd..132bb0927b8 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java @@ -1,26 +1,12 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.application; -import com.yahoo.cloud.config.ConfigserverConfig; -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.ClusterSpec; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.applicationmodel.ApplicationInstanceId; import com.yahoo.vespa.applicationmodel.ClusterId; -import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceType; import com.yahoo.vespa.applicationmodel.TenantId; -import com.yahoo.vespa.service.monitor.internal.ModelGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** * A service/application model of the config server with health status. @@ -35,45 +21,8 @@ public class ConfigServerApplication extends HostedVespaApplication { public static final ServiceType SERVICE_TYPE = new ServiceType("configserver"); public static final String CONFIG_ID_PREFIX = "configid."; - public static ConfigId configIdFrom(int index) { - return new ConfigId(CONFIG_ID_PREFIX + index); - } - private ConfigServerApplication() { super("zone-config-servers", NodeType.config, ClusterSpec.Type.admin, ClusterSpec.Id.from("zone-config-servers")); } - - public ApplicationInfo makeApplicationInfo(ConfigserverConfig config) { - List<HostInfo> hostInfos = new ArrayList<>(); - List<ConfigserverConfig.Zookeeperserver> zooKeeperServers = config.zookeeperserver(); - for (int index = 0; index < zooKeeperServers.size(); ++index) { - String hostname = zooKeeperServers.get(index).hostname(); - hostInfos.add(makeHostInfo(hostname, index)); - } - - return new ApplicationInfo( - CONFIG_SERVER_APPLICATION.getApplicationId(), - 0, - new HostsModel(hostInfos)); - } - - private static HostInfo makeHostInfo(String hostname, int configIndex) { - // /state/v1/health API is available with STATE and either HTTP or HTTPS. - PortInfo portInfo = new PortInfo(4443, Arrays.asList("HTTPS", "STATE")); - - Map<String, String> properties = new HashMap<>(); - properties.put(ModelGenerator.CLUSTER_ID_PROPERTY_NAME, CLUSTER_ID.s()); - - ServiceInfo serviceInfo = new ServiceInfo( - // service name == service type for the first service of each type on each host - SERVICE_TYPE.s(), - SERVICE_TYPE.s(), - Collections.singletonList(portInfo), - properties, - configIdFrom(configIndex).s(), - hostname); - - return new HostInfo(hostname, Collections.singletonList(serviceInfo)); - } } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java new file mode 100644 index 00000000000..2691a8bf1ee --- /dev/null +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java @@ -0,0 +1,127 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.service.monitor.application; + +import com.yahoo.config.model.api.ApplicationInfo; +import com.yahoo.config.model.api.HostInfo; +import com.yahoo.config.model.api.ServiceInfo; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.applicationmodel.ApplicationInstance; +import com.yahoo.vespa.applicationmodel.ApplicationInstanceId; +import com.yahoo.vespa.applicationmodel.ClusterId; +import com.yahoo.vespa.applicationmodel.ConfigId; +import com.yahoo.vespa.applicationmodel.HostName; +import com.yahoo.vespa.applicationmodel.ServiceCluster; +import com.yahoo.vespa.applicationmodel.ServiceClusterKey; +import com.yahoo.vespa.applicationmodel.ServiceInstance; +import com.yahoo.vespa.applicationmodel.ServiceStatus; +import com.yahoo.vespa.applicationmodel.ServiceType; +import com.yahoo.vespa.applicationmodel.TenantId; +import com.yahoo.vespa.service.monitor.ServiceStatusProvider; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Class to generate an ApplicationInstance given service status for a standard (deployed) application. + * + * @author hakon + */ +public class DeployedAppGenerator implements ApplicationInstanceGenerator { + public static final String CLUSTER_ID_PROPERTY_NAME = "clustername"; + + private final ApplicationInfo applicationInfo; + private final Zone zone; + + public DeployedAppGenerator(ApplicationInfo applicationInfo, Zone zone) { + this.applicationInfo = applicationInfo; + this.zone = zone; + } + + @Override + public ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider) { + Map<ServiceClusterKey, Set<ServiceInstance>> groupedServiceInstances = new HashMap<>(); + + for (HostInfo host : applicationInfo.getModel().getHosts()) { + HostName hostName = new HostName(host.getHostname()); + for (ServiceInfo serviceInfo : host.getServices()) { + ServiceClusterKey serviceClusterKey = toServiceClusterKey(serviceInfo); + ServiceInstance serviceInstance = + toServiceInstance( + applicationInfo.getApplicationId(), + serviceClusterKey.clusterId(), + serviceInfo, + hostName, + serviceStatusProvider); + + if (!groupedServiceInstances.containsKey(serviceClusterKey)) { + groupedServiceInstances.put(serviceClusterKey, new HashSet<>()); + } + groupedServiceInstances.get(serviceClusterKey).add(serviceInstance); + } + } + + Set<ServiceCluster> serviceClusters = groupedServiceInstances.entrySet().stream() + .map(entry -> new ServiceCluster( + entry.getKey().clusterId(), + entry.getKey().serviceType(), + entry.getValue())) + .collect(Collectors.toSet()); + + ApplicationInstance applicationInstance = new ApplicationInstance( + new TenantId(applicationInfo.getApplicationId().tenant().toString()), + toApplicationInstanceId(applicationInfo, zone), + serviceClusters); + + // Fill back-references + for (ServiceCluster serviceCluster : applicationInstance.serviceClusters()) { + serviceCluster.setApplicationInstance(applicationInstance); + for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) { + serviceInstance.setServiceCluster(serviceCluster); + } + } + + return applicationInstance; + } + + static ClusterId getClusterId(ServiceInfo serviceInfo) { + return new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse("")); + } + + private ServiceClusterKey toServiceClusterKey(ServiceInfo serviceInfo) { + ClusterId clusterId = getClusterId(serviceInfo); + ServiceType serviceType = toServiceType(serviceInfo); + return new ServiceClusterKey(clusterId, serviceType); + } + + private ServiceInstance toServiceInstance( + ApplicationId applicationId, + ClusterId clusterId, + ServiceInfo serviceInfo, + HostName hostName, + ServiceStatusProvider serviceStatusProvider) { + ConfigId configId = new ConfigId(serviceInfo.getConfigId()); + + ServiceStatus status = serviceStatusProvider.getStatus( + applicationId, + clusterId, + toServiceType(serviceInfo), configId); + + return new ServiceInstance(configId, hostName, status); + } + + private ApplicationInstanceId toApplicationInstanceId(ApplicationInfo applicationInfo, Zone zone) { + return new ApplicationInstanceId(String.format("%s:%s:%s:%s", + applicationInfo.getApplicationId().application().value(), + zone.environment().value(), + zone.region().value(), + applicationInfo.getApplicationId().instance().value())); + } + + private ServiceType toServiceType(ServiceInfo serviceInfo) { + return new ServiceType(serviceInfo.getServiceType()); + } +} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java deleted file mode 100644 index 225ffb0adbc..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.application; - -import com.yahoo.config.FileReference; -import com.yahoo.config.model.api.FileDistribution; -import com.yahoo.config.model.api.HostInfo; -import com.yahoo.config.model.api.Model; -import com.yahoo.config.provision.AllocatedHosts; -import com.yahoo.vespa.config.ConfigKey; -import com.yahoo.vespa.config.ConfigPayload; -import com.yahoo.vespa.config.buildergen.ConfigDefinition; - -import java.time.Instant; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * Model that only supports the subset necessary to create an ApplicationInstance. - * - * @author hakon - */ -public class HostsModel implements Model { - private final Collection<HostInfo> hosts; - - public HostsModel(List<HostInfo> hosts) { - this.hosts = Collections.unmodifiableCollection(hosts); - } - - @Override - public Collection<HostInfo> getHosts() { - return hosts; - } - - @Override - public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition configDefinition) { - throw new UnsupportedOperationException(); - } - - @Override - public Set<ConfigKey<?>> allConfigsProduced() { - throw new UnsupportedOperationException(); - } - - @Override - public Set<String> allConfigIds() { - throw new UnsupportedOperationException(); - } - - @Override - public void distributeFiles(FileDistribution fileDistribution) { - throw new UnsupportedOperationException(); - } - - @Override - public Set<FileReference> fileReferences() { - throw new UnsupportedOperationException(); - } - - @Override - public AllocatedHosts allocatedHosts() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean allowModelVersionMismatch(Instant now) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean skipOldConfigModels(Instant now) { - throw new UnsupportedOperationException(); - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java index c10015d3bfa..6bbf0cb6d1d 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java @@ -21,8 +21,8 @@ public class ZoneApplication { .createHostedVespaApplicationId("routing"); public static boolean isNodeAdminService(ApplicationId applicationId, - ClusterId clusterId, - ServiceType serviceType) { + ClusterId clusterId, + ServiceType serviceType) { return Objects.equals(applicationId, ZONE_APPLICATION_ID) && Objects.equals(serviceType, ServiceType.CONTAINER) && Objects.equals(clusterId, ClusterId.NODE_ADMIN); diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java deleted file mode 100644 index 26d20482d02..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; - -import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.model.api.SuperModel; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION; - -/** - * The {@code DuperModel} unites the {@link com.yahoo.config.model.api.SuperModel SuperModel} - * with the synthetically produced applications like the config server application. - * - * @author hakon - */ -public class DuperModel { - private final List<ApplicationInfo> staticApplicationInfos = new ArrayList<>(); - - public DuperModel(ConfigserverConfig configServerConfig) { - if (configServerConfig.hostedVespa()) { - staticApplicationInfos.add(CONFIG_SERVER_APPLICATION.makeApplicationInfo(configServerConfig)); - } - } - - /** For testing. */ - DuperModel(ApplicationInfo... staticApplicationInfos) { - this.staticApplicationInfos.addAll(Arrays.asList(staticApplicationInfos)); - } - - public List<ApplicationInfo> getApplicationInfos(SuperModel superModelSnapshot) { - List<ApplicationInfo> allApplicationInfos = new ArrayList<>(); - allApplicationInfos.addAll(staticApplicationInfos); - allApplicationInfos.addAll(superModelSnapshot.getAllApplicationInfos()); - return allApplicationInfos; - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java deleted file mode 100644 index 235c7db5c36..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; - -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.model.api.SuperModel; -import com.yahoo.config.provision.ApplicationId; - -/** - * Interface for listening for changes to the {@link DuperModel}. - * - * @author hakon - */ -public interface DuperModelListener { - /** - * An application has been activated: - * - * <ul> - * <li>A synthetic application like the config server application has been added/"activated" - * <li>A super model application has been activated (see - * {@link com.yahoo.config.model.api.SuperModelListener#applicationActivated(SuperModel, ApplicationInfo) - * SuperModelListener} - * </ul> - */ - void applicationActivated(ApplicationInfo application); - - /** Application has been removed. */ - void applicationRemoved(ApplicationId id); -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java index ad2f223acf8..9da449289a7 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java @@ -1,40 +1,56 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.internal; -import com.yahoo.config.model.api.ApplicationInfo; +import com.yahoo.config.model.api.SuperModel; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.applicationmodel.ApplicationInstance; import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference; import com.yahoo.vespa.service.monitor.ServiceModel; import com.yahoo.vespa.service.monitor.ServiceStatusProvider; import com.yahoo.vespa.service.monitor.application.ApplicationInstanceGenerator; +import com.yahoo.vespa.service.monitor.application.ConfigServerAppGenerator; +import com.yahoo.vespa.service.monitor.application.DeployedAppGenerator; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** - * Util to make ServiceModel and its related application model classes + * Util to convert SuperModel to ServiceModel and application model classes */ public class ModelGenerator { public static final String CLUSTER_ID_PROPERTY_NAME = "clustername"; + private final List<ApplicationInstanceGenerator> staticGenerators; + + public ModelGenerator(List<String> configServerHosts) { + if (configServerHosts.isEmpty()) { + staticGenerators = Collections.emptyList(); + } else { + staticGenerators = Collections.singletonList(new ConfigServerAppGenerator(configServerHosts)); + } + } + /** * Create service model based primarily on super model. * * If the configServerhosts is non-empty, a config server application is added. */ - public ServiceModel toServiceModel(List<ApplicationInfo> allApplicationInfos, - Zone zone, - ServiceStatusProvider serviceStatusProvider) { - Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances = - allApplicationInfos.stream() - .map(info -> new ApplicationInstanceGenerator(info, zone) - .makeApplicationInstance(serviceStatusProvider)) - .collect(Collectors.toMap(ApplicationInstance::reference, Function.identity())); + ServiceModel toServiceModel( + SuperModel superModel, + Zone zone, + ServiceStatusProvider serviceStatusProvider) { + List<ApplicationInstanceGenerator> generators = new ArrayList<>(staticGenerators); + superModel.getAllApplicationInfos() + .forEach(info -> generators.add(new DeployedAppGenerator(info, zone))); + + Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances = generators.stream() + .map(generator -> generator.makeApplicationInstance(serviceStatusProvider)) + .collect(Collectors.toMap(ApplicationInstance::reference, Function.identity())); return new ServiceModel(applicationInstances); } - } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java index 1edf3a18215..49863672c43 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java @@ -1,10 +1,11 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; +package com.yahoo.vespa.service.monitor.internal;// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +import com.yahoo.config.model.api.SuperModelListener; import com.yahoo.vespa.service.monitor.ServiceStatusProvider; /** * @author hakon */ -public interface MonitorManager extends DuperModelListener, ServiceStatusProvider { +public interface MonitorManager extends SuperModelListener, ServiceStatusProvider { } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java deleted file mode 100644 index 993ea7fed5c..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; - -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.vespa.applicationmodel.ClusterId; -import com.yahoo.vespa.applicationmodel.ConfigId; -import com.yahoo.vespa.applicationmodel.ServiceType; - -import javax.annotation.concurrent.Immutable; -import java.util.Objects; - -/** - * Identifies a service. - * - * @author hakon - */ -@Immutable -public class ServiceId { - private final ApplicationId applicationId; - private final ClusterId clusterId; - private final ServiceType serviceType; - private final ConfigId configId; - - public ServiceId(ApplicationId applicationId, - ClusterId clusterId, - ServiceType serviceType, - ConfigId configId) { - this.applicationId = applicationId; - this.clusterId = clusterId; - this.serviceType = serviceType; - this.configId = configId; - } - - public ApplicationId getApplicationId() { - return applicationId; - } - - public ClusterId getClusterId() { - return clusterId; - } - - public ServiceType getServiceType() { - return serviceType; - } - - public ConfigId getConfigId() { - return configId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ServiceId serviceId = (ServiceId) o; - return Objects.equals(applicationId, serviceId.applicationId) && - Objects.equals(clusterId, serviceId.clusterId) && - Objects.equals(serviceType, serviceId.serviceType) && - Objects.equals(configId, serviceId.configId); - } - - @Override - public int hashCode() { - return Objects.hash(applicationId, clusterId, serviceType, configId); - } - - @Override - public String toString() { - return "ServiceId{" + - "applicationId=" + applicationId + - ", clusterId=" + clusterId + - ", serviceType=" + serviceType + - ", configId=" + configId + - '}'; - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java index bd8fd4a50e0..97c4fdda0f3 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java @@ -14,7 +14,10 @@ import com.yahoo.vespa.service.monitor.ServiceMonitor; import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager; import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class ServiceMonitorImpl implements ServiceMonitor { private final ServiceModelCache serviceModelCache; @@ -29,20 +32,30 @@ public class ServiceMonitorImpl implements ServiceMonitor { Zone zone = superModelProvider.getZone(); ServiceMonitorMetrics metrics = new ServiceMonitorMetrics(metric, timer); - DuperModel duperModel = new DuperModel(configserverConfig); - UnionMonitorManager monitorManager = - new UnionMonitorManager(slobrokMonitorManager, healthMonitorManager); + UnionMonitorManager monitorManager = new UnionMonitorManager( + slobrokMonitorManager, + healthMonitorManager, + configserverConfig); SuperModelListenerImpl superModelListener = new SuperModelListenerImpl( monitorManager, metrics, - duperModel, - new ModelGenerator(), + new ModelGenerator(toConfigServerList(configserverConfig)), zone); superModelListener.start(superModelProvider); serviceModelCache = new ServiceModelCache(superModelListener, timer); } + private List<String> toConfigServerList(ConfigserverConfig configserverConfig) { + if (configserverConfig.multitenant()) { + return configserverConfig.zookeeperserver().stream() + .map(ConfigserverConfig.Zookeeperserver::hostname) + .collect(Collectors.toList()); + } + + return Collections.emptyList(); + } + @Override public Map<ApplicationInstanceReference, ApplicationInstance> getAllApplicationInstances() { return serviceModelCache.get().getAllApplicationInstances(); diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java index f509809c33d..b2f3617131b 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java @@ -8,9 +8,7 @@ import com.yahoo.config.model.api.SuperModelProvider; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.service.monitor.ServiceModel; -import com.yahoo.vespa.service.monitor.ServiceStatusProvider; -import java.util.List; import java.util.function.Supplier; import java.util.logging.Logger; @@ -18,7 +16,6 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv private static final Logger logger = Logger.getLogger(SuperModelListenerImpl.class.getName()); private final ServiceMonitorMetrics metrics; - private final DuperModel duperModel; private final ModelGenerator modelGenerator; private final Zone zone; @@ -30,12 +27,10 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv SuperModelListenerImpl(MonitorManager monitorManager, ServiceMonitorMetrics metrics, - DuperModel duperModel, ModelGenerator modelGenerator, Zone zone) { this.monitorManager = monitorManager; this.metrics = metrics; - this.duperModel = duperModel; this.modelGenerator = modelGenerator; this.zone = zone; } @@ -46,7 +41,8 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv // since applicationActivated()/applicationRemoved() may be called // asynchronously even before snapshot() returns. this.superModel = superModelProvider.snapshot(this); - duperModel.getApplicationInfos(superModel).forEach(monitorManager::applicationActivated); + superModel.getAllApplicationInfos().stream().forEach(application -> + monitorManager.applicationActivated(superModel, application)); } } @@ -54,7 +50,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv public void applicationActivated(SuperModel superModel, ApplicationInfo application) { synchronized (monitor) { this.superModel = superModel; - monitorManager.applicationActivated(application); + monitorManager.applicationActivated(superModel, application); } } @@ -62,7 +58,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv public void applicationRemoved(SuperModel superModel, ApplicationId id) { synchronized (monitor) { this.superModel = superModel; - monitorManager.applicationRemoved(id); + monitorManager.applicationRemoved(superModel, id); } } @@ -75,9 +71,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv dummy(measurement); // WARNING: The slobrok monitor manager may be out-of-sync with super model (no locking) - List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel); - - return modelGenerator.toServiceModel(applicationInfos, zone, (ServiceStatusProvider) monitorManager); + return modelGenerator.toServiceModel(superModel, zone, monitorManager); } } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java index 81cf6f2af5e..82d2043bd17 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java @@ -1,12 +1,16 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.internal; +import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.config.model.api.ApplicationInfo; +import com.yahoo.config.model.api.SuperModel; import com.yahoo.config.provision.ApplicationId; import com.yahoo.vespa.applicationmodel.ClusterId; import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceStatus; import com.yahoo.vespa.applicationmodel.ServiceType; +import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; +import com.yahoo.vespa.service.monitor.application.ZoneApplication; import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager; import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl; @@ -16,11 +20,14 @@ import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImp public class UnionMonitorManager implements MonitorManager { private final SlobrokMonitorManagerImpl slobrokMonitorManager; private final HealthMonitorManager healthMonitorManager; + private final ConfigserverConfig configserverConfig; UnionMonitorManager(SlobrokMonitorManagerImpl slobrokMonitorManager, - HealthMonitorManager healthMonitorManager) { + HealthMonitorManager healthMonitorManager, + ConfigserverConfig configserverConfig) { this.slobrokMonitorManager = slobrokMonitorManager; this.healthMonitorManager = healthMonitorManager; + this.configserverConfig = configserverConfig; } @Override @@ -28,25 +35,33 @@ public class UnionMonitorManager implements MonitorManager { ClusterId clusterId, ServiceType serviceType, ConfigId configId) { - // Trust the new health monitoring status if it actually monitors the particular service. - ServiceStatus status = healthMonitorManager.getStatus(applicationId, clusterId, serviceType, configId); - if (status != ServiceStatus.NOT_CHECKED) { - return status; + + if (applicationId.equals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId())) { + // todo: use health + return ServiceStatus.NOT_CHECKED; } - // fallback is the older slobrok - return slobrokMonitorManager.getStatus(applicationId, clusterId, serviceType, configId); + MonitorManager monitorManager = useHealth(applicationId, clusterId, serviceType) ? + healthMonitorManager : + slobrokMonitorManager; + + return monitorManager.getStatus(applicationId, clusterId, serviceType, configId); } @Override - public void applicationActivated(ApplicationInfo application) { - slobrokMonitorManager.applicationActivated(application); - healthMonitorManager.applicationActivated(application); + public void applicationActivated(SuperModel superModel, ApplicationInfo application) { + slobrokMonitorManager.applicationActivated(superModel, application); + healthMonitorManager.applicationActivated(superModel, application); } @Override - public void applicationRemoved(ApplicationId id) { - slobrokMonitorManager.applicationRemoved(id); - healthMonitorManager.applicationRemoved(id); + public void applicationRemoved(SuperModel superModel, ApplicationId id) { + slobrokMonitorManager.applicationRemoved(superModel, id); + healthMonitorManager.applicationRemoved(superModel, id); + } + + private boolean useHealth(ApplicationId applicationId, ClusterId clusterId, ServiceType serviceType) { + return !configserverConfig.nodeAdminInContainer() && + ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType); } } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java deleted file mode 100644 index e3d35f6d6e9..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -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.vespa.applicationmodel.ClusterId; -import com.yahoo.vespa.applicationmodel.ConfigId; -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.applicationmodel.ServiceType; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; -import com.yahoo.vespa.service.monitor.ServiceStatusProvider; -import com.yahoo.vespa.service.monitor.application.ApplicationInstanceGenerator; -import com.yahoo.vespa.service.monitor.internal.ServiceId; - -import java.net.URL; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import static com.yahoo.yolean.Exceptions.uncheck; - -/** - * Responsible for monitoring a whole application using /state/v1/health. - * - * @author hakon - */ -public class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable { - private final Map<ServiceId, HealthMonitor> healthMonitors; - - public static ApplicationHealthMonitor startMonitoring( - ApplicationInfo application, - ServiceIdentityProvider identityProvider) { - return new ApplicationHealthMonitor(makeHealthMonitors(application, identityProvider)); - } - - private ApplicationHealthMonitor(Map<ServiceId, HealthMonitor> healthMonitors) { - this.healthMonitors = healthMonitors; - } - - @Override - public ServiceStatus getStatus(ApplicationId applicationId, - ClusterId clusterId, - ServiceType serviceType, - ConfigId configId) { - ServiceId serviceId = new ServiceId(applicationId, clusterId, serviceType, configId); - HealthMonitor monitor = healthMonitors.get(serviceId); - if (monitor == null) { - return ServiceStatus.NOT_CHECKED; - } - - return monitor.getStatus(); - } - - @Override - public void close() { - healthMonitors.values().forEach(HealthMonitor::close); - healthMonitors.clear(); - } - - private static Map<ServiceId, HealthMonitor> makeHealthMonitors( - ApplicationInfo application, - ServiceIdentityProvider identityProvider) { - Map<ServiceId, HealthMonitor> healthMonitors = new HashMap<>(); - for (HostInfo hostInfo : application.getModel().getHosts()) { - for (ServiceInfo serviceInfo : hostInfo.getServices()) { - for (PortInfo portInfo : serviceInfo.getPorts()) { - maybeCreateHealthMonitor( - application, - hostInfo, - serviceInfo, - portInfo, - identityProvider) - .ifPresent(healthMonitor -> healthMonitors.put( - ApplicationInstanceGenerator.getServiceId(application, serviceInfo), - healthMonitor)); - } - } - } - return healthMonitors; - } - - private static Optional<HealthMonitor> maybeCreateHealthMonitor( - ApplicationInfo applicationInfo, - HostInfo hostInfo, - ServiceInfo serviceInfo, - PortInfo portInfo, - ServiceIdentityProvider identityProvider) { - Collection<String> portTags = portInfo.getTags(); - if (portTags.contains("STATE")) { - if (portTags.contains("HTTPS")) { - URL url = uncheck(() -> new URL( - "https", - hostInfo.getHostname(), - portInfo.getPort(), - "/state/v1/health")); - // todo: get hostname verifier - // "vespa.vespa[.cd].provider_%s_%s" from AthenzProviderServiceConfig - // new AthenzIdentityVerifier(Collections.singleton("vespa.vespa[.cd].provider_%s_%s")); - // HealthEndpoint healthEndpoint = HealthEndpoint.forHttps(...); - // HealthMonitor healthMonitor = new HealthMonitor(url, identityProvider, hostnameVerifier); - // healthMonitor.startMonitoring() - return Optional.empty(); - } - } - - return Optional.empty(); - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java deleted file mode 100644 index 1ecdf432ada..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.yahoo.config.provision.HostName; -import com.yahoo.vespa.athenz.api.AthenzService; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.config.Registry; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.ConnectionKeepAliveStrategy; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.protocol.HttpContext; -import org.apache.http.util.EntityUtils; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import java.net.URL; - -import static com.yahoo.yolean.Exceptions.uncheck; - -/** - * @author hakon - */ -public class HealthClient implements AutoCloseable, ServiceIdentityProvider.Listener { - private static final ObjectMapper mapper = new ObjectMapper(); - private static final long MAX_CONTENT_LENGTH = 1L << 20; // 1 MB - private static final int DEFAULT_TIMEOUT_MILLIS = 1_000; - - private static final ConnectionKeepAliveStrategy KEEP_ALIVE_STRATEGY = - new DefaultConnectionKeepAliveStrategy() { - @Override - public long getKeepAliveDuration(HttpResponse response, HttpContext context) { - long keepAlive = super.getKeepAliveDuration(response, context); - if (keepAlive == -1) { - // Keep connections alive 60 seconds if a keep-alive value - // has not be explicitly set by the server - keepAlive = 60000; - } - return keepAlive; - } - }; - - private final URL url; - private final ServiceIdentityProvider serviceIdentityProvider; - private final HostnameVerifier hostnameVerifier; - - private volatile CloseableHttpClient httpClient; - - public HealthClient(HostName hostname, - int port, - ServiceIdentityProvider identityProvider, - HostnameVerifier hostnameVerifier) { - this(uncheck(() -> new URL("https", hostname.value(), port, "/state/v1/health")), - identityProvider, - hostnameVerifier); - } - - public HealthClient(URL stateV1HealthEndpoint, - ServiceIdentityProvider serviceIdentityProvider, - HostnameVerifier hostnameVerifier) { - this.url = stateV1HealthEndpoint; - this.serviceIdentityProvider = serviceIdentityProvider; - this.hostnameVerifier = hostnameVerifier; - - onCredentialsUpdate(serviceIdentityProvider.getIdentitySslContext(), null); - serviceIdentityProvider.addIdentityListener(this); - } - - @Override - public void onCredentialsUpdate(SSLContext sslContext, AthenzService ignored) { - SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); - - Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() - .register("https", socketFactory) - .build(); - - HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(registry); - - RequestConfig requestConfig = RequestConfig.custom() - .setConnectTimeout(DEFAULT_TIMEOUT_MILLIS) // establishment of connection - .setConnectionRequestTimeout(DEFAULT_TIMEOUT_MILLIS) // connection from connection manager - .setSocketTimeout(DEFAULT_TIMEOUT_MILLIS) // waiting for data - .build(); - - this.httpClient = HttpClients.custom() - .setKeepAliveStrategy(KEEP_ALIVE_STRATEGY) - .setConnectionManager(connectionManager) - .disableAutomaticRetries() - .setDefaultRequestConfig(requestConfig) - .build(); - } - - public HealthInfo getHealthInfo() { - try { - return probeHealth(); - } catch (Exception e) { - return HealthInfo.fromException(e); - } - } - - @Override - public void close() { - serviceIdentityProvider.removeIdentityListener(this); - - try { - httpClient.close(); - } catch (Exception e) { - // ignore - } - httpClient = null; - } - - private HealthInfo probeHealth() throws Exception { - HttpGet httpget = new HttpGet(url.toString()); - CloseableHttpResponse httpResponse; - - CloseableHttpClient httpClient = this.httpClient; - if (httpClient == null) { - throw new IllegalStateException("HTTP client has closed"); - } - - httpResponse = httpClient.execute(httpget); - - int httpStatusCode = httpResponse.getStatusLine().getStatusCode(); - if (httpStatusCode < 200 || httpStatusCode >= 300) { - return HealthInfo.fromBadHttpStatusCode(httpStatusCode); - } - - HttpEntity bodyEntity = httpResponse.getEntity(); - long contentLength = bodyEntity.getContentLength(); - if (contentLength > MAX_CONTENT_LENGTH) { - throw new IllegalArgumentException("Content too long: " + contentLength + " bytes"); - } - String body = EntityUtils.toString(bodyEntity); - HealthResponse healthResponse = mapper.readValue(body, HealthResponse.class); - - if (healthResponse.status == null || healthResponse.status.code == null) { - return HealthInfo.fromHealthStatusCode(HealthResponse.Status.DEFAULT_STATUS); - } else { - return HealthInfo.fromHealthStatusCode(healthResponse.status.code); - } - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java deleted file mode 100644 index d3b81c213dc..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.config.provision.HostName; -import com.yahoo.vespa.athenz.api.AthenzIdentity; -import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier; - -import javax.net.ssl.HostnameVerifier; -import java.net.URL; -import java.util.Collections; - -import static com.yahoo.yolean.Exceptions.uncheck; - -/** - * @author hakon - */ -class HealthEndpoint { - private final URL url; - private final HostnameVerifier hostnameVerifier; - - static HealthEndpoint forHttps(HostName hostname, int port, AthenzIdentity remoteIdentity) { - URL url = uncheck(() -> new URL("https", hostname.value(), port, "/state/v1/health")); - HostnameVerifier peerVerifier = new AthenzIdentityVerifier(Collections.singleton(remoteIdentity)); - return new HealthEndpoint(url, peerVerifier); - } - - private HealthEndpoint(URL url, HostnameVerifier hostnameVerifier) { - this.url = url; - this.hostnameVerifier = hostnameVerifier; - } - - public URL getStateV1HealthUrl() { - return url; - } - - public HostnameVerifier getHostnameVerifier() { - return hostnameVerifier; - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java deleted file mode 100644 index a3fe3cb3106..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.yolean.Exceptions; - -import java.time.Instant; -import java.util.Optional; -import java.util.OptionalInt; - -/** - * The result of a health lookup. - * - * @author hakon - */ -public class HealthInfo { - public static final String UP_STATUS_CODE = "up"; - - private final Optional<Exception> exception; - private final OptionalInt httpStatusCode; - private final Optional<String> healthStatusCode; - private final Instant time; - - static HealthInfo fromException(Exception exception) { - return new HealthInfo(Optional.of(exception), OptionalInt.empty(), Optional.empty()); - } - - static HealthInfo fromBadHttpStatusCode(int httpStatusCode) { - return new HealthInfo(Optional.empty(), OptionalInt.of(httpStatusCode), Optional.empty()); - } - - static HealthInfo fromHealthStatusCode(String healthStatusCode) { - return new HealthInfo(Optional.empty(), OptionalInt.empty(), Optional.of(healthStatusCode)); - } - - static HealthInfo empty() { - return new HealthInfo(Optional.empty(), OptionalInt.empty(), Optional.empty()); - } - - private HealthInfo(Optional<Exception> exception, - OptionalInt httpStatusCode, - Optional<String> healthStatusCode) { - this.exception = exception; - this.httpStatusCode = httpStatusCode; - this.healthStatusCode = healthStatusCode; - this.time = Instant.now(); - } - - public boolean isHealthy() { - return healthStatusCode.map(UP_STATUS_CODE::equals).orElse(false); - } - - public ServiceStatus toSerivceStatus() { - return isHealthy() ? ServiceStatus.UP : ServiceStatus.DOWN; - } - - public Instant time() { - return time; - } - - @Override - public String toString() { - if (isHealthy()) { - return UP_STATUS_CODE; - } else if (healthStatusCode.isPresent()) { - return "Bad health status code '" + healthStatusCode.get() + "'"; - } else if (exception.isPresent()) { - return Exceptions.toMessageString(exception.get()); - } else if (httpStatusCode.isPresent()) { - return "Bad HTTP response status code " + httpStatusCode.getAsInt(); - } else { - return "No health info available"; - } - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java deleted file mode 100644 index 2ad623f15cf..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.log.LogLevel; -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; - -import javax.net.ssl.HostnameVerifier; -import java.net.URL; -import java.time.Duration; -import java.util.Random; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -/** - * Used to monitor the health of a single URL endpoint. - * - * @author hakon - */ -public class HealthMonitor implements AutoCloseable { - private static final Logger logger = Logger.getLogger(HealthMonitor.class.getName()); - private static final Duration DELAY = Duration.ofSeconds(20); - // About 'static': Javadoc says "Instances of java.util.Random are threadsafe." - private static final Random random = new Random(); - - private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); - private final HealthClient healthClient; - - private volatile HealthInfo lastHealthInfo = HealthInfo.empty(); - - public HealthMonitor(URL stateV1HealthEndpoint, - ServiceIdentityProvider identityProvider, - HostnameVerifier hostnameVerifier) { - this.healthClient = new HealthClient(stateV1HealthEndpoint, identityProvider, hostnameVerifier); - } - - /** For testing. */ - HealthMonitor(HealthClient healthClient) { - this.healthClient = healthClient; - } - - public void startMonitoring() { - executor.scheduleWithFixedDelay( - this::updateSynchronously, - initialDelayInSeconds(DELAY.getSeconds()), - DELAY.getSeconds(), - TimeUnit.SECONDS); - } - - public ServiceStatus getStatus() { - // todo: return lastHealthInfo.toServiceStatus(); - return ServiceStatus.NOT_CHECKED; - } - - @Override - public void close() { - executor.shutdown(); - - try { - executor.awaitTermination(2, TimeUnit.SECONDS); - } catch (InterruptedException e) { - logger.log(LogLevel.INFO, "Interrupted while waiting for health monitor termination: " + - e.getMessage()); - } - - healthClient.close(); - } - - private long initialDelayInSeconds(long maxInitialDelayInSeconds) { - return random.nextLong() % maxInitialDelayInSeconds; - } - - private void updateSynchronously() { - lastHealthInfo = healthClient.getHealthInfo(); - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java index 54d26798ad2..5a4b7251ae2 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java @@ -2,52 +2,29 @@ package com.yahoo.vespa.service.monitor.internal.health; import com.google.inject.Inject; -import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.config.model.api.ApplicationInfo; +import com.yahoo.config.model.api.SuperModel; import com.yahoo.config.provision.ApplicationId; import com.yahoo.vespa.applicationmodel.ClusterId; import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceStatus; import com.yahoo.vespa.applicationmodel.ServiceType; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; import com.yahoo.vespa.service.monitor.application.ZoneApplication; import com.yahoo.vespa.service.monitor.internal.MonitorManager; -import java.util.HashMap; -import java.util.Map; - /** * @author hakon */ public class HealthMonitorManager implements MonitorManager { - private final Map<ApplicationId, ApplicationHealthMonitor> healthMonitors = new HashMap<>(); - private final ConfigserverConfig configserverConfig; - private final ServiceIdentityProvider serviceIdentityProvider; - @Inject - public HealthMonitorManager(ConfigserverConfig configserverConfig, - ServiceIdentityProvider serviceIdentityProvider) { - this.configserverConfig = configserverConfig; - this.serviceIdentityProvider = serviceIdentityProvider; - } + public HealthMonitorManager() {} @Override - public void applicationActivated(ApplicationInfo application) { - if (applicationMonitored(application.getApplicationId())) { - ApplicationHealthMonitor monitor = - ApplicationHealthMonitor.startMonitoring(application, serviceIdentityProvider); - healthMonitors.put(application.getApplicationId(), monitor); - } + public void applicationActivated(SuperModel superModel, ApplicationInfo application) { } @Override - public void applicationRemoved(ApplicationId id) { - if (applicationMonitored(id)) { - ApplicationHealthMonitor monitor = healthMonitors.remove(id); - if (monitor != null) { - monitor.close(); - } - } + public void applicationRemoved(SuperModel superModel, ApplicationId id) { } @Override @@ -55,18 +32,13 @@ public class HealthMonitorManager implements MonitorManager { ClusterId clusterId, ServiceType serviceType, ConfigId configId) { - if (!configserverConfig.nodeAdminInContainer() && - ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType)) { - // If node admin doesn't run in a JDisc container, it must be monitored with health. - // TODO: Do proper health check + // TODO: Do proper health check + if (ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType)) { return ServiceStatus.UP; } - return ServiceStatus.NOT_CHECKED; - } - - private boolean applicationMonitored(ApplicationId id) { - // todo: health-check config server - return false; + throw new IllegalArgumentException("Health monitoring not implemented for application " + + applicationId.toShortString() + ", cluster " + clusterId.s() + ", serviceType " + + serviceType); } } diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java deleted file mode 100644 index 574523ad564..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.yahoo.text.JSON; - -/** - * Response entity from /state/v1/health - * - * @author hakon - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class HealthResponse { - @JsonProperty("status") - public Status status = new Status(); - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Status { - public static final String DEFAULT_STATUS = "down"; - - @JsonProperty("code") - public String code = DEFAULT_STATUS; - - @Override - public String toString() { - return "{ \"code\": \"" + JSON.escape(code) + "\" }"; - } - } - - @Override - public String toString() { - return "{ \"status\": " + status.toString() + " }"; - } -} diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java index 68958c94dfd..aaaab22e742 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java @@ -3,6 +3,8 @@ package com.yahoo.vespa.service.monitor.internal.slobrok; import com.google.inject.Inject; import com.yahoo.config.model.api.ApplicationInfo; +import com.yahoo.config.model.api.SuperModel; +import com.yahoo.config.model.api.SuperModelListener; import com.yahoo.config.provision.ApplicationId; import com.yahoo.jrt.slobrok.api.Mirror; import com.yahoo.log.LogLevel; @@ -11,7 +13,6 @@ import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceStatus; import com.yahoo.vespa.applicationmodel.ServiceType; import com.yahoo.vespa.service.monitor.SlobrokApi; -import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; import com.yahoo.vespa.service.monitor.internal.MonitorManager; import java.util.HashMap; @@ -20,7 +21,7 @@ import java.util.Optional; import java.util.function.Supplier; import java.util.logging.Logger; -public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager { +public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi, MonitorManager { private static final Logger logger = Logger.getLogger(SlobrokMonitorManagerImpl.class.getName()); @@ -39,11 +40,7 @@ public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager { } @Override - public void applicationActivated(ApplicationInfo application) { - if (!applicationMonitoredWithSlobrok(application.getApplicationId())) { - return; - } - + public void applicationActivated(SuperModel superModel, ApplicationInfo application) { synchronized (monitor) { SlobrokMonitor slobrokMonitor = slobrokMonitors.computeIfAbsent( application.getApplicationId(), @@ -53,11 +50,7 @@ public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager { } @Override - public void applicationRemoved(ApplicationId id) { - if (!applicationMonitoredWithSlobrok(id)) { - return; - } - + public void applicationRemoved(SuperModel superModel, ApplicationId id) { synchronized (monitor) { SlobrokMonitor slobrokMonitor = slobrokMonitors.remove(id); if (slobrokMonitor == null) { @@ -86,10 +79,6 @@ public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager { ClusterId clusterId, ServiceType serviceType, ConfigId configId) { - if (!applicationMonitoredWithSlobrok(applicationId)) { - return ServiceStatus.NOT_CHECKED; - } - Optional<String> slobrokServiceName = findSlobrokServiceName(serviceType, configId); if (slobrokServiceName.isPresent()) { synchronized (monitor) { @@ -106,14 +95,6 @@ public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager { } } - private boolean applicationMonitoredWithSlobrok(ApplicationId applicationId) { - if (applicationId.equals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId())) { - return false; - } - - return true; - } - /** * Get the Slobrok service name of the service, or empty if the service * is not registered with Slobrok. diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGeneratorTest.java index 899cc59bb34..58f99786017 100644 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGeneratorTest.java @@ -1,27 +1,22 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.application; -import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.provision.Zone; import com.yahoo.vespa.applicationmodel.ApplicationInstance; import com.yahoo.vespa.applicationmodel.ServiceStatus; import com.yahoo.vespa.service.monitor.ServiceStatusProvider; -import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil; import org.junit.Test; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class ApplicationInstanceGeneratorTest { +public class ConfigServerAppGeneratorTest { private static final String configServer1 = "cfg1.yahoo.com"; private static final String configServer2 = "cfg2.yahoo.com"; private static final String configServer3 = "cfg3.yahoo.com"; @@ -33,17 +28,9 @@ public class ApplicationInstanceGeneratorTest { private final ServiceStatusProvider statusProvider = mock(ServiceStatusProvider.class); @Test - public void toApplicationInstance() { + public void toApplicationInstance() throws Exception { when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED); - ConfigserverConfig config = ConfigserverUtil.create( - true, - true, - configServer1, - configServer2, - configServer3); - Zone zone = mock(Zone.class); - ApplicationInfo configServer = CONFIG_SERVER_APPLICATION.makeApplicationInfo(config); - ApplicationInstance applicationInstance = new ApplicationInstanceGenerator(configServer, zone) + ApplicationInstance applicationInstance = new ConfigServerAppGenerator(configServerList) .makeApplicationInstance(statusProvider); assertEquals( diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java deleted file mode 100644 index 8ad153ba8e7..00000000000 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; - -import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; - -/** - * @author hakon - */ -public class ConfigserverUtil { - /** Create a ConfigserverConfig with the given settings. */ - public static ConfigserverConfig create( - boolean hostedVespa, - boolean nodeAdminInContainer, - String configServerHostname1, - String configServerHostname2, - String configServerHostname3) { - return new ConfigserverConfig( - new ConfigserverConfig.Builder() - .hostedVespa(hostedVespa) - .nodeAdminInContainer(nodeAdminInContainer) - .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname1).port(1)) - .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname2).port(2)) - .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname3).port(3))); - } - - public static ConfigserverConfig createExampleConfigserverConfig(boolean nodeAdminInContainer) { - return create(true, nodeAdminInContainer, "cfg1", "cfg2", "cfg3"); - } - - public static ApplicationInfo makeConfigServerApplicationInfo( - boolean hostedVespa, - String configServerHostname1, - String configServerHostname2, - String configServerHostname3) { - return ConfigServerApplication.CONFIG_SERVER_APPLICATION.makeApplicationInfo(create( - hostedVespa, - true, - configServerHostname1, - configServerHostname2, - configServerHostname3)); - } - - public static ApplicationInfo makeExampleConfigServer() { - return makeConfigServerApplicationInfo(true, "cfg1", "cfg2", "cfg3"); - } -} diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java deleted file mode 100644 index 0a68b4b0ff7..00000000000 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal; - -import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.model.api.SuperModel; -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.service.monitor.ServiceStatusProvider; -import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; -import org.junit.Test; - -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author hakon - */ -public class DuperModelTest { - private final ServiceStatusProvider statusProvider = mock(ServiceStatusProvider.class); - - @Test - public void toApplicationInstance() { - when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED); - ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true); - DuperModel duperModel = new DuperModel(config); - SuperModel superModel = mock(SuperModel.class); - ApplicationInfo superModelApplicationInfo = mock(ApplicationInfo.class); - when(superModel.getAllApplicationInfos()).thenReturn(Collections.singletonList(superModelApplicationInfo)); - List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel); - assertEquals(2, applicationInfos.size()); - assertEquals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(), applicationInfos.get(0).getApplicationId()); - assertSame(superModelApplicationInfo, applicationInfos.get(1)); - } -} diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java index 72326c7352a..a21691ee4d0 100644 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java @@ -1,7 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.internal; -import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.config.model.api.SuperModel; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; @@ -16,9 +15,13 @@ import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl; import org.junit.Test; +import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; @@ -36,10 +39,9 @@ public class ModelGeneratorTest { SuperModel superModel = ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT); - ConfigserverConfig config = ConfigserverUtil.create( - true, true, "cfg1", "cfg2", "cfg3"); - DuperModel duperModel = new DuperModel(config); - ModelGenerator modelGenerator = new ModelGenerator(); + List<String> configServerHosts = Stream.of("cfg1", "cfg2", "cfg3") + .collect(Collectors.toList()); + ModelGenerator modelGenerator = new ModelGenerator(configServerHosts); Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION)); @@ -49,7 +51,7 @@ public class ModelGeneratorTest { ServiceModel serviceModel = modelGenerator.toServiceModel( - duperModel.getApplicationInfos(superModel), + superModel, zone, slobrokMonitorManager); @@ -78,11 +80,9 @@ public class ModelGeneratorTest { @Test public void toApplicationModel() throws Exception { - SuperModel superModel = ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT); - ConfigserverConfig config = ConfigserverUtil.create( - false, true, "cfg1", "cfg2", "cfg3"); - DuperModel duperModel = new DuperModel(config); - ModelGenerator modelGenerator = new ModelGenerator(); + SuperModel superModel = + ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT); + ModelGenerator modelGenerator = new ModelGenerator(Collections.emptyList()); Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION)); @@ -90,12 +90,14 @@ public class ModelGeneratorTest { when(slobrokMonitorManager.getStatus(any(), any(), any(), any())) .thenReturn(ServiceStatus.UP); - ServiceModel serviceModel = modelGenerator.toServiceModel( - duperModel.getApplicationInfos(superModel), - zone, - slobrokMonitorManager); + ServiceModel serviceModel = + modelGenerator.toServiceModel( + superModel, + zone, + slobrokMonitorManager); - Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances = + Map<ApplicationInstanceReference, + ApplicationInstance> applicationInstances = serviceModel.getAllApplicationInstances(); assertEquals(1, applicationInstances.size()); diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java index eb6d6d583f7..83bad0ddb2a 100644 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java @@ -14,7 +14,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -23,13 +22,11 @@ public class SuperModelListenerImplTest { public void sanityCheck() { SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class); ServiceMonitorMetrics metrics = mock(ServiceMonitorMetrics.class); - DuperModel duperModel = mock(DuperModel.class); ModelGenerator modelGenerator = mock(ModelGenerator.class); Zone zone = mock(Zone.class); SuperModelListenerImpl listener = new SuperModelListenerImpl( slobrokMonitorManager, metrics, - duperModel, modelGenerator, zone); @@ -41,15 +38,13 @@ public class SuperModelListenerImplTest { ApplicationInfo application2 = mock(ApplicationInfo.class); List<ApplicationInfo> applications = Stream.of(application1, application2) .collect(Collectors.toList()); - when(duperModel.getApplicationInfos(superModel)).thenReturn(applications); + when(superModel.getAllApplicationInfos()).thenReturn(applications); listener.start(superModelProvider); - verify(duperModel, times(1)).getApplicationInfos(superModel); - verify(slobrokMonitorManager).applicationActivated(application1); - verify(slobrokMonitorManager).applicationActivated(application2); + verify(slobrokMonitorManager).applicationActivated(superModel, application1); + verify(slobrokMonitorManager).applicationActivated(superModel, application2); ServiceModel serviceModel = listener.get(); - verify(duperModel, times(2)).getApplicationInfos(superModel); - verify(modelGenerator).toServiceModel(applications, zone, slobrokMonitorManager); + verify(modelGenerator).toServiceModel(superModel, zone, slobrokMonitorManager); } }
\ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java index 79916e43712..b7c3ed8e1e1 100644 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java @@ -1,44 +1,95 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.monitor.internal; +import com.yahoo.cloud.config.ConfigserverConfig; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.vespa.applicationmodel.ClusterId; import com.yahoo.vespa.applicationmodel.ConfigId; -import com.yahoo.vespa.applicationmodel.ServiceStatus; +import com.yahoo.vespa.applicationmodel.ServiceType; import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager; import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl; import org.junit.Test; import static com.yahoo.vespa.applicationmodel.ClusterId.NODE_ADMIN; -import static com.yahoo.vespa.applicationmodel.ServiceStatus.*; -import static com.yahoo.vespa.applicationmodel.ServiceStatus.NOT_CHECKED; -import static com.yahoo.vespa.applicationmodel.ServiceStatus.UP; import static com.yahoo.vespa.applicationmodel.ServiceType.CONTAINER; import static com.yahoo.vespa.service.monitor.application.ZoneApplication.ZONE_APPLICATION_ID; -import static org.junit.Assert.assertSame; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; public class UnionMonitorManagerTest { - private final SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class); - private final HealthMonitorManager healthMonitorManager = mock(HealthMonitorManager.class); - - private final UnionMonitorManager manager = new UnionMonitorManager( - slobrokMonitorManager, - healthMonitorManager); + @Test + public void nodeAdminInContainer() { + testWith( + true, + ZONE_APPLICATION_ID, + NODE_ADMIN, + CONTAINER, + 1, + 0); + } @Test - public void verifyHealthTakesPriority() { - testWith(UP, DOWN, UP); - testWith(NOT_CHECKED, DOWN, DOWN); - testWith(NOT_CHECKED, NOT_CHECKED, NOT_CHECKED); + public void nodeAdminOutsideContainer() { + boolean inContainer = false; + + // When nodeAdminInContainer is set, then only the node admin cluster should use health + testWith( + inContainer, + ZONE_APPLICATION_ID, + NODE_ADMIN, + CONTAINER, + 0, + 1); + + testWith( + inContainer, + ApplicationId.fromSerializedForm("a:b:default"), + NODE_ADMIN, + CONTAINER, + 1, + 0); + + testWith( + inContainer, + ZONE_APPLICATION_ID, + new ClusterId("foo"), + CONTAINER, + 1, + 0); + + testWith( + inContainer, + ZONE_APPLICATION_ID, + NODE_ADMIN, + new ServiceType("foo"), + 1, + 0); } - private void testWith(ServiceStatus healthStatus, - ServiceStatus slobrokStatus, - ServiceStatus expectedStatus) { - when(healthMonitorManager.getStatus(any(), any(), any(), any())).thenReturn(healthStatus); - when(slobrokMonitorManager.getStatus(any(), any(), any(), any())).thenReturn(slobrokStatus); - ServiceStatus status = manager.getStatus(ZONE_APPLICATION_ID, NODE_ADMIN, CONTAINER, new ConfigId("config-id")); - assertSame(expectedStatus, status); + private void testWith(boolean nodeAdminInContainer, + ApplicationId applicationId, + ClusterId clusterId, + ServiceType serviceType, + int expectedSlobrokCalls, + int expectedHealthCalls) { + SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class); + HealthMonitorManager healthMonitorManager = mock(HealthMonitorManager.class); + + ConfigserverConfig.Builder builder = new ConfigserverConfig.Builder(); + builder.nodeAdminInContainer(nodeAdminInContainer); + ConfigserverConfig config = new ConfigserverConfig(builder); + + + UnionMonitorManager manager = new UnionMonitorManager( + slobrokMonitorManager, + healthMonitorManager, + config); + + manager.getStatus(applicationId, clusterId, serviceType, new ConfigId("config-id")); + + verify(slobrokMonitorManager, times(expectedSlobrokCalls)).getStatus(any(), any(), any(), any()); + verify(healthMonitorManager, times(expectedHealthCalls)).getStatus(any(), any(), any(), any()); } }
\ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java deleted file mode 100644 index fd96b519649..00000000000 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; -import com.yahoo.vespa.service.monitor.application.ConfigServerApplication; -import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil; -import org.junit.Test; - -import static com.yahoo.vespa.applicationmodel.ServiceStatus.NOT_CHECKED; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -public class ApplicationHealthMonitorTest { - @Test - public void sanityCheck() { - ServiceIdentityProvider provider = mock(ServiceIdentityProvider.class); - ApplicationHealthMonitor monitor = ApplicationHealthMonitor.startMonitoring( - ConfigserverUtil.makeExampleConfigServer(), - provider); - ServiceStatus status = monitor.getStatus( - ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(), - ConfigServerApplication.CLUSTER_ID, - ConfigServerApplication.SERVICE_TYPE, - ConfigServerApplication.configIdFrom(0)); - assertEquals(NOT_CHECKED, status); - } -}
\ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java deleted file mode 100644 index b416e3f6f2a..00000000000 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.vespa.applicationmodel.ClusterId; -import com.yahoo.vespa.applicationmodel.ConfigId; -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import com.yahoo.vespa.applicationmodel.ServiceType; -import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; -import com.yahoo.vespa.service.monitor.application.ZoneApplication; -import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -public class HealthMonitorManagerTest { - @Test - public void addRemove() { - ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true); - ServiceIdentityProvider provider = mock(ServiceIdentityProvider.class); - HealthMonitorManager manager = new HealthMonitorManager(config, provider); - ApplicationInfo applicationInfo = ConfigserverUtil.makeExampleConfigServer(); - manager.applicationActivated(applicationInfo); - manager.applicationRemoved(applicationInfo.getApplicationId()); - } - - @Test - public void withNodeAdmin() { - ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true); - ServiceIdentityProvider provider = mock(ServiceIdentityProvider.class); - HealthMonitorManager manager = new HealthMonitorManager(config, provider); - ServiceStatus status = manager.getStatus( - ZoneApplication.ZONE_APPLICATION_ID, - ClusterId.NODE_ADMIN, - ServiceType.CONTAINER, - new ConfigId("config-id-1")); - assertEquals(ServiceStatus.NOT_CHECKED, status); - } - - @Test - public void withHostAdmin() { - ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(false); - ServiceIdentityProvider provider = mock(ServiceIdentityProvider.class); - HealthMonitorManager manager = new HealthMonitorManager(config, provider); - ServiceStatus status = manager.getStatus( - ZoneApplication.ZONE_APPLICATION_ID, - ClusterId.NODE_ADMIN, - ServiceType.CONTAINER, - new ConfigId("config-id-1")); - assertEquals(ServiceStatus.UP, status); - } -}
\ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java deleted file mode 100644 index cca1530ad97..00000000000 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.service.monitor.internal.health; - -import com.yahoo.vespa.applicationmodel.ServiceStatus; -import org.junit.Test; - -import java.net.MalformedURLException; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - -public class HealthMonitorTest { - @Test - public void basicTests() throws MalformedURLException { - HealthClient healthClient = mock(HealthClient.class); - try (HealthMonitor monitor = new HealthMonitor(healthClient)) { - monitor.startMonitoring(); - assertEquals(ServiceStatus.NOT_CHECKED, monitor.getStatus()); - } - } -}
\ No newline at end of file diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java index a567559980b..8e4443df83b 100644 --- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java +++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.service.monitor.internal.slobrok; import com.yahoo.config.model.api.ApplicationInfo; -import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.model.api.SuperModel; import com.yahoo.vespa.applicationmodel.ClusterId; import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceStatus; @@ -28,19 +28,18 @@ public class SlobrokMonitorManagerImplTest { private final SlobrokMonitorManagerImpl slobrokMonitorManager = new SlobrokMonitorManagerImpl(slobrokMonitorFactory); private final SlobrokMonitor slobrokMonitor = mock(SlobrokMonitor.class); - private final ApplicationId applicationId = ApplicationId.from("tenant", "app", "instance"); + private final SuperModel superModel = mock(SuperModel.class); private final ApplicationInfo application = mock(ApplicationInfo.class); private final ClusterId clusterId = new ClusterId("cluster-id"); @Before public void setup() { when(slobrokMonitorFactory.get()).thenReturn(slobrokMonitor); - when(application.getApplicationId()).thenReturn(applicationId); } @Test public void testActivationOfApplication() { - slobrokMonitorManager.applicationActivated(application); + slobrokMonitorManager.applicationActivated(superModel, application); verify(slobrokMonitorFactory, times(1)).get(); } @@ -52,14 +51,14 @@ public class SlobrokMonitorManagerImplTest { @Test public void testGetStatus_ApplicationInSlobrok() { - slobrokMonitorManager.applicationActivated(application); + slobrokMonitorManager.applicationActivated(superModel, application); when(slobrokMonitor.registeredInSlobrok("config.id")).thenReturn(true); assertEquals(ServiceStatus.UP, getStatus("topleveldispatch")); } @Test public void testGetStatus_ServiceNotInSlobrok() { - slobrokMonitorManager.applicationActivated(application); + slobrokMonitorManager.applicationActivated(superModel, application); when(slobrokMonitor.registeredInSlobrok("config.id")).thenReturn(false); assertEquals(ServiceStatus.DOWN, getStatus("topleveldispatch")); } |