Skip to content

Commit 3d99b3f

Browse files
Merge pull request #152 from LorenzoTettamanti/feature/ebpf-core
Added IP addresses persistence in CLI config metadata
2 parents aa42487 + 205e3d3 commit 3d99b3f

27 files changed

Lines changed: 1547 additions & 788 deletions

cli/Cargo.lock

Lines changed: 526 additions & 74 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ tonic = "0.14.1"
2323
tonic-reflection = "0.14.1"
2424
prost-types = "0.14.1"
2525
prost = "0.14.1"
26-
cortexflow_agent_api = "0.1.1-beta.2"
26+
cortexflow_agent_api = {path = "../core/api",features = ["client"]}
27+
kube = "2.0.1"
28+
k8s-openapi = {version = "0.26.0", features = ["v1_34"]}
2729

2830
[[bin]]
2931
name = "cfcli"

cli/src/essential.rs

Lines changed: 134 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
1+
use std::collections::BTreeMap;
2+
use std::ptr::read;
3+
//TODO: Check if is possible to use the get_config_path function. Check for reusable components
14
use std::{fs, io::stdin, path::PathBuf, process::exit};
25

36
use directories::ProjectDirs;
7+
use k8s_openapi::api::core::v1::ConfigMap;
8+
use k8s_openapi::serde_json::json;
9+
use kube::Config;
10+
use prost_types::MethodDescriptorProto;
411
use serde::Serialize;
5-
use std::fs::OpenOptions;
12+
use std::fs::{Metadata, OpenOptions};
13+
use std::result::Result::Ok;
614

715
use colored::Colorize;
816
use std::thread;
917
use std::time::Duration;
1018

1119
use std::process::Command;
1220

