feat(k8s): add Kubernetes deployment resource handling
Introduce new modules to handle Kubernetes resources specifically focusing on Deployment resources. Added `K8sResource` and `K8sDeployment` structs along with necessary traits implementations for interpretation and execution in the inventory system. Also, fixed module reordering issues in opnsense-config-xml and corrected some fields types within its data structures.
This commit is contained in:
parent
caec71f06d
commit
d6c8650d52
4
harmony-rs/Cargo.lock
generated
4
harmony-rs/Cargo.lock
generated
@ -931,6 +931,9 @@ dependencies = [
|
||||
"env_logger",
|
||||
"harmony_macros",
|
||||
"harmony_types",
|
||||
"http 1.2.0",
|
||||
"k8s-openapi",
|
||||
"kube",
|
||||
"libredfish",
|
||||
"log",
|
||||
"opnsense-config",
|
||||
@ -941,6 +944,7 @@ dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"tokio",
|
||||
"url",
|
||||
"uuid",
|
||||
|
@ -26,6 +26,10 @@ russh = "0.45.0"
|
||||
russh-keys = "0.45.0"
|
||||
rand = "0.8.5"
|
||||
url = "2.5.4"
|
||||
kube = "0.98.0"
|
||||
k8s-openapi = { version = "0.24.0", features = [ "v1_30" ] }
|
||||
serde_yaml = "0.9.34"
|
||||
http = "1.2.0"
|
||||
|
||||
[workspace.dependencies.uuid]
|
||||
version = "1.11.0"
|
||||
|
@ -23,3 +23,7 @@ harmony_macros = { path = "../harmony_macros" }
|
||||
harmony_types = { path = "../harmony_types" }
|
||||
uuid = { workspace = true }
|
||||
url = { workspace = true }
|
||||
kube = { workspace = true }
|
||||
k8s-openapi = { workspace = true }
|
||||
serde_yaml = { workspace = true }
|
||||
http = { workspace = true }
|
||||
|
@ -3,7 +3,6 @@ use std::sync::Arc;
|
||||
use derive_new::new;
|
||||
use harmony_types::net::MacAddress;
|
||||
|
||||
|
||||
pub type HostGroup = Vec<PhysicalHost>;
|
||||
pub type SwitchGroup = Vec<Switch>;
|
||||
pub type FirewallGroup = Vec<PhysicalHost>;
|
||||
@ -29,7 +28,11 @@ impl PhysicalHost {
|
||||
}
|
||||
|
||||
pub fn cluster_mac(&self) -> MacAddress {
|
||||
self.network.get(0).expect("Cluster physical host should have a network interface").mac_address.clone()
|
||||
self.network
|
||||
.get(0)
|
||||
.expect("Cluster physical host should have a network interface")
|
||||
.mac_address
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,3 +108,12 @@ impl From<ExecutorError> for InterpretError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<kube::Error> for InterpretError{
|
||||
fn from(value: kube::Error) -> Self {
|
||||
Self {
|
||||
msg: format!("InterpretError : {value}"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
mod host_binding;
|
||||
mod http;
|
||||
mod load_balancer;
|
||||
pub mod openshift;
|
||||
mod router;
|
||||
mod tftp;
|
||||
pub use load_balancer::*;
|
||||
use openshift::OpenshiftClient;
|
||||
pub use router::*;
|
||||
mod network;
|
||||
pub use host_binding::*;
|
||||
@ -29,6 +31,12 @@ pub struct HAClusterTopology {
|
||||
pub switch: Vec<LogicalHost>,
|
||||
}
|
||||
|
||||
impl HAClusterTopology {
|
||||
pub async fn oc_client(&self) -> Result<Arc<OpenshiftClient>, kube::Error> {
|
||||
Ok(Arc::new(OpenshiftClient::try_default().await?))
|
||||
}
|
||||
}
|
||||
|
||||
pub type IpAddress = IpAddr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
55
harmony-rs/harmony/src/domain/topology/openshift.rs
Normal file
55
harmony-rs/harmony/src/domain/topology/openshift.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use k8s_openapi::NamespaceResourceScope;
|
||||
use kube::{api::PostParams, Api, Client, Error, Resource};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub struct OpenshiftClient {
|
||||
client: Client,
|
||||
}
|
||||
|
||||
impl OpenshiftClient {
|
||||
pub async fn try_default() -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
client: Client::try_default().await?,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn apply_all<
|
||||
K: Resource<Scope = NamespaceResourceScope>
|
||||
+ std::fmt::Debug
|
||||
+ Sync
|
||||
+ DeserializeOwned
|
||||
+ Default
|
||||
+ serde::Serialize
|
||||
+ Clone,
|
||||
>(
|
||||
&self,
|
||||
resource: &Vec<K>,
|
||||
) -> Result<Vec<K>, kube::Error>
|
||||
where
|
||||
<K as kube::Resource>::DynamicType: Default,
|
||||
{
|
||||
let mut result = vec![];
|
||||
for r in resource.iter() {
|
||||
let api: Api<K> = Api::all(self.client.clone());
|
||||
result.push(api.create(&PostParams::default(), &r).await?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn apply_namespaced<K>(&self, resource: &Vec<K>) -> Result<K, Error>
|
||||
where
|
||||
K: Resource<Scope = NamespaceResourceScope>
|
||||
+ Clone
|
||||
+ std::fmt::Debug
|
||||
+ DeserializeOwned
|
||||
+ serde::Serialize
|
||||
+ Default,
|
||||
<K as kube::Resource>::DynamicType: Default,
|
||||
{
|
||||
for r in resource.iter() {
|
||||
let api: Api<K> = Api::default_namespaced(self.client.clone());
|
||||
api.create(&PostParams::default(), &r).await?;
|
||||
}
|
||||
todo!("")
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{data::{Id, Version}, interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome}, inventory::Inventory, score::Score, topology::HAClusterTopology};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sResourceScore {}
|
||||
|
||||
impl Score for K8sResourceScore {
|
||||
type InterpretType = K8sResourceInterpret;
|
||||
|
||||
fn create_interpret(self) -> Self::InterpretType {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sResourceInterpret {
|
||||
score: K8sResourceScore,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Interpret for K8sResourceInterpret {
|
||||
async fn execute(
|
||||
&self,
|
||||
inventory: &Inventory,
|
||||
topology: &HAClusterTopology,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
todo!()
|
||||
}
|
||||
fn get_name(&self) -> InterpretName {
|
||||
todo!()
|
||||
}
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
53
harmony-rs/harmony/src/modules/k8s/deployment.rs
Normal file
53
harmony-rs/harmony/src/modules/k8s/deployment.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use harmony_macros::yaml;
|
||||
use k8s_openapi::api::apps::v1::Deployment;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::score::Score;
|
||||
|
||||
use super::resource::{K8sResourceInterpret, K8sResourceScore};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sDeploymentScore {
|
||||
pub name: String,
|
||||
pub image: String,
|
||||
}
|
||||
|
||||
impl Score for K8sDeploymentScore {
|
||||
type InterpretType = K8sResourceInterpret<Deployment>;
|
||||
|
||||
fn create_interpret(self) -> Self::InterpretType {
|
||||
let deployment: Deployment = serde_json::from_value(json!(
|
||||
{
|
||||
"metadata": {
|
||||
"name": self.name
|
||||
},
|
||||
"spec": {
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": self.name
|
||||
},
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": self.name
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"image": self.image,
|
||||
"name": self.image
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
.unwrap();
|
||||
K8sResourceInterpret {
|
||||
score: K8sResourceScore::single(deployment),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
|
||||
pub mod Resource;
|
||||
pub mod resource;
|
||||
pub mod deployment;
|
||||
|
||||
|
92
harmony-rs/harmony/src/modules/k8s/resource.rs
Normal file
92
harmony-rs/harmony/src/modules/k8s/resource.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use async_trait::async_trait;
|
||||
use k8s_openapi::NamespaceResourceScope;
|
||||
use kube::Resource;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
use crate::{
|
||||
data::{Id, Version},
|
||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||
inventory::Inventory,
|
||||
score::Score,
|
||||
topology::HAClusterTopology,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sResourceScore<K: Resource + std::fmt::Debug> {
|
||||
pub resource: Vec<K>,
|
||||
}
|
||||
|
||||
impl<K: Resource + std::fmt::Debug> K8sResourceScore<K> {
|
||||
pub fn single(resource: K) -> Self {
|
||||
Self {
|
||||
resource: vec![resource],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
K: Resource<Scope = NamespaceResourceScope>
|
||||
+ std::fmt::Debug
|
||||
+ Sync
|
||||
+ DeserializeOwned
|
||||
+ Default
|
||||
+ serde::Serialize
|
||||
+ Clone,
|
||||
> Score for K8sResourceScore<K>
|
||||
where
|
||||
<K as kube::Resource>::DynamicType: Default,
|
||||
{
|
||||
type InterpretType = K8sResourceInterpret<K>;
|
||||
|
||||
fn create_interpret(self) -> Self::InterpretType {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct K8sResourceInterpret<K: Resource + std::fmt::Debug + Sync> {
|
||||
pub score: K8sResourceScore<K>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<
|
||||
K: Resource<Scope = NamespaceResourceScope>
|
||||
+ Clone
|
||||
+ std::fmt::Debug
|
||||
+ DeserializeOwned
|
||||
+ serde::Serialize
|
||||
+ Default
|
||||
+ Sync,
|
||||
> Interpret for K8sResourceInterpret<K>
|
||||
where
|
||||
<K as kube::Resource>::DynamicType: Default,
|
||||
{
|
||||
async fn execute(
|
||||
&self,
|
||||
inventory: &Inventory,
|
||||
topology: &HAClusterTopology,
|
||||
) -> Result<Outcome, InterpretError> {
|
||||
topology
|
||||
.oc_client()
|
||||
.await
|
||||
.expect("Environment should provide enough information to instanciate a client")
|
||||
.apply_namespaced(&self.score.resource)
|
||||
.await?;
|
||||
|
||||
Ok(Outcome::success(
|
||||
"Successfully applied resource".to_string(),
|
||||
))
|
||||
}
|
||||
fn get_name(&self) -> InterpretName {
|
||||
todo!()
|
||||
}
|
||||
fn get_version(&self) -> Version {
|
||||
todo!()
|
||||
}
|
||||
fn get_status(&self) -> InterpretStatus {
|
||||
todo!()
|
||||
}
|
||||
fn get_children(&self) -> Vec<Id> {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
mod opnsense;
|
||||
mod interfaces;
|
||||
mod caddy;
|
||||
mod dhcpd;
|
||||
mod haproxy;
|
||||
mod caddy;
|
||||
mod interfaces;
|
||||
mod opnsense;
|
||||
pub use caddy::*;
|
||||
pub use haproxy::*;
|
||||
pub use opnsense::*;
|
||||
pub use interfaces::*;
|
||||
pub use dhcpd::*;
|
||||
pub use haproxy::*;
|
||||
pub use interfaces::*;
|
||||
pub use opnsense::*;
|
||||
|
@ -141,6 +141,7 @@ pub struct Rule {
|
||||
pub struct Source {
|
||||
pub any: Option<u8>,
|
||||
pub network: Option<MaybeString>,
|
||||
pub address: Option<MaybeString>,
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||
@ -164,7 +165,7 @@ pub struct Sysctl {
|
||||
|
||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||
pub struct SysctlItem {
|
||||
pub descr: String,
|
||||
pub descr: MaybeString,
|
||||
pub tunable: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod xml_utils;
|
||||
mod data;
|
||||
mod xml_utils;
|
||||
pub use data::*;
|
||||
pub use yaserde::MaybeString;
|
||||
|
Loading…
Reference in New Issue
Block a user