Compare commits
1 Commits
master
...
06ea40e1e0
Author | SHA1 | Date | |
---|---|---|---|
06ea40e1e0 |
@ -46,9 +46,8 @@ steps:
|
|||||||
- cd virtweb_backend
|
- cd virtweb_backend
|
||||||
- mv /tmp/web_build/dist static
|
- mv /tmp/web_build/dist static
|
||||||
- cargo build --release
|
- cargo build --release
|
||||||
- cargo build --release --example api_curl
|
- ls -lah target/release/virtweb_backend
|
||||||
- ls -lah target/release/virtweb_backend target/release/examples/api_curl
|
- cp target/release/virtweb_backend /tmp/release
|
||||||
- cp target/release/virtweb_backend target/release/examples/api_curl /tmp/release
|
|
||||||
|
|
||||||
- name: gitea_release
|
- name: gitea_release
|
||||||
image: plugins/gitea-release
|
image: plugins/gitea-release
|
||||||
|
200
virtweb_backend/Cargo.lock
generated
200
virtweb_backend/Cargo.lock
generated
@ -435,21 +435,6 @@ dependencies = [
|
|||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android-tzdata"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.18"
|
version = "0.6.18"
|
||||||
@ -511,9 +496,6 @@ name = "arbitrary"
|
|||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||||
dependencies = [
|
|
||||||
"derive_arbitrary",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arg_enum_proc_macro"
|
name = "arg_enum_proc_macro"
|
||||||
@ -733,25 +715,6 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bzip2"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
|
|
||||||
dependencies = [
|
|
||||||
"bzip2-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bzip2-sys"
|
|
||||||
version = "0.1.13+1.0.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.23"
|
version = "1.2.23"
|
||||||
@ -785,20 +748,6 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.41"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
|
||||||
dependencies = [
|
|
||||||
"android-tzdata",
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-traits",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@ -867,12 +816,6 @@ version = "0.9.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "constant_time_eq"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@ -1038,12 +981,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deflate64"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
@ -1064,17 +1001,6 @@ dependencies = [
|
|||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_arbitrary"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.20"
|
version = "0.99.20"
|
||||||
@ -1295,7 +1221,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"libz-rs-sys",
|
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1455,11 +1380,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi",
|
||||||
"wasi 0.14.2+wasi-0.2.4",
|
"wasi 0.14.2+wasi-0.2.4",
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1718,30 +1641,6 @@ dependencies = [
|
|||||||
"windows-registry",
|
"windows-registry",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.63"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"log",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"windows-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -2098,26 +1997,6 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "liblzma"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "66352d7a8ac12d4877b6e6ea5a9b7650ee094257dc40889955bea5bc5b08c1d0"
|
|
||||||
dependencies = [
|
|
||||||
"liblzma-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "liblzma-sys"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libyml"
|
name = "libyml"
|
||||||
version = "0.0.5"
|
version = "0.0.5"
|
||||||
@ -2128,15 +2007,6 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libz-rs-sys"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221"
|
|
||||||
dependencies = [
|
|
||||||
"zlib-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "light-openid"
|
name = "light-openid"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -2559,16 +2429,6 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pbkdf2"
|
|
||||||
version = "0.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
|
||||||
dependencies = [
|
|
||||||
"digest",
|
|
||||||
"hmac",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pem"
|
name = "pem"
|
||||||
version = "3.0.5"
|
version = "3.0.5"
|
||||||
@ -3921,7 +3781,6 @@ dependencies = [
|
|||||||
"actix-ws",
|
"actix-ws",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"basic-jwt",
|
"basic-jwt",
|
||||||
"chrono",
|
|
||||||
"clap",
|
"clap",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@ -3949,7 +3808,6 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
"virt",
|
"virt",
|
||||||
"zip",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4488,20 +4346,6 @@ name = "zeroize"
|
|||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||||
dependencies = [
|
|
||||||
"zeroize_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zeroize_derive"
|
|
||||||
version = "1.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
@ -4536,50 +4380,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zip"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af7dcdb4229c0e79c2531a24de7726a0e980417a74fb4d030a35f535665439a0"
|
|
||||||
dependencies = [
|
|
||||||
"aes",
|
|
||||||
"arbitrary",
|
|
||||||
"bzip2",
|
|
||||||
"constant_time_eq",
|
|
||||||
"crc32fast",
|
|
||||||
"deflate64",
|
|
||||||
"flate2",
|
|
||||||
"getrandom 0.3.3",
|
|
||||||
"hmac",
|
|
||||||
"indexmap",
|
|
||||||
"liblzma",
|
|
||||||
"memchr",
|
|
||||||
"pbkdf2",
|
|
||||||
"sha1",
|
|
||||||
"time",
|
|
||||||
"zeroize",
|
|
||||||
"zopfli",
|
|
||||||
"zstd",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zlib-rs"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zopfli"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"crc32fast",
|
|
||||||
"log",
|
|
||||||
"simd-adler32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zstd"
|
name = "zstd"
|
||||||
version = "0.13.3"
|
version = "0.13.3"
|
||||||
|
@ -45,5 +45,3 @@ rust-embed = { version = "8.7.2", features = ["mime-guess"] }
|
|||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
nix = { version = "0.30.1", features = ["net"] }
|
nix = { version = "0.30.1", features = ["net"] }
|
||||||
basic-jwt = "0.3.0"
|
basic-jwt = "0.3.0"
|
||||||
zip = "4.1.0"
|
|
||||||
chrono = "0.4.41"
|
|
@ -4,7 +4,6 @@ use actix_web::body::BoxBody;
|
|||||||
use actix_web::{HttpResponse, web};
|
use actix_web::{HttpResponse, web};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use zip::result::ZipError;
|
|
||||||
|
|
||||||
pub mod api_tokens_controller;
|
pub mod api_tokens_controller;
|
||||||
pub mod auth_controller;
|
pub mod auth_controller;
|
||||||
@ -103,12 +102,6 @@ impl From<actix_web::Error> for HttpErr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ZipError> for HttpErr {
|
|
||||||
fn from(value: ZipError) -> Self {
|
|
||||||
HttpErr::Err(std::io::Error::other(value.to_string()).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HttpResponse> for HttpErr {
|
impl From<HttpResponse> for HttpErr {
|
||||||
fn from(value: HttpResponse) -> Self {
|
fn from(value: HttpResponse) -> Self {
|
||||||
HttpErr::HTTPResponse(value)
|
HttpErr::HTTPResponse(value)
|
||||||
|
@ -1,24 +1,14 @@
|
|||||||
use crate::actors::vnc_tokens_actor::VNC_TOKEN_LIFETIME;
|
use crate::actors::vnc_tokens_actor::VNC_TOKEN_LIFETIME;
|
||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
|
use crate::constants;
|
||||||
use crate::constants::{DISK_NAME_MAX_LEN, DISK_NAME_MIN_LEN, DISK_SIZE_MAX, DISK_SIZE_MIN};
|
use crate::constants::{DISK_NAME_MAX_LEN, DISK_NAME_MIN_LEN, DISK_SIZE_MAX, DISK_SIZE_MIN};
|
||||||
use crate::controllers::{HttpResult, LibVirtReq};
|
use crate::controllers::{HttpResult, LibVirtReq};
|
||||||
use crate::extractors::local_auth_extractor::LocalAuthEnabled;
|
use crate::extractors::local_auth_extractor::LocalAuthEnabled;
|
||||||
use crate::libvirt_rest_structures::hypervisor::HypervisorInfo;
|
use crate::libvirt_rest_structures::hypervisor::HypervisorInfo;
|
||||||
use crate::libvirt_rest_structures::net::NetworkInfo;
|
|
||||||
use crate::libvirt_rest_structures::nw_filter::NetworkFilter;
|
|
||||||
use crate::libvirt_rest_structures::vm::VMInfo;
|
|
||||||
use crate::nat::nat_hook;
|
use crate::nat::nat_hook;
|
||||||
use crate::utils::net_utils;
|
use crate::utils::net_utils;
|
||||||
use crate::utils::time_utils::{format_date, time};
|
use actix_web::{HttpResponse, Responder};
|
||||||
use crate::{api_tokens, constants};
|
|
||||||
use actix_files::NamedFile;
|
|
||||||
use actix_web::{HttpRequest, HttpResponse, Responder};
|
|
||||||
use serde::Serialize;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use sysinfo::{Components, Disks, Networks, System};
|
use sysinfo::{Components, Disks, Networks, System};
|
||||||
use zip::ZipWriter;
|
|
||||||
use zip::write::SimpleFileOptions;
|
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
struct StaticConfig {
|
struct StaticConfig {
|
||||||
@ -209,85 +199,3 @@ pub async fn networks_list() -> HttpResult {
|
|||||||
pub async fn bridges_list() -> HttpResult {
|
pub async fn bridges_list() -> HttpResult {
|
||||||
Ok(HttpResponse::Ok().json(net_utils::bridges_list()?))
|
Ok(HttpResponse::Ok().json(net_utils::bridges_list()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add JSON file to ZIP
|
|
||||||
fn zip_json<E: Serialize, F>(
|
|
||||||
zip: &mut ZipWriter<File>,
|
|
||||||
dir: &str,
|
|
||||||
content: &Vec<E>,
|
|
||||||
file_name: F,
|
|
||||||
) -> anyhow::Result<()>
|
|
||||||
where
|
|
||||||
F: Fn(&E) -> String,
|
|
||||||
{
|
|
||||||
for entry in content {
|
|
||||||
let file_encoded = serde_json::to_string(&entry)?;
|
|
||||||
|
|
||||||
let options = SimpleFileOptions::default()
|
|
||||||
.compression_method(zip::CompressionMethod::Deflated)
|
|
||||||
.unix_permissions(0o750);
|
|
||||||
|
|
||||||
zip.start_file(format!("{dir}/{}.json", file_name(entry)), options)?;
|
|
||||||
zip.write_all(file_encoded.as_bytes())?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Export all configuration elements at once
|
|
||||||
pub async fn export_all_configs(req: HttpRequest, client: LibVirtReq) -> HttpResult {
|
|
||||||
// Perform extractions
|
|
||||||
let vms = client
|
|
||||||
.get_full_domains_list()
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.map(VMInfo::from_domain)
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
let networks = client
|
|
||||||
.get_full_networks_list()
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.map(NetworkInfo::from_xml)
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
let nw_filters = client
|
|
||||||
.get_full_network_filters_list()
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.map(NetworkFilter::lib2rest)
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
let tokens = api_tokens::full_list().await?;
|
|
||||||
|
|
||||||
// Create ZIP file
|
|
||||||
let dest_dir = tempfile::tempdir_in(&AppConfig::get().temp_dir)?;
|
|
||||||
let zip_path = dest_dir.path().join("export.zip");
|
|
||||||
|
|
||||||
let file = File::create(&zip_path)?;
|
|
||||||
let mut zip = ZipWriter::new(file);
|
|
||||||
|
|
||||||
// Encode entities to JSON
|
|
||||||
zip_json(&mut zip, "vms", &vms, |v| v.name.to_string())?;
|
|
||||||
zip_json(&mut zip, "networks", &networks, |v| v.name.0.to_string())?;
|
|
||||||
zip_json(
|
|
||||||
&mut zip,
|
|
||||||
"nw_filters",
|
|
||||||
&nw_filters,
|
|
||||||
|v| match constants::BUILTIN_NETWORK_FILTER_RULES.contains(&v.name.0.as_str()) {
|
|
||||||
true => format!("builtin/{}", v.name.0),
|
|
||||||
false => v.name.0.to_string(),
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
zip_json(&mut zip, "tokens", &tokens, |v| v.id.0.to_string())?;
|
|
||||||
|
|
||||||
// Finalize ZIP and return response
|
|
||||||
zip.finish()?;
|
|
||||||
let file = File::open(zip_path)?;
|
|
||||||
|
|
||||||
let file = NamedFile::from_file(
|
|
||||||
file,
|
|
||||||
format!(
|
|
||||||
"export_{}.zip",
|
|
||||||
format_date(time() as i64).unwrap().replace('/', "-")
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(file.into_response(&req))
|
|
||||||
}
|
|
||||||
|
@ -157,10 +157,6 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/server/bridges",
|
"/api/server/bridges",
|
||||||
web::get().to(server_controller::bridges_list),
|
web::get().to(server_controller::bridges_list),
|
||||||
)
|
)
|
||||||
.route(
|
|
||||||
"/api/server/export_configs",
|
|
||||||
web::get().to(server_controller::export_all_configs),
|
|
||||||
)
|
|
||||||
// Auth controller
|
// Auth controller
|
||||||
.route(
|
.route(
|
||||||
"/api/auth/local",
|
"/api/auth/local",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use chrono::Datelike;
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
/// Get the current time since epoch
|
/// Get the current time since epoch
|
||||||
@ -14,15 +13,3 @@ pub fn time() -> u64 {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs()
|
.as_secs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format given UNIX time in a simple format
|
|
||||||
pub fn format_date(time: i64) -> anyhow::Result<String> {
|
|
||||||
let date = chrono::DateTime::from_timestamp(time, 0).ok_or(anyhow::anyhow!("invalid date"))?;
|
|
||||||
|
|
||||||
Ok(format!(
|
|
||||||
"{:0>2}/{:0>2}/{}",
|
|
||||||
date.day(),
|
|
||||||
date.month(),
|
|
||||||
date.year()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
19
virtweb_frontend/package-lock.json
generated
19
virtweb_frontend/package-lock.json
generated
@ -10,7 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@fontsource/roboto": "^5.2.6",
|
"@fontsource/roboto": "^5.2.5",
|
||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
@ -29,14 +29,13 @@
|
|||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"react-vnc": "^3.1.0",
|
"react-vnc": "^3.1.0",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"xml-formatter": "^3.6.6",
|
"xml-formatter": "^3.6.6"
|
||||||
"yaml": "^2.8.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.27.0",
|
"@eslint/js": "^9.27.0",
|
||||||
"@types/humanize-duration": "^3.27.4",
|
"@types/humanize-duration": "^3.27.4",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.6",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
@ -781,9 +780,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@fontsource/roboto": {
|
"node_modules/@fontsource/roboto": {
|
||||||
"version": "5.2.6",
|
"version": "5.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.2.5.tgz",
|
||||||
"integrity": "sha512-hzarG7yAhMoP418smNgfY4fO7UmuUEm5JUtbxCoCcFHT0hOJB+d/qAEyoNjz7YkPU5OjM2LM8rJnW8hfm0JLaA==",
|
"integrity": "sha512-70r2UZ0raqLn5W+sPeKhqlf8wGvUXFWlofaDlcbt/S3d06+17gXKr3VNqDODB0I1ASme3dGT5OJj9NABt7OTZQ==",
|
||||||
"license": "OFL-1.1",
|
"license": "OFL-1.1",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ayuhito"
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
@ -1625,9 +1624,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.1.8",
|
"version": "19.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.6.tgz",
|
||||||
"integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
|
"integrity": "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@fontsource/roboto": "^5.2.6",
|
"@fontsource/roboto": "^5.2.5",
|
||||||
"@mdi/js": "^7.4.47",
|
"@mdi/js": "^7.4.47",
|
||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
@ -31,14 +31,13 @@
|
|||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"react-vnc": "^3.1.0",
|
"react-vnc": "^3.1.0",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"xml-formatter": "^3.6.6",
|
"xml-formatter": "^3.6.6"
|
||||||
"yaml": "^2.8.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.27.0",
|
"@eslint/js": "^9.27.0",
|
||||||
"@types/humanize-duration": "^3.27.4",
|
"@types/humanize-duration": "^3.27.4",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.6",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
|
@ -232,16 +232,4 @@ export class ServerApi {
|
|||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Export all server configs
|
|
||||||
*/
|
|
||||||
static async ExportServerConfigs(): Promise<Blob> {
|
|
||||||
return (
|
|
||||||
await APIClient.exec({
|
|
||||||
method: "GET",
|
|
||||||
uri: "/server/export_configs",
|
|
||||||
})
|
|
||||||
).data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,21 +9,18 @@ import {
|
|||||||
import Icon from "@mdi/react";
|
import Icon from "@mdi/react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
|
||||||
LinearProgress,
|
LinearProgress,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
import { PieChart } from "@mui/x-charts";
|
import { PieChart } from "@mui/x-charts";
|
||||||
import { filesize } from "filesize";
|
import { filesize } from "filesize";
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
import IosShareIcon from "@mui/icons-material/IosShare";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
DiskInfo,
|
DiskInfo,
|
||||||
@ -34,8 +31,6 @@ import {
|
|||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { VirtWebPaper } from "../widgets/VirtWebPaper";
|
import { VirtWebPaper } from "../widgets/VirtWebPaper";
|
||||||
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
|
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
|
||||||
import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
|
|
||||||
import { useAlert } from "../hooks/providers/AlertDialogProvider";
|
|
||||||
|
|
||||||
export function SysInfoRoute(): React.ReactElement {
|
export function SysInfoRoute(): React.ReactElement {
|
||||||
const [info, setInfo] = React.useState<ServerSystemInfo>();
|
const [info, setInfo] = React.useState<ServerSystemInfo>();
|
||||||
@ -57,23 +52,6 @@ export function SysInfoRoute(): React.ReactElement {
|
|||||||
export function SysInfoRouteInner(p: {
|
export function SysInfoRouteInner(p: {
|
||||||
info: ServerSystemInfo;
|
info: ServerSystemInfo;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
const alert = useAlert();
|
|
||||||
const loadingMessage = useLoadingMessage();
|
|
||||||
const downloadAllConfig = async () => {
|
|
||||||
try {
|
|
||||||
loadingMessage.show("Downloading server config...");
|
|
||||||
const res = await ServerApi.ExportServerConfigs();
|
|
||||||
|
|
||||||
const url = URL.createObjectURL(res);
|
|
||||||
window.location.href = url;
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to download server config!", e);
|
|
||||||
alert(`Failed to download server config! ${e}`);
|
|
||||||
} finally {
|
|
||||||
loadingMessage.hide();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sumDiskUsage = p.info.disks.reduce(
|
const sumDiskUsage = p.info.disks.reduce(
|
||||||
(prev, disk) => {
|
(prev, disk) => {
|
||||||
return {
|
return {
|
||||||
@ -85,16 +63,7 @@ export function SysInfoRouteInner(p: {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtWebRouteContainer
|
<VirtWebRouteContainer label="Sysinfo">
|
||||||
label="Sysinfo"
|
|
||||||
actions={
|
|
||||||
<Tooltip title="Export all server configs">
|
|
||||||
<IconButton onClick={downloadAllConfig}>
|
|
||||||
<IosShareIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{/* Memory */}
|
{/* Memory */}
|
||||||
<Grid size={{ xs: 4 }}>
|
<Grid size={{ xs: 4 }}>
|
||||||
|
@ -17,9 +17,7 @@ export function CheckboxInput(p: {
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
disabled={!p.editable}
|
disabled={!p.editable}
|
||||||
checked={p.checked}
|
checked={p.checked}
|
||||||
onChange={(e) => {
|
onChange={(e) => { p.onValueChange(e.target.checked); }}
|
||||||
p.onValueChange(e.target.checked);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label={p.label}
|
label={p.label}
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-base-to-string */
|
|
||||||
|
|
||||||
import Editor from "@monaco-editor/react";
|
import Editor from "@monaco-editor/react";
|
||||||
import BookIcon from "@mui/icons-material/Book";
|
|
||||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||||
import { Grid, IconButton, InputAdornment, Tooltip } from "@mui/material";
|
import { Grid, IconButton, InputAdornment, Tooltip } from "@mui/material";
|
||||||
import React from "react";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import YAML from "yaml";
|
|
||||||
import { VMInfo } from "../../api/VMApi";
|
import { VMInfo } from "../../api/VMApi";
|
||||||
import { RouterLink } from "../RouterLink";
|
|
||||||
import { CheckboxInput } from "./CheckboxInput";
|
import { CheckboxInput } from "./CheckboxInput";
|
||||||
import { EditSection } from "./EditSection";
|
import { EditSection } from "./EditSection";
|
||||||
import { SelectInput } from "./SelectInput";
|
import { SelectInput } from "./SelectInput";
|
||||||
@ -44,14 +38,6 @@ export function CloudInitEditor(p: CloudInitProps): React.ReactElement {
|
|||||||
{...p}
|
{...p}
|
||||||
editable={p.editable && p.vm.cloud_init.attach_config}
|
editable={p.editable && p.vm.cloud_init.attach_config}
|
||||||
/>
|
/>
|
||||||
<CloudInitNetworkConfig
|
|
||||||
{...p}
|
|
||||||
editable={p.editable && p.vm.cloud_init.attach_config}
|
|
||||||
/>
|
|
||||||
<CloudInitUserDataAssistant
|
|
||||||
{...p}
|
|
||||||
editable={p.editable && p.vm.cloud_init.attach_config}
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@ -122,27 +108,12 @@ function CloudInitMetadata(p: CloudInitProps): React.ReactElement {
|
|||||||
|
|
||||||
function CloudInitRawUserData(p: CloudInitProps): React.ReactElement {
|
function CloudInitRawUserData(p: CloudInitProps): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<EditSection
|
<EditSection title="User data">
|
||||||
title="User data"
|
|
||||||
actions={
|
|
||||||
<RouterLink
|
|
||||||
target="_blank"
|
|
||||||
to="https://cloudinit.readthedocs.io/en/latest/reference/index.html"
|
|
||||||
>
|
|
||||||
<Tooltip title="Official reference">
|
|
||||||
<IconButton size="small">
|
|
||||||
<BookIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</RouterLink>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Editor
|
<Editor
|
||||||
theme="vs-dark"
|
theme="vs-dark"
|
||||||
options={{
|
options={{
|
||||||
readOnly: !p.editable,
|
readOnly: !p.editable,
|
||||||
quickSuggestions: { other: true, comments: true, strings: true },
|
quickSuggestions: { other: true, comments: true, strings: true },
|
||||||
wordWrap: "on",
|
|
||||||
}}
|
}}
|
||||||
language="yaml"
|
language="yaml"
|
||||||
height={"30vh"}
|
height={"30vh"}
|
||||||
@ -155,187 +126,3 @@ function CloudInitRawUserData(p: CloudInitProps): React.ReactElement {
|
|||||||
</EditSection>
|
</EditSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CloudInitNetworkConfig(p: CloudInitProps): React.ReactElement {
|
|
||||||
if (!p.editable && !p.vm.cloud_init.network_configuration) return <></>;
|
|
||||||
return (
|
|
||||||
<EditSection
|
|
||||||
title="Network configuration"
|
|
||||||
actions={
|
|
||||||
<RouterLink
|
|
||||||
target="_blank"
|
|
||||||
to="https://cloudinit.readthedocs.io/en/latest/reference/network-config-format-v2.html"
|
|
||||||
>
|
|
||||||
<Tooltip title="Official network configuration reference">
|
|
||||||
<IconButton size="small">
|
|
||||||
<BookIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</RouterLink>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Editor
|
|
||||||
theme="vs-dark"
|
|
||||||
options={{
|
|
||||||
readOnly: !p.editable,
|
|
||||||
quickSuggestions: { other: true, comments: true, strings: true },
|
|
||||||
wordWrap: "on",
|
|
||||||
}}
|
|
||||||
language="yaml"
|
|
||||||
height={"30vh"}
|
|
||||||
value={p.vm.cloud_init.network_configuration ?? ""}
|
|
||||||
onChange={(v) => {
|
|
||||||
if (v && v !== "") p.vm.cloud_init.network_configuration = v;
|
|
||||||
else p.vm.cloud_init.network_configuration = undefined;
|
|
||||||
p.onChange?.();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</EditSection>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CloudInitUserDataAssistant(p: CloudInitProps): React.ReactElement {
|
|
||||||
const user_data = React.useMemo(() => {
|
|
||||||
return YAML.parseDocument(p.vm.cloud_init.user_data);
|
|
||||||
}, [p.vm.cloud_init.user_data]);
|
|
||||||
|
|
||||||
const onChange = () => {
|
|
||||||
p.vm.cloud_init.user_data = user_data.toString();
|
|
||||||
|
|
||||||
if (!p.vm.cloud_init.user_data.startsWith("#cloud-config"))
|
|
||||||
p.vm.cloud_init.user_data = `#cloud-config\n${p.vm.cloud_init.user_data}`;
|
|
||||||
|
|
||||||
p.onChange?.();
|
|
||||||
};
|
|
||||||
|
|
||||||
const SYSTEMD_NOT_SERIAL = `/bin/sh -c "rm -f /etc/default/grub.d/50-cloudimg-settings.cfg && sed -i 's/quiet splash//g' /etc/default/grub && update-grub"`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EditSection title="User data assistant">
|
|
||||||
<CloudInitTextInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Default user name"
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#set-passwords"
|
|
||||||
attrPath={["user", "name"]}
|
|
||||||
onChange={onChange}
|
|
||||||
yaml={user_data}
|
|
||||||
/>
|
|
||||||
<CloudInitTextInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Default user password"
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#set-passwords"
|
|
||||||
attrPath={["password"]}
|
|
||||||
onChange={onChange}
|
|
||||||
yaml={user_data}
|
|
||||||
/>
|
|
||||||
<CloudInitBooleanInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Expire password to require new password on next login"
|
|
||||||
yaml={user_data}
|
|
||||||
attrPath={["chpasswd", "expire"]}
|
|
||||||
onChange={onChange}
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#set-passwords"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<CloudInitBooleanInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Enable SSH password auth"
|
|
||||||
yaml={user_data}
|
|
||||||
attrPath={["ssh_pwauth"]}
|
|
||||||
onChange={onChange}
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#set-passwords"
|
|
||||||
/>
|
|
||||||
<CloudInitTextInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Keyboard layout"
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#keyboard"
|
|
||||||
attrPath={["keyboard", "layout"]}
|
|
||||||
onChange={onChange}
|
|
||||||
yaml={user_data}
|
|
||||||
/>
|
|
||||||
<CloudInitTextInput
|
|
||||||
editable={p.editable}
|
|
||||||
name="Final message"
|
|
||||||
refUrl="https://cloudinit.readthedocs.io/en/latest/reference/modules.html#final-message"
|
|
||||||
attrPath={["final_message"]}
|
|
||||||
onChange={onChange}
|
|
||||||
yaml={user_data}
|
|
||||||
/>
|
|
||||||
{/* /bin/sh -c "rm -f /etc/default/grub.d/50-cloudimg-settings.cfg && update-grub" */}
|
|
||||||
<CheckboxInput
|
|
||||||
editable={p.editable}
|
|
||||||
label="Show all startup messages on tty1, not serial"
|
|
||||||
checked={
|
|
||||||
!!(user_data.get("runcmd") as any)?.items.find(
|
|
||||||
(a: any) => a.value === SYSTEMD_NOT_SERIAL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onValueChange={(c) => {
|
|
||||||
if (!user_data.getIn(["runcmd"])) user_data.addIn(["runcmd"], []);
|
|
||||||
|
|
||||||
const runcmd = user_data.getIn(["runcmd"]) as any;
|
|
||||||
|
|
||||||
if (c) {
|
|
||||||
runcmd.addIn([], SYSTEMD_NOT_SERIAL);
|
|
||||||
} else {
|
|
||||||
const idx = runcmd.items.findIndex(
|
|
||||||
(o: any) => o.value === SYSTEMD_NOT_SERIAL
|
|
||||||
);
|
|
||||||
runcmd.items.splice(idx, 1);
|
|
||||||
}
|
|
||||||
onChange();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</EditSection>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CloudInitTextInput(p: {
|
|
||||||
editable: boolean;
|
|
||||||
name: string;
|
|
||||||
refUrl: string;
|
|
||||||
attrPath: Iterable<unknown>;
|
|
||||||
yaml: YAML.Document;
|
|
||||||
onChange?: () => void;
|
|
||||||
}): React.ReactElement {
|
|
||||||
return (
|
|
||||||
<TextInput
|
|
||||||
editable={p.editable}
|
|
||||||
label={p.name}
|
|
||||||
value={String(p.yaml.getIn(p.attrPath) ?? "")}
|
|
||||||
onValueChange={(v) => {
|
|
||||||
if (v !== undefined) p.yaml.setIn(p.attrPath, v);
|
|
||||||
else p.yaml.deleteIn(p.attrPath);
|
|
||||||
p.onChange?.();
|
|
||||||
}}
|
|
||||||
endAdornment={
|
|
||||||
<RouterLink to={p.refUrl} target="_blank">
|
|
||||||
<IconButton size="small">
|
|
||||||
<BookIcon />
|
|
||||||
</IconButton>
|
|
||||||
</RouterLink>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function CloudInitBooleanInput(p: {
|
|
||||||
editable: boolean;
|
|
||||||
name: string;
|
|
||||||
refUrl: string;
|
|
||||||
attrPath: Iterable<unknown>;
|
|
||||||
yaml: YAML.Document;
|
|
||||||
onChange?: () => void;
|
|
||||||
}): React.ReactElement {
|
|
||||||
return (
|
|
||||||
<CheckboxInput
|
|
||||||
editable={p.editable}
|
|
||||||
label={p.name}
|
|
||||||
checked={p.yaml.getIn(p.attrPath) === true}
|
|
||||||
onValueChange={(v) => {
|
|
||||||
p.yaml.setIn(p.attrPath, v);
|
|
||||||
p.onChange?.();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -19,10 +19,13 @@ export function EditSection(
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
marginBottom: "15px",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{p.title && <Typography variant="h5">{p.title}</Typography>}
|
{p.title && (
|
||||||
|
<Typography variant="h5" style={{ marginBottom: "15px" }}>
|
||||||
|
{p.title}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
{p.actions}
|
{p.actions}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
@ -799,11 +799,6 @@ export function TokenRightsEditor(p: {
|
|||||||
right={{ verb: "GET", path: "/api/server/bridges" }}
|
right={{ verb: "GET", path: "/api/server/bridges" }}
|
||||||
label="Get list of network bridges"
|
label="Get list of network bridges"
|
||||||
/>
|
/>
|
||||||
<RouteRight
|
|
||||||
{...p}
|
|
||||||
right={{ verb: "GET", path: "/api/server/export_configs" }}
|
|
||||||
label="Export all configurations"
|
|
||||||
/>
|
|
||||||
</RightsSection>
|
</RightsSection>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user