mirror of
https://github.com/faas-rs/faasd-in-rust.git
synced 2025-06-08 15:56:48 +00:00
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:
parent
9277d3ef0b
commit
7cbe9361db
@ -1,6 +1,8 @@
|
|||||||
use actix_web::{App, HttpServer, web};
|
use actix_web::{App, HttpServer, web};
|
||||||
use provider::{
|
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,
|
proxy::proxy_handler::proxy_handler,
|
||||||
types::config::FaaSConfig,
|
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::post().to(deploy_handler))
|
||||||
.route("/system/functions", web::delete().to(delete_handler))
|
.route("/system/functions", web::delete().to(delete_handler))
|
||||||
.route("/function/{name}{path:/?.*}", web::to(proxy_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")?;
|
.bind("0.0.0.0:8090")?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::handlers::function_list::Function;
|
use crate::handlers::function_list::Function;
|
||||||
// use service::spec::{ Mount, Spec};
|
// use service::spec::{ Mount, Spec};
|
||||||
use actix_web::cookie::time::Duration;
|
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 std::{collections::HashMap, time::UNIX_EPOCH};
|
||||||
use thiserror::Error;
|
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> {
|
pub async fn get_function(function_name: &str, namespace: &str) -> Result<Function, FunctionError> {
|
||||||
let cid = function_name;
|
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)
|
let container = ContainerdManager::load_container(cid, namespace)
|
||||||
.await
|
.await
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
use std::{collections::HashMap, time::SystemTime};
|
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 struct Function {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub namespace: String,
|
pub namespace: String,
|
||||||
@ -16,3 +22,52 @@ pub struct Function {
|
|||||||
// pub memory_limit: i64,
|
// pub memory_limit: i64,
|
||||||
pub created_at: SystemTime,
|
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)
|
||||||
|
}
|
||||||
|
@ -12,13 +12,13 @@ impl InvokeResolver {
|
|||||||
//根据函数名和containerd获取函数ip,
|
//根据函数名和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);
|
let namespace = get_namespace_or_default(function_name, DEFAULT_FUNCTION_NAMESPACE);
|
||||||
// if function_name.contains('.') {
|
if function_name.contains('.') {
|
||||||
// actual_function_name = function_name.trim_end_matches(&format!(".{}", namespace));
|
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,
|
Ok(function) => function,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to get function:{}", e);
|
log::error!("Failed to get function:{}", e);
|
||||||
|
@ -24,7 +24,7 @@ pub async fn proxy_handler(
|
|||||||
| Method::HEAD
|
| Method::HEAD
|
||||||
| Method::OPTIONS => match proxy_request(&req, payload, &proxy_client).await {
|
| Method::OPTIONS => match proxy_request(&req, payload, &proxy_client).await {
|
||||||
Ok(resp) => resp,
|
Ok(resp) => resp,
|
||||||
Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
|
Err(e) => HttpResponse::from_error(e),
|
||||||
},
|
},
|
||||||
_ => HttpResponse::MethodNotAllowed().body("method not allowed"),
|
_ => HttpResponse::MethodNotAllowed().body("method not allowed"),
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,10 @@ use tokio::{
|
|||||||
time::{Duration, timeout},
|
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();
|
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 ports = ImageManager::get_runtime_config(image_name).unwrap().ports;
|
||||||
let network_config = NetworkConfig::new(ip, 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 删除cni网络,删除全局map中的网络配置
|
/// 删除cni网络,删除全局map中的网络配置
|
||||||
fn remove_cni_network(cid: &str, ns: &str) -> Result<(), ContainerdError> {
|
fn remove_cni_network(cid: &str, ns: &str) -> Result<(), ContainerdError> {
|
||||||
cni::delete_cni_network(ns, cid);
|
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(())
|
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();
|
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 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()
|
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();
|
let mut map = GLOBAL_NETNS_MAP.write().unwrap();
|
||||||
map.remove(cid);
|
map.remove(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_namespaces() -> Result<Vec<String>, ContainerdError> {
|
pub async fn list_namespaces() -> Result<Vec<String>, ContainerdError> {
|
||||||
|
@ -11,11 +11,17 @@ use std::{
|
|||||||
// config.json,dockerhub密钥
|
// config.json,dockerhub密钥
|
||||||
// const DOCKER_CONFIG_DIR: &str = "/var/lib/faasd/.docker/";
|
// 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! {
|
lazy_static::lazy_static! {
|
||||||
static ref GLOBAL_NETNS_MAP: NetnsMap = Arc::new(RwLock::new(HashMap::new()));
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NetworkConfig {
|
pub struct NetworkConfig {
|
||||||
ip: String,
|
ip: String,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user