Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 138 additions & 99 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
"init",
"interface-manager",
"k8s-intf",
"k8s-less",
"left-right-tlcache",
"mgmt",
"nat",
Expand Down Expand Up @@ -63,6 +64,7 @@ id = { path = "./id", package = "dataplane-id", features = [] }
init = { path = "./init", package = "dataplane-init", features = [] }
interface-manager = { path = "./interface-manager", package = "dataplane-interface-manager", features = [] }
k8s-intf = { path = "./k8s-intf", package = "dataplane-k8s-intf", features = [] }
k8s-less = { path = "./k8s-less", package = "dataplane-k8s-less", features = [] }
left-right-tlcache = { path = "./left-right-tlcache", package = "dataplane-left-right-tlcache", features = [] }
lpm = { path = "./lpm", package = "dataplane-lpm", features = [] }
mgmt = { path = "./mgmt", package = "dataplane-mgmt", features = [] }
Expand Down Expand Up @@ -116,6 +118,7 @@ hashbrown = { version = "0.16.1", default-features = false, features = [] }
hwlocality = { version = "1.0.0-alpha.11", default-features = false, features = [] }
hyper = { version = "1.8.1", default-features = false, features = [] }
hyper-util = { version = "0.1.19", default-features = false, features = [] }
inotify = { version = "0.11.0", default-features = false, features = [] }
ipnet = { version = "2.11.0", default-features = false, features = [] }
k8s-openapi = { version = "0.26.1", default-features = false, features = [] }
kanal = { version = "0.1.1", default-features = false, features = [] }
Expand Down
2 changes: 1 addition & 1 deletion args/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ serde = { workspace = true, features = ["derive"] }
sha2 = { workspace = true, features = [] }
thiserror = { workspace = true, features = [] }
tracing = { workspace = true, features = ["std"] }
url = { workspace = true, features = ["std"] }
url = { workspace = true, features = ["std", "serde"] }
uuid = { workspace = true, features = [] }

