feat(provider): add add get_function_list to route (#77)

* feat(namespace):replace netns_map's key with (string,string) so that key (cid,ns) refers to the only net work

* fix:fix the error response in proxy_handler

* feat:add get_function_list to route

* feat:replace map's key (string,string) with struct
This commit is contained in:
DoL 2025-04-24 15:12:45 +08:00 committed by GitHub
parent 9277d3ef0b
commit 7cbe9361db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 102 additions and 20 deletions

View File

@ -1,6 +1,8 @@
use actix_web::{App, HttpServer, web};
use provider::{
handlers::{delete::delete_handler, deploy::deploy_handler},
handlers::{
delete::delete_handler, deploy::deploy_handler, function_list::function_list_handler,
},
proxy::proxy_handler::proxy_handler,
types::config::FaaSConfig,
};
@ -24,6 +26,10 @@ async fn main() -> std::io::Result<()> {
.route("/system/functions", web::post().to(deploy_handler))
.route("/system/functions", web::delete().to(delete_handler))
.route("/function/{name}{path:/?.*}", web::to(proxy_handler))
.route(
"/system/functions/{namespace}",
web::get().to(function_list_handler),
)
// 更多路由配置...
})
.bind("0.0.0.0:8090")?;

View File

@ -1,7 +1,7 @@
use crate::handlers::function_list::Function;
// use service::spec::{ Mount, Spec};
use actix_web::cookie::time::Duration;
use service::{containerd_manager::ContainerdManager, image_manager::ImageManager};
use service::{FunctionScope, containerd_manager::ContainerdManager, image_manager::ImageManager};
use std::{collections::HashMap, time::UNIX_EPOCH};
use thiserror::Error;
@ -23,7 +23,11 @@ impl From<Box<dyn std::error::Error>> for FunctionError {
pub async fn get_function(function_name: &str, namespace: &str) -> Result<Function, FunctionError> {
let cid = function_name;
let address = ContainerdManager::get_address(cid);
let function = FunctionScope {
function_name: cid.to_string(),
namespace: namespace.to_string(),
};
let address = ContainerdManager::get_address(&function);
let container = ContainerdManager::load_container(cid, namespace)
.await

View File

@ -1,6 +1,12 @@
use std::{collections::HashMap, time::SystemTime};
#[derive(Debug)]
use actix_web::{HttpRequest, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use service::containerd_manager::ContainerdManager;
use super::{function_get::get_function, utils::CustomError};
#[derive(Debug, Serialize, Deserialize)]
pub struct Function {
pub name: String,
pub namespace: String,
@ -16,3 +22,52 @@ pub struct Function {
// pub memory_limit: i64,
pub created_at: SystemTime,
}
pub async fn function_list_handler(req: HttpRequest) -> impl Responder {
let namespace = req.match_info().get("namespace").unwrap_or("");
if namespace.is_empty() {
return HttpResponse::BadRequest().body("provide namespace in path");
}
match get_function_list(namespace).await {
Ok(functions) => HttpResponse::Ok().body(serde_json::to_string(&functions).unwrap()),
Err(e) => HttpResponse::from_error(e),
}
}
async fn get_function_list(namespace: &str) -> Result<Vec<Function>, CustomError> {
let namespaces = match ContainerdManager::list_namespaces().await {
Ok(namespace) => namespace,
Err(e) => {
return Err(CustomError::OtherError(format!(
"Failed to list namespaces:{}",
e
)));
}
};
if !namespaces.contains(&namespace.to_string()) {
return Err(CustomError::OtherError(format!(
"Namespace '{}' not valid or does not exist",
namespace
)));
}
let container_list = match ContainerdManager::list_container_into_string(namespace).await {
Ok(container_list) => container_list,
Err(e) => {
return Err(CustomError::OtherError(format!(
"Failed to list container:{}",
e
)));
}
};
log::info!("container_list: {:?}", container_list);
let mut functions: Vec<Function> = Vec::new();
for cid in container_list {
log::info!("cid: {}", cid);
let function = match get_function(&cid, namespace).await {
Ok(function) => function,
Err(e) => return Err(CustomError::FunctionError(e)),
};
functions.push(function);
}
Ok(functions)
}

View File

@ -12,13 +12,13 @@ impl InvokeResolver {
//根据函数名和containerd获取函数ip
//从函数名称中提取命名空间。如果函数名称中包含 .,则将其后的部分作为命名空间;否则使用默认命名空间
// let mut actual_function_name = function_name;
let mut actual_function_name = function_name;
let namespace = get_namespace_or_default(function_name, DEFAULT_FUNCTION_NAMESPACE);
// if function_name.contains('.') {
// actual_function_name = function_name.trim_end_matches(&format!(".{}", namespace));
// }
if function_name.contains('.') {
actual_function_name = function_name.trim_end_matches(&format!(".{}", namespace));
}
let function = match get_function(function_name, &namespace).await {
let function = match get_function(actual_function_name, &namespace).await {
Ok(function) => function,
Err(e) => {
log::error!("Failed to get function:{}", e);

View File

@ -24,7 +24,7 @@ pub async fn proxy_handler(
| Method::HEAD
| Method::OPTIONS => match proxy_request(&req, payload, &proxy_client).await {
Ok(resp) => resp,
Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
Err(e) => HttpResponse::from_error(e),
},
_ => HttpResponse::MethodNotAllowed().body("method not allowed"),
}

View File

@ -20,7 +20,10 @@ use tokio::{
time::{Duration, timeout},
};
use crate::{GLOBAL_NETNS_MAP, NetworkConfig, image_manager::ImageManager, spec::generate_spec};
use crate::{
FunctionScope, GLOBAL_NETNS_MAP, NetworkConfig, image_manager::ImageManager,
spec::generate_spec,
};
pub(super) static CLIENT: OnceCell<Arc<Client>> = OnceCell::const_new();
@ -474,31 +477,39 @@ impl ContainerdManager {
})?;
let ports = ImageManager::get_runtime_config(image_name).unwrap().ports;
let network_config = NetworkConfig::new(ip, ports);
Self::save_container_network_config(cid, network_config);
let function = FunctionScope {
function_name: cid.to_string(),
namespace: ns.to_string(),
};
Self::save_container_network_config(function, network_config);
Ok(())
}
/// 删除cni网络删除全局map中的网络配置
fn remove_cni_network(cid: &str, ns: &str) -> Result<(), ContainerdError> {
cni::delete_cni_network(ns, cid);
Self::remove_container_network_config(cid);
let function = FunctionScope {
function_name: cid.to_string(),
namespace: ns.to_string(),
};
Self::remove_container_network_config(&function);
Ok(())
}
fn save_container_network_config(cid: &str, net_conf: NetworkConfig) {
fn save_container_network_config(function: FunctionScope, net_conf: NetworkConfig) {
let mut map = GLOBAL_NETNS_MAP.write().unwrap();
map.insert(cid.to_string(), net_conf);
map.insert(function, net_conf);
}
pub fn get_address(cid: &str) -> String {
pub fn get_address(function: &FunctionScope) -> String {
let map = GLOBAL_NETNS_MAP.read().unwrap();
let addr = map.get(cid).map(|net_conf| net_conf.get_address());
let addr = map.get(function).map(|net_conf| net_conf.get_address());
addr.unwrap_or_default()
}
fn remove_container_network_config(cid: &str) {
fn remove_container_network_config(function: &FunctionScope) {
let mut map = GLOBAL_NETNS_MAP.write().unwrap();
map.remove(cid);
map.remove(function);
}
pub async fn list_namespaces() -> Result<Vec<String>, ContainerdError> {

View File

@ -11,11 +11,17 @@ use std::{
// config.json,dockerhub密钥
// const DOCKER_CONFIG_DIR: &str = "/var/lib/faasd/.docker/";
type NetnsMap = Arc<RwLock<HashMap<String, NetworkConfig>>>;
type NetnsMap = Arc<RwLock<HashMap<FunctionScope, NetworkConfig>>>;
lazy_static::lazy_static! {
static ref GLOBAL_NETNS_MAP: NetnsMap = Arc::new(RwLock::new(HashMap::new()));
}
#[derive(Hash, Eq, PartialEq)]
pub struct FunctionScope {
pub function_name: String,
pub namespace: String,
}
#[derive(Debug, Clone)]
pub struct NetworkConfig {
ip: String,