Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 3 additions & 20 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion frontend/providers/dbprovider/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ NEXT_PUBLIC_MOCK_USER=
SEALOS_DOMAIN="cloud.sealos.io"
FASTGPT_KEY=
STORAGE_CLASSNAME=choosable
MONITOR_URL=""
# Metrics for database monitor (Victoria Metrics / Prometheus API base URL)
# vm-cluster example: http://127.0.0.1:8481/select/0/prometheus
# vmsingle example: http://127.0.0.1:8429
METRICS_URL=""
# Optional: allow kubeconfig cluster server to bypass in-cluster apiserver override in local dev
WHITELIST_KUBERNETES_HOSTS=""

MINIO_URL=
MINIO_ACCESS_KEY=
Expand Down
3 changes: 2 additions & 1 deletion frontend/providers/dbprovider/deploy/Kubefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ COPY manifests manifests
ENV cloudDomain="127.0.0.1.nip.io"
ENV cloudPort=""
ENV certSecretName="wildcard-cert"
ENV monitorUrl="http://database-monitor.sealos.svc.cluster.local:9090"
ENV metricsUrl="http://vmselect-vm-stack-victoria-metrics-k8s-stack.vm.svc.cluster.local:8481/select/0/prometheus"
ENV whitelistKubernetesHosts=""
ENV minioUrl=""
ENV minioAccessKey=""
ENV minioSecretKey=""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ spec:
value: {{ .cloudDomain }}
- name: SEALOS_PORT
value: "{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}"
- name: MONITOR_URL
value: {{ .monitorUrl }}
- name: METRICS_URL
value: {{ default "http://vmselect-vm-stack-victoria-metrics-k8s-stack.vm.svc.cluster.local:8481/select/0/prometheus" .metricsUrl }}
- name: WHITELIST_KUBERNETES_HOSTS
value: "{{ .whitelistKubernetesHosts }}"
- name: MINIO_URL
value: {{ .minioUrl }}
- name: MINIO_ACCESS_KEY
Expand Down
1 change: 1 addition & 0 deletions frontend/providers/dbprovider/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"react-syntax-highlighter": "^15.5.0",
"sass": "^1.68.0",
"sealos-desktop-sdk": "workspace:*",
"sealos-metrics-sdk": "workspace:^",
"sharp": "^0.32.6",
"typescript": "^5.2.2",
"zod": "^4.0.8",
Expand Down
108 changes: 96 additions & 12 deletions frontend/providers/dbprovider/src/services/handleStream.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,104 @@
import { AxiosRequestConfig } from 'axios';
import { MetricsClient } from 'sealos-metrics-sdk';
import type { DatabaseQueryParams, DatabaseType, RawQueryParams } from 'sealos-metrics-sdk';

type LegacyMonitorParams = {
query?: string | string[];
namespace?: string | string[];
start?: string | number | string[];
end?: string | number | string[];
step?: string | string[];
app?: string | string[];
type?: string | string[];
};

const normalizeParam = (value: unknown): string | undefined => {
if (Array.isArray(value)) return value.length > 0 ? String(value[0]) : undefined;
if (value === undefined || value === null) return undefined;
return String(value);
};

const parseRange = (params: LegacyMonitorParams): RawQueryParams['range'] => {
const startRaw = normalizeParam(params.start);
if (!startRaw) return undefined;

const endRaw = normalizeParam(params.end);
const step = normalizeParam(params.step);

return {
start: Number(startRaw),
...(endRaw ? { end: Number(endRaw) } : {}),
...(step ? { step } : {})
};
};

const parseWhitelist = (raw?: string): string[] | undefined => {
if (!raw) return undefined;
const parsed = raw
.split(',')
.map((host) => host.trim())
.filter(Boolean);
return parsed.length > 0 ? parsed : undefined;
};

const isSupportedDatabaseType = (value: string): value is DatabaseType =>
['apecloud-mysql', 'postgresql', 'mongodb', 'redis', 'kafka', 'milvus'].includes(value);

export const handleAxiosStream = async (props: AxiosRequestConfig, kubeconfig: string) => {
try {
const { url, params } = props;
const queryString = new URLSearchParams(params).toString();
const requestOptions = {
method: 'GET',
headers: {
Authorization: encodeURIComponent(kubeconfig)
const url = normalizeParam(props.url) || '';
const params = (props.params || {}) as LegacyMonitorParams;
const metricsURL = process.env.METRICS_URL;
const whitelistKubernetesHosts = parseWhitelist(process.env.WHITELIST_KUBERNETES_HOSTS);

const client = new MetricsClient({
kubeconfig,
metricsURL,
whitelistKubernetesHosts
});

if (url === '/query') {
const query = normalizeParam(params.query);
if (!query) {
throw new Error('monitor query is required');
}

const namespace = normalizeParam(params.namespace);
const range = parseRange(params);
const request: RawQueryParams = {
query,
...(namespace ? { namespace } : {}),
...(range ? { range } : {})
};

return client.database.rawQuery(request);
}

if (url === '/q') {
const query = normalizeParam(params.query);
const app = normalizeParam(params.app);
const type = normalizeParam(params.type);
if (!query || !app || !type) {
throw new Error('monitor query/app/type are required');
}
if (!isSupportedDatabaseType(type)) {
throw new Error(`Unsupported database type: ${type}`);
}
};
const doMain = process.env.MONITOR_URL || 'http://monitor-system.cloud.sealos.run';
const response = await fetch(`${doMain}${url}?${queryString}`, requestOptions).then((res) =>
res.json()
);
return response;

const namespace = normalizeParam(params.namespace);
const range = parseRange(params);
const request: DatabaseQueryParams = {
query,
app,
type,
...(namespace ? { namespace } : {}),
...(range ? { range } : {})
};

return client.database.query(request);
}

throw new Error(`Unsupported monitor endpoint: ${url}`);
} catch (error) {
console.log('===monitor===\n', error);
throw error;
Expand Down
Loading