Merge branch 'master' into feat/settingUpNDC
This commit is contained in:
19
examples/cli/Cargo.toml
Normal file
19
examples/cli/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "example-cli"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
harmony = { path = "../../harmony" }
|
||||
harmony_cli = { path = "../../harmony_cli" }
|
||||
harmony_types = { path = "../../harmony_types" }
|
||||
cidr = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
harmony_macros = { path = "../../harmony_macros" }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
url = { workspace = true }
|
||||
assert_cmd = "2.0.16"
|
||||
20
examples/cli/src/main.rs
Normal file
20
examples/cli/src/main.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use harmony::{
|
||||
inventory::Inventory,
|
||||
maestro::Maestro,
|
||||
modules::dummy::{ErrorScore, PanicScore, SuccessScore},
|
||||
topology::LocalhostTopology,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let inventory = Inventory::autoload();
|
||||
let topology = LocalhostTopology::new();
|
||||
let mut maestro = Maestro::initialize(inventory, topology).await.unwrap();
|
||||
|
||||
maestro.register_all(vec![
|
||||
Box::new(SuccessScore {}),
|
||||
Box::new(ErrorScore {}),
|
||||
Box::new(PanicScore {}),
|
||||
]);
|
||||
harmony_cli::init(maestro, None).await.unwrap();
|
||||
}
|
||||
@@ -18,3 +18,4 @@ kube = "0.98.0"
|
||||
k8s-openapi = { version = "0.24.0", features = [ "v1_30" ] }
|
||||
http = "1.2.0"
|
||||
serde_yaml = "0.9.34"
|
||||
inquire.workspace = true
|
||||
|
||||
@@ -1,20 +1,32 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use harmony_macros::yaml;
|
||||
use inquire::Confirm;
|
||||
use k8s_openapi::{
|
||||
api::{
|
||||
apps::v1::{Deployment, DeploymentSpec},
|
||||
core::v1::{Container, Node, Pod, PodSpec, PodTemplateSpec},
|
||||
core::v1::{Container, PodSpec, PodTemplateSpec},
|
||||
},
|
||||
apimachinery::pkg::apis::meta::v1::LabelSelector,
|
||||
};
|
||||
use kube::{
|
||||
Api, Client, Config, ResourceExt,
|
||||
api::{ListParams, ObjectMeta, PostParams},
|
||||
Api, Client, ResourceExt,
|
||||
api::{ObjectMeta, PostParams},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let confirmation = Confirm::new(
|
||||
"This will install various ressources to your default kubernetes cluster. Are you sure?",
|
||||
)
|
||||
.with_default(false)
|
||||
.prompt()
|
||||
.expect("Unexpected prompt error");
|
||||
|
||||
if !confirmation {
|
||||
return;
|
||||
}
|
||||
|
||||
let client = Client::try_default()
|
||||
.await
|
||||
.expect("Should instanciate client from defaults");
|
||||
@@ -42,8 +54,7 @@ async fn main() {
|
||||
// println!("found node {} status {:?}", n.name_any(), n.status.unwrap())
|
||||
// }
|
||||
|
||||
let nginxdeployment = nginx_deployment_2();
|
||||
let nginxdeployment = nginx_deployment_serde();
|
||||
assert_eq!(nginx_deployment(), nginx_macro());
|
||||
assert_eq!(nginx_deployment_2(), nginx_macro());
|
||||
assert_eq!(nginx_deployment_serde(), nginx_macro());
|
||||
let nginxdeployment = nginx_macro();
|
||||
@@ -149,6 +160,7 @@ fn nginx_deployment_2() -> Deployment {
|
||||
|
||||
deployment
|
||||
}
|
||||
|
||||
fn nginx_deployment() -> Deployment {
|
||||
let deployment = Deployment {
|
||||
metadata: ObjectMeta {
|
||||
|
||||
18
examples/lamp/Cargo.toml
Normal file
18
examples/lamp/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "example-lamp"
|
||||
edition = "2024"
|
||||
version.workspace = true
|
||||
readme.workspace = true
|
||||
license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
harmony = { path = "../../harmony" }
|
||||
harmony_cli = { path = "../../harmony_cli" }
|
||||
harmony_types = { path = "../../harmony_types" }
|
||||
cidr = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
harmony_macros = { path = "../../harmony_macros" }
|
||||
log = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
url = { workspace = true }
|
||||
85
examples/lamp/php/index.php
Normal file
85
examples/lamp/php/index.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$host = getenv('MYSQL_HOST') ?: '';
|
||||
$user = getenv('MYSQL_USER') ?: 'root';
|
||||
$pass = getenv('MYSQL_PASSWORD') ?: '';
|
||||
$db = 'testfill';
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
$dsn = "mysql:host=$host;charset=$charset";
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
$pdo->exec("CREATE DATABASE IF NOT EXISTS `$db`");
|
||||
$pdo->exec("USE `$db`");
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS filler (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
data LONGBLOB
|
||||
)
|
||||
");
|
||||
} catch (\PDOException $e) {
|
||||
die("❌ DB connection failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
function getDbStats($pdo, $db) {
|
||||
$stmt = $pdo->query("
|
||||
SELECT
|
||||
ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS total_size_gb,
|
||||
SUM(table_rows) AS total_rows
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = '$db'
|
||||
");
|
||||
$result = $stmt->fetch();
|
||||
$sizeGb = $result['total_size_gb'] ?? '0';
|
||||
$rows = $result['total_rows'] ?? '0';
|
||||
$avgMb = ($rows > 0) ? round(($sizeGb * 1024) / $rows, 2) : 0;
|
||||
return [$sizeGb, $rows, $avgMb];
|
||||
}
|
||||
|
||||
list($dbSize, $rowCount, $avgRowMb) = getDbStats($pdo, $db);
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['fill'])) {
|
||||
$iterations = 1024;
|
||||
$data = str_repeat(random_bytes(1024), 1024); // 1MB
|
||||
$stmt = $pdo->prepare("INSERT INTO filler (data) VALUES (:data)");
|
||||
|
||||
for ($i = 0; $i < $iterations; $i++) {
|
||||
$stmt->execute([':data' => $data]);
|
||||
}
|
||||
|
||||
list($dbSize, $rowCount, $avgRowMb) = getDbStats($pdo, $db);
|
||||
|
||||
$message = "<p style='color: green;'>✅ 1GB inserted into MariaDB successfully.</p>";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>MariaDB Filler</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>MariaDB Storage Filler</h1>
|
||||
<?= $message ?>
|
||||
<ul>
|
||||
<li><strong>📦 MariaDB Used Size:</strong> <?= $dbSize ?> GB</li>
|
||||
<li><strong>📊 Total Rows:</strong> <?= $rowCount ?></li>
|
||||
<li><strong>📐 Average Row Size:</strong> <?= $avgRowMb ?> MB</li>
|
||||
</ul>
|
||||
|
||||
<form method="post">
|
||||
<button name="fill" value="1" type="submit">Insert 1GB into DB</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
46
examples/lamp/src/main.rs
Normal file
46
examples/lamp/src/main.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use harmony::{
|
||||
data::Version,
|
||||
inventory::Inventory,
|
||||
maestro::Maestro,
|
||||
modules::lamp::{LAMPConfig, LAMPScore},
|
||||
topology::{K8sAnywhereTopology, Url},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// This here is the whole configuration to
|
||||
// - setup a local K3D cluster
|
||||
// - Build a docker image with the PHP project builtin and production grade settings
|
||||
// - Deploy a mariadb database using a production grade helm chart
|
||||
// - Deploy the new container using a kubernetes deployment
|
||||
// - Configure networking between the PHP container and the database
|
||||
// - Provision a public route and an SSL certificate automatically on production environments
|
||||
//
|
||||
// Enjoy :)
|
||||
let lamp_stack = LAMPScore {
|
||||
name: "harmony-lamp-demo".to_string(),
|
||||
domain: Url::Url(url::Url::parse("https://lampdemo.harmony.nationtech.io").unwrap()),
|
||||
php_version: Version::from("8.4.4").unwrap(),
|
||||
// This config can be extended as needed for more complicated configurations
|
||||
config: LAMPConfig {
|
||||
project_root: "./php".into(),
|
||||
database_size: format!("2Gi").into(),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
// You can choose the type of Topology you want, we suggest starting with the
|
||||
// K8sAnywhereTopology as it is the most automatic one that enables you to easily deploy
|
||||
// locally, to development environment from a CI, to staging, and to production with settings
|
||||
// that automatically adapt to each environment grade.
|
||||
let mut maestro = Maestro::<K8sAnywhereTopology>::initialize(
|
||||
Inventory::autoload(),
|
||||
K8sAnywhereTopology::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
maestro.register_all(vec![Box::new(lamp_stack)]);
|
||||
// Here we bootstrap the CLI, this gives some nice features if you need them
|
||||
harmony_cli::init(maestro, None).await.unwrap();
|
||||
}
|
||||
// That's it, end of the infra as code.
|
||||
@@ -19,7 +19,6 @@ use harmony::{
|
||||
},
|
||||
tftp::TftpScore,
|
||||
},
|
||||
score::Score,
|
||||
topology::{LogicalHost, UnmanagedRouter, Url},
|
||||
};
|
||||
use harmony_macros::{ip, mac_address};
|
||||
@@ -131,7 +130,7 @@ async fn main() {
|
||||
"./data/watchguard/pxe-http-files".to_string(),
|
||||
));
|
||||
let ipxe_score = IpxeScore::new();
|
||||
let mut maestro = Maestro::new(inventory, topology);
|
||||
let mut maestro = Maestro::initialize(inventory, topology).await.unwrap();
|
||||
maestro.register_all(vec![
|
||||
Box::new(dns_score),
|
||||
Box::new(bootstrap_dhcp_score),
|
||||
|
||||
@@ -12,7 +12,7 @@ use harmony::{
|
||||
modules::{
|
||||
dummy::{ErrorScore, PanicScore, SuccessScore},
|
||||
http::HttpScore,
|
||||
okd::{dhcp::OKDDhcpScore, dns::OKDDnsScore},
|
||||
okd::{dhcp::OKDDhcpScore, dns::OKDDnsScore, load_balancer::OKDLoadBalancerScore},
|
||||
opnsense::OPNsenseShellCommandScore,
|
||||
tftp::TftpScore,
|
||||
},
|
||||
@@ -78,14 +78,13 @@ async fn main() {
|
||||
|
||||
let dhcp_score = OKDDhcpScore::new(&topology, &inventory);
|
||||
let dns_score = OKDDnsScore::new(&topology);
|
||||
let load_balancer_score =
|
||||
harmony::modules::okd::load_balancer::OKDLoadBalancerScore::new(&topology);
|
||||
let load_balancer_score = OKDLoadBalancerScore::new(&topology);
|
||||
|
||||
let tftp_score = TftpScore::new(Url::LocalFolder("./data/watchguard/tftpboot".to_string()));
|
||||
let http_score = HttpScore::new(Url::LocalFolder(
|
||||
"./data/watchguard/pxe-http-files".to_string(),
|
||||
));
|
||||
let mut maestro = Maestro::new(inventory, topology);
|
||||
let mut maestro = Maestro::initialize(inventory, topology).await.unwrap();
|
||||
maestro.register_all(vec![
|
||||
Box::new(dns_score),
|
||||
Box::new(dhcp_score),
|
||||
|
||||
@@ -1,20 +1,70 @@
|
||||
use std::net::{SocketAddr, SocketAddrV4};
|
||||
|
||||
use harmony::{
|
||||
inventory::Inventory,
|
||||
maestro::Maestro,
|
||||
modules::{dummy::{ErrorScore, PanicScore, SuccessScore}, k8s::deployment::K8sDeploymentScore},
|
||||
topology::HAClusterTopology,
|
||||
modules::{
|
||||
dns::DnsScore,
|
||||
dummy::{ErrorScore, PanicScore, SuccessScore},
|
||||
load_balancer::LoadBalancerScore,
|
||||
},
|
||||
topology::{
|
||||
BackendServer, DummyInfra, HealthCheck, HttpMethod, HttpStatusCode, LoadBalancerService,
|
||||
},
|
||||
};
|
||||
use harmony_macros::ipv4;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let inventory = Inventory::autoload();
|
||||
let topology = HAClusterTopology::autoload();
|
||||
let mut maestro = Maestro::new(inventory, topology);
|
||||
let topology = DummyInfra {};
|
||||
let mut maestro = Maestro::initialize(inventory, topology).await.unwrap();
|
||||
|
||||
maestro.register_all(vec![
|
||||
Box::new(SuccessScore {}),
|
||||
Box::new(ErrorScore {}),
|
||||
Box::new(PanicScore {}),
|
||||
Box::new(DnsScore::new(vec![], None)),
|
||||
Box::new(build_large_score()),
|
||||
]);
|
||||
harmony_tui::init(maestro).await.unwrap();
|
||||
}
|
||||
|
||||
fn build_large_score() -> LoadBalancerScore {
|
||||
let backend_server = BackendServer {
|
||||
address: "192.168.0.0".to_string(),
|
||||
port: 342,
|
||||
};
|
||||
let lb_service = LoadBalancerService {
|
||||
backend_servers: vec![
|
||||
backend_server.clone(),
|
||||
backend_server.clone(),
|
||||
backend_server.clone(),
|
||||
],
|
||||
listening_port: SocketAddr::V4(SocketAddrV4::new(ipv4!("192.168.0.0"), 49387)),
|
||||
health_check: Some(HealthCheck::HTTP(
|
||||
"/some_long_ass_path_to_see_how_it_is_displayed_but_it_has_to_be_even_longer"
|
||||
.to_string(),
|
||||
HttpMethod::GET,
|
||||
HttpStatusCode::Success2xx,
|
||||
)),
|
||||
};
|
||||
LoadBalancerScore {
|
||||
public_services: vec![
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
],
|
||||
private_services: vec![
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
lb_service.clone(),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user