monitoring-alerting #30
75
Cargo.lock
generated
75
Cargo.lock
generated
@ -356,9 +356,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.19"
|
version = "1.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
@ -382,9 +382,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.40"
|
version = "0.4.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
@ -519,11 +519,20 @@ version = "0.1.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.16",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"tiny-keccak",
|
"tiny-keccak",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@ -1020,8 +1029,8 @@ dependencies = [
|
|||||||
"cidr",
|
"cidr",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"harmony",
|
"harmony",
|
||||||
|
"harmony_cli",
|
||||||
"harmony_macros",
|
"harmony_macros",
|
||||||
"harmony_tui",
|
|
||||||
"harmony_types",
|
"harmony_types",
|
||||||
"log",
|
"log",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -1289,9 +1298,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -1383,6 +1392,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"cidr",
|
"cidr",
|
||||||
|
"convert_case",
|
||||||
"derive-new",
|
"derive-new",
|
||||||
"directories",
|
"directories",
|
||||||
"dockerfile_builder",
|
"dockerfile_builder",
|
||||||
@ -1409,6 +1419,7 @@ dependencies = [
|
|||||||
"serde-value",
|
"serde-value",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"temp-file",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -2064,9 +2075,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff"
|
name = "jiff"
|
||||||
version = "0.2.8"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0"
|
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jiff-static",
|
"jiff-static",
|
||||||
"log",
|
"log",
|
||||||
@ -2077,9 +2088,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff-static"
|
name = "jiff-static"
|
||||||
version = "0.2.8"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605"
|
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2238,9 +2249,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.11"
|
version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredfish"
|
name = "libredfish"
|
||||||
@ -2947,7 +2958,7 @@ version = "0.2.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy 0.8.24",
|
"zerocopy 0.8.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3073,7 +3084,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3121,7 +3132,7 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
@ -3259,7 +3270,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.16",
|
||||||
"libc",
|
"libc",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@ -3806,9 +3817,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.2"
|
version = "1.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -3996,9 +4007,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -4079,6 +4090,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "temp-file"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5ff282c3f91797f0acb021f3af7fffa8a78601f0f2fd0a9f79ee7dcf9a9af9e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.19.1"
|
version = "3.19.1"
|
||||||
@ -4259,9 +4276,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.14"
|
version = "0.7.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
|
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -5096,11 +5113,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.24"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
|
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive 0.8.24",
|
"zerocopy-derive 0.8.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5116,9 +5133,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.24"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
|
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@ -35,6 +35,7 @@ serde_yaml = "0.9.34"
|
|||||||
serde-value = "0.7.0"
|
serde-value = "0.7.0"
|
||||||
http = "1.2.0"
|
http = "1.2.0"
|
||||||
inquire = "0.7.5"
|
inquire = "0.7.5"
|
||||||
|
convert_case = "0.8.0"
|
||||||
|
|
||||||
[workspace.dependencies.uuid]
|
[workspace.dependencies.uuid]
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
|||||||
@ -8,7 +8,7 @@ publish = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
harmony = { path = "../../harmony" }
|
harmony = { path = "../../harmony" }
|
||||||
harmony_tui = { path = "../../harmony_tui" }
|
harmony_cli = { path = "../../harmony_cli" }
|
||||||
harmony_types = { path = "../../harmony_types" }
|
harmony_types = { path = "../../harmony_types" }
|
||||||
cidr = { workspace = true }
|
cidr = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|||||||
@ -1,3 +1,85 @@
|
|||||||
<?php
|
<?php
|
||||||
print_r("Hello this is from 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>
|
||||||
|
|
||||||
|
|||||||
@ -8,17 +8,31 @@ use harmony::{
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
// let _ = env_logger::Builder::from_default_env().filter_level(log::LevelFilter::Info).try_init();
|
// 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 {
|
let lamp_stack = LAMPScore {
|
||||||
name: "harmony-lamp-demo".to_string(),
|
name: "harmony-lamp-demo".to_string(),
|
||||||
domain: Url::Url(url::Url::parse("https://lampdemo.harmony.nationtech.io").unwrap()),
|
domain: Url::Url(url::Url::parse("https://lampdemo.harmony.nationtech.io").unwrap()),
|
||||||
php_version: Version::from("8.4.4").unwrap(),
|
php_version: Version::from("8.4.4").unwrap(),
|
||||||
|
// This config can be extended as needed for more complicated configurations
|
||||||
config: LAMPConfig {
|
config: LAMPConfig {
|
||||||
project_root: "./php".into(),
|
project_root: "./php".into(),
|
||||||
|
database_size: format!("2Gi").into(),
|
||||||
..Default::default()
|
..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(
|
let mut maestro = Maestro::<K8sAnywhereTopology>::initialize(
|
||||||
Inventory::autoload(),
|
Inventory::autoload(),
|
||||||
K8sAnywhereTopology::new(),
|
K8sAnywhereTopology::new(),
|
||||||
@ -26,5 +40,7 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
maestro.register_all(vec![Box::new(lamp_stack)]);
|
maestro.register_all(vec![Box::new(lamp_stack)]);
|
||||||
harmony_tui::init(maestro).await.unwrap();
|
// 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.
|
||||||
|
|||||||
@ -13,23 +13,23 @@ rust-ipmi = "0.1.1"
|
|||||||
semver = "1.0.23"
|
semver = "1.0.23"
|
||||||
serde = { version = "1.0.209", features = ["derive"] }
|
serde = { version = "1.0.209", features = ["derive"] }
|
||||||
serde_json = "1.0.127"
|
serde_json = "1.0.127"
|
||||||
tokio = { workspace = true }
|
tokio.workspace = true
|
||||||
derive-new = { workspace = true }
|
derive-new.workspace = true
|
||||||
log = { workspace = true }
|
log.workspace = true
|
||||||
env_logger = { workspace = true }
|
env_logger.workspace = true
|
||||||
async-trait = { workspace = true }
|
async-trait.workspace = true
|
||||||
cidr = { workspace = true }
|
cidr.workspace = true
|
||||||
opnsense-config = { path = "../opnsense-config" }
|
opnsense-config = { path = "../opnsense-config" }
|
||||||
opnsense-config-xml = { path = "../opnsense-config-xml" }
|
opnsense-config-xml = { path = "../opnsense-config-xml" }
|
||||||
harmony_macros = { path = "../harmony_macros" }
|
harmony_macros = { path = "../harmony_macros" }
|
||||||
harmony_types = { path = "../harmony_types" }
|
harmony_types = { path = "../harmony_types" }
|
||||||
uuid = { workspace = true }
|
uuid.workspace = true
|
||||||
url = { workspace = true }
|
url.workspace = true
|
||||||
kube = { workspace = true }
|
kube.workspace = true
|
||||||
k8s-openapi = { workspace = true }
|
k8s-openapi.workspace = true
|
||||||
serde_yaml = { workspace = true }
|
serde_yaml.workspace = true
|
||||||
http = { workspace = true }
|
http.workspace = true
|
||||||
serde-value = { workspace = true }
|
serde-value.workspace = true
|
||||||
inquire.workspace = true
|
inquire.workspace = true
|
||||||
helm-wrapper-rs = "0.4.0"
|
helm-wrapper-rs = "0.4.0"
|
||||||
non-blank-string-rs = "1.0.4"
|
non-blank-string-rs = "1.0.4"
|
||||||
@ -37,3 +37,5 @@ k3d-rs = { path = "../k3d" }
|
|||||||
directories = "6.0.0"
|
directories = "6.0.0"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
dockerfile_builder = "0.1.5"
|
dockerfile_builder = "0.1.5"
|
||||||
|
temp-file = "0.1.9"
|
||||||
|
convert_case.workspace = true
|
||||||
|
|||||||
@ -6,4 +6,8 @@ lazy_static! {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.data_dir()
|
.data_dir()
|
||||||
.join("harmony");
|
.join("harmony");
|
||||||
|
pub static ref REGISTRY_URL: String = std::env::var("HARMONY_REGISTRY_URL")
|
||||||
|
.unwrap_or_else(|_| "hub.nationtech.io".to_string());
|
||||||
|
pub static ref REGISTRY_PROJECT: String =
|
||||||
|
std::env::var("HARMONY_REGISTRY_PROJECT").unwrap_or_else(|_| "harmony".to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ impl K8sClient {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn apply_namespaced<K>(&self, resource: &Vec<K>) -> Result<K, Error>
|
pub async fn apply_namespaced<K>(&self, resource: &Vec<K>, ns: Option<&str>) -> Result<K, Error>
|
||||||
where
|
where
|
||||||
K: Resource<Scope = NamespaceResourceScope>
|
K: Resource<Scope = NamespaceResourceScope>
|
||||||
+ Clone
|
+ Clone
|
||||||
@ -49,7 +49,10 @@ impl K8sClient {
|
|||||||
<K as kube::Resource>::DynamicType: Default,
|
<K as kube::Resource>::DynamicType: Default,
|
||||||
{
|
{
|
||||||
for r in resource.iter() {
|
for r in resource.iter() {
|
||||||
let api: Api<K> = Api::default_namespaced(self.client.clone());
|
let api: Api<K> = match ns {
|
||||||
|
Some(ns) => Api::namespaced(self.client.clone(), ns),
|
||||||
|
None => Api::default_namespaced(self.client.clone()),
|
||||||
|
};
|
||||||
api.create(&PostParams::default(), &r).await?;
|
api.create(&PostParams::default(), &r).await?;
|
||||||
}
|
}
|
||||||
todo!("")
|
todo!("")
|
||||||
|
|||||||
@ -6,9 +6,13 @@ use crate::topology::{HelmCommand, Topology};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use helm_wrapper_rs;
|
use helm_wrapper_rs;
|
||||||
use helm_wrapper_rs::blocking::{DefaultHelmExecutor, HelmExecutor};
|
use helm_wrapper_rs::blocking::{DefaultHelmExecutor, HelmExecutor};
|
||||||
|
use log::info;
|
||||||
pub use non_blank_string_rs::NonBlankString;
|
pub use non_blank_string_rs::NonBlankString;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use temp_file::TempFile;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct HelmChartScore {
|
pub struct HelmChartScore {
|
||||||
@ -17,6 +21,11 @@ pub struct HelmChartScore {
|
|||||||
pub chart_name: NonBlankString,
|
pub chart_name: NonBlankString,
|
||||||
pub chart_version: Option<NonBlankString>,
|
pub chart_version: Option<NonBlankString>,
|
||||||
pub values_overrides: Option<HashMap<NonBlankString, String>>,
|
pub values_overrides: Option<HashMap<NonBlankString, String>>,
|
||||||
|
pub values_yaml: Option<String>,
|
||||||
|
pub create_namespace: bool,
|
||||||
|
|
||||||
|
/// Wether to run `helm upgrade --install` under the hood or only install when not present
|
||||||
|
pub install_only: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Topology + HelmCommand> Score<T> for HelmChartScore {
|
impl<T: Topology + HelmCommand> Score<T> for HelmChartScore {
|
||||||
@ -48,16 +57,68 @@ impl<T: Topology + HelmCommand> Interpret<T> for HelmChartInterpret {
|
|||||||
.namespace
|
.namespace
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or_else(|| todo!("Get namespace from active kubernetes cluster"));
|
.unwrap_or_else(|| todo!("Get namespace from active kubernetes cluster"));
|
||||||
|
|
||||||
|
let tf: TempFile;
|
||||||
|
let yaml_path: Option<&Path> = match self.score.values_yaml.as_ref() {
|
||||||
|
Some(yaml_str) => {
|
||||||
|
tf = temp_file::with_contents(yaml_str.as_bytes());
|
||||||
|
Some(tf.path())
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let helm_executor = DefaultHelmExecutor::new();
|
let helm_executor = DefaultHelmExecutor::new();
|
||||||
|
|
||||||
|
let mut helm_options = Vec::new();
|
||||||
|
if self.score.create_namespace {
|
||||||
|
helm_options.push(NonBlankString::from_str("--create-namespace").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.score.install_only {
|
||||||
|
let chart_list = match helm_executor.list(Some(ns)) {
|
||||||
|
Ok(charts) => charts,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(InterpretError::new(format!(
|
||||||
|
"Failed to list scores in namespace {:?} because of error : {}",
|
||||||
|
self.score.namespace, e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if chart_list
|
||||||
|
.iter()
|
||||||
|
.any(|item| item.name == self.score.release_name.to_string())
|
||||||
|
{
|
||||||
|
info!(
|
||||||
|
"Release '{}' already exists in namespace '{}'. Skipping installation as install_only is true.",
|
||||||
|
self.score.release_name, ns
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
format!(
|
||||||
|
"Helm Chart '{}' already installed to namespace {ns} and install_only=true",
|
||||||
|
self.score.release_name
|
||||||
|
),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"Release '{}' not found in namespace '{}'. Proceeding with installation.",
|
||||||
|
self.score.release_name, ns
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let res = helm_executor.install_or_upgrade(
|
let res = helm_executor.install_or_upgrade(
|
||||||
&ns,
|
&ns,
|
||||||
&self.score.release_name,
|
&self.score.release_name,
|
||||||
&self.score.chart_name,
|
&self.score.chart_name,
|
||||||
self.score.chart_version.as_ref(),
|
self.score.chart_version.as_ref(),
|
||||||
self.score.values_overrides.as_ref(),
|
self.score.values_overrides.as_ref(),
|
||||||
None,
|
yaml_path,
|
||||||
None,
|
Some(&helm_options),
|
||||||
);
|
);
|
||||||
|
|
||||||
let status = match res {
|
let status = match res {
|
||||||
Ok(status) => status,
|
Ok(status) => status,
|
||||||
Err(err) => return Err(InterpretError::new(err.to_string())),
|
Err(err) => return Err(InterpretError::new(err.to_string())),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use k8s_openapi::api::apps::v1::Deployment;
|
use k8s_openapi::{DeepMerge, api::apps::v1::Deployment};
|
||||||
|
use log::debug;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
@ -14,11 +15,13 @@ use super::resource::{K8sResourceInterpret, K8sResourceScore};
|
|||||||
pub struct K8sDeploymentScore {
|
pub struct K8sDeploymentScore {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub image: String,
|
pub image: String,
|
||||||
|
pub namespace: Option<String>,
|
||||||
|
pub env_vars: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Topology + K8sclient> Score<T> for K8sDeploymentScore {
|
impl<T: Topology + K8sclient> Score<T> for K8sDeploymentScore {
|
||||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
let deployment: Deployment = serde_json::from_value(json!(
|
let deployment = json!(
|
||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"name": self.name
|
"name": self.name
|
||||||
@ -38,18 +41,21 @@ impl<T: Topology + K8sclient> Score<T> for K8sDeploymentScore {
|
|||||||
"spec": {
|
"spec": {
|
||||||
"containers": [
|
"containers": [
|
||||||
{
|
{
|
||||||
"image": self.image,
|
"image": self.image,
|
||||||
"name": self.image
|
"name": self.name,
|
||||||
|
"imagePullPolicy": "IfNotPresent",
|
||||||
|
"env": self.env_vars,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
);
|
||||||
.unwrap();
|
|
||||||
|
let deployment: Deployment = serde_json::from_value(deployment).unwrap();
|
||||||
Box::new(K8sResourceInterpret {
|
Box::new(K8sResourceInterpret {
|
||||||
score: K8sResourceScore::single(deployment.clone()),
|
score: K8sResourceScore::single(deployment.clone(), self.namespace.clone()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod deployment;
|
pub mod deployment;
|
||||||
|
pub mod namespace;
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
|
|||||||
46
harmony/src/modules/k8s/namespace.rs
Normal file
46
harmony/src/modules/k8s/namespace.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use k8s_openapi::api::core::v1::Namespace;
|
||||||
|
use non_blank_string_rs::NonBlankString;
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
interpret::Interpret,
|
||||||
|
score::Score,
|
||||||
|
topology::{K8sclient, Topology},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct K8sNamespaceScore {
|
||||||
|
pub name: Option<NonBlankString>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Topology + K8sclient> Score<T> for K8sNamespaceScore {
|
||||||
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
|
let name = match &self.name {
|
||||||
|
Some(name) => name,
|
||||||
|
None => todo!(
|
||||||
|
"Return NoOp interpret when no namespace specified or something that makes sense"
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let _namespace: Namespace = serde_json::from_value(json!(
|
||||||
|
{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Namespace",
|
||||||
|
"metadata": {
|
||||||
|
"name": name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
todo!(
|
||||||
|
"We currently only support namespaced ressources (see Scope = NamespaceResourceScope)"
|
||||||
|
);
|
||||||
|
// Box::new(K8sResourceInterpret {
|
||||||
|
// score: K8sResourceScore::single(namespace.clone()),
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"K8sNamespaceScore".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,12 +14,14 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct K8sResourceScore<K: Resource + std::fmt::Debug> {
|
pub struct K8sResourceScore<K: Resource + std::fmt::Debug> {
|
||||||
pub resource: Vec<K>,
|
pub resource: Vec<K>,
|
||||||
|
pub namespace: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Resource + std::fmt::Debug> K8sResourceScore<K> {
|
impl<K: Resource + std::fmt::Debug> K8sResourceScore<K> {
|
||||||
pub fn single(resource: K) -> Self {
|
pub fn single(resource: K, namespace: Option<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
resource: vec![resource],
|
resource: vec![resource],
|
||||||
|
namespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +79,7 @@ where
|
|||||||
.k8s_client()
|
.k8s_client()
|
||||||
.await
|
.await
|
||||||
.expect("Environment should provide enough information to instanciate a client")
|
.expect("Environment should provide enough information to instanciate a client")
|
||||||
.apply_namespaced(&self.score.resource)
|
.apply_namespaced(&self.score.resource, self.score.namespace.as_deref())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Outcome::success(
|
Ok(Outcome::success(
|
||||||
|
|||||||
@ -1,9 +1,19 @@
|
|||||||
|
use convert_case::{Case, Casing};
|
||||||
|
use dockerfile_builder::instruction::{CMD, COPY, ENV, EXPOSE, FROM, RUN, WORKDIR};
|
||||||
|
use dockerfile_builder::{Dockerfile, instruction_builder::EnvBuilder};
|
||||||
|
use non_blank_string_rs::NonBlankString;
|
||||||
|
use serde_json::json;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::info;
|
use log::{debug, info};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::config::{REGISTRY_PROJECT, REGISTRY_URL};
|
||||||
|
use crate::topology::HelmCommand;
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{Id, Version},
|
data::{Id, Version},
|
||||||
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||||
@ -13,6 +23,8 @@ use crate::{
|
|||||||
topology::{K8sclient, Topology, Url},
|
topology::{K8sclient, Topology, Url},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::helm::chart::HelmChartScore;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct LAMPScore {
|
pub struct LAMPScore {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -25,6 +37,7 @@ pub struct LAMPScore {
|
|||||||
pub struct LAMPConfig {
|
pub struct LAMPConfig {
|
||||||
pub project_root: PathBuf,
|
pub project_root: PathBuf,
|
||||||
pub ssl_enabled: bool,
|
pub ssl_enabled: bool,
|
||||||
|
pub database_size: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LAMPConfig {
|
impl Default for LAMPConfig {
|
||||||
@ -32,14 +45,16 @@ impl Default for LAMPConfig {
|
|||||||
LAMPConfig {
|
LAMPConfig {
|
||||||
project_root: Path::new("./src").to_path_buf(),
|
project_root: Path::new("./src").to_path_buf(),
|
||||||
ssl_enabled: true,
|
ssl_enabled: true,
|
||||||
|
database_size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Topology + K8sclient> Score<T> for LAMPScore {
|
impl<T: Topology + K8sclient + HelmCommand> Score<T> for LAMPScore {
|
||||||
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
fn create_interpret(&self) -> Box<dyn Interpret<T>> {
|
||||||
Box::new(LAMPInterpret {
|
Box::new(LAMPInterpret {
|
||||||
score: self.clone(),
|
score: self.clone(),
|
||||||
|
namespace: "harmony-lamp".to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +66,11 @@ impl<T: Topology + K8sclient> Score<T> for LAMPScore {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LAMPInterpret {
|
pub struct LAMPInterpret {
|
||||||
score: LAMPScore,
|
score: LAMPScore,
|
||||||
|
namespace: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: Topology + K8sclient> Interpret<T> for LAMPInterpret {
|
impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for LAMPInterpret {
|
||||||
async fn execute(
|
async fn execute(
|
||||||
&self,
|
&self,
|
||||||
inventory: &Inventory,
|
inventory: &Inventory,
|
||||||
@ -70,18 +86,54 @@ impl<T: Topology + K8sclient> Interpret<T> for LAMPInterpret {
|
|||||||
};
|
};
|
||||||
info!("LAMP docker image built {image_name}");
|
info!("LAMP docker image built {image_name}");
|
||||||
|
|
||||||
|
let remote_name = match self.push_docker_image(&image_name) {
|
||||||
|
Ok(remote_name) => remote_name,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(InterpretError::new(format!(
|
||||||
|
"Could not push docker image {e}"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
info!("LAMP docker image pushed to {remote_name}");
|
||||||
|
|
||||||
|
info!("Deploying database");
|
||||||
|
self.deploy_database(inventory, topology).await?;
|
||||||
|
|
||||||
|
let base_name = self.score.name.to_case(Case::Kebab);
|
||||||
|
let secret_name = format!("{}-database-mariadb", base_name);
|
||||||
|
|
||||||
let deployment_score = K8sDeploymentScore {
|
let deployment_score = K8sDeploymentScore {
|
||||||
name: <LAMPScore as Score<T>>::name(&self.score),
|
name: <LAMPScore as Score<T>>::name(&self.score).to_case(Case::Kebab),
|
||||||
image: image_name,
|
image: remote_name,
|
||||||
|
namespace: self.get_namespace().map(|nbs| nbs.to_string()),
|
||||||
|
env_vars: json!([
|
||||||
|
{
|
||||||
|
"name": "MYSQL_PASSWORD",
|
||||||
|
"valueFrom": {
|
||||||
|
"secretKeyRef": {
|
||||||
|
"name": secret_name,
|
||||||
|
"key": "mariadb-root-password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MYSQL_HOST",
|
||||||
|
"value": secret_name
|
||||||
|
},
|
||||||
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("LAMP deployment_score {deployment_score:?}");
|
info!("Deploying score {deployment_score:#?}");
|
||||||
todo!();
|
|
||||||
deployment_score
|
deployment_score
|
||||||
.create_interpret()
|
.create_interpret()
|
||||||
.execute(inventory, topology)
|
.execute(inventory, topology)
|
||||||
.await?;
|
.await?;
|
||||||
todo!()
|
|
||||||
|
info!("LAMP deployment_score {deployment_score:?}");
|
||||||
|
todo!("1. [x] Use HelmChartScore to deploy mariadb
|
||||||
|
2. [x] Use deploymentScore to deploy lamp docker container
|
||||||
|
3. for remote clusters, push the image to some registry (use nationtech's for demos? push to the cluster's registry?)");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_name(&self) -> InterpretName {
|
fn get_name(&self) -> InterpretName {
|
||||||
@ -101,15 +153,37 @@ impl<T: Topology + K8sclient> Interpret<T> for LAMPInterpret {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use dockerfile_builder::instruction::{CMD, COPY, ENV, EXPOSE, FROM, RUN, WORKDIR};
|
|
||||||
use dockerfile_builder::{Dockerfile, instruction_builder::EnvBuilder};
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
impl LAMPInterpret {
|
impl LAMPInterpret {
|
||||||
pub fn build_dockerfile(
|
async fn deploy_database<T: Topology + K8sclient + HelmCommand>(
|
||||||
&self,
|
&self,
|
||||||
score: &LAMPScore,
|
inventory: &Inventory,
|
||||||
) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
topology: &T,
|
||||||
|
) -> Result<Outcome, InterpretError> {
|
||||||
|
let mut values_overrides = HashMap::new();
|
||||||
|
if let Some(database_size) = self.score.config.database_size.clone() {
|
||||||
|
values_overrides.insert(
|
||||||
|
NonBlankString::from_str("primary.persistence.size").unwrap(),
|
||||||
|
database_size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let score = HelmChartScore {
|
||||||
|
namespace: self.get_namespace(),
|
||||||
|
release_name: NonBlankString::from_str(&format!("{}-database", self.score.name))
|
||||||
|
.unwrap(),
|
||||||
|
chart_name: NonBlankString::from_str(
|
||||||
|
"oci://registry-1.docker.io/bitnamicharts/mariadb",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
chart_version: None,
|
||||||
|
values_overrides: Some(values_overrides),
|
||||||
|
create_namespace: true,
|
||||||
|
install_only: true,
|
||||||
|
values_yaml: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
score.create_interpret().execute(inventory, topology).await
|
||||||
|
}
|
||||||
|
fn build_dockerfile(&self, score: &LAMPScore) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
let mut dockerfile = Dockerfile::new();
|
let mut dockerfile = Dockerfile::new();
|
||||||
|
|
||||||
// Use the PHP version from the score to determine the base image
|
// Use the PHP version from the score to determine the base image
|
||||||
@ -196,6 +270,13 @@ opcache.fast_shutdown=1
|
|||||||
sed -i 's/ServerSignature On/ServerSignature Off/' /etc/apache2/conf-enabled/security.conf"
|
sed -i 's/ServerSignature On/ServerSignature Off/' /etc/apache2/conf-enabled/security.conf"
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Set env vars
|
||||||
|
dockerfile.push(RUN::from(
|
||||||
|
"echo 'PassEnv MYSQL_PASSWORD' >> /etc/apache2/sites-available/000-default.conf \
|
||||||
|
&& echo 'PassEnv MYSQL_USER' >> /etc/apache2/sites-available/000-default.conf \
|
||||||
|
&& echo 'PassEnv MYSQL_HOST' >> /etc/apache2/sites-available/000-default.conf",
|
||||||
|
));
|
||||||
|
|
||||||
// Create a dedicated user for running Apache
|
// Create a dedicated user for running Apache
|
||||||
dockerfile.push(RUN::from(
|
dockerfile.push(RUN::from(
|
||||||
"groupadd -g 1000 appuser && \
|
"groupadd -g 1000 appuser && \
|
||||||
@ -227,6 +308,43 @@ opcache.fast_shutdown=1
|
|||||||
Ok(dockerfile_path)
|
Ok(dockerfile_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_output(
|
||||||
|
&self,
|
||||||
|
output: &std::process::Output,
|
||||||
|
msg: &str,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(format!("{msg}: {}", String::from_utf8_lossy(&output.stderr)).into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_docker_image(&self, image_name: &str) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
let full_tag = format!("{}/{}/{}", *REGISTRY_URL, *REGISTRY_PROJECT, &image_name);
|
||||||
|
let output = std::process::Command::new("docker")
|
||||||
|
.args(["tag", image_name, &full_tag])
|
||||||
|
.output()?;
|
||||||
|
self.check_output(&output, "Tagging docker image failed")?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"docker tag output {} {}",
|
||||||
|
String::from_utf8_lossy(&output.stdout),
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = std::process::Command::new("docker")
|
||||||
|
.args(["push", &full_tag])
|
||||||
|
.output()?;
|
||||||
|
self.check_output(&output, "Pushing docker image failed")?;
|
||||||
|
debug!(
|
||||||
|
"docker push output {} {}",
|
||||||
|
String::from_utf8_lossy(&output.stdout),
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(full_tag)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_docker_image(&self) -> Result<String, Box<dyn std::error::Error>> {
|
pub fn build_docker_image(&self) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
info!("Generating Dockerfile");
|
info!("Generating Dockerfile");
|
||||||
let dockerfile = self.build_dockerfile(&self.score)?;
|
let dockerfile = self.build_dockerfile(&self.score)?;
|
||||||
@ -260,4 +378,8 @@ opcache.fast_shutdown=1
|
|||||||
|
|
||||||
Ok(image_name)
|
Ok(image_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_namespace(&self) -> Option<NonBlankString> {
|
||||||
|
Some(NonBlankString::from_str(&self.namespace).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,14 +4,14 @@ pub mod modules;
|
|||||||
|
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
#[cfg(e2e_test)]
|
||||||
|
mod e2e_test {
|
||||||
use opnsense_config_xml::StaticMap;
|
use opnsense_config_xml::StaticMap;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
|
|
||||||
#[cfg(opnsenseendtoend)]
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_public_sdk() {
|
async fn test_public_sdk() {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user