Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into edit-config
Browse files Browse the repository at this point in the history
  • Loading branch information
lynnagara committed Dec 17, 2021
2 parents f2861a9 + 080a49b commit 71809b0
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 36 deletions.
12 changes: 8 additions & 4 deletions snuba/admin/clickhouse/system_queries.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from dataclasses import dataclass
from typing import Any, Dict, Optional, Sequence, Tuple, Type, cast
from typing import Dict, Optional, Sequence, Type

from snuba import settings
from snuba.clickhouse.native import ClickhousePool
from snuba.clickhouse.native import ClickhousePool, ClickhouseResult
from snuba.clusters.cluster import ClickhouseClientSettings, ClickhouseCluster
from snuba.datasets.storages import StorageKey
from snuba.datasets.storages.factory import get_storage
Expand All @@ -21,6 +21,10 @@ class InvalidStorageError(SerializableException):
pass


class InvalidResultError(SerializableException):
pass


class _QueryRegistry:
"""Keep a mapping of SystemQueries to their names"""

Expand Down Expand Up @@ -99,7 +103,7 @@ def run_system_query_on_host_by_name(
clickhouse_port: int,
storage_name: str,
system_query_name: str,
) -> Tuple[Sequence[Any], Sequence[Tuple[str, str]]]:
) -> ClickhouseResult:
query = SystemQuery.from_name(system_query_name)

if not query:
Expand Down Expand Up @@ -132,4 +136,4 @@ def run_system_query_on_host_by_name(
)
query_result = connection.execute(query=query.sql, with_column_types=True)
connection.close()
return cast(Tuple[Sequence[Any], Sequence[Tuple[str, str]]], query_result,)
return query_result
2 changes: 1 addition & 1 deletion snuba/admin/dist/bundle.js

Large diffs are not rendered by default.

21 changes: 20 additions & 1 deletion snuba/admin/static/api_client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import {
ConfigChange,
} from "./runtime_config/types";

import { ClickhouseNodeData } from "./clickhouse_queries/types";
import {
ClickhouseCannedQuery,
ClickhouseNodeData,
QueryRequest,
QueryResult,
} from "./clickhouse_queries/types";

interface Client {
getConfigs: () => Promise<Config[]>;
Expand All @@ -14,6 +19,8 @@ interface Client {
editConfig: (key: ConfigKey, value: ConfigValue) => Promise<Config>;
getAuditlog: () => Promise<ConfigChange[]>;
getClickhouseNodes: () => Promise<[ClickhouseNodeData]>;
getClickhouseCannedQueries: () => Promise<[ClickhouseCannedQuery]>;
executeQuery: (req: QueryRequest) => Promise<QueryResult>;
}

function Client() {
Expand Down Expand Up @@ -87,6 +94,18 @@ function Client() {
})
);
},
getClickhouseCannedQueries: () => {
const url = baseUrl + "clickhouse_queries";
return fetch(url).then((resp) => resp.json());
},
executeQuery: (query: QueryRequest) => {
const url = baseUrl + "run_clickhouse_system_query";
return fetch(url, {
headers: { "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify(query),
}).then((resp) => resp.json());
},
};
}

Expand Down
87 changes: 71 additions & 16 deletions snuba/admin/static/clickhouse_queries/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
import React, { useEffect, useState } from "react";
import Client from "../api_client";
import { Table } from "../table";

import { ClickhouseNodeData } from "./types";
import {
ClickhouseNodeData,
ClickhouseCannedQuery,
QueryRequest,
QueryResult,
} from "./types";

type QueryState = {
storage: string | null;
host: string | null;
port: number | null;
};
type QueryState = Partial<QueryRequest>;

