set endpoint topology with depth

This commit is contained in:
Qiuxia Fan 2022-02-15 17:00:43 +08:00
parent 832521af9d
commit 995f572a47
3 changed files with 220 additions and 45 deletions

View File

@ -173,20 +173,6 @@ export const topologyStore = defineStore({
}
return res.data;
},
async getEndpointTopology() {
const endpointId = useSelectorStore().currentPod.id;
const duration = useAppStoreWithOut().durationTime;
const res: AxiosResponse = await graphql
.query("getEndpointTopology")
.params({
endpointId,
duration,
});
if (!res.data.errors) {
this.setEndpointTopology(res.data.data.topology);
}
return res.data;
},
async getInstanceTopology() {
const serverServiceId = useSelectorStore().currentService.id;
const clientServiceId = useSelectorStore().currentDestService.id;
@ -203,6 +189,150 @@ export const topologyStore = defineStore({
}
return res.data;
},
async updateEndpointTopology(endpointIds: string[], depth: number) {
const res = await this.getEndpointTopology(endpointIds);
if (depth > 1) {
const ids = res.nodes
.map((item: Node) => item.id)
.filter((d: string) => !endpointIds.includes(d));
if (!ids.length) {
this.setEndpointTopology(res);
return;
}
const json = await this.getEndpointTopology(ids);
if (depth > 2) {
const pods = json.nodes
.map((item: Node) => item.id)
.filter((d: string) => ![...ids, ...endpointIds].includes(d));
if (!pods.length) {
const nodes = [...res.nodes, ...json.nodes];
const calls = [...res.calls, ...json.calls];
this.setEndpointTopology({ nodes, calls });
return;
}
const topo = await this.getEndpointTopology(pods);
if (depth > 3) {
const endpoints = topo.nodes
.map((item: Node) => item.id)
.filter(
(d: string) => ![...ids, ...pods, ...endpointIds].includes(d)
);
if (!endpoints.length) {
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
const calls = [...res.calls, ...json.calls, ...topo.calls];
this.setEndpointTopology({ nodes, calls });
return;
}
const data = await this.getEndpointTopology(endpoints);
if (depth > 4) {
const nodeIds = data.nodes
.map((item: Node) => item.id)
.filter(
(d: string) =>
![...endpoints, ...ids, ...pods, ...endpointIds].includes(d)
);
if (!nodeIds.length) {
const nodes = [
...res.nodes,
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setEndpointTopology({ nodes, calls });
return;
}
const toposObj = await this.getEndpointTopology(nodeIds);
const nodes = [
...res.nodes,
...json.nodes,
...topo.nodes,
...data.nodes,
...toposObj.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
...toposObj.calls,
];
this.setEndpointTopology({ nodes, calls });
} else {
const nodes = [
...res.nodes,
...json.nodes,
...topo.nodes,
...data.nodes,
];
const calls = [
...res.calls,
...json.calls,
...topo.calls,
...data.calls,
];
this.setEndpointTopology({ nodes, calls });
}
} else {
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
const calls = [...res.calls, ...json.calls, ...topo.calls];
this.setEndpointTopology({ nodes, calls });
}
} else {
this.setEndpointTopology({
nodes: [...res.nodes, ...json.nodes],
calls: [...res.calls, ...json.calls],
});
}
} else {
this.setEndpointTopology(res);
}
},
async getEndpointTopology(endpointIds: string[]) {
// const endpointId = useSelectorStore().currentPod.id;
const duration = useAppStoreWithOut().durationTime;
const variables = ["$duration: Duration!"];
const fragment = endpointIds.map((id: string, index: number) => {
return `endpointTopology${index}: getEndpointDependencies(endpointId: "${id}", duration: $duration) {
nodes {
id
name
serviceId
serviceName
type
isReal
}
calls {
id
source
target
detectPoints
}
}`;
});
const queryStr = `query queryData(${variables}) {${fragment}}`;
const conditions = { duration };
const res: AxiosResponse = await query({ queryStr, conditions });
if (res.data.errors) {
return res.data;
}
const topo = res.data.data;
const calls = [] as any;
const nodes = [] as any;
for (const key of Object.keys(topo)) {
calls.push(...topo[key].calls);
nodes.push(...topo[key].nodes);
}
// this.setEndpointTopology({ calls, nodes });
return { calls, nodes };
},
async getNodeMetrics(param: {
queryStr: string;
conditions: { [key: string]: unknown };

View File

@ -14,6 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="tool">
<span class="label">{{ t("currentDepth") }}</span>
<Selector
class="inputs"
:value="depth"
:options="depthList"
placeholder="Select metrics"
@change="changeDepth"
:style="`background: '#2b3037';`"
/>
<span class="switch-icon ml-5" title="Settings">
<Icon @click="setConfig" size="middle" iconName="settings" />
</span>
@ -21,18 +30,48 @@ limitations under the License. -->
<Settings @update="updateConfig" />
</div>
</div>
<div class="sankey" :style="`height:${height}px;width:${width}px;`">
<div
class="sankey"
:style="`height:${height}px;width:${width}px;`"
v-loading="loading"
>
<Sankey />
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { ref, onMounted } from "vue";
import { Option } from "@/types/app";
import { useTopologyStore } from "@/store/modules/topology";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useSelectorStore } from "@/store/modules/selectors";
import { EntityType } from "../../../data";
import { ElMessage } from "element-plus";
import Sankey from "./Sankey.vue";
import Settings from "./Settings.vue";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
const topologyStore = useTopologyStore();
const loading = ref<boolean>(false);
const height = ref<number>(document.body.clientHeight - 110);
const width = ref<number>(document.body.clientWidth - 40);
const showSettings = ref<boolean>(false);
const depth = ref<string>("2");
const depthList = [1, 2, 3, 4, 5].map((item: number) => ({
value: String(item),
label: String(item),
}));
onMounted(async () => {
loading.value = true;
const resp = await getTopology();
loading.value = false;
if (resp && resp.errors) {
ElMessage.error(resp.errors);
}
});
function setConfig() {
showSettings.value = !showSettings.value;
@ -41,6 +80,33 @@ function setConfig() {
function updateConfig(config: any) {
console.log(config);
}
async function changeDepth(opt: Option[]) {
depth.value = opt[0].value;
console.log(depth.value);
loading.value = true;
const resp = await getTopology();
loading.value = false;
if (resp && resp.errors) {
ElMessage.error(resp.errors);
}
}
async function getTopology() {
let resp;
switch (dashboardStore.entity) {
case EntityType[2].value:
resp = await topologyStore.updateEndpointTopology(
[selectorStore.currentPod.id],
Number(depth.value)
);
break;
case EntityType[4].value:
resp = await topologyStore.getInstanceTopology();
break;
}
return resp;
}
</script>
<style lang="scss" scoped>
.sankey {
@ -81,4 +147,10 @@ function updateConfig(config: any) {
display: inline-block;
border-radius: 3px;
}
.label {
color: #ccc;
display: inline-block;
margin-right: 5px;
}
</style>

View File

@ -14,29 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<Graph :option="option" v-loading="loading" />
<Graph :option="option" />
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from "vue";
import { computed } from "vue";
import { useTopologyStore } from "@/store/modules/topology";
import { useDashboardStore } from "@/store/modules/dashboard";
import { EntityType } from "../../../data";
import { ElMessage } from "element-plus";
const topologyStore = useTopologyStore();
const dashboardStore = useDashboardStore();
const loading = ref<boolean>(false);
const option = computed(() => getOption());
onMounted(async () => {
loading.value = true;
const resp = await getTopology();
loading.value = false;
if (resp && resp.errors) {
ElMessage.error(resp.errors);
}
});
function getOption() {
return {
tooltip: {
@ -85,19 +71,6 @@ function getOption() {
},
};
}
async function getTopology() {
let resp;
switch (dashboardStore.entity) {
case EntityType[2].value:
resp = await topologyStore.getEndpointTopology();
break;
case EntityType[4].value:
resp = await topologyStore.getInstanceTopology();
break;
}
return resp;
}
</script>
<style lang="scss" scoped>
.sankey {