schedule and route

pull/4271/head
handsomewu 2024-11-13 15:36:18 +08:00
parent 587134e5c6
commit b4fe3ec8db
11 changed files with 1102 additions and 24 deletions

View File

@ -96,14 +96,14 @@ export const constantRoutes = [
]
},
{
path: '/guide',
path: '/schedule',
component: Layout,
redirect: '/guide/index',
redirect: '/schedule/index',
children: [
{
path: 'index',
component: () => import('@/views/guide/index'),
name: 'Guide',
component: () => import('@/views/schedule/index'),
name: 'Schedule',
meta: { title: '调度决策', icon: 'guide', noCache: true }
}
]

View File

@ -3,49 +3,61 @@
import Layout from '@/layout'
const chartsRouter = {
path: '/charts',
path: '/route',
component: Layout,
redirect: 'noRedirect',
name: 'Charts',
name: 'Route',
meta: {
title: '路由控制',
icon: 'tree'
},
children: [
{
path: 'keyboard',
component: () => import('@/views/charts/keyboard'),
name: 'KeyboardChart',
path: 'show_paths',
component: () => import('@/views/route/show_paths'),
name: 'ShowPaths',
meta: { title: '查看最短路径', noCache: true }
},
{
path: 'keyboard',
component: () => import('@/views/charts/keyboard'),
name: 'KeyboardChart',
path: 'show_sid',
component: () => import('@/views/route/show_sid'),
name: 'ShowSID',
meta: { title: '查看SID', noCache: true }
},
{
path: 'line',
component: () => import('@/views/charts/line'),
name: 'LineChart',
path: 'show_policy',
component: () => import('@/views/route/show_policy.vue'),
name: 'ShowPolicy',
meta: { title: '查看路由', noCache: true }
},
{
path: 'mix-chart',
component: () => import('@/views/charts/mix-chart'),
name: 'MixChart',
path: 'show_steer',
component: () => import('@/views/route/show_steer'),
name: 'ShowSteer',
meta: { title: '查看引导', noCache: true }
},
{
path: 'add_policy',
component: () => import('@/views/route/add_policy.vue'),
name: 'AddPolicy',
meta: { title: '添加路由', noCache: true }
},
{
path: 'mix-chart',
component: () => import('@/views/charts/mix-chart'),
name: 'MixChart',
path: 'steer',
component: () => import('@/views/route/steer.vue'),
name: 'Steer',
meta: { title: '更新引导', noCache: true }
},
{
path: 'mix-chart',
component: () => import('@/views/charts/mix-chart'),
name: 'MixChart',
path: 'del_steer',
component: () => import('@/views/route/del_steer.vue'),
name: 'DelSteer',
meta: { title: '删除引导', noCache: true }
},
{
path: 'del_policy',
component: () => import('@/views/route/del_policy.vue'),
name: 'DelPolicy',
meta: { title: '删除路由', noCache: true }
}
]

View File

@ -0,0 +1,135 @@
<template>
<div class="add-policy">
<h2>添加SRv6路由策略</h2>
<!-- 输入表单 -->
<form @submit.prevent="submitPolicy">
<div class="form-group">
<label for="router">路由器</label>
<select id="router" v-model="router" required>
<option disabled value="">选择路由器</option>
<option value="r0">路由器r0</option>
<option value="r3">路由器r3</option>
<option value="r6">路由器r6</option>
</select>
</div>
<div class="form-group">
<label for="bsid">绑定 SID (BSID)</label>
<input id="bsid" v-model="bsid" type="text" required placeholder="fe00::1a">
</div>
<div class="form-group">
<label for="sids">SIDs (逗号分隔)</label>
<input id="sids" v-model="sids" type="text" required placeholder="fc00:1::a,fc00:2::a">
</div>
<button type="submit">添加路由</button>
</form>
<!-- 显示结果 -->
<div v-if="resultMessage" class="result-message">
<p><strong>{{ resultMessage }}</strong></p>
<pre>{{ result }}</pre>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>Error: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
router: '', //
bsid: '', // BSID
sids: '', // SIDs
resultMessage: '', //
result: '', //
error: null //
}
},
methods: {
async submitPolicy() {
try {
const data = {
bsid: this.bsid,
sids: this.sids
}
const response = await axios.post(`http://localhost:5060/route/add_policy?router=${this.router}`, data, {
headers: { 'Content-Type': 'application/json' }
})
this.resultMessage = response.data.message
this.result = response.data.result.join('\n') //
this.error = null
} catch (error) {
this.error = error.message
this.resultMessage = ''
this.result = ''
}
}
}
}
</script>
<style scoped>
.add-policy {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input, .form-group select {
width: 100%;
padding: 8px;
margin-bottom: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.result-message, .error-message {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
}
.result-message {
background-color: #e7f4e4;
color: #3c763d;
}
.error-message {
background-color: #f8d7da;
color: #721c24;
}
</style>

View File

@ -0,0 +1,144 @@
<template>
<div class="del-policy">
<h2>删除 SRv6 策略</h2>
<!-- 表单 -->
<form @submit.prevent="submitDelPolicy">
<div class="form-group">
<label for="router">选择路由器</label>
<select id="router" v-model="router" required>
<option disabled value="">选择路由器</option>
<option value="r0">路由器r0</option>
<option value="r3">路由器r3</option>
<option value="r6">路由器r6</option>
</select>
</div>
<div class="form-group">
<label for="bsid">BSID</label>
<input
id="bsid"
v-model="bsid"
type="text"
required
placeholder="请输入 Binding SID如 fe00:1::1"
>
</div>
<button type="submit">删除策略</button>
</form>
<!-- 显示结果 -->
<div v-if="resultMessage" class="result-message">
<p><strong>{{ resultMessage }}</strong></p>
<pre>{{ result }}</pre>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>错误: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
router: '', //
bsid: '', // Binding SID
resultMessage: '', //
result: '', //
error: null //
}
},
methods: {
async submitDelPolicy() {
try {
// body
const data = {
bsid: this.bsid
}
// DELETE
const response = await axios.delete(
`http://localhost:5060/route/del_policy?router=${this.router}`,
{
headers: { 'Content-Type': 'application/json' },
data
}
)
//
this.resultMessage = response.data.message
this.result = response.data.result.join('\n') //
this.error = null
} catch (error) {
//
this.error = error.message
this.resultMessage = ''
this.result = ''
}
}
}
}
</script>
<style scoped>
.del-policy {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 8px;
margin-bottom: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.result-message,
.error-message {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
}
.result-message {
background-color: #e7f4e4;
color: #3c763d;
}
.error-message {
background-color: #f8d7da;
color: #721c24;
}
</style>

View File

@ -0,0 +1,144 @@
<template>
<div class="del-steer-policy">
<h2>删除引导策略</h2>
<!-- 表单 -->
<form @submit.prevent="submitDelSteerPolicy">
<div class="form-group">
<label for="router">选择路由器</label>
<select id="router" v-model="router" required>
<option disabled value="">选择路由器</option>
<option value="r0">路由器r0</option>
<option value="r3">路由器r3</option>
<option value="r6">路由器r6</option>
</select>
</div>
<div class="form-group">
<label for="ip_prefix">目标IP</label>
<input
id="ip_prefix"
v-model="ip_prefix"
type="text"
required
placeholder="请输入目标 IP如 10.10.0.0/24"
>
</div>
<button type="submit">删除引导策略</button>
</form>
<!-- 显示结果 -->
<div v-if="resultMessage" class="result-message">
<p><strong>{{ resultMessage }}</strong></p>
<pre>{{ result }}</pre>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>错误: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
router: '', //
ip_prefix: '', // IP
resultMessage: '', //
result: '', //
error: null //
}
},
methods: {
async submitDelSteerPolicy() {
try {
// body
const data = {
ip_prefix: this.ip_prefix
}
// DELETE
const response = await axios.delete(
`http://localhost:5060/route/del_steer?router=${this.router}`,
{
headers: { 'Content-Type': 'application/json' },
data
}
)
//
this.resultMessage = response.data.message
this.result = response.data.result.join('\n') //
this.error = null
} catch (error) {
//
this.error = error.message
this.resultMessage = ''
this.result = ''
}
}
}
}
</script>
<style scoped>
.del-steer-policy {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 8px;
margin-bottom: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.result-message,
.error-message {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
}
.result-message {
background-color: #e7f4e4;
color: #3c763d;
}
.error-message {
background-color: #f8d7da;
color: #721c24;
}
</style>

View File

@ -0,0 +1,87 @@
<template>
<div class="show-paths">
<h2>最短路径信息</h2>
<!-- 检查是否在加载状态 -->
<div v-if="loading">...</div>
<!-- 如果有路径数据则显示 -->
<div v-else>
<ul v-if="paths.length > 0">
<li v-for="(path, index) in paths" :key="index">{{ path }}</li>
</ul>
<!-- 如果没有路径数据则显示消息 -->
<div v-else>
<p>未找到</p>
</div>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>加载路径错误: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'ShowPaths',
data() {
return {
paths: [],
loading: false,
error: null
}
},
mounted() {
//
this.fetchPaths()
},
methods: {
// API
fetchPaths() {
this.loading = true
this.error = null
axios
.get('http://localhost:5060/route/show_paths')
.then((response) => {
// paths
if (response.data && response.data.paths) {
this.paths = response.data.paths
} else {
this.error = 'No paths data found in the response.'
}
})
.catch((error) => {
this.error = error.message || 'An error occurred while fetching paths.'
})
.finally(() => {
this.loading = false
})
}
}
}
</script>
<style scoped>
.show-paths {
font-family: Arial, sans-serif;
padding: 20px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin-bottom: 10px;
}
.error-message {
color: red;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,106 @@
<template>
<div class="show-policy">
<h2>SRv6路径: {{ selectedRouter }}</h2>
<!-- 路由器选择器 -->
<div class="router-selector">
<label for="router">选择路由器:</label>
<select v-model="selectedRouter" @change="fetchPolicyInfo">
<option value="r0">r0</option>
<option value="r3">r3</option>
<option value="r6">r6</option>
</select>
</div>
<!-- 显示加载状态 -->
<div v-if="loading">...</div>
<!-- 列表形式展示策略信息 -->
<ul v-if="!loading && policyData.length > 0" class="policy-list">
<li v-for="(policy, index) in policyData" :key="index">
{{ policy }}
</li>
</ul>
<!-- 如果没有策略信息 -->
<div v-else-if="!loading && policyData.length === 0">
<p>No policy information available for the selected router.</p>
</div>
<!-- 错误信息 -->
<div v-if="error" class="error-message">
<p>Error loading policy information: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'ShowPolicy',
data() {
return {
selectedRouter: 'r0', // r0
policyData: [],
loading: false,
error: null
}
},
mounted() {
//
this.fetchPolicyInfo()
},
methods: {
// API
fetchPolicyInfo() {
this.loading = true
this.error = null
axios
.get(`http://localhost:5060/route/show_policy`, { params: { router: this.selectedRouter }})
.then((response) => {
if (response.data && response.data.policies) {
this.policyData = response.data.policies //
} else {
this.policyData = []
this.error = 'No policy data found in the response.'
}
})
.catch((error) => {
this.error = error.message || 'An error occurred while fetching policy data.'
})
.finally(() => {
this.loading = false
})
}
}
}
</script>
<style scoped>
.show-policy {
font-family: Arial, sans-serif;
padding: 20px;
}
.router-selector {
margin-bottom: 20px;
}
ul.policy-list {
list-style-type: none;
padding-left: 0;
}
ul.policy-list li {
background-color: #ffffff;
margin-bottom: 5px;
padding: 5px;
border: 1px solid #ffffff;
}
.error-message {
color: red;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<div class="show-sid">
<h2>SID信息</h2>
<!-- 下拉选择路由器 -->
<div class="router-selector">
<label for="router">选择路由器:</label>
<select v-model="selectedRouter" @change="fetchSIDInfo">
<option value="r0">r0</option>
<option value="r3">r3</option>
<option value="r6">r6</option>
</select>
</div>
<!-- 显示加载提示 -->
<div v-if="loading">SID...</div>
<!-- 列表形式展示 SID 信息 -->
<ul v-if="!loading && sidData.length > 0" class="sid-list">
<li v-for="(sid, index) in sidData" :key="index">
{{ sid }}
</li>
</ul>
<!-- 如果没有 SID 数据则显示消息 -->
<div v-else-if="!loading && sidData.length === 0">
<p>No SID information available for the selected router.</p>
</div>
<!-- 错误信息 -->
<div v-if="error" class="error-message">
<p>Error loading SID information: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'ShowSID',
data() {
return {
selectedRouter: 'r0', // r0
sidData: [],
loading: false,
error: null
}
},
mounted() {
// SID
this.fetchSIDInfo()
},
methods: {
// API SID
fetchSIDInfo() {
this.loading = true
this.error = null
axios
.get(`http://localhost:5060/route/show_sid`, { params: { router: this.selectedRouter }})
.then((response) => {
if (response.data && response.data.localsids) {
this.sidData = response.data.localsids // SID
} else {
this.sidData = []
this.error = 'No SID data found in the response.'
}
})
.catch((error) => {
this.error = error.message || 'An error occurred while fetching SID data.'
})
.finally(() => {
this.loading = false
})
}
}
}
</script>
<style scoped>
.show-sid {
font-family: Arial, sans-serif;
padding: 20px;
}
.router-selector {
margin-bottom: 20px;
}
ul.sid-list {
list-style-type: none;
padding-left: 0;
}
ul.sid-list li {
background-color: #ffffff;
margin-bottom: 5px;
padding: 5px;
border: 1px solid #ffffff;
}
.error-message {
color: red;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,106 @@
<template>
<div class="show-steer">
<h2>流量引导: {{ selectedRouter }}</h2>
<!-- 路由器选择器 -->
<div class="router-selector">
<label for="router">选择路由器:</label>
<select v-model="selectedRouter" @change="fetchSteerInfo">
<option value="r0">r0</option>
<option value="r3">r3</option>
<option value="r6">r6</option>
</select>
</div>
<!-- 显示加载状态 -->
<div v-if="loading">...</div>
<!-- 列表形式展示策略信息 -->
<ul v-if="!loading && policyData.length > 0" class="steer-list">
<li v-for="(policy, index) in policyData" :key="index">
{{ policy }}
</li>
</ul>
<!-- 如果没有策略信息 -->
<div v-else-if="!loading && policyData.length === 0">
<p>No steer information available for the selected router.</p>
</div>
<!-- 错误信息 -->
<div v-if="error" class="error-message">
<p>Error loading steer information: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'ShowSteer',
data() {
return {
selectedRouter: 'r0', // r0
policyData: [],
loading: false,
error: null
}
},
mounted() {
//
this.fetchSteerInfo()
},
methods: {
// API
fetchSteerInfo() {
this.loading = true
this.error = null
axios
.get(`http://localhost:5060/route/show_steer`, { params: { router: this.selectedRouter }})
.then((response) => {
if (response.data && response.data.steering_policies) {
this.policyData = response.data.steering_policies //
} else {
this.policyData = []
this.error = 'No policy data found in the response.'
}
})
.catch((error) => {
this.error = error.message || 'An error occurred while fetching policy data.'
})
.finally(() => {
this.loading = false
})
}
}
}
</script>
<style scoped>
.show-steer {
font-family: Arial, sans-serif;
padding: 20px;
}
.router-selector {
margin-bottom: 20px;
}
ul.steer-list {
list-style-type: none;
padding-left: 0;
}
ul.steer-list li {
background-color: #ffffff;
margin-bottom: 5px;
padding: 5px;
border: 1px solid #ffffff;
}
.error-message {
color: red;
font-weight: bold;
}
</style>

