mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 10:14:35 +00:00
support pause a network (#528)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
||||||
import { Md5 } from 'ts-md5'
|
import { Md5 } from 'ts-md5'
|
||||||
|
import { UUID } from './utils';
|
||||||
|
|
||||||
export interface ValidateConfigResponse {
|
export interface ValidateConfigResponse {
|
||||||
toml_config: string;
|
toml_config: string;
|
||||||
@@ -31,6 +32,11 @@ export interface Summary {
|
|||||||
device_count: number;
|
device_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ListNetworkInstanceIdResponse {
|
||||||
|
running_inst_ids: Array<UUID>,
|
||||||
|
disabled_inst_ids: Array<UUID>,
|
||||||
|
}
|
||||||
|
|
||||||
export class ApiClient {
|
export class ApiClient {
|
||||||
private client: AxiosInstance;
|
private client: AxiosInstance;
|
||||||
private authFailedCb: Function | undefined;
|
private authFailedCb: Function | undefined;
|
||||||
@@ -141,6 +147,17 @@ export class ApiClient {
|
|||||||
return response.machines;
|
return response.machines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async list_deivce_instance_ids(machine_id: string): Promise<ListNetworkInstanceIdResponse> {
|
||||||
|
const response = await this.client.get<any, ListNetworkInstanceIdResponse>('/machines/' + machine_id + '/networks');
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update_device_instance_state(machine_id: string, inst_id: string, disabled: boolean): Promise<undefined> {
|
||||||
|
await this.client.put<string>('/machines/' + machine_id + '/networks/' + inst_id, {
|
||||||
|
disabled: disabled,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async get_network_info(machine_id: string, inst_id: string): Promise<any> {
|
public async get_network_info(machine_id: string, inst_id: string): Promise<any> {
|
||||||
const response = await this.client.get<any, Record<string, any>>('/machines/' + machine_id + '/networks/info/' + inst_id);
|
const response = await this.client.get<any, Record<string, any>>('/machines/' + machine_id + '/networks/info/' + inst_id);
|
||||||
return response.info.map;
|
return response.info.map;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Toolbar, IftaLabel, Select, Button, ConfirmPopup, Dialog, useConfirm, useToast } from 'primevue';
|
import { Toolbar, IftaLabel, Select, Button, ConfirmPopup, Dialog, useConfirm, useToast } from 'primevue';
|
||||||
import { NetworkTypes, Status, Utils, Api, } from 'easytier-frontend-lib';
|
import { NetworkTypes, Status, Utils, Api, } from 'easytier-frontend-lib';
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
import { watch, computed, onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -33,9 +33,16 @@ const isEditing = ref(false);
|
|||||||
const showCreateNetworkDialog = ref(false);
|
const showCreateNetworkDialog = ref(false);
|
||||||
const newNetworkConfig = ref<NetworkTypes.NetworkConfig>(NetworkTypes.DEFAULT_NETWORK_CONFIG());
|
const newNetworkConfig = ref<NetworkTypes.NetworkConfig>(NetworkTypes.DEFAULT_NETWORK_CONFIG());
|
||||||
|
|
||||||
|
const listInstanceIdResponse = ref<Api.ListNetworkInstanceIdResponse | undefined>(undefined);
|
||||||
|
|
||||||
const instanceIdList = computed(() => {
|
const instanceIdList = computed(() => {
|
||||||
let insts = deviceInfo.value?.running_network_instances || [];
|
let insts = new Set(deviceInfo.value?.running_network_instances || []);
|
||||||
let options = insts.map((instance: string) => {
|
let t = listInstanceIdResponse.value;
|
||||||
|
if (t) {
|
||||||
|
t.running_inst_ids.forEach((u) => insts.add(Utils.UuidToStr(u)));
|
||||||
|
t.disabled_inst_ids.forEach((u) => insts.add(Utils.UuidToStr(u)));
|
||||||
|
}
|
||||||
|
let options = Array.from(insts).map((instance: string) => {
|
||||||
return { uuid: instance };
|
return { uuid: instance };
|
||||||
});
|
});
|
||||||
return options;
|
return options;
|
||||||
@@ -51,6 +58,53 @@ const selectedInstanceId = computed({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const needShowNetworkStatus = computed(() => {
|
||||||
|
if (!selectedInstanceId.value) {
|
||||||
|
// nothing selected
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (networkIsDisabled.value) {
|
||||||
|
// network is disabled
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
|
||||||
|
const networkIsDisabled = computed(() => {
|
||||||
|
if (!selectedInstanceId.value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return listInstanceIdResponse.value?.disabled_inst_ids.map(Utils.UuidToStr).includes(selectedInstanceId.value?.uuid);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(selectedInstanceId, async (newVal, oldVal) => {
|
||||||
|
if (newVal?.uuid !== oldVal?.uuid && networkIsDisabled.value) {
|
||||||
|
await loadDisabledNetworkConfig();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const disabledNetworkConfig = ref<NetworkTypes.NetworkConfig | undefined>(undefined);
|
||||||
|
|
||||||
|
const loadDisabledNetworkConfig = async () => {
|
||||||
|
disabledNetworkConfig.value = undefined;
|
||||||
|
|
||||||
|
if (!deviceId.value || !selectedInstanceId.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = await props.api?.get_network_config(deviceId.value, selectedInstanceId.value.uuid);
|
||||||
|
disabledNetworkConfig.value = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateNetworkState = async (disabled: boolean) => {
|
||||||
|
if (!deviceId.value || !selectedInstanceId.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await props.api?.update_device_instance_state(deviceId.value, selectedInstanceId.value.uuid, disabled);
|
||||||
|
await loadNetworkInstanceIds();
|
||||||
|
}
|
||||||
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const confirmDeleteNetwork = (event: any) => {
|
const confirmDeleteNetwork = (event: any) => {
|
||||||
confirm.require({
|
confirm.require({
|
||||||
@@ -128,6 +182,15 @@ const editNetwork = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const loadNetworkInstanceIds = async () => {
|
||||||
|
if (!deviceId.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listInstanceIdResponse.value = await props.api?.list_deivce_instance_ids(deviceId.value);
|
||||||
|
console.debug("loadNetworkInstanceIds", listInstanceIdResponse.value);
|
||||||
|
}
|
||||||
|
|
||||||
const loadDeviceInfo = async () => {
|
const loadDeviceInfo = async () => {
|
||||||
if (!deviceId.value || !instanceId.value) {
|
if (!deviceId.value || !instanceId.value) {
|
||||||
return;
|
return;
|
||||||
@@ -146,7 +209,7 @@ const loadDeviceInfo = async () => {
|
|||||||
|
|
||||||
let periodFunc = new Utils.PeriodicTask(async () => {
|
let periodFunc = new Utils.PeriodicTask(async () => {
|
||||||
try {
|
try {
|
||||||
await loadDeviceInfo();
|
await Promise.all([loadNetworkInstanceIds(), loadDeviceInfo()]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.debug(e);
|
console.debug(e);
|
||||||
}
|
}
|
||||||
@@ -188,8 +251,23 @@ onUnmounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
|
||||||
<Status v-bind:cur-network-inst="curNetworkInfo" v-if="!!selectedInstanceId">
|
<!-- For running network, show the status -->
|
||||||
</Status>
|
<div v-if="needShowNetworkStatus">
|
||||||
|
<Status v-bind:cur-network-inst="curNetworkInfo" v-if="needShowNetworkStatus">
|
||||||
|
</Status>
|
||||||
|
<center>
|
||||||
|
<Button @click="updateNetworkState(true)" label="Disable Network" severity="warn" />
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- For disabled network, show the config -->
|
||||||
|
<div v-if="networkIsDisabled">
|
||||||
|
<Config :cur-network="disabledNetworkConfig" @run-network="updateNetworkState(false)"
|
||||||
|
v-if="disabledNetworkConfig" />
|
||||||
|
<div v-else>
|
||||||
|
<div class="text-center text-xl"> Network is disabled, Loading config... </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 place-content-center h-full" v-if="!selectedInstanceId">
|
<div class="grid grid-cols-1 gap-4 place-content-center h-full" v-if="!selectedInstanceId">
|
||||||
<div class="text-center text-xl"> Select or create a network instance to manage </div>
|
<div class="text-center text-xl"> Select or create a network instance to manage </div>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ use easytier::{
|
|||||||
};
|
};
|
||||||
use tokio::sync::{broadcast, RwLock};
|
use tokio::sync::{broadcast, RwLock};
|
||||||
|
|
||||||
|
use crate::db::ListNetworkProps;
|
||||||
|
|
||||||
use super::storage::{Storage, StorageToken, WeakRefStorage};
|
use super::storage::{Storage, StorageToken, WeakRefStorage};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -206,7 +208,11 @@ impl Session {
|
|||||||
|
|
||||||
let local_configs = match storage
|
let local_configs = match storage
|
||||||
.db
|
.db
|
||||||
.list_network_configs(user_id, Some(req.machine_id.unwrap().into()), true)
|
.list_network_configs(
|
||||||
|
user_id,
|
||||||
|
Some(req.machine_id.unwrap().into()),
|
||||||
|
ListNetworkProps::EnabledOnly,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(configs) => configs,
|
Ok(configs) => configs,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ pub mod entity;
|
|||||||
|
|
||||||
use entity::user_running_network_configs;
|
use entity::user_running_network_configs;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
sea_query::OnConflict, ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait as _,
|
prelude::Expr, sea_query::OnConflict, ActiveModelTrait, ColumnTrait as _, DatabaseConnection,
|
||||||
QueryFilter as _, SqlxSqliteConnector, TransactionTrait as _,
|
DbErr, EntityTrait, QueryFilter as _, SqlxSqliteConnector, TransactionTrait as _,
|
||||||
};
|
};
|
||||||
use sea_orm_migration::MigratorTrait as _;
|
use sea_orm_migration::MigratorTrait as _;
|
||||||
use sqlx::{migrate::MigrateDatabase as _, types::chrono, Sqlite, SqlitePool};
|
use sqlx::{migrate::MigrateDatabase as _, types::chrono, Sqlite, SqlitePool};
|
||||||
@@ -14,6 +14,12 @@ use crate::migrator;
|
|||||||
|
|
||||||
type UserIdInDb = i32;
|
type UserIdInDb = i32;
|
||||||
|
|
||||||
|
pub enum ListNetworkProps {
|
||||||
|
All,
|
||||||
|
EnabledOnly,
|
||||||
|
DisabledOnly,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Db {
|
pub struct Db {
|
||||||
db_path: String,
|
db_path: String,
|
||||||
@@ -115,17 +121,51 @@ impl Db {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn update_network_config_state(
|
||||||
|
&self,
|
||||||
|
user_id: UserIdInDb,
|
||||||
|
network_inst_id: uuid::Uuid,
|
||||||
|
disabled: bool,
|
||||||
|
) -> Result<entity::user_running_network_configs::Model, DbErr> {
|
||||||
|
use entity::user_running_network_configs as urnc;
|
||||||
|
|
||||||
|
urnc::Entity::update_many()
|
||||||
|
.filter(urnc::Column::UserId.eq(user_id))
|
||||||
|
.filter(urnc::Column::NetworkInstanceId.eq(network_inst_id.to_string()))
|
||||||
|
.col_expr(urnc::Column::Disabled, Expr::value(disabled))
|
||||||
|
.col_expr(
|
||||||
|
urnc::Column::UpdateTime,
|
||||||
|
Expr::value(chrono::Local::now().fixed_offset()),
|
||||||
|
)
|
||||||
|
.exec(self.orm_db())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
urnc::Entity::find()
|
||||||
|
.filter(urnc::Column::UserId.eq(user_id))
|
||||||
|
.filter(urnc::Column::NetworkInstanceId.eq(network_inst_id.to_string()))
|
||||||
|
.one(self.orm_db())
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::RecordNotFound(format!(
|
||||||
|
"Network config not found for user {} and network instance {}",
|
||||||
|
user_id, network_inst_id
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn list_network_configs(
|
pub async fn list_network_configs(
|
||||||
&self,
|
&self,
|
||||||
user_id: UserIdInDb,
|
user_id: UserIdInDb,
|
||||||
device_id: Option<uuid::Uuid>,
|
device_id: Option<uuid::Uuid>,
|
||||||
only_enabled: bool,
|
props: ListNetworkProps,
|
||||||
) -> Result<Vec<user_running_network_configs::Model>, DbErr> {
|
) -> Result<Vec<user_running_network_configs::Model>, DbErr> {
|
||||||
use entity::user_running_network_configs as urnc;
|
use entity::user_running_network_configs as urnc;
|
||||||
|
|
||||||
let configs = urnc::Entity::find().filter(urnc::Column::UserId.eq(user_id));
|
let configs = urnc::Entity::find().filter(urnc::Column::UserId.eq(user_id));
|
||||||
let configs = if only_enabled {
|
let configs = if matches!(
|
||||||
configs.filter(urnc::Column::Disabled.eq(false))
|
props,
|
||||||
|
ListNetworkProps::EnabledOnly | ListNetworkProps::DisabledOnly
|
||||||
|
) {
|
||||||
|
configs
|
||||||
|
.filter(urnc::Column::Disabled.eq(matches!(props, ListNetworkProps::DisabledOnly)))
|
||||||
} else {
|
} else {
|
||||||
configs
|
configs
|
||||||
};
|
};
|
||||||
@@ -140,6 +180,24 @@ impl Db {
|
|||||||
Ok(configs)
|
Ok(configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_network_config(
|
||||||
|
&self,
|
||||||
|
user_id: UserIdInDb,
|
||||||
|
device_id: &uuid::Uuid,
|
||||||
|
network_inst_id: &String,
|
||||||
|
) -> Result<Option<user_running_network_configs::Model>, DbErr> {
|
||||||
|
use entity::user_running_network_configs as urnc;
|
||||||
|
|
||||||
|
let config = urnc::Entity::find()
|
||||||
|
.filter(urnc::Column::UserId.eq(user_id))
|
||||||
|
.filter(urnc::Column::DeviceId.eq(device_id.to_string()))
|
||||||
|
.filter(urnc::Column::NetworkInstanceId.eq(network_inst_id))
|
||||||
|
.one(self.orm_db())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_user_id<T: ToString>(
|
pub async fn get_user_id<T: ToString>(
|
||||||
&self,
|
&self,
|
||||||
user_name: T,
|
user_name: T,
|
||||||
@@ -167,7 +225,7 @@ impl Db {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter as _};
|
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter as _};
|
||||||
|
|
||||||
use crate::db::{entity::user_running_network_configs, Db};
|
use crate::db::{entity::user_running_network_configs, Db, ListNetworkProps};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_user_network_config_management() {
|
async fn test_user_network_config_management() {
|
||||||
@@ -209,7 +267,7 @@ mod tests {
|
|||||||
assert_ne!(result.update_time, result2.update_time);
|
assert_ne!(result.update_time, result2.update_time);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.list_network_configs(user_id, Some(device_id), true)
|
db.list_network_configs(user_id, Some(device_id), ListNetworkProps::All)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.len(),
|
.len(),
|
||||||
|
|||||||
@@ -93,9 +93,12 @@ async fn main() {
|
|||||||
let db = db::Db::new(cli.db).await.unwrap();
|
let db = db::Db::new(cli.db).await.unwrap();
|
||||||
|
|
||||||
let listener = UdpTunnelListener::new(
|
let listener = UdpTunnelListener::new(
|
||||||
format!("udp://0.0.0.0:{}", cli.config_server_port)
|
format!(
|
||||||
.parse()
|
"{}://0.0.0.0:{}",
|
||||||
.unwrap(),
|
cli.config_server_protocol, cli.config_server_port
|
||||||
|
)
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
let mut mgr = client_manager::ClientManager::new(db.clone());
|
let mut mgr = client_manager::ClientManager::new(db.clone());
|
||||||
mgr.serve(listener).await.unwrap();
|
mgr.serve(listener).await.unwrap();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use easytier::proto::web::*;
|
|||||||
|
|
||||||
use crate::client_manager::session::Session;
|
use crate::client_manager::session::Session;
|
||||||
use crate::client_manager::ClientManager;
|
use crate::client_manager::ClientManager;
|
||||||
|
use crate::db::ListNetworkProps;
|
||||||
|
|
||||||
use super::users::AuthSession;
|
use super::users::AuthSession;
|
||||||
use super::{
|
use super::{
|
||||||
@@ -46,13 +47,21 @@ struct ColletNetworkInfoJsonReq {
|
|||||||
inst_ids: Option<Vec<uuid::Uuid>>,
|
inst_ids: Option<Vec<uuid::Uuid>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
struct UpdateNetworkStateJsonReq {
|
||||||
|
disabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
struct RemoveNetworkJsonReq {
|
struct RemoveNetworkJsonReq {
|
||||||
inst_ids: Vec<uuid::Uuid>,
|
inst_ids: Vec<uuid::Uuid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
struct ListNetworkInstanceIdsJsonResp(Vec<uuid::Uuid>);
|
struct ListNetworkInstanceIdsJsonResp {
|
||||||
|
running_inst_ids: Vec<easytier::proto::common::Uuid>,
|
||||||
|
disabled_inst_ids: Vec<easytier::proto::common::Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
struct ListMachineItem {
|
struct ListMachineItem {
|
||||||
@@ -190,7 +199,7 @@ impl NetworkApi {
|
|||||||
auth_session: AuthSession,
|
auth_session: AuthSession,
|
||||||
State(client_mgr): AppState,
|
State(client_mgr): AppState,
|
||||||
Path(machine_id): Path<uuid::Uuid>,
|
Path(machine_id): Path<uuid::Uuid>,
|
||||||
Query(payload): Query<ColletNetworkInfoJsonReq>,
|
Json(payload): Json<ColletNetworkInfoJsonReq>,
|
||||||
) -> Result<Json<CollectNetworkInfoResponse>, HttpHandleError> {
|
) -> Result<Json<CollectNetworkInfoResponse>, HttpHandleError> {
|
||||||
let result =
|
let result =
|
||||||
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
|
Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
|
||||||
@@ -226,10 +235,28 @@ impl NetworkApi {
|
|||||||
.list_network_instance(BaseController::default(), ListNetworkInstanceRequest {})
|
.list_network_instance(BaseController::default(), ListNetworkInstanceRequest {})
|
||||||
.await
|
.await
|
||||||
.map_err(convert_rpc_error)?;
|
.map_err(convert_rpc_error)?;
|
||||||
Ok(
|
|
||||||
ListNetworkInstanceIdsJsonResp(ret.inst_ids.into_iter().map(Into::into).collect())
|
let running_inst_ids = ret.inst_ids.clone().into_iter().map(Into::into).collect();
|
||||||
.into(),
|
|
||||||
)
|
// collect networks that are disabled
|
||||||
|
let disabled_inst_ids = client_mgr
|
||||||
|
.db()
|
||||||
|
.list_network_configs(
|
||||||
|
auth_session.user.unwrap().id(),
|
||||||
|
Some(machine_id),
|
||||||
|
ListNetworkProps::DisabledOnly,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(convert_db_error)?
|
||||||
|
.iter()
|
||||||
|
.filter_map(|x| x.network_instance_id.clone().try_into().ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(ListNetworkInstanceIdsJsonResp {
|
||||||
|
running_inst_ids,
|
||||||
|
disabled_inst_ids,
|
||||||
|
}
|
||||||
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_remove_network_instance(
|
async fn handle_remove_network_instance(
|
||||||
@@ -289,6 +316,54 @@ impl NetworkApi {
|
|||||||
Ok(Json(ListMachineJsonResp { machines }))
|
Ok(Json(ListMachineJsonResp { machines }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_update_network_state(
|
||||||
|
auth_session: AuthSession,
|
||||||
|
State(client_mgr): AppState,
|
||||||
|
Path((machine_id, inst_id)): Path<(uuid::Uuid, Option<uuid::Uuid>)>,
|
||||||
|
Json(payload): Json<UpdateNetworkStateJsonReq>,
|
||||||
|
) -> Result<(), HttpHandleError> {
|
||||||
|
let Some(inst_id) = inst_id else {
|
||||||
|
// not implement disable all
|
||||||
|
return Err((
|
||||||
|
StatusCode::NOT_IMPLEMENTED,
|
||||||
|
other_error(format!("Not implemented")).into(),
|
||||||
|
))
|
||||||
|
.into();
|
||||||
|
};
|
||||||
|
|
||||||
|
let sess = Self::get_session_by_machine_id(&auth_session, &client_mgr, &machine_id).await?;
|
||||||
|
let cfg = client_mgr
|
||||||
|
.db()
|
||||||
|
.update_network_config_state(auth_session.user.unwrap().id(), inst_id, payload.disabled)
|
||||||
|
.await
|
||||||
|
.map_err(convert_db_error)?;
|
||||||
|
|
||||||
|
let c = sess.scoped_rpc_client();
|
||||||
|
|
||||||
|
if payload.disabled {
|
||||||
|
c.delete_network_instance(
|
||||||
|
BaseController::default(),
|
||||||
|
DeleteNetworkInstanceRequest {
|
||||||
|
inst_ids: vec![inst_id.into()],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(convert_rpc_error)?;
|
||||||
|
} else {
|
||||||
|
c.run_network_instance(
|
||||||
|
BaseController::default(),
|
||||||
|
RunNetworkInstanceRequest {
|
||||||
|
inst_id: Some(inst_id.into()),
|
||||||
|
config: Some(serde_json::from_str(&cfg.network_config).unwrap()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(convert_rpc_error)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_get_network_config(
|
async fn handle_get_network_config(
|
||||||
auth_session: AuthSession,
|
auth_session: AuthSession,
|
||||||
State(client_mgr): AppState,
|
State(client_mgr): AppState,
|
||||||
@@ -298,25 +373,24 @@ impl NetworkApi {
|
|||||||
|
|
||||||
let db_row = client_mgr
|
let db_row = client_mgr
|
||||||
.db()
|
.db()
|
||||||
.list_network_configs(auth_session.user.unwrap().id(), Some(machine_id), false)
|
.get_network_config(auth_session.user.unwrap().id(), &machine_id, &inst_id)
|
||||||
.await
|
.await
|
||||||
.map_err(convert_db_error)?
|
.map_err(convert_db_error)?
|
||||||
.iter()
|
|
||||||
.find(|x| x.network_instance_id == inst_id)
|
|
||||||
.map(|x| x.network_config.clone())
|
|
||||||
.ok_or((
|
.ok_or((
|
||||||
StatusCode::NOT_FOUND,
|
StatusCode::NOT_FOUND,
|
||||||
other_error(format!("No such network instance: {}", inst_id)).into(),
|
other_error(format!("No such network instance: {}", inst_id)).into(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
Ok(serde_json::from_str::<NetworkConfig>(&db_row)
|
Ok(
|
||||||
.map_err(|e| {
|
serde_json::from_str::<NetworkConfig>(&db_row.network_config)
|
||||||
(
|
.map_err(|e| {
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
(
|
||||||
other_error(format!("Failed to parse network config: {:?}", e)).into(),
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
)
|
other_error(format!("Failed to parse network config: {:?}", e)).into(),
|
||||||
})?
|
)
|
||||||
.into())
|
})?
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_route(&mut self) -> Router<AppStateInner> {
|
pub fn build_route(&mut self) -> Router<AppStateInner> {
|
||||||
@@ -332,7 +406,7 @@ impl NetworkApi {
|
|||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/machines/:machine-id/networks/:inst-id",
|
"/api/v1/machines/:machine-id/networks/:inst-id",
|
||||||
delete(Self::handle_remove_network_instance),
|
delete(Self::handle_remove_network_instance).put(Self::handle_update_network_state),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/machines/:machine-id/networks/info",
|
"/api/v1/machines/:machine-id/networks/info",
|
||||||
|
|||||||
Reference in New Issue
Block a user