21+
use kube::api::{Api, ObjectMeta, Patch, PatchParams, PostParams};
22+
use kube::client::Client;
23+
1324
pub struct GeneralData {
1425
env: String,
1526
}
1627
#[derive(Serialize)]
1728
pub struct MetadataConfigFile {
18-
env: String,
29+
blocklist: Vec<String>,
1930
}
2031
#[derive(Debug)]
2132
pub enum Environments {
@@ -27,10 +38,10 @@ impl TryFrom<&str> for Environments {
2738
fn try_from(environment: &str) -> Result<Self, Self::Error> {
2839
match environment {
2940
"kubernetes" | "k8s" => Ok(Environments::Kubernetes),
30-
_ => Err(format!(
31-
"Environment '{}' not supported. Please insert a supported value: Kubernetes, K8s",
32-
environment
33-
)),
41+
_ =>
42+
Err(
43+
format!("Environment '{}' not supported. Please insert a supported value: Kubernetes, K8s", environment)
44+
),
3445
}
3546
}
3647
}
@@ -75,141 +86,155 @@ impl GeneralData {
7586

7687
pub fn update_cli() {
7788
println!("{} {}", "=====>".blue().bold(), "Updating CortexFlow CLI");
78-
println!(
79-
"{} {}",
80-
"=====>".blue().bold(),
81-
"Looking for a newer version"
82-
);
89+
println!("{} {}", "=====>".blue().bold(), "Looking for a newer version");
8390

84-
let output = Command::new("cargo")
85-
.args(["update", "cortexflow-cli"])
86-
.output()
87-
.expect("error");
91+
let output = Command::new("cargo").args(["update", "cortexflow-cli"]).output().expect("error");
8892

8993
if !output.status.success() {
90-
eprintln!(
91-
"Error updating CLI : {}",
92-
String::from_utf8_lossy(&output.stderr)
93-
);
94+
eprintln!("Error updating CLI : {}", String::from_utf8_lossy(&output.stderr));
9495
} else {
9596
println!("✅ Updated CLI");
9697
}
9798
}
9899
pub fn info(general_data: GeneralData) {
99-
println!(
100-
"{} {} {}",
101-
"=====>".blue().bold(),
102-
"Version:",
103-
GeneralData::VERSION
104-
);
105-
println!(
106-
"{} {} {}",
107-
"=====>".blue().bold(),
108-
"Author:",
109-
GeneralData::AUTHOR
110-
);
111-
println!(
112-
"{} {} {}",
113-
"=====>".blue().bold(),
114-
"Description:",
115-
GeneralData::DESCRIPTION
116-
);
117-
println!(
118-
"{} {} {}",
119-
"=====>".blue().bold(),
120-
"Environment:",
121-
general_data.get_env()
122-
);
100+
println!("{} {} {}", "=====>".blue().bold(), "Version:", GeneralData::VERSION);
101+
println!("{} {} {}", "=====>".blue().bold(), "Author:", GeneralData::AUTHOR);
102+
println!("{} {} {}", "=====>".blue().bold(), "Description:", GeneralData::DESCRIPTION);
103+
println!("{} {} {}", "=====>".blue().bold(), "Environment:", general_data.get_env());
123104
}
124105

125106
fn is_supported_env(env: &str) -> bool {
126107
matches!(env.to_lowercase().trim(), "kubernetes" | "k8s")
127108
}
128109

129110
pub fn create_configs() -> MetadataConfigFile {
130-
let mut user_input: String = String::new();
131-
println!(
132-
"{} {}",
133-
"=====>".blue().bold(),
134-
"Insert your cluster environment (e.g. Kubernetes)".white()
135-
);
136-
stdin().read_line(&mut user_input).unwrap();
137-
let cluster_environment = user_input.trim().to_string();
138-
139-
if !is_supported_env(&cluster_environment) {
140-
eprintln!(
141-
"Cannot save cluster environment data. Installation aborted. Please insert supported environment"
142-
);
143-
exit(1);
144-
}
111+
let mut blocklist: Vec<String> = Vec::new();
112+
blocklist.push("".to_string());
145113

146-
let configs = MetadataConfigFile {
147-
env: cluster_environment,
148-
};
114+
let configs = MetadataConfigFile { blocklist };
149115
configs
150116
}
151-
//TODO: add here and explaination of what read_configs returns
152-
pub fn read_configs(config_path: PathBuf) -> String {
153-
let config = fs::File::open(config_path).unwrap();
154-
let parsed_config: Result<serde_yaml::Value, serde_yaml::Error> =
155-
serde_yaml::from_reader(config);
156-
157-
match parsed_config {
158-
Ok(cfg) => {
159-
let env = &cfg["env"].as_str().unwrap().to_string();
160-
thread::sleep(Duration::from_secs(1));
161-
println!(
162-
"{} {} {:?}",
163-
"[SYSTEM]".blue().bold(),
164-
"Readed configs for env variable:".white(),
165-
env
166-
);
167-
return env.to_string();
117+
pub async fn read_configs() -> Result<Vec<String>, anyhow::Error> {
118+
let client = Client::try_default().await?;
119+
let namespace = "cortexflow";
120+
let configmap = "cortexbrain-client-config";
121+
let api: Api<ConfigMap> = Api::namespaced(client, namespace);
122+
123+
let cm = api.get(configmap).await?;
124+
125+
if let Some(data) = cm.data {
126+
if let Some(blocklist_raw) = data.get("blocklist") {
127+
let lines: Vec<String> = blocklist_raw
128+
.lines()
129+
.map(|s| s.trim().to_string())
130+
.filter(|s| !s.is_empty()) // ignora righe vuote
131+
.collect();
132+
133+
return Ok(lines);
134+
}
135+
}
136+
137+
Ok(Vec::new()) //in case the key fails
138+
}
139+
pub async fn create_config_file(config_struct: MetadataConfigFile) -> Result<(), anyhow::Error> {
140+
let client = Client::try_default().await?;
141+
let namespace = "cortexflow";
142+
let configmap = "cortexbrain-client-config";
143+
144+
let api: Api<ConfigMap> = Api::namespaced(client, namespace);
145+
146+
// create configmap
147+
let mut data = BTreeMap::new();
148+
for x in config_struct.blocklist {
149+
data.insert("blocklist".to_string(), x);
150+
}
151+
let cm = ConfigMap {
152+
metadata: ObjectMeta {
153+
name: Some("cortexbrain-client-config".to_string()),
154+
..Default::default()
155+
}, // type ObjectMeta
156+
data: Some(data), //type Option<BTreeMap<String, String, Global>>
157+
..Default::default()
158+
};
159+
match api.create(&PostParams::default(), &cm).await {
160+
Ok(_) => {
161+
println!("Configmap created successfully");
168162
}
169163
Err(e) => {
170-
eprintln!("An error occured while reading the config file: {:?}", e);
171-
exit(1)
164+
eprintln!("An error occured: {}", e);
172165
}
173-
}
166+
};
167+
Ok(())
174168
}
175169

176-
pub fn create_config_file(config_struct: MetadataConfigFile) {
177-
let dirs = ProjectDirs::from("org", "cortexflow", "cfcli")
178-
.expect("Cannot determine the config directory");
179-
let config_dir = dirs.config_dir().to_path_buf();
180-
let config_save_path = config_dir.join("config.yaml");
170+
pub async fn update_config_metadata(input: &str, action: &str) {
171+
if action == "add" {
172+
//retrieve current blocked ips list
173+
let mut ips = read_configs().await.unwrap();
174+
println!("Readed current blocked ips: {:?}", ips);
175+
176+
//create a temporary vector of ips
177+
ips.push(input.to_string());
178+
179+
// override blocklist parameters
180+
let new_configs = MetadataConfigFile { blocklist: ips };
181+
//create a new config
182+
update_configmap(new_configs).await;
183+
} else if action == "delete" {
184+
let mut ips = read_configs().await.unwrap();
185+
if let Some(index) = ips.iter().position(|target| target == &input.to_string()) {
186+
ips.remove(index);
187+
} else {
188+
eprintln!("Index of element not found");
189+
}
181190

182-
//create directory
183-
fs::create_dir_all(&config_dir).expect("Cannot create directories");
191+
// override blocklist parameters
192+
let new_configs = MetadataConfigFile { blocklist: ips };
193+
//create a new config
194+
update_configmap(new_configs).await;
195+
}
196+
}
184197

185-
let configs = OpenOptions::new()
186-
.write(true)
187-
.create(true)
188-
.open(&config_save_path)
189-
.expect("Cannot open config file");
198+
pub async fn update_configmap(config_struct: MetadataConfigFile) -> Result<(), anyhow::Error> {
199+
let client = Client::try_default().await?;
200+
let namespace = "cortexflow";
201+
let name = "cortexbrain-client-config";
202+
let api: Api<ConfigMap> = Api::namespaced(client, namespace);
203+
204+
let blocklist_yaml = config_struct
205+
.blocklist
206+
.iter()
207+
.map(|x| format!("{}", x))
208+
.collect::<Vec<String>>()
209+
.join("\n");
210+
211+
let patch = Patch::Apply(json!({
212+
"apiVersion": "v1",
213+
"kind": "ConfigMap",
214+
"data": {
215+
"blocklist": blocklist_yaml
216+
}
217+
}));
190218

191-
match serde_yaml::to_writer(configs, &config_struct) {
219+
let patch_params = PatchParams::apply("cortexbrain").force();
220+
match api.patch(name, &patch_params, &patch).await {
192221
Ok(_) => {
193-
println!("\n");
194-
thread::sleep(Duration::from_secs(1));
195-
println!(
196-
"{} {}{:?}",
197-
"[SYSTEM]".blue().bold(),
198-
"Configuration files saved in path :".white(),
199-
&config_save_path.display()
200-
);
201-
println!("\n");
222+
println!("Map updated successfully");
223+
}
224+
Err(e) => {
225+
eprintln!("An error occured during the patching process: {}", e);
226+
return Err(e.into());
202227
}
203-
Err(e) => eprintln!(
204-
"An error occured during the creation of the config files. {:?}",
205-
e
206-
),
207228
}
229+
230+
Ok(())
208231
}
232+
209233
//TODO: add here an explanation of what are config_dir and file_path
210234
pub fn get_config_directory() -> Result<(PathBuf, PathBuf), ()> {
211-
let dirs = ProjectDirs::from("org", "cortexflow", "cfcli")
212-
.expect("Cannot determine the config directory");
235+
let dirs = ProjectDirs::from("org", "cortexflow", "cfcli").expect(
236+
"Cannot determine the config directory"
237+
);
213238
let config_dir = dirs.config_dir().to_path_buf();
214239
let file_path = config_dir.join("config.yaml");
215240

@@ -224,4 +249,3 @@ pub fn get_startup_config_dir() -> bool {
224249
})
225250
.unwrap_or(false)
226251
}
227-
// TODO: add save to config function

0 commit comments

Comments
 (0)