[dev-dependencies]
Expand Down
34 changes: 27 additions & 7 deletions args/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ pub struct RoutingConfigSection {
#[rkyv(attr(derive(PartialEq, Eq, Debug)))]
pub struct ConfigServerSection {
/// gRPC server address (TCP or Unix socket)
pub address: GrpcAddress,
pub address: Option<GrpcAddress>,
pub config_dir: Option<String>,
}

/// Complete dataplane launch configuration.
Expand Down Expand Up @@ -1088,12 +1089,12 @@ impl TryFrom<CmdArgs> for LaunchConfiguration {
general: GeneralConfigSection {
name: value.get_name().cloned(),
},
config_server: value
.grpc_address()
.map_err(InvalidCmdArguments::InvalidGrpcAddress)?
.map(|grpc_address| ConfigServerSection {
address: grpc_address,
}),
config_server: Some(ConfigServerSection {
address: value
.grpc_address()
.map_err(InvalidCmdArguments::InvalidGrpcAddress)?,
config_dir: value.config_dir().cloned(),
}),
driver: match &value.driver {
Some(driver) if driver == "dpdk" => {
// TODO: adjust command line to specify lcore usage more flexibly in next PR
Expand Down Expand Up @@ -1275,6 +1276,17 @@ E.g. default=error,all=info,nat=debug will set the default target to error, and

#[arg(long, help = "Set the name of this gateway")]
name: Option<String>,

#[arg(
long,
help = "Run in k8s-less mode using this directory to watch for configurations.
You can copy json/yaml config files in this directory to reconfigure dataplane. You can modify existing
files or just 'touch' them to trigger a new reconfiguration. Every change will increase the generation id by one.
NOTE: dataplane tracks file 'save' events. If you modify an existing file, depending on the editor used, this will
trigger more than one reconfiguration (e.g. gedit). If this is undesired, use nano or vi(m), or edit your file
elsewhere and copy it in the configuration directory. This mode is meant mostly for debugging or early testing."
)]
config_dir: Option<String>,
}

impl CmdArgs {
Expand Down Expand Up @@ -1464,6 +1476,14 @@ impl CmdArgs {
pub fn get_name(&self) -> Option<&String> {
self.name.as_ref()
}

/// Get the configuration directory.
/// Setting the configuration directory enables k8s-less mode, where configurations are retrieved from files
/// or their changes in the configuration directory.
#[must_use]
pub fn config_dir(&self) -> Option<&String> {
self.config_dir.as_ref()
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions dataplane/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ fn main() {
/* start management */
start_mgmt(MgmtParams {
grpc_addr,
config_dir: args.config_dir().cloned(),
hostname: get_gw_name().unwrap_or_else(|| unreachable!()).to_owned(),
processor_params: ConfigProcessorParams {
router_ctl: setup.router.get_ctl_tx(),
Expand Down
1 change: 1 addition & 0 deletions k8s-intf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ schemars = { workspace = true, features = ["derive", "std"] }
serde = { workspace = true }
serde-duration-ext = { workspace = true }
serde_json = { workspace = true }
serde_yaml_ng = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }

Expand Down
1 change: 1 addition & 0 deletions k8s-intf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
pub mod bolero;
pub mod client;
pub mod generated;
pub mod utils;

pub mod gateway_agent_crd {
pub use crate::generated::gateway_agent_crd::*;
Expand Down
86 changes: 86 additions & 0 deletions k8s-intf/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

//! Utils to build the gateway CRD `GatewayAgentSpec` from JSON / YAML text files.

use crate::gateway_agent_crd::GatewayAgentSpec;
use serde::Serialize;
use serde_yaml_ng;
use std::fs;
use std::path::Path;

/// Read the file at `path` and deserialize it from YAML into a `GatewayAgentSpec` object.
fn load_crd_from_yaml(path: &str) -> Result<GatewayAgentSpec, String> {
let yaml = fs::read_to_string(path)
.map_err(|e| format!("Failed to read CRD from YAML file ({path}): {e}"))?;
let crd: GatewayAgentSpec = serde_yaml_ng::from_str(&yaml)
.map_err(|e| format!("Failed to deserialize CRD from YAML file ({path}): {e}"))?;
Ok(crd)
}

/// Read the file at `path` and deserialize it from JSON into a `GatewayAgentSpec` object.
fn load_crd_from_json(path: &str) -> Result<GatewayAgentSpec, String> {
let json = fs::read_to_string(path)
.map_err(|e| format!("Failed to read CRD from JSON file ({path}): {e}"))?;
let crd: GatewayAgentSpec = serde_json::from_str(&json)
.map_err(|e| format!("Failed to deserialize CRD from JSON file ({path}): {e}"))?;
Ok(crd)
}

/// Read the file at `path` and deserialize into a `GatewayAgentSpec` object.
/// The file is assumed to contain a gateway spec CRD in JSON or YAML.
///
/// # Errors
/// This function may fail if the file does not exist or cannot be opened / read, or if the contents
/// cannot be deserialized.
pub fn load_crd_from_file(path: &str) -> Result<GatewayAgentSpec, String> {
let ext = Path::new(path).extension();
match ext {
Some(ext) if ext.eq_ignore_ascii_case("yaml") || ext.eq_ignore_ascii_case("yml") => {
load_crd_from_yaml(path)
}
Some(ext) if ext.eq_ignore_ascii_case("json") => load_crd_from_json(path),
Some(ext) => Err(format!("Unsupported file extension {}", ext.display())),
None => Err("Missing file extension".to_string()),
}
}

/// Serialize an object as JSON and store it in the file at path `path`.
/// This function will create the file if it does not exist.
///
/// # Errors
/// This function may fail if the object cannot be serialized or if the
/// full directory path does not exist.
pub fn save_as_json<T: Serialize>(path: &str, object: &T) -> Result<(), String> {
let json =
serde_json::to_string(object).map_err(|e| format!("Failed to serialize as JSON: {e}"))?;
fs::write(path, json).map_err(|e| format!("Failed to write json file at {path}: {e}"))
}

/// Serialize an object as YAML and store it in the file at path `path`.
/// This function will create the file if it does not exist.
///
/// # Errors
/// This function may fail if the object cannot be serialized or if the
/// full directory path does not exist.
pub fn save_as_yaml<T: Serialize>(path: &str, object: &T) -> Result<(), String> {
let yaml = serde_yaml_ng::to_string(object)
.map_err(|e| format!("Failed to serialize as YAML: {e}"))?;
fs::write(path, yaml).map_err(|e| format!("Failed to write YAML file at {path}: {e}"))
}

/// Serialize an object as JSON and YAML and store both in separate files
/// with extensions .json and .yaml added to the indicated filename in `path`.
/// The files will be created if they do not exist.
///
/// # Errors
/// This function may fail if the object cannot be serialized or if the
/// full directory path does not exist.
pub fn save<T: Serialize>(path: &str, object: &T) -> Result<(), String> {
let p = Path::new(path);
let yaml_file = p.with_added_extension("yaml");
let json_file = p.with_added_extension("json");
save_as_yaml(yaml_file.to_str().unwrap_or_else(|| unreachable!()), object)?;
save_as_json(json_file.to_str().unwrap_or_else(|| unreachable!()), object)?;
Ok(())
}
16 changes: 16 additions & 0 deletions k8s-less/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "dataplane-k8s-less"
version.workspace = true
edition.workspace = true
license.workspace = true
publish.workspace = true
repository.workspace = true

[dependencies]
gwname = { workspace = true }
inotify = { workspace = true, features = ["stream"] }
k8s-intf = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt", "fs"] }
tracectl = { workspace = true }
tracing = { workspace = true }
tracing-test = { workspace = true }
8 changes: 8 additions & 0 deletions k8s-less/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

//! Support for k8s-less mode where CRDs are learnt from a file

mod local;

pub use local::kubeless_watch_gateway_agent_crd;
Loading
Loading