Refactor haproxy rt api

This commit is contained in:
Daniel M 2022-03-24 23:35:11 +01:00
parent c9431c62b8
commit 27caa5edac

View File

@ -1,6 +1,9 @@
use std::{path::Path, time::Duration};
use log::debug; use log::debug;
use tokio::{io::{AsyncReadExt, AsyncWriteExt}, time::timeout}; use std::{path::Path, time::Duration};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
time::timeout,
};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum HaProxyErr { pub enum HaProxyErr {
@ -28,49 +31,86 @@ impl HaProxyApi {
let cert_path = cert_path.as_ref(); let cert_path = cert_path.as_ref();
let cert_name = cert_path.file_name().unwrap().to_string_lossy().to_string(); let cert_name = cert_path.file_name().unwrap().to_string_lossy().to_string();
let cert_content = tokio::fs::read_to_string(cert_path).await.unwrap(); let cert_content = tokio::fs::read_to_string(cert_path).await.unwrap();
let haproxy_ssl_dir = &self.cert_dir; let haproxy_cert_path = format!("{}/{cert_name}", &self.cert_dir);
debug!("Trying to update haproxy cert in memory: {haproxy_ssl_dir}/{cert_name} <- {}", cert_path.display()); debug!(
"Trying to update haproxy cert in memory: {}/{cert_name} <- {}",
&self.cert_dir,
cert_path.display()
);
// Check for active transactions and abort them // Check for active transactions and abort them
let resp = self.send(&format!("show ssl cert")).await?; let resp = self.send(&format!("show ssl cert")).await?;
let transactions = resp.lines().filter(|line| line.starts_with("*")).map(|line| &line[1..]).collect::<Vec<_>>(); let transactions = resp
.lines()
.filter(|line| line.starts_with("*"))
.map(|line| &line[1..])
.collect::<Vec<_>>();
for transaction in transactions { for transaction in transactions {
self.send(&format!("abort ssl cert {transaction}")).await?; self.abort_cert(transaction).await?;
} }
// Try to create a new certificate in memory. This will do nothing when existing self.new_cert(&haproxy_cert_path).await?;
let resp = self.send(&format!("new ssl cert {haproxy_ssl_dir}/{cert_name}")).await?; self.set_cert(&haproxy_cert_path, &cert_content).await?;
self.commit_ssl_cert(&haproxy_cert_path).await?;
if !resp.contains("already exists") && !resp.contains("New empty certificate store ") { self.add_ssl_crt_list(&self.cert_dir, &haproxy_cert_path)
return Err(HaProxyErr::UpdateFailed); .await?;
}
// Set the cert data in memory to the new cert. This beginns a transaction
let resp = self.send(&format!("set ssl cert {haproxy_ssl_dir}/{cert_name} <<\n{cert_content}")).await?;
if !resp.contains("Transaction created") {
return Err(HaProxyErr::UpdateFailed);
}
// Commit the cert data transaction
let resp = self.send(&format!("commit ssl cert {haproxy_ssl_dir}/{cert_name}")).await?;
if !resp.contains("Success") {
self.send(&format!("abort ssl cert {haproxy_ssl_dir}/{cert_name}")).await?;
return Err(HaProxyErr::UpdateFailed);
}
// Try to add the certificate to the active list. This will do nothing if it is contained already
let resp = self.send(&format!("add ssl crt-list {haproxy_ssl_dir} <<\n{haproxy_ssl_dir}/{cert_name}\n")).await?;
if !resp.contains("already exists") && !resp.contains("Inserting certificate") {
return Err(HaProxyErr::UpdateFailed);
}
Ok(()) Ok(())
} }
/// See: https://www.haproxy.com/documentation/hapee/latest/api/runtime-api/abort-ssl-cert/
pub async fn abort_cert(&self, cert_path: &str) -> Result<(), HaProxyErr> {
self.send(&format!("abort ssl cert {cert_path}")).await?;
Ok(())
}
/// See: https://www.haproxy.com/documentation/hapee/latest/api/runtime-api/new-ssl-cert/
pub async fn new_cert(&self, cert_path: &str) -> Result<(), HaProxyErr> {
let resp = self.send(&format!("new ssl cert {cert_path}")).await?;
if !resp.contains("already exists") && !resp.contains("New empty certificate store ") {
return Err(HaProxyErr::UpdateFailed);
}
Ok(())
}
/// See: https://www.haproxy.com/documentation/hapee/latest/api/runtime-api/set-ssl-cert/
pub async fn set_cert(&self, cert_path: &str, cert_content: &str) -> Result<(), HaProxyErr> {
let resp = self
.send(&format!("set ssl cert {cert_path} <<\n{cert_content}"))
.await?;
if !resp.contains("Transaction created") {
return Err(HaProxyErr::UpdateFailed);
}
Ok(())
}
/// See: https://www.haproxy.com/documentation/hapee/latest/api/runtime-api/commit-ssl-cert/
pub async fn commit_ssl_cert(&self, cert_path: &str) -> Result<(), HaProxyErr> {
let resp = self.send(&format!("commit ssl cert {cert_path}")).await?;
if !resp.contains("Success") {
self.send(&format!("abort ssl cert {cert_path}")).await?;
return Err(HaProxyErr::UpdateFailed);
}
Ok(())
}
/// See: https://www.haproxy.com/documentation/hapee/latest/api/runtime-api/add-ssl-crt-list/
pub async fn add_ssl_crt_list(
&self,
list_path: &str,
cert_path: &str,
) -> Result<(), HaProxyErr> {
let resp = self
.send(&format!("add ssl crt-list {list_path} <<\n{cert_path}\n"))
.await?;
if !resp.contains("already exists") && !resp.contains("Inserting certificate") {
return Err(HaProxyErr::UpdateFailed);
}
Ok(())
}
/// Send a string command to the haproxy runtime api and return the response string
pub async fn send(&self, cmd: &str) -> Result<String, HaProxyErr> { pub async fn send(&self, cmd: &str) -> Result<String, HaProxyErr> {
debug!("[Haproxy] send> '{cmd}'"); debug!("[Haproxy] send> '{cmd}'");