135
src/views/route/steer.vue Normal file
View File

@ -0,0 +1,135 @@
<template>
<div class="steer-policy">
<h2>更新引导策略</h2>
<!-- 输入表单 -->
<form @submit.prevent="submitSteerPolicy">
<div class="form-group">
<label for="router">路由器</label>
<select id="router" v-model="router" required>
<option disabled value="">选择路由器</option>
<option value="r0">路由器r0</option>
<option value="r3">路由器r3</option>
<option value="r6">路由器r6</option>
</select>
</div>
<div class="form-group">
<label for="bsid">绑定SID (BSID)</label>
<input id="bsid" v-model="bsid" type="text" required placeholder="fe00::1a">
</div>
<div class="form-group">
<label for="ip_prefix">目标IP</label>
<input id="ip_prefix" v-model="ip_prefix" type="text" required placeholder="10.10.0.0/24">
</div>
<button type="submit">添加引导策略</button>
</form>
<!-- 显示结果 -->
<div v-if="resultMessage" class="result-message">
<p><strong>{{ resultMessage }}</strong></p>
<pre>{{ result }}</pre>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>Error: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
router: '', //
bsid: '', // BSID
ip_prefix: '', // IP Prefix
resultMessage: '', //
result: '', //
error: null //
}
},
methods: {
async submitSteerPolicy() {
try {
const data = {
bsid: this.bsid,
ip_prefix: this.ip_prefix
}
const response = await axios.post(`http://localhost:5060/route/steer?router=${this.router}`, data, {
headers: { 'Content-Type': 'application/json' }
})
this.resultMessage = response.data.message
this.result = response.data.result.join('\n') //
this.error = null
} catch (error) {
this.error = error.message
this.resultMessage = ''
this.result = ''
}
}
}
}
</script>
<style scoped>
.steer-policy {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input, .form-group select {
width: 100%;
padding: 8px;
margin-bottom: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.result-message, .error-message {
margin-top: 20px;
padding: 10px;
border-radius: 4px;
}
.result-message {
background-color: #e7f4e4;
color: #3c763d;
}
.error-message {
background-color: #f8d7da;
color: #721c24;
}
</style>

View File

@ -0,0 +1,104 @@
<template>
<div class="schedule-decision">
<h2>调度决策</h2>
<!-- 表格展示平均资源和评分 -->
<table class="decision-table">
<thead>
<tr>
<th>集群</th>
<th>平均空闲CPU (%)</th>
<th>平均空闲内存 (bytes)</th>
<th>平均空闲存储 (bytes)</th>
<th>分数</th>
</tr>
</thead>
<tbody>
<tr v-for="(resource, index) in averageResources" :key="index" :class="{ best: clusters[index] === bestCluster }">
<td>{{ clusters[index] }}</td>
<td>{{ resource[0].toFixed(2) }}</td>
<td>{{ resource[1].toFixed(0).toLocaleString() }}</td>
<td>{{ resource[2].toFixed(0).toLocaleString() }}</td>
<td>{{ scores[index].toFixed(2) }}</td>
</tr>
</tbody>
</table>
<!-- 最佳集群展示 -->
<div class="best-cluster">
<h3>最佳集群: {{ bestCluster }}</h3>
</div>
<!-- 错误消息 -->
<div v-if="error" class="error-message">
<p>Error loading schedule data: {{ error }}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'ScheduleDecision',
data() {
return {
clusters: ['hosta', 'hostb'],
averageResources: [],
scores: [],
bestCluster: '',
error: null
}
},
mounted() {
this.fetchScheduleDecision()
},
methods: {
fetchScheduleDecision() {
axios
.get('http://localhost:5060/schedule')
.then((response) => {
const data = response.data
this.averageResources = data.average_resource || []
this.scores = data.scores || []
this.bestCluster = data.best_cluster || ''
})
.catch((error) => {
this.error = error.message || 'An error occurred while fetching schedule data.'
})
}
}
}
</script>
<style scoped>
.schedule-decision {
font-family: Arial, sans-serif;
padding: 20px;
}
table.decision-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
table.decision-table th, table.decision-table td {
padding: 10px;
border: 1px solid #ddd;
text-align: center;
}
table.decision-table tr.best {
background-color: #e0f7fa;
}
.best-cluster h3 {
color: #00796b;
}
.error-message {
color: red;
font-weight: bold;
}
</style>