Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
byrnedo committed Jul 18, 2024
1 parent 0d1fc0d commit bcc0af0
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 35 deletions.
1 change: 0 additions & 1 deletion images/nginx-ingress/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ http {
listen 80;
access_log "/usr/local/openresty/nginx/logs/access.log" vhost;

# Endpoint used for performing domain verification with Let's Encrypt.

location /assets {
root "/usr/local/openresty/nginx/html";
Expand Down
58 changes: 53 additions & 5 deletions src/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use anyhow::anyhow;
use clap::{Args, Subcommand};
use itertools::Itertools;
use crate::config::Config;
use crate::refresh::refreshed_state;
use crate::skate::ConfigFileArgs;
use crate::ssh;

#[derive(Debug, Args)]
pub struct DeleteArgs {
Expand All @@ -15,25 +17,71 @@ pub struct DeleteArgs {

#[derive(Debug, Subcommand)]
pub enum DeleteCommands {
Node(DeleteNodeArgs),
Node(DeleteResourceArgs),
Ingress(DeleteResourceArgs),
}

#[derive(Debug, Args)]
pub struct DeleteNodeArgs {
#[arg(long, long_help = "Name of the node.")]
pub struct DeleteResourceArgs {
#[arg(long, long_help = "Name of the resource.")]
name: String,
#[arg(long, long_help = "Namespace of the resource.")]
namespace: String,
#[command(flatten)]
config: ConfigFileArgs,

}


pub async fn delete(args: DeleteArgs) -> Result<(), Box<dyn Error>> {
match args.command {
DeleteCommands::Node(args) => delete_node(args).await.expect("failed to delete node")
DeleteCommands::Node(args) => delete_node(args).await.expect("failed to delete node"),
DeleteCommands::Ingress(args) => delete_ingress(args).await.expect("failed to delete ingress"),
}
Ok(())
}

async fn delete_ingress(args: DeleteResourceArgs) -> Result<(), Box<dyn Error>> {
// fetch state for resource type from nodes

let config = Config::load(Some(args.config.skateconfig.clone()))?;
let (conns, errors) = ssh::cluster_connections(config.current_cluster()?).await;
if errors.is_some() {
eprintln!("{}", errors.unwrap())
}

if conns.is_none() {
return Ok(());
}

let conns = conns.unwrap();

let state = refreshed_state(&config.current_context.clone().unwrap_or("".to_string()), &conns, &config).await?;


// let result = conns.execute("skatelet", &["delete", "ingress", &args.name, "--namespace", &args.namespace]);
// for (node, output) in result {
// match output {
// Ok(output) => {
// if output.exit_status == 0 {
// println!("deleted ingress {} on {}", args.name, node.name);
// } else {
// eprintln!("failed to delete ingress {} on {}: {}", args.name, node.name, output.stderr);
// }
// }
// Err(e) => {
// eprintln!("failed to delete ingress {} on {}: {}", args.name, node.name, e);
// }
// }
// }


// delete resources from nodes they're on using skatelet
// update state
Ok(())
}

async fn delete_node(args: DeleteNodeArgs) -> Result<(), Box<dyn Error>> {
async fn delete_node(args: DeleteResourceArgs) -> Result<(), Box<dyn Error>> {
let mut config = Config::load(Some(args.config.skateconfig.clone()))?;

let context = match args.config.context {
Expand Down
12 changes: 8 additions & 4 deletions src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ impl DefaultExecutor {
}

fn apply_ingress(&self, ingress: Ingress) -> Result<(), Box<dyn Error>> {

let ingress_string = serde_yaml::to_string(&ingress).map_err(|e| anyhow!(e).context("failed to serialize manifest to yaml"))?;
self.store.write_file("ingress", &metadata_name(&ingress).name, "manifest.yaml", ingress_string.as_bytes())?;

let output = exec_cmd("mkdir", &["-p", "/var/lib/skate/ingress/services"])?;

let main_template_data = json!({
Expand Down Expand Up @@ -82,8 +86,8 @@ impl DefaultExecutor {
let json_ingress_string = json_ingress.to_string();


let mut child = process::Command::new("bash")
.args(&["-c", "skatelet template --file /var/lib/skate/ingress/service.conf.tmpl"])
let mut child = process::Command::new("skatelet")
.args(&["template","--file", "/var/lib/skate/ingress/service.conf.tmpl", "-"])
.stdin(Stdio::piped())
.stdout(Stdio::piped()).spawn()?;

Expand All @@ -96,7 +100,7 @@ impl DefaultExecutor {
return Err(anyhow!("exit code {}, stderr: {}", output.status.code().unwrap(), String::from_utf8_lossy(&output.stderr).to_string()).into());
}

self.store.write_file("ingress", &metadata_name(&ingress).name, &format!("{}.conf", port).as_bytes())?;
self.store.write_file("ingress", &metadata_name(&ingress).name, &format!("{}.conf", port), output.stdout.as_slice())?;
}

self.reload_ingress()?;
Expand All @@ -105,7 +109,7 @@ impl DefaultExecutor {
}

fn remove_ingress(&self, ingress: Ingress) -> Result<(), Box<dyn Error>> {
self.store.remove_name("ingress", &metadata_name(&ingress).name)?;
self.store.remove_object("ingress", &metadata_name(&ingress).name)?;

self.reload_ingress()?;

Expand Down
54 changes: 36 additions & 18 deletions src/filestore.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::error::Error;
use std::fs::{create_dir_all, File};
use std::io::Write;
use anyhow::anyhow;

// all dirs/files live under /var/lib/skate/store
Expand All @@ -20,32 +21,49 @@ impl FileStore {
}
}

pub fn write_file(&self, object_type: &str, name: &str, file: &[u8]) -> Result<String, Box<dyn Error>> {
let dir = format!("{}/{}/{}", self.base_path, object_type, name);
create_dir_all(dir).map_err(|e| anyhow!(e).context(format!("failed to create directory {}", dir)))?;
let file_path = format!("{}/{}/{}/{}", self.base_path, object_type, name, file);
let result = File::create(file_path).map_err(|e| anyhow!(e).context(format!("failed to create file {}", file_path)));
if result.is_err() {
return Err(result.err().into());
// will clobber
pub fn write_file(&self, object_type: &str, object_name: &str, file_name: &str, file_contents: &[u8]) -> Result<String, Box<dyn Error>> {
let dir = format!("{}/{}/{}", self.base_path, object_type, object_name);
create_dir_all(&dir).map_err(|e| anyhow!(e).context(format!("failed to create directory {}", dir)))?;
let file_path = format!("{}/{}/{}/{}", self.base_path, object_type, object_name, file_name);


let file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open(&file_path);
match file.map_err(|e| anyhow!(e).context(format!("failed to create file {}", file_path))) {
Err(e) => return Err(e.into()),
Ok(mut file) => file.write_all(file_contents).map(|_| file_path).map_err(|e| e.into())
}
Ok(file_path.to_string())
}

pub fn remove_file(&self, object_type: &str, name: &str, file: &str) -> Result<(), Box<dyn Error>> {
let file_path = format!("{}/{}/{}/{}", self.base_path, object_type, name, file);
let result = std::fs::remove_file(file_path).map_err(|e| anyhow!(e).context(format!("failed to remove file {}", file_path)));
pub fn remove_file(&self, object_type: &str, object_name: &str, file_name: &str) -> Result<(), Box<dyn Error>> {
let file_path = format!("{}/{}/{}/{}", self.base_path, object_type, object_name, file_name);
let result = std::fs::remove_file(&file_path).map_err(|e| anyhow!(e).context(format!("failed to remove file {}", file_path)));
if result.is_err() {
return Err(result.err().into());
return Err(result.err().unwrap().into());
}
Ok(())
}

pub fn remove_name(&self, object_type: &str, name: &str) -> Result<(), Box<dyn Error>> {
let dir = format!("{}/{}/{}", self.base_path, object_type, name);
let result = std::fs::remove_dir_all(dir).map_err(|e| anyhow!(e).context(format!("failed to remove directory {}", dir)));
if result.is_err() {
return Err(result.err().into());
pub fn exists_file(&self, object_type: &str, object_name: &str, file_name: &str) -> bool {
let file_path = format!("{}/{}/{}/{}", self.base_path, object_type, object_name, file_name);
std::path::Path::new(&file_path).exists()
}

pub fn remove_object(&self, object_type: &str, object_name: &str) -> Result<(), Box<dyn Error>> {
let dir = format!("{}/{}/{}", self.base_path, object_type, object_name);
std::fs::remove_dir_all(&dir).map_err(|e| anyhow!(e).context(format!("failed to remove directory {}", dir)).into())
}

pub fn list_objects(&self, object_type: &str) -> Result<Vec<String>, Box<dyn Error>> {
let dir = format!("{}/{}", self.base_path, object_type);
let entries = std::fs::read_dir(&dir).map_err(|e| anyhow!(e).context(format!("failed to read directory {}", dir)))?;
let mut result = Vec::new();
for entry in entries {
let entry = entry.map_err(|e| anyhow!(e).context("failed to read entry"))?;
let path = entry.path();
let file_name = path.file_name().ok_or(anyhow!("failed to get file name"))?;
result.push(file_name.to_string_lossy().to_string());
}
Ok(())
Ok(result)
}
}
76 changes: 71 additions & 5 deletions src/get.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashMap;
use std::error::Error;
use anyhow::anyhow;

use chrono::{Local, SecondsFormat};
use clap::{Args, Subcommand};
Expand All @@ -8,10 +9,11 @@ use crate::config::Config;
use crate::refresh::refreshed_state;


use crate::skate::ConfigFileArgs;
use crate::skate::{ConfigFileArgs, ResourceType, SupportedResources};
use crate::skatelet::{PodmanPodInfo, PodmanPodStatus};
use crate::ssh;
use crate::{skate, ssh};
use crate::state::state::{ClusterState, NodeState};
use crate::util::NamespacedName;


#[derive(Debug, Clone, Args)]
Expand Down Expand Up @@ -44,14 +46,17 @@ pub enum GetCommands {
Deployment(GetObjectArgs),
#[command(alias("nodes"))]
Node(GetObjectArgs),
#[command()]
Ingress(GetObjectArgs),
}

pub async fn get(args: GetArgs) -> Result<(), Box<dyn Error>> {
let global_args = args.clone();
match args.commands {
GetCommands::Pod(p_args) => get_pod(global_args, p_args).await,
GetCommands::Deployment(d_args) => get_deployment(global_args, d_args).await,
GetCommands::Node(n_args) => get_nodes(global_args, n_args).await
GetCommands::Pod(args) => get_pod(global_args, args).await,
GetCommands::Deployment(args) => get_deployment(global_args, args).await,
GetCommands::Node(args) => get_nodes(global_args, args).await,
GetCommands::Ingress(args) => get_ingress(global_args, args).await,
}
}

Expand Down Expand Up @@ -123,12 +128,73 @@ impl Lister<PodmanPodInfo> for PodLister {
}
}

struct GenericLister {
resource: ResourceType,
}

impl Lister<NamespacedName> for GenericLister {
fn list(&self, filters: &GetObjectArgs, state: &ClusterState) -> Vec<NamespacedName> {
let ns = filters.namespace.clone().unwrap_or_default();
let id = match filters.id.clone() {
Some(cmd) => match cmd {
IdCommand::Id(ids) => ids.into_iter().next().unwrap_or("".to_string())
}
None => "".to_string()
};

let resources: Vec<_> = match &self.resource {
ResourceType::Ingress => {
state.nodes.iter().map(|node| {
match &node.host_info {
Some(hi) => match &hi.system_info {
Some(si) => match &si.ingresses {
Some(ingresses) => ingresses.iter().filter(|i|
(!ns.is_empty() && i.namespace == ns)
|| (!id.is_empty() && i.name == id) || (ns.is_empty() && id.is_empty())
).map(|i| {
i.clone()
}).collect(),
None => vec![]
}
None => vec![]
}
None => vec![]
}
}).flatten().collect()
}
_ => panic!("unsupported resource type for generic lister")
};

resources

// resources.iter().map(|(p, _)| p.clone()).collect()
}

fn print(&self, resources: Vec<NamespacedName>) {
println!(
"{0: <30} {1: <10}",
"NAME", "CREATED",
);
for resource in resources {
println!(
"{0: <30} {1: <10}",
format!("{}.{}", resource.name, resource.namespace), "?"
)
}
}
}


async fn get_pod(global_args: GetArgs, args: GetObjectArgs) -> Result<(), Box<dyn Error>> {
let lister = PodLister {};
get_objects(global_args, args, &lister).await
}

async fn get_ingress(global_args: GetArgs, args: GetObjectArgs) -> Result<(), Box<dyn Error>> {
let lister = GenericLister { resource: ResourceType::Ingress };
get_objects(global_args, args, &lister).await
}

struct DeploymentLister {}

impl Lister<(String, PodmanPodInfo)> for DeploymentLister {
Expand Down
7 changes: 7 additions & 0 deletions src/skate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ pub async fn skate() -> Result<(), Box<dyn Error>> {
}
}

#[derive(Debug, Serialize, Deserialize, Display, Clone)]
pub enum ResourceType {
Pod,
Deployment,
DaemonSet,
Ingress,
}

#[derive(Debug, Serialize, Deserialize, Display, Clone)]
pub enum SupportedResources {
Expand Down
15 changes: 15 additions & 0 deletions src/skatelet/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::{BTreeMap};
use std::env::consts::ARCH;
use sysinfo::{CpuExt, CpuRefreshKind, DiskExt, DiskKind, RefreshKind, System, SystemExt};
use std::error::Error;
use std::ops::Deref;

use anyhow::anyhow;
use chrono::{DateTime, Local};
Expand All @@ -10,8 +11,10 @@ use k8s_openapi::api::core::v1::{Pod, PodSpec, PodStatus as K8sPodStatus};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
use serde::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};
use crate::filestore::FileStore;

use crate::skate::{Distribution, exec_cmd, Os, Platform};
use crate::util::NamespacedName;


#[derive(Debug, Args)]
Expand Down Expand Up @@ -51,6 +54,7 @@ pub struct SystemInfo {
pub num_cpus: usize,
pub root_disk: Option<DiskInfo>,
pub pods: Option<Vec<PodmanPodInfo>>,
pub ingresses: Option<Vec<NamespacedName>>,
pub cpu_freq_mhz: u64,
pub cpu_usage: f32,
pub cpu_brand: String,
Expand Down Expand Up @@ -307,6 +311,16 @@ async fn info() -> Result<(), Box<dyn Error>> {

let podman_pod_info: Vec<PodmanPodInfo> = serde_json::from_str(&result).map_err(|e| anyhow!(e).context("failed to deserialize pod info"))?;


let store = FileStore::new();
// list ingresses
let ingresses = store.list_objects("ingress")?;
let ingresses = match ingresses.is_empty() {
true => None,
false => Some(ingresses.iter().map(|i| NamespacedName::from(i.as_str())).collect())
};


let iface_ipv4 = match get_ips(&os) {
Ok(v) => v,
Err(e) => {
Expand Down Expand Up @@ -345,6 +359,7 @@ async fn info() -> Result<(), Box<dyn Error>> {
cpu_vendor_id: sys.global_cpu_info().vendor_id().to_string(),
root_disk,
pods: Some(podman_pod_info),
ingresses: ingresses,
hostname: sys.host_name().unwrap_or("".to_string()),
external_ip_address: iface_ipv4.0,
internal_ip_address: iface_ipv4.1,
Expand Down
Loading

0 comments on commit bcc0af0

Please sign in to comment.