// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.admin.metricsproxy; import ai.vespa.metricsproxy.http.metrics.NodeInfoConfig; import ai.vespa.metricsproxy.metric.dimensions.NodeDimensionsConfig; import ai.vespa.metricsproxy.metric.dimensions.PublicDimensions; import ai.vespa.metricsproxy.rpc.RpcConnectorConfig; import ai.vespa.metricsproxy.service.VespaServicesConfig; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.vespa.model.VespaModel; import org.junit.jupiter.api.Test; import static com.yahoo.config.model.api.container.ContainerServiceType.METRICS_PROXY_CONTAINER; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.CONTAINER_CONFIG_ID; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.TestMode.hosted; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.TestMode.self_hosted; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.containerConfigId; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getModel; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getNodeDimensionsConfig; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getRpcConnectorConfig; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getVespaServicesConfig; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author gjoranv */ public class MetricsProxyContainerTest { @Test void one_metrics_proxy_container_is_added_to_every_node() { int numberOfHosts = 7; VespaModel model = getModel(hostedServicesWithManyNodes(), hosted, new DeployState.Builder(), numberOfHosts); assertEquals(numberOfHosts, model.getRoot().hostSystem().getHosts().size()); for (var host : model.hostSystem().getHosts()) { assertNotNull(host.getService(METRICS_PROXY_CONTAINER.serviceName)); long metricsProxies = host.getServices().stream() .filter(s -> s.getClass().equals(MetricsProxyContainer.class)) .count(); assertEquals(1, metricsProxies); } } @Test void one_metrics_proxy_container_is_added_to_every_node_also_when_dedicated_CCC() { int numberOfHosts = 7; VespaModel model = getModel(hostedServicesWithManyNodes(), hosted, new DeployState.Builder(), numberOfHosts); assertEquals(numberOfHosts, model.getRoot().hostSystem().getHosts().size()); for (var host : model.hostSystem().getHosts()) { assertNotNull(host.getService(METRICS_PROXY_CONTAINER.serviceName)); long metricsProxies = host.getServices().stream() .filter(s -> s.getClass().equals(MetricsProxyContainer.class)) .count(); assertEquals(1, metricsProxies); } } @Test void http_server_is_running_on_expected_port() { VespaModel model = getModel(hostedServicesWithContent(), self_hosted); MetricsProxyContainer container = (MetricsProxyContainer) model.id2producer().get(CONTAINER_CONFIG_ID); assertEquals(19092, container.getSearchPort()); assertEquals(19092, container.getHealthPort()); assertTrue(container.getPortsMeta().getTagsAt(0).contains("http")); assertTrue(container.getPortsMeta().getTagsAt(0).contains("state")); } @Test void metrics_rpc_server_is_running_on_expected_port() { VespaModel model = getModel(hostedServicesWithContent(), self_hosted); MetricsProxyContainer container = (MetricsProxyContainer) model.id2producer().get(CONTAINER_CONFIG_ID); int offset = 3; assertEquals(2, container.getPortsMeta().getTagsAt(offset).size()); assertTrue(container.getPortsMeta().getTagsAt(offset).contains("rpc")); assertTrue(container.getPortsMeta().getTagsAt(offset).contains("metrics")); RpcConnectorConfig config = getRpcConnectorConfig(model); assertEquals(19095, config.port()); } @Test void admin_rpc_server_is_running() { VespaModel model = getModel(hostedServicesWithContent(), self_hosted); MetricsProxyContainer container = (MetricsProxyContainer) model.id2producer().get(CONTAINER_CONFIG_ID); int offset = 2; assertEquals(2, container.getPortsMeta().getTagsAt(offset).size()); assertTrue(container.getPortsMeta().getTagsAt(offset).contains("rpc")); assertTrue(container.getPortsMeta().getTagsAt(offset).contains("admin")); } @Test void preload_is_empty() { VespaModel model = getModel(hostedServicesWithContent(), self_hosted); MetricsProxyContainer container = (MetricsProxyContainer) model.id2producer().get(CONTAINER_CONFIG_ID); assertEquals("", container.getPreLoad()); } @Test void hosted_application_propagates_node_dimensions() { String services = hostedServicesWithContent(); VespaModel hostedModel = getModel(services, hosted); assertEquals(4, hostedModel.getHosts().size()); String configId = containerConfigId(hostedModel, hosted); NodeDimensionsConfig config = getNodeDimensionsConfig(hostedModel, configId); assertEquals("content", config.dimensions(PublicDimensions.INTERNAL_CLUSTER_TYPE)); assertEquals("my-content", config.dimensions(PublicDimensions.INTERNAL_CLUSTER_ID)); assertEquals("default.mock-application.default.prod.default.my-content", config.dimensions(PublicDimensions.DEPLOYMENT_CLUSTER)); } @Test void metrics_v2_handler_is_set_up_with_node_info_config() { String services = hostedServicesWithContent(); VespaModel hostedModel = getModel(services, hosted); var container = (MetricsProxyContainer) hostedModel.id2producer().get(containerConfigId(hostedModel, hosted)); var handlers = container.getHandlers().getComponents(); assertEquals(1, handlers.size()); var metricsV2Handler = handlers.iterator().next(); NodeInfoConfig config = hostedModel.getConfig(NodeInfoConfig.class, metricsV2Handler.getConfigId()); assertTrue(config.role().startsWith("content/my-content/0/")); assertTrue(config.hostname().startsWith("node-1-3-50-")); } @Test void vespa_services_config_has_all_services() { VespaServicesConfig vespaServicesConfig = getVespaServicesConfig(hostedServicesWithContent()); assertEquals(9, vespaServicesConfig.service().size()); for (var service : vespaServicesConfig.service()) { if (service.configId().equals("admin/cluster-controllers/0")) { assertEquals("container-clustercontroller", service.name(), "Wrong service name"); assertEquals(1, service.dimension().size()); assertEquals("clustername", service.dimension(0).key()); assertEquals("cluster-controllers", service.dimension(0).value()); } } } @Test void vespa_services_config_has_service_dimensions() { VespaServicesConfig vespaServicesConfig = getVespaServicesConfig(hostedServicesWithContent()); for (var service : vespaServicesConfig.service()) { if (service.configId().equals("admin/cluster-controllers/0")) { assertEquals(1, service.dimension().size()); assertEquals("clustername", service.dimension(0).key()); assertEquals("cluster-controllers", service.dimension(0).value()); } } } private static String hostedServicesWithManyNodes() { return String.join("\n", "", " ", " ", " ", " ", " 2" + " ", " ", " ", ""); } private static String hostedServicesWithContent() { return String.join("\n", "", " ", " 1" + " ", " ", " ", "" ); } }