support pause a network (#528)

This commit is contained in:
Sijie.Sun
2024-12-22 20:29:59 -05:00
committed by GitHub
parent 4cf61f0d4a
commit f3de00be37
6 changed files with 272 additions and 36 deletions

View File

@@ -15,6 +15,8 @@ use easytier::{
};
use tokio::sync::{broadcast, RwLock};
use crate::db::ListNetworkProps;
use super::storage::{Storage, StorageToken, WeakRefStorage};
#[derive(Debug)]
@@ -206,7 +208,11 @@ impl Session {
let local_configs = match storage
.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
{
Ok(configs) => configs,

View File

@@ -4,8 +4,8 @@ pub mod entity;
use entity::user_running_network_configs;
use sea_orm::{
sea_query::OnConflict, ColumnTrait as _, DatabaseConnection, DbErr, EntityTrait as _,
QueryFilter as _, SqlxSqliteConnector, TransactionTrait as _,
prelude::Expr, sea_query::OnConflict, ActiveModelTrait, ColumnTrait as _, DatabaseConnection,
DbErr, EntityTrait, QueryFilter as _, SqlxSqliteConnector, TransactionTrait as _,
};
use sea_orm_migration::MigratorTrait as _;
use sqlx::{migrate::MigrateDatabase as _, types::chrono, Sqlite, SqlitePool};
@@ -14,6 +14,12 @@ use crate::migrator;
type UserIdInDb = i32;
pub enum ListNetworkProps {
All,
EnabledOnly,
DisabledOnly,
}
#[derive(Debug, Clone)]
pub struct Db {
db_path: String,
@@ -115,17 +121,51 @@ impl Db {
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(
&self,
user_id: UserIdInDb,
device_id: Option<uuid::Uuid>,
only_enabled: bool,
props: ListNetworkProps,
) -> Result<Vec<user_running_network_configs::Model>, DbErr> {
use entity::user_running_network_configs as urnc;
let configs = urnc::Entity::find().filter(urnc::Column::UserId.eq(user_id));
let configs = if only_enabled {
configs.filter(urnc::Column::Disabled.eq(false))
let configs = if matches!(
props,
ListNetworkProps::EnabledOnly | ListNetworkProps::DisabledOnly
) {
configs
.filter(urnc::Column::Disabled.eq(matches!(props, ListNetworkProps::DisabledOnly)))
} else {
configs
};
@@ -140,6 +180,24 @@ impl Db {
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>(
&self,
user_name: T,
@@ -167,7 +225,7 @@ impl Db {
mod tests {
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]
async fn test_user_network_config_management() {
@@ -209,7 +267,7 @@ mod tests {
assert_ne!(result.update_time, result2.update_time);
assert_eq!(
db.list_network_configs(user_id, Some(device_id), true)
db.list_network_configs(user_id, Some(device_id), ListNetworkProps::All)
.await
.unwrap()
.len(),

View File

@@ -93,9 +93,12 @@ async fn main() {
let db = db::Db::new(cli.db).await.unwrap();
let listener = UdpTunnelListener::new(
format!("udp://0.0.0.0:{}", cli.config_server_port)
.parse()
.unwrap(),
format!(
"{}://0.0.0.0:{}",
cli.config_server_protocol, cli.config_server_port
)
.parse()
.unwrap(),
);
let mut mgr = client_manager::ClientManager::new(db.clone());
mgr.serve(listener).await.unwrap();

View File

@@ -13,6 +13,7 @@ use easytier::proto::web::*;
use crate::client_manager::session::Session;
use crate::client_manager::ClientManager;
use crate::db::ListNetworkProps;
use super::users::AuthSession;
use super::{
@@ -46,13 +47,21 @@ struct ColletNetworkInfoJsonReq {
inst_ids: Option<Vec<uuid::Uuid>>,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct UpdateNetworkStateJsonReq {
disabled: bool,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct RemoveNetworkJsonReq {
inst_ids: Vec<uuid::Uuid>,
}
#[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)]
struct ListMachineItem {
@@ -190,7 +199,7 @@ impl NetworkApi {
auth_session: AuthSession,
State(client_mgr): AppState,
Path(machine_id): Path<uuid::Uuid>,
Query(payload): Query<ColletNetworkInfoJsonReq>,
Json(payload): Json<ColletNetworkInfoJsonReq>,
) -> Result<Json<CollectNetworkInfoResponse>, HttpHandleError> {
let result =
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 {})
.await
.map_err(convert_rpc_error)?;
Ok(
ListNetworkInstanceIdsJsonResp(ret.inst_ids.into_iter().map(Into::into).collect())
.into(),
)
let running_inst_ids = ret.inst_ids.clone().into_iter().map(Into::into).collect();
// 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(
@@ -289,6 +316,54 @@ impl NetworkApi {
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(
auth_session: AuthSession,
State(client_mgr): AppState,
@@ -298,25 +373,24 @@ impl NetworkApi {
let db_row = client_mgr
.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
.map_err(convert_db_error)?
.iter()
.find(|x| x.network_instance_id == inst_id)
.map(|x| x.network_config.clone())
.ok_or((
StatusCode::NOT_FOUND,
other_error(format!("No such network instance: {}", inst_id)).into(),
))?;
Ok(serde_json::from_str::<NetworkConfig>(&db_row)
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
other_error(format!("Failed to parse network config: {:?}", e)).into(),
)
})?
.into())
Ok(
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(),
)
})?
.into(),
)
}
pub fn build_route(&mut self) -> Router<AppStateInner> {
@@ -332,7 +406,7 @@ impl NetworkApi {
)
.route(
"/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(
"/api/v1/machines/:machine-id/networks/info",