feat(opnsense-config): add caddy module with configuration management
Introduce a new Caddy module within opnsense-config to manage Caddy server configurations. This includes enabling/disabling Caddy, setting ports, and reloading/restarting the service via OPNsense shell commands. Additionally, provide a sample Caddy configuration file for PXE booting and a test file in the pxe-http-files directory.
This commit is contained in:
parent
925e84e4d2
commit
81d40ec163
@ -9,7 +9,9 @@ use harmony::{
|
|||||||
infra::opnsense::OPNSenseManagementInterface,
|
infra::opnsense::OPNSenseManagementInterface,
|
||||||
inventory::Inventory,
|
inventory::Inventory,
|
||||||
maestro::Maestro,
|
maestro::Maestro,
|
||||||
modules::{okd::{dhcp::OKDBootstrapDhcpScore, dns::OKDBootstrapDnsScore}, tftp::TftpScore},
|
modules::{
|
||||||
|
http::HttpScore, okd::{dhcp::OKDBootstrapDhcpScore, dns::OKDBootstrapDnsScore}, tftp::TftpScore
|
||||||
|
},
|
||||||
topology::{LogicalHost, UnmanagedRouter, Url},
|
topology::{LogicalHost, UnmanagedRouter, Url},
|
||||||
};
|
};
|
||||||
use harmony_macros::ip;
|
use harmony_macros::ip;
|
||||||
@ -24,14 +26,8 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let opnsense = Arc::new(
|
let opnsense = Arc::new(
|
||||||
harmony::infra::opnsense::OPNSenseFirewall::new(
|
harmony::infra::opnsense::OPNSenseFirewall::new(firewall, None, "lan", "root", "opnsense")
|
||||||
firewall,
|
.await,
|
||||||
None,
|
|
||||||
"lan",
|
|
||||||
"root",
|
|
||||||
"opnsense",
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
);
|
);
|
||||||
let lan_subnet = Ipv4Addr::new(10, 100, 8, 0);
|
let lan_subnet = Ipv4Addr::new(10, 100, 8, 0);
|
||||||
let gateway_ipv4 = Ipv4Addr::new(10, 100, 8, 1);
|
let gateway_ipv4 = Ipv4Addr::new(10, 100, 8, 1);
|
||||||
@ -45,6 +41,7 @@ async fn main() {
|
|||||||
load_balancer: opnsense.clone(),
|
load_balancer: opnsense.clone(),
|
||||||
firewall: opnsense.clone(),
|
firewall: opnsense.clone(),
|
||||||
tftp_server: opnsense.clone(),
|
tftp_server: opnsense.clone(),
|
||||||
|
http_server: opnsense.clone(),
|
||||||
dhcp_server: opnsense.clone(),
|
dhcp_server: opnsense.clone(),
|
||||||
dns_server: opnsense.clone(),
|
dns_server: opnsense.clone(),
|
||||||
control_plane: vec![LogicalHost {
|
control_plane: vec![LogicalHost {
|
||||||
@ -82,9 +79,13 @@ async fn main() {
|
|||||||
// harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology);
|
// harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology);
|
||||||
|
|
||||||
let tftp_score = TftpScore::new(Url::LocalFolder("../../../watchguard/tftpboot".to_string()));
|
let tftp_score = TftpScore::new(Url::LocalFolder("../../../watchguard/tftpboot".to_string()));
|
||||||
|
let http_score = HttpScore::new(Url::LocalFolder(
|
||||||
|
"../../../watchguard/pxe-http-files".to_string(),
|
||||||
|
));
|
||||||
let maestro = Maestro::new(inventory, topology);
|
let maestro = Maestro::new(inventory, topology);
|
||||||
// maestro.interpret(dns_score).await.unwrap();
|
// maestro.interpret(dns_score).await.unwrap();
|
||||||
// maestro.interpret(dhcp_score).await.unwrap();
|
// maestro.interpret(dhcp_score).await.unwrap();
|
||||||
// maestro.interpret(load_balancer_score).await.unwrap();
|
// maestro.interpret(load_balancer_score).await.unwrap();
|
||||||
maestro.interpret(tftp_score).await.unwrap();
|
// maestro.interpret(tftp_score).await.unwrap();
|
||||||
|
maestro.interpret(http_score).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,8 @@ pub enum InterpretName {
|
|||||||
OPNSenseDHCP,
|
OPNSenseDHCP,
|
||||||
OPNSenseDns,
|
OPNSenseDns,
|
||||||
LoadBalancer,
|
LoadBalancer,
|
||||||
Tftp
|
Tftp,
|
||||||
|
Http,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for InterpretName {
|
impl std::fmt::Display for InterpretName {
|
||||||
@ -24,6 +25,7 @@ impl std::fmt::Display for InterpretName {
|
|||||||
InterpretName::OPNSenseDns => f.write_str("OPNSenseDns"),
|
InterpretName::OPNSenseDns => f.write_str("OPNSenseDns"),
|
||||||
InterpretName::LoadBalancer => f.write_str("LoadBalancer"),
|
InterpretName::LoadBalancer => f.write_str("LoadBalancer"),
|
||||||
InterpretName::Tftp => f.write_str("Tftp"),
|
InterpretName::Tftp => f.write_str("Tftp"),
|
||||||
|
InterpretName::Http => f.write_str("Http"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
harmony-rs/harmony/src/domain/topology/http.rs
Normal file
24
harmony-rs/harmony/src/domain/topology/http.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use crate::executors::ExecutorError;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use super::{IpAddress, Url};
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait HttpServer: Send + Sync {
|
||||||
|
async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError>;
|
||||||
|
fn get_ip(&self) -> IpAddress;
|
||||||
|
|
||||||
|
// async fn set_ip(&self, ip: IpAddress) -> Result<(), ExecutorError>;
|
||||||
|
async fn ensure_initialized(&self) -> Result<(), ExecutorError>;
|
||||||
|
async fn commit_config(&self) -> Result<(), ExecutorError>;
|
||||||
|
async fn reload_restart(&self) -> Result<(), ExecutorError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for dyn HttpServer {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"HttpServer serving files at {}",
|
||||||
|
self.get_ip()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,12 +2,14 @@ mod host_binding;
|
|||||||
mod load_balancer;
|
mod load_balancer;
|
||||||
mod router;
|
mod router;
|
||||||
mod tftp;
|
mod tftp;
|
||||||
|
mod http;
|
||||||
pub use load_balancer::*;
|
pub use load_balancer::*;
|
||||||
pub use router::*;
|
pub use router::*;
|
||||||
mod network;
|
mod network;
|
||||||
pub use host_binding::*;
|
pub use host_binding::*;
|
||||||
pub use network::*;
|
pub use network::*;
|
||||||
pub use tftp::*;
|
pub use tftp::*;
|
||||||
|
pub use http::*;
|
||||||
|
|
||||||
use std::{net::IpAddr, sync::Arc};
|
use std::{net::IpAddr, sync::Arc};
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ pub struct HAClusterTopology {
|
|||||||
pub firewall: Arc<dyn Firewall>,
|
pub firewall: Arc<dyn Firewall>,
|
||||||
pub dhcp_server: Arc<dyn DhcpServer>,
|
pub dhcp_server: Arc<dyn DhcpServer>,
|
||||||
pub tftp_server: Arc<dyn TftpServer>,
|
pub tftp_server: Arc<dyn TftpServer>,
|
||||||
|
pub http_server: Arc<dyn HttpServer>,
|
||||||
pub dns_server: Arc<dyn DnsServer>,
|
pub dns_server: Arc<dyn DnsServer>,
|
||||||
pub control_plane: Vec<LogicalHost>,
|
pub control_plane: Vec<LogicalHost>,
|
||||||
pub workers: Vec<LogicalHost>,
|
pub workers: Vec<LogicalHost>,
|
||||||
|
|||||||
75
harmony-rs/harmony/src/infra/opnsense/http.rs
Normal file
75
harmony-rs/harmony/src/infra/opnsense/http.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use log::{debug, info};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
executors::ExecutorError,
|
||||||
|
topology::{HttpServer, IpAddress, Url},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::OPNSenseFirewall;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl HttpServer for OPNSenseFirewall {
|
||||||
|
async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> {
|
||||||
|
let http_root_path = "/usr/local/http";
|
||||||
|
|
||||||
|
let config = self.opnsense_config.read().await;
|
||||||
|
info!("Uploading files from url {url} to {http_root_path}");
|
||||||
|
match url {
|
||||||
|
Url::LocalFolder(path) => {
|
||||||
|
config
|
||||||
|
.upload_files(path, http_root_path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
}
|
||||||
|
Url::Remote(url) => todo!(),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ip(&self) -> IpAddress {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn commit_config(&self) -> Result<(), ExecutorError> {
|
||||||
|
OPNSenseFirewall::commit_config(self).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn reload_restart(&self) -> Result<(), ExecutorError> {
|
||||||
|
self.opnsense_config
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.caddy()
|
||||||
|
.reload_restart()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_initialized(&self) -> Result<(), ExecutorError> {
|
||||||
|
let mut config = self.opnsense_config.write().await;
|
||||||
|
let caddy = config.caddy();
|
||||||
|
if let None = caddy.get_full_config() {
|
||||||
|
info!("Http config not available in opnsense config, installing package");
|
||||||
|
config.install_package("os-caddy").await.map_err(|e| {
|
||||||
|
ExecutorError::UnexpectedError(format!(
|
||||||
|
"Executor failed when trying to install os-caddy package with error {e:?}"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
} else {
|
||||||
|
info!("Http config available in opnsense config, assuming it is already installed");
|
||||||
|
}
|
||||||
|
info!("Adding custom caddy config files");
|
||||||
|
config
|
||||||
|
.upload_files(
|
||||||
|
"../../../watchguard/caddy_config",
|
||||||
|
"/usr/local/etc/caddy/caddy.d/",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
|
||||||
|
info!("Enabling http server");
|
||||||
|
config.caddy().enable(true);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ mod firewall;
|
|||||||
mod load_balancer;
|
mod load_balancer;
|
||||||
mod management;
|
mod management;
|
||||||
mod tftp;
|
mod tftp;
|
||||||
|
mod http;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use management::*;
|
pub use management::*;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ impl TftpServer for OPNSenseFirewall {
|
|||||||
async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> {
|
async fn serve_files(&self, url: &Url) -> Result<(), ExecutorError> {
|
||||||
let tftp_root_path = "/usr/local/tftp";
|
let tftp_root_path = "/usr/local/tftp";
|
||||||
|
|
||||||
let config = self.opnsense_config.write().await;
|
let config = self.opnsense_config.read().await;
|
||||||
info!("Uploading files from url {url} to {tftp_root_path}");
|
info!("Uploading files from url {url} to {tftp_root_path}");
|
||||||
match url {
|
match url {
|
||||||
Url::LocalFolder(path) => {
|
Url::LocalFolder(path) => {
|
||||||
@ -28,7 +28,7 @@ impl TftpServer for OPNSenseFirewall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_ip(&self) -> IpAddress {
|
fn get_ip(&self) -> IpAddress {
|
||||||
OPNSenseFirewall::get_ip(self)
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_ip(&self, ip: IpAddress) -> Result<(), ExecutorError> {
|
async fn set_ip(&self, ip: IpAddress) -> Result<(), ExecutorError> {
|
||||||
|
|||||||
64
harmony-rs/harmony/src/modules/http.rs
Normal file
64
harmony-rs/harmony/src/modules/http.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use derive_new::new;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
data::{Id, Version},
|
||||||
|
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||||
|
inventory::Inventory,
|
||||||
|
score::Score,
|
||||||
|
topology::{HAClusterTopology, Url},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, new, Clone)]
|
||||||
|
pub struct HttpScore {
|
||||||
|
files_to_serve: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Score for HttpScore {
|
||||||
|
type InterpretType = HttpInterpret;
|
||||||
|
|
||||||
|
fn create_interpret(self) -> Self::InterpretType {
|
||||||
|
HttpInterpret::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, new, Clone)]
|
||||||
|
pub struct HttpInterpret {
|
||||||
|
score: HttpScore,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Interpret for HttpInterpret {
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
inventory: &Inventory,
|
||||||
|
topology: &HAClusterTopology,
|
||||||
|
) -> Result<Outcome, InterpretError> {
|
||||||
|
let http_server = &topology.http_server;
|
||||||
|
http_server.ensure_initialized().await?;
|
||||||
|
// http_server.set_ip(topology.router.get_gateway()).await?;
|
||||||
|
http_server.serve_files(&self.score.files_to_serve).await?;
|
||||||
|
http_server.commit_config().await?;
|
||||||
|
http_server.reload_restart().await?;
|
||||||
|
Ok(Outcome::success(format!(
|
||||||
|
"Http Server running and serving files from {}",
|
||||||
|
self.score.files_to_serve
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> InterpretName {
|
||||||
|
InterpretName::Http
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_version(&self) -> Version {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status(&self) -> InterpretStatus {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_children(&self) -> Vec<Id> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,3 +3,4 @@ pub mod dns;
|
|||||||
pub mod okd;
|
pub mod okd;
|
||||||
pub mod load_balancer;
|
pub mod load_balancer;
|
||||||
pub mod tftp;
|
pub mod tftp;
|
||||||
|
pub mod http;
|
||||||
|
|||||||
83
harmony-rs/opnsense-config-xml/src/data/caddy.rs
Normal file
83
harmony-rs/opnsense-config-xml/src/data/caddy.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use yaserde::MaybeString;
|
||||||
|
use yaserde_derive::{YaDeserialize, YaSerialize};
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
pub struct Pischem {
|
||||||
|
pub caddy: Caddy,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
pub struct Caddy {
|
||||||
|
pub general: CaddyGeneral,
|
||||||
|
pub reverseproxy: MaybeString,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
pub struct CaddyGeneral {
|
||||||
|
pub enabled: u8,
|
||||||
|
#[yaserde(rename = "EnableLayer4")]
|
||||||
|
pub enable_layer4: Option<u8>,
|
||||||
|
#[yaserde(rename = "HttpPort")]
|
||||||
|
pub http_port: Option<u16>,
|
||||||
|
#[yaserde(rename = "HttpsPort")]
|
||||||
|
pub https_port: Option<u16>,
|
||||||
|
#[yaserde(rename = "TlsEmail")]
|
||||||
|
pub tls_email: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsAutoHttps")]
|
||||||
|
pub tls_auto_https: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsProvider")]
|
||||||
|
pub tls_dns_provider: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsApiKey")]
|
||||||
|
pub tls_dns_api_key: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsSecretApiKey")]
|
||||||
|
pub tls_dns_secret_api_key: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsOptionalField1")]
|
||||||
|
pub tls_dns_optional_field1: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsOptionalField2")]
|
||||||
|
pub tls_dns_optional_field2: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsOptionalField3")]
|
||||||
|
pub tls_dns_optional_field3: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsOptionalField4")]
|
||||||
|
pub tls_dns_optional_field4: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsPropagationTimeout")]
|
||||||
|
pub tls_dns_propagation_timeout: MaybeString,
|
||||||
|
#[yaserde(rename = "TlsDnsPropagationResolvers")]
|
||||||
|
pub tls_dns_propagation_resolvers: MaybeString,
|
||||||
|
pub accesslist: MaybeString,
|
||||||
|
#[yaserde(rename = "DisableSuperuser")]
|
||||||
|
pub disable_superuser: Option<i32>,
|
||||||
|
#[yaserde(rename = "GracePeriod")]
|
||||||
|
pub grace_period: Option<u16>,
|
||||||
|
#[yaserde(rename = "HttpVersion")]
|
||||||
|
pub http_version: MaybeString,
|
||||||
|
#[yaserde(rename = "LogCredentials")]
|
||||||
|
pub log_credentials: MaybeString,
|
||||||
|
#[yaserde(rename = "LogAccessPlain")]
|
||||||
|
pub log_access_plain: MaybeString,
|
||||||
|
#[yaserde(rename = "LogAccessPlainKeep")]
|
||||||
|
pub log_access_plain_keep: Option<u16>,
|
||||||
|
#[yaserde(rename = "LogLevel")]
|
||||||
|
pub log_level: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsSimpleHttp")]
|
||||||
|
pub dyn_dns_simple_http: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsInterface")]
|
||||||
|
pub dyn_dns_interface: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsInterval")]
|
||||||
|
pub dyn_dns_interval: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsIpVersions")]
|
||||||
|
pub dyn_dns_ip_versions: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsTtl")]
|
||||||
|
pub dyn_dns_ttl: MaybeString,
|
||||||
|
#[yaserde(rename = "DynDnsUpdateOnly")]
|
||||||
|
pub dyn_dns_update_only: MaybeString,
|
||||||
|
#[yaserde(rename = "AuthProvider")]
|
||||||
|
pub auth_provider: MaybeString,
|
||||||
|
#[yaserde(rename = "AuthToDomain")]
|
||||||
|
pub auth_to_domain: MaybeString,
|
||||||
|
#[yaserde(rename = "AuthToPort")]
|
||||||
|
pub auth_to_port: MaybeString,
|
||||||
|
#[yaserde(rename = "AuthToTls")]
|
||||||
|
pub auth_to_tls: Option<i32>,
|
||||||
|
#[yaserde(rename = "AuthToUri")]
|
||||||
|
pub auth_to_uri: MaybeString,
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@ mod opnsense;
|
|||||||
mod interfaces;
|
mod interfaces;
|
||||||
mod dhcpd;
|
mod dhcpd;
|
||||||
mod haproxy;
|
mod haproxy;
|
||||||
|
mod caddy;
|
||||||
|
pub use caddy::*;
|
||||||
pub use haproxy::*;
|
pub use haproxy::*;
|
||||||
pub use opnsense::*;
|
pub use opnsense::*;
|
||||||
pub use interfaces::*;
|
pub use interfaces::*;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use uuid::Uuid;
|
|||||||
use yaserde::{MaybeString, NamedList, RawXml};
|
use yaserde::{MaybeString, NamedList, RawXml};
|
||||||
use yaserde_derive::{YaDeserialize, YaSerialize};
|
use yaserde_derive::{YaDeserialize, YaSerialize};
|
||||||
|
|
||||||
use super::Interface;
|
use super::{Interface, Pischem};
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
#[yaserde(rename = "opnsense")]
|
#[yaserde(rename = "opnsense")]
|
||||||
@ -44,7 +44,7 @@ pub struct OPNsense {
|
|||||||
pub wireless: Wireless,
|
pub wireless: Wireless,
|
||||||
pub hasync: Hasync,
|
pub hasync: Hasync,
|
||||||
#[yaserde(rename = "Pischem")]
|
#[yaserde(rename = "Pischem")]
|
||||||
pub pischem: Option<RawXml>,
|
pub pischem: Option<Pischem>,
|
||||||
pub ifgroups: Ifgroups,
|
pub ifgroups: Ifgroups,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1370,7 +1370,6 @@ pub struct ConfigOpenVPN {
|
|||||||
pub StaticKeys: MaybeString,
|
pub StaticKeys: MaybeString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct StaticRoutes {
|
pub struct StaticRoutes {
|
||||||
#[yaserde(attribute)]
|
#[yaserde(attribute)]
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::{sync::Arc, time::Duration};
|
|||||||
use crate::{
|
use crate::{
|
||||||
config::{SshConfigManager, SshCredentials, SshOPNSenseShell},
|
config::{SshConfigManager, SshCredentials, SshOPNSenseShell},
|
||||||
error::Error,
|
error::Error,
|
||||||
modules::{dhcp::DhcpConfig, dns::DnsConfig, load_balancer::LoadBalancerConfig, tftp::TftpConfig},
|
modules::{caddy::CaddyConfig, dhcp::DhcpConfig, dns::DnsConfig, load_balancer::LoadBalancerConfig, tftp::TftpConfig},
|
||||||
};
|
};
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use opnsense_config_xml::OPNsense;
|
use opnsense_config_xml::OPNsense;
|
||||||
@ -42,6 +42,10 @@ impl Config {
|
|||||||
TftpConfig::new(&mut self.opnsense, self.shell.clone())
|
TftpConfig::new(&mut self.opnsense, self.shell.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn caddy(&mut self) -> CaddyConfig {
|
||||||
|
CaddyConfig::new(&mut self.opnsense, self.shell.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_balancer(&mut self) -> LoadBalancerConfig {
|
pub fn load_balancer(&mut self) -> LoadBalancerConfig {
|
||||||
LoadBalancerConfig::new(&mut self.opnsense, self.shell.clone())
|
LoadBalancerConfig::new(&mut self.opnsense, self.shell.clone())
|
||||||
}
|
}
|
||||||
@ -50,6 +54,17 @@ impl Config {
|
|||||||
self.shell.upload_folder(source, destination).await
|
self.shell.upload_folder(source, destination).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Here maybe we should take ownership of `mut self` instead of `&mut self`
|
||||||
|
// I don't think there can be faulty pointers to previous versions of the config but I have a
|
||||||
|
// hard time wrapping my head around it right now :
|
||||||
|
// - the caller has a mutable reference to us
|
||||||
|
// - caller gets a reference to a piece of configuration (.haproxy.general.servers[0])
|
||||||
|
// - caller calls install_package wich reloads the config from remote
|
||||||
|
// - haproxy.general.servers[0] does not exist anymore
|
||||||
|
// - broken?
|
||||||
|
//
|
||||||
|
// Although I did not try explicitely the above workflow so maybe rust prevents taking a
|
||||||
|
// read-only reference across the &mut call
|
||||||
pub async fn install_package(&mut self, package_name: &str) -> Result<(), Error> {
|
pub async fn install_package(&mut self, package_name: &str) -> Result<(), Error> {
|
||||||
info!("Installing opnsense package {package_name}");
|
info!("Installing opnsense package {package_name}");
|
||||||
let output = self.shell
|
let output = self.shell
|
||||||
|
|||||||
49
harmony-rs/opnsense-config/src/modules/caddy.rs
Normal file
49
harmony-rs/opnsense-config/src/modules/caddy.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use opnsense_config_xml::{Caddy, OPNsense, Pischem};
|
||||||
|
|
||||||
|
use crate::{config::OPNsenseShell, Error};
|
||||||
|
|
||||||
|
pub struct CaddyConfig<'a> {
|
||||||
|
opnsense: &'a mut OPNsense,
|
||||||
|
opnsense_shell: Arc<dyn OPNsenseShell>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CaddyConfig<'a> {
|
||||||
|
pub fn new(opnsense: &'a mut OPNsense, opnsense_shell: Arc<dyn OPNsenseShell>) -> Self {
|
||||||
|
Self {
|
||||||
|
opnsense,
|
||||||
|
opnsense_shell,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_full_config(&self) -> &Option<Pischem> {
|
||||||
|
&self.opnsense.pischem
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_caddy<F, R>(&mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Caddy) -> R,
|
||||||
|
{
|
||||||
|
match &mut self.opnsense.pischem.as_mut() {
|
||||||
|
Some(pischem) => f(&mut pischem.caddy),
|
||||||
|
None => unimplemented!("Accessing caddy config is not supported when not available yet"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(&mut self, enabled: bool) {
|
||||||
|
self.with_caddy(|caddy| {caddy.general.enabled = enabled as u8;
|
||||||
|
caddy.general.http_port = Some(8080);
|
||||||
|
caddy.general.https_port = Some(8443);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn reload_restart(&self) -> Result<(), Error> {
|
||||||
|
self.opnsense_shell.exec("configctl caddy stop").await?;
|
||||||
|
self.opnsense_shell.exec("configctl template reload OPNsense/Caddy").await?;
|
||||||
|
self.opnsense_shell.exec("configctl template reload OPNsense/Caddy/rc.conf.d").await?;
|
||||||
|
self.opnsense_shell.exec("configctl caddy validate").await?;
|
||||||
|
self.opnsense_shell.exec("configctl caddy start").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,3 +2,4 @@ pub mod dhcp;
|
|||||||
pub mod dns;
|
pub mod dns;
|
||||||
pub mod load_balancer;
|
pub mod load_balancer;
|
||||||
pub mod tftp;
|
pub mod tftp;
|
||||||
|
pub mod caddy;
|
||||||
|
|||||||
4
watchguard/caddy_config/caddy_pxe.conf
Normal file
4
watchguard/caddy_config/caddy_pxe.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
:8080 {
|
||||||
|
root * /usr/local/http
|
||||||
|
file_server
|
||||||
|
}
|
||||||
1
watchguard/pxe-http-files/paul
Normal file
1
watchguard/pxe-http-files/paul
Normal file
@ -0,0 +1 @@
|
|||||||
|
hey i am paul
|
||||||
Loading…
Reference in New Issue
Block a user