diff options
10 files changed, 98 insertions, 12 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/HorizonClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/HorizonClient.java index c9f6f67df6c..77a36610dc7 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/HorizonClient.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/HorizonClient.java @@ -22,4 +22,6 @@ public interface HorizonClient { InputStream getClipboard(String dashboardId); + InputStream getMetaData(byte[] query); + } diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/MockHorizonClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/MockHorizonClient.java index 7d7af046810..0ecad973cff 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/MockHorizonClient.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/horizon/MockHorizonClient.java @@ -42,4 +42,9 @@ public class MockHorizonClient implements HorizonClient { public InputStream getClipboard(String dashboardId) { return null; } + + @Override + public InputStream getMetaData(byte[] query) { + return null; + } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java index 035d32e1837..a7875b0d1ae 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/HorizonApiHandler.java @@ -16,7 +16,6 @@ import com.yahoo.yolean.Exceptions; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UncheckedIOException; import java.util.Optional; import java.util.function.Supplier; import java.util.logging.Level; @@ -68,8 +67,8 @@ public class HorizonApiHandler extends LoggingRequestHandler { private HttpResponse post(HttpRequest request) { Path path = new Path(request.getUri()); - if (path.matches("/horizon/v1/tsdb/api/query/graph")) return tsdbQuery(request); - if (path.matches("/horizon/v1/meta/search/timeseries")) assert true; // TODO + if (path.matches("/horizon/v1/tsdb/api/query/graph")) return tsdbQuery(request, true); + if (path.matches("/horizon/v1/meta/search/timeseries")) return tsdbQuery(request, false); return ErrorResponse.notFoundError("Nothing at " + path); } @@ -79,11 +78,11 @@ public class HorizonApiHandler extends LoggingRequestHandler { return ErrorResponse.notFoundError("Nothing at " + path); } - private HttpResponse tsdbQuery(HttpRequest request) { + private HttpResponse tsdbQuery(HttpRequest request, boolean isMetricQuery) { SecurityContext securityContext = getAttribute(request, SecurityContext.ATTRIBUTE_NAME, SecurityContext.class); try { byte[] data = TsdbQueryRewriter.rewrite(request.getData().readAllBytes(), securityContext.roles(), systemName); - return new JsonInputStreamResponse(() -> client.getMetrics(data)); + return new JsonInputStreamResponse(() -> isMetricQuery ? client.getMetrics(data) : client.getMetaData(data)); } catch (TsdbQueryRewriter.UnauthorizedException e) { return ErrorResponse.forbidden("Access denied"); } catch (IOException e) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriter.java index 0c20571032a..0dadfa93940 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriter.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriter.java @@ -39,14 +39,16 @@ public class TsdbQueryRewriter { JsonNode root = mapper.readTree(data); getField(root, "executionGraph", ArrayNode.class) - .ifPresent(graph -> rewriteExecutionGraph(graph, authorizedTenants, operator, systemName)); + .ifPresent(graph -> rewriteQueryGraph(graph, authorizedTenants, operator, systemName)); getField(root, "filters", ArrayNode.class) .ifPresent(filters -> rewriteFilters(filters, authorizedTenants, operator, systemName)); + getField(root, "queries", ArrayNode.class) + .ifPresent(graph -> rewriteQueryGraph(graph, authorizedTenants, operator, systemName)); return mapper.writeValueAsBytes(root); } - private static void rewriteExecutionGraph(ArrayNode executionGraph, Set<TenantName> tenantNames, boolean operator, SystemName systemName) { + private static void rewriteQueryGraph(ArrayNode executionGraph, Set<TenantName> tenantNames, boolean operator, SystemName systemName) { for (int i = 0; i < executionGraph.size(); i++) { JsonNode execution = executionGraph.get(i); @@ -66,7 +68,7 @@ public class TsdbQueryRewriter { ObjectNode prev = ((ObjectNode) parent.get("filter")); ArrayNode filters; // If we dont already have a filter object, or the object that we have is not an AND filter - if (prev == null || !"Chain".equals(prev.get("type").asText()) || !"AND".equals(prev.get("op").asText())) { + if (prev == null || !"Chain".equals(prev.get("type").asText()) || prev.get("op") == null || !"AND".equals(prev.get("op").asText())) { // Create new filter object filters = parent.putObject("filter") .put("type", "Chain") @@ -88,7 +90,7 @@ public class TsdbQueryRewriter { ObjectNode appFilter = filters.addObject(); appFilter.put("type", "TagValueRegex"); appFilter.put("filter", - tenantNames.stream().map(TenantName::value).sorted().collect(Collectors.joining("|", "(", ")\\..*"))); + tenantNames.stream().map(TenantName::value).sorted().collect(Collectors.joining("|", "^(", ")\\..*"))); appFilter.put("tagKey", "applicationId"); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriterTest.java index 937b0e95440..7c1a84f80bc 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/horizon/TsdbQueryRewriterTest.java @@ -35,6 +35,10 @@ public class TsdbQueryRewriterTest { assertRewrite("no-filters.json", "no-filters.expected.json", Role.reader(TenantName.from("tenant2")), Role.athenzTenantAdmin(TenantName.from("tenant3"))); + + assertRewrite("meta-query.json", + "filters-meta-query.json", + Role.reader(TenantName.from("tenant2")), Role.athenzTenantAdmin(TenantName.from("tenant3"))); } @Test(expected = TsdbQueryRewriter.UnauthorizedException.class) diff --git a/controller-server/src/test/resources/horizon/filter-in-execution-graph.expected.json b/controller-server/src/test/resources/horizon/filter-in-execution-graph.expected.json index 26497a0434a..a71fd812de9 100644 --- a/controller-server/src/test/resources/horizon/filter-in-execution-graph.expected.json +++ b/controller-server/src/test/resources/horizon/filter-in-execution-graph.expected.json @@ -27,7 +27,7 @@ }, { "type": "TagValueRegex", - "filter": "(tenant2|tenant3)\\..*", + "filter": "^(tenant2|tenant3)\\..*", "tagKey": "applicationId" } ] diff --git a/controller-server/src/test/resources/horizon/filters-complex.expected.json b/controller-server/src/test/resources/horizon/filters-complex.expected.json index 68ccb7895de..b3416f8a410 100644 --- a/controller-server/src/test/resources/horizon/filters-complex.expected.json +++ b/controller-server/src/test/resources/horizon/filters-complex.expected.json @@ -35,7 +35,7 @@ }, { "type": "TagValueRegex", - "filter": "(tenant2)\\..*", + "filter": "^(tenant2)\\..*", "tagKey": "applicationId" } ] diff --git a/controller-server/src/test/resources/horizon/filters-meta-query.json b/controller-server/src/test/resources/horizon/filters-meta-query.json new file mode 100644 index 00000000000..0a9429fd833 --- /dev/null +++ b/controller-server/src/test/resources/horizon/filters-meta-query.json @@ -0,0 +1,45 @@ +{ + "from": 0, + "to": 1, + "order": "ASCENDING", + "type": "TAG_KEYS_AND_VALUES", + "source": "", + "aggregationSize": 1000, + "queries": [ + { + "id": "id-0", + "namespace": "Vespa", + "filter": { + "type": "Chain", + "op": "AND", + "filters": [ + { + "type": "Chain", + "filters": [ + { + "type": "TagValueRegex", + "filter": ".*", + "tagKey": "applicationId" + }, + { + "type": "MetricLiteral", + "metric": "vespa.distributor.vds.distributor.docsstored.average|vespa.searchnode.content.proton.resource_usage.disk.average|vespa.searchnode.content.proton.resource_usage.memory.average|vespa.container.peak_qps.max" + } + ] + }, + { + "type": "TagValueLiteralOr", + "filter": "public", + "tagKey": "system" + }, + { + "type": "TagValueRegex", + "filter": "^(tenant2|tenant3)\\..*", + "tagKey": "applicationId" + } + ] + } + } + ], + "aggregationField": "applicationId" +} diff --git a/controller-server/src/test/resources/horizon/meta-query.json b/controller-server/src/test/resources/horizon/meta-query.json new file mode 100644 index 00000000000..ed59bef5eaa --- /dev/null +++ b/controller-server/src/test/resources/horizon/meta-query.json @@ -0,0 +1,29 @@ +{ + "from": 0, + "to": 1, + "order": "ASCENDING", + "type": "TAG_KEYS_AND_VALUES", + "source": "", + "aggregationSize": 1000, + "queries": [ + { + "id": "id-0", + "namespace": "Vespa", + "filter": { + "type": "Chain", + "filters": [ + { + "type": "TagValueRegex", + "filter": ".*", + "tagKey": "applicationId" + }, + { + "type": "MetricLiteral", + "metric": "vespa.distributor.vds.distributor.docsstored.average|vespa.searchnode.content.proton.resource_usage.disk.average|vespa.searchnode.content.proton.resource_usage.memory.average|vespa.container.peak_qps.max" + } + ] + } + } + ], + "aggregationField": "applicationId" +}
\ No newline at end of file diff --git a/controller-server/src/test/resources/horizon/no-filters.expected.json b/controller-server/src/test/resources/horizon/no-filters.expected.json index ab26885b839..35decea21db 100644 --- a/controller-server/src/test/resources/horizon/no-filters.expected.json +++ b/controller-server/src/test/resources/horizon/no-filters.expected.json @@ -22,7 +22,7 @@ }, { "type": "TagValueRegex", - "filter": "(tenant2|tenant3)\\..*", + "filter": "^(tenant2|tenant3)\\..*", "tagKey": "applicationId" } ] |