diff options
Diffstat (limited to 'service-monitor/src/main/java')
23 files changed, 290 insertions, 993 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 5ad38cebcfc..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 com.yahoo.vespa.service.monitor.internal.health.ApplicationHealthMonitor; - -import java.util.ArrayList; -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,44 +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, config.httpport(), index)); - } - - return new ApplicationInfo( - CONFIG_SERVER_APPLICATION.getApplicationId(), - 0, - new HostsModel(hostInfos)); - } - - private static HostInfo makeHostInfo(String hostname, int port, int configIndex) { - PortInfo portInfo = new PortInfo(port, ApplicationHealthMonitor.PORT_TAGS_HEALTH); - - 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 d3c6f92312c..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java +++ /dev/null @@ -1,38 +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) { - 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..8183d5e1960 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,9 @@ 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.List; import java.util.Map; +import java.util.stream.Collectors; public class ServiceMonitorImpl implements ServiceMonitor { private final ServiceModelCache serviceModelCache; @@ -29,20 +31,26 @@ 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) { + return configserverConfig.zookeeperserver().stream() + .map(ConfigserverConfig.Zookeeperserver::hostname) + .collect(Collectors.toList()); + } + @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 bd2658db8aa..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java +++ /dev/null @@ -1,102 +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.config.provision.HostName; -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.ServiceStatusProvider; -import com.yahoo.vespa.service.monitor.application.ApplicationInstanceGenerator; -import com.yahoo.vespa.service.monitor.internal.ServiceId; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * Responsible for monitoring a whole application using /state/v1/health. - * - * @author hakon - */ -public class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable { - public static final String PORT_TAG_STATE = "STATE"; - public static final String PORT_TAG_HTTP = "HTTP"; - /** Port tags implying /state/v1/health is served */ - public static final List<String> PORT_TAGS_HEALTH = - Collections.unmodifiableList(Arrays.asList(PORT_TAG_HTTP, PORT_TAG_STATE)); - - private final Map<ServiceId, HealthMonitor> healthMonitors; - - public static ApplicationHealthMonitor startMonitoring(ApplicationInfo application) { - return new ApplicationHealthMonitor(makeHealthMonitors(application)); - } - - 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) { - 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) - .ifPresent(healthMonitor -> healthMonitors.put( - ApplicationInstanceGenerator.getServiceId(application, serviceInfo), - healthMonitor)); - } - } - } - return healthMonitors; - } - - private static Optional<HealthMonitor> maybeCreateHealthMonitor( - ApplicationInfo applicationInfo, - HostInfo hostInfo, - ServiceInfo serviceInfo, - PortInfo portInfo) { - if (portInfo.getTags().containsAll(PORT_TAGS_HEALTH)) { - HostName hostname = HostName.from(hostInfo.getHostname()); - HealthEndpoint endpoint = HealthEndpoint.forHttp(hostname, portInfo.getPort()); - // todo: make HealthMonitor - // HealthMonitor healthMonitor = new HealthMonitor(endpoint); - // 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 43a02a385be..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java +++ /dev/null @@ -1,139 +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.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.SSLContext; - -/** - * @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 HealthEndpoint endpoint; - - private volatile CloseableHttpClient httpClient; - - public HealthClient(HealthEndpoint endpoint) { - this.endpoint = endpoint; - } - - public void start() { - endpoint.getServiceIdentityProvider().ifPresent(provider -> { - onCredentialsUpdate(provider.getIdentitySslContext(), null); - provider.addIdentityListener(this); - }); - } - - @Override - public void onCredentialsUpdate(SSLContext sslContext, AthenzService ignored) { - SSLConnectionSocketFactory socketFactory = - new SSLConnectionSocketFactory(sslContext, endpoint.getHostnameVerifier().orElse(null)); - - 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() { - endpoint.getServiceIdentityProvider().ifPresent(provider -> provider.removeIdentityListener(this)); - - try { - httpClient.close(); - } catch (Exception e) { - // ignore - } - httpClient = null; - } - - private HealthInfo probeHealth() throws Exception { - HttpGet httpget = new HttpGet(endpoint.getStateV1HealthUrl().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 e9d17a9ab70..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java +++ /dev/null @@ -1,57 +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.identity.ServiceIdentityProvider; -import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier; - -import javax.net.ssl.HostnameVerifier; -import java.net.URL; -import java.util.Collections; -import java.util.Optional; - -import static com.yahoo.yolean.Exceptions.uncheck; - -/** - * @author hakon - */ -class HealthEndpoint { - private final URL url; - private final Optional<HostnameVerifier> hostnameVerifier; - private final Optional<ServiceIdentityProvider> serviceIdentityProvider; - - static HealthEndpoint forHttp(HostName hostname, int port) { - URL url = uncheck(() -> new URL("http", hostname.value(), port, "/state/v1/health")); - return new HealthEndpoint(url, Optional.empty(), Optional.empty()); - } - - static HealthEndpoint forHttps(HostName hostname, - int port, - ServiceIdentityProvider serviceIdentityProvider, - 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, Optional.of(serviceIdentityProvider), Optional.of(peerVerifier)); - } - - private HealthEndpoint(URL url, - Optional<ServiceIdentityProvider> serviceIdentityProvider, - Optional<HostnameVerifier> hostnameVerifier) { - this.url = url; - this.serviceIdentityProvider = serviceIdentityProvider; - this.hostnameVerifier = hostnameVerifier; - } - - public URL getStateV1HealthUrl() { - return url; - } - - public Optional<ServiceIdentityProvider> getServiceIdentityProvider() { - return serviceIdentityProvider; - } - - public Optional<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 fd809b32918..00000000000 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java +++ /dev/null @@ -1,73 +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 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(HealthEndpoint stateV1HealthEndpoint) { - this.healthClient = new HealthClient(stateV1HealthEndpoint); - } - - /** For testing. */ - HealthMonitor(HealthClient healthClient) { - this.healthClient = healthClient; - } - - public void startMonitoring() { - healthClient.start(); - 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 473ef5e3a94..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,8 +2,8 @@ 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; @@ -12,38 +12,19 @@ import com.yahoo.vespa.applicationmodel.ServiceType; 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; - @Inject - public HealthMonitorManager(ConfigserverConfig configserverConfig) { - this.configserverConfig = configserverConfig; - } + public HealthMonitorManager() {} @Override - public void applicationActivated(ApplicationInfo application) { - if (applicationMonitored(application.getApplicationId())) { - ApplicationHealthMonitor monitor = - ApplicationHealthMonitor.startMonitoring(application); - 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 @@ -51,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. |