function ClickhouseQueries(props: { api: Client }) {
const [nodeData, setNodeData] = useState<ClickhouseNodeData[]>([]);

const [query, setQuery] = useState<QueryState>({
storage: null,
host: null,
port: null,
});
const [cannedQueries, setCannedQueries] = useState<ClickhouseCannedQuery[]>(
[]
);
const [query, setQuery] = useState<QueryState>({});
const [queryResultHistory, setQueryResultHistory] = useState<QueryResult[]>(
[]
);

useEffect(() => {
props.api.getClickhouseNodes().then((res) => {
setNodeData(res);
});
props.api.getClickhouseCannedQueries().then((res) => {
setCannedQueries(res);
});
}, []);

function selectStorage(storage: string) {
setQuery({
storage,
host: null,
port: null,
setQuery((prevQuery) => {
return {
...prevQuery,
storage: storage,
};
});
}

Expand All @@ -44,9 +51,26 @@ function ClickhouseQueries(props: { api: Client }) {
});
}

function selectCannedQuery(queryName: string) {
setQuery((prevQuery) => {
return {
...prevQuery,
query_name: queryName,
};
});
}

function executeQuery() {
props.api.executeQuery(query as QueryRequest).then((result) => {
result.input_query = `${query.query_name}(${query.storage},${query.host}:${query.port})`;
setQueryResultHistory((prevHistory) => [result, ...prevHistory]);
});
}

return (
<div>
<form>
<h2>Construct a query</h2>
<select
value={query.storage || ""}
onChange={(evt) => selectStorage(evt.target.value)}
Expand Down Expand Up @@ -82,7 +106,38 @@ function ClickhouseQueries(props: { api: Client }) {
))}
</select>
)}
{query.storage && query.host && query.port && (
<select
value={query.query_name || ""}
onChange={(evt) => selectCannedQuery(evt.target.value)}
>
<option disabled value="">
Select a query
</option>
{cannedQueries.map((cannedQuery) => (
<option key={`${cannedQuery.name}`} value={`${cannedQuery.name}`}>
{cannedQuery.name}: {cannedQuery.description}
</option>
))}
</select>
)}
{query.storage && query.host && query.port && query.query_name && (
<button onClick={(_) => executeQuery()}>Execute query</button>
)}
</form>
<div>
<h2>Query results</h2>
<Table
headerData={["Query", "Response"]}
rowData={queryResultHistory.map((queryResult) => [
<span>{queryResult.input_query}</span>,
<Table
headerData={queryResult.column_names}
rowData={queryResult.rows}
/>,
])}
/>
</div>
</div>
);
}
Expand Down
25 changes: 24 additions & 1 deletion snuba/admin/static/clickhouse_queries/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,27 @@ type ClickhouseNodeData = {
local_nodes: ClickhouseNode[];
};

export { ClickhouseNodeData };
type ClickhouseCannedQuery = {
description: string | null;
name: string;
sql: string;
};

type QueryRequest = {
storage: string;
host: string;
port: number;
query_name: string;
};

type QueryResultColumnMetadata = [string];
type QueryResultRow = [string];

type QueryResult = {
input_query?: string;
timestamp: number;
column_names: QueryResultColumnMetadata;
rows: [QueryResultRow];
};

export { ClickhouseNodeData, ClickhouseCannedQuery, QueryRequest, QueryResult };
10 changes: 7 additions & 3 deletions snuba/admin/static/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { COLORS } from "./theme";
type TableProps = {
headerData: ReactNode[];
rowData: ReactNode[][];
columnWidths: number[];
columnWidths?: number[];
};

function Table(props: TableProps) {
const { headerData, rowData, columnWidths } = props;

const sumColumnWidths = columnWidths.reduce((acc, i) => acc + i, 0);
const autoColumnWidths = Array(headerData.length).fill(1);
const notEmptyColumnWidths = columnWidths ?? autoColumnWidths;
const sumColumnWidths = notEmptyColumnWidths.reduce((acc, i) => acc + i, 0);

return (
<table style={tableStyle}>
Expand All @@ -22,7 +24,9 @@ function Table(props: TableProps) {
key={idx}
style={{
...thStyle,
width: `${(columnWidths[idx] * 100) / sumColumnWidths}%`,
width: `${
(notEmptyColumnWidths[idx] * 100) / sumColumnWidths
}%`,
}}
>
{col}
Expand Down
29 changes: 19 additions & 10 deletions snuba/admin/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, List, MutableMapping, Optional
from typing import Any, List, MutableMapping, Optional, cast

import simplejson as json
from flask import Flask, Response, jsonify, make_response, request
Expand All @@ -7,6 +7,7 @@
from snuba.admin.clickhouse.nodes import get_storage_info
from snuba.admin.clickhouse.system_queries import (
InvalidNodeError,
InvalidResultError,
InvalidStorageError,
NonExistentSystemQuery,
SystemQuery,
Expand Down Expand Up @@ -52,18 +53,26 @@ def clickhouse_queries() -> Response:
def clickhouse_system_query() -> Response:
req = request.get_json()
try:
results, columns = run_system_query_on_host_by_name(
result = run_system_query_on_host_by_name(
req.get("host"), req.get("port"), req.get("storage"), req.get("query_name"),
)
res: MutableMapping[str, Any] = {}
rows: List[List[str]] = []
res["column_names"] = [name for name, _ in columns]
res["rows"] = rows
for row in results:
res["rows"].append([str(col) for col in row])

return make_response(jsonify(res), 200)
except (InvalidNodeError, NonExistentSystemQuery, InvalidStorageError) as err:
rows, columns = cast(List[List[str]], result.results), result.meta

if columns:
res: MutableMapping[str, Any] = {}
res["column_names"] = [name for name, _ in columns]
res["rows"] = [[str(col) for col in row] for row in rows]

return make_response(jsonify(res), 200)
else:
raise InvalidResultError
except (
InvalidNodeError,
NonExistentSystemQuery,
InvalidStorageError,
InvalidResultError,
) as err:
return make_response(
jsonify({"error": err.__class__.__name__, "data": err.extra_data}), 400
)
Expand Down

0 comments on commit 71809b0

Please sign in to comment.