mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 21:21:32 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
a320efad6b | |||
a61e2fb30a | |||
3cb0e214e9 | |||
0e0c5264eb | |||
19f35ef20a | |||
79e27256e6 | |||
b6c726e7aa | |||
0d2b7a3ae3 |
14
CHANGELOG.md
14
CHANGELOG.md
@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.0.21](https://github.com/edera-dev/krata/compare/v0.0.20...v0.0.21) - 2024-09-03
|
||||
|
||||
### Other
|
||||
- update Cargo.lock dependencies
|
||||
|
||||
## [0.0.20](https://github.com/edera-dev/krata/compare/v0.0.19...v0.0.20) - 2024-08-27
|
||||
|
||||
### Added
|
||||
- *(krata)* implement network reservation list ([#366](https://github.com/edera-dev/krata/pull/366))
|
||||
- *(zone-exec)* implement terminal resize support ([#363](https://github.com/edera-dev/krata/pull/363))
|
||||
|
||||
### Other
|
||||
- update Cargo.toml dependencies
|
||||
|
||||
## [0.0.19](https://github.com/edera-dev/krata/compare/v0.0.18...v0.0.19) - 2024-08-25
|
||||
|
||||
### Added
|
||||
|
70
Cargo.lock
generated
70
Cargo.lock
generated
@ -814,9 +814,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666"
|
||||
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.0",
|
||||
@ -1297,7 +1297,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1337,7 +1337,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-buildtools"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
@ -1352,7 +1352,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-ctl"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1382,7 +1382,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-daemon"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1414,14 +1414,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-loopdev"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "krata-network"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1445,7 +1445,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-oci"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
@ -1472,7 +1472,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-runtime"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backhand",
|
||||
@ -1513,7 +1513,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xencall"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"libc",
|
||||
@ -1526,7 +1526,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xenclient"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"env_logger",
|
||||
@ -1544,7 +1544,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xenevtchn"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"libc",
|
||||
@ -1556,7 +1556,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xengnt"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"nix 0.29.0",
|
||||
@ -1565,7 +1565,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xenplatform"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"c2rust-bitfields",
|
||||
@ -1588,7 +1588,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-xenstore"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"env_logger",
|
||||
@ -1600,7 +1600,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "krata-zone"
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cgroups-rs",
|
||||
@ -2229,9 +2229,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.6"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd"
|
||||
checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"rand",
|
||||
@ -2304,9 +2304,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.28.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ba6a365afbe5615999275bea2446b970b10a41102500e27ce7678d50d978303"
|
||||
checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cassowary",
|
||||
@ -2345,9 +2345,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redb"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6dd20d3cdeb9c7d2366a0b16b93b35b75aec15309fbeb7ce477138c9f68c8c0"
|
||||
checksum = "58323dc32ea52a8ae105ff94bc0460c5d906307533ba3401aa63db3cbe491fe5"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@ -2577,9 +2577,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2596,9 +2596,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2607,9 +2607,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.125"
|
||||
version = "1.0.127"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@ -2867,9 +2867,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.31.2"
|
||||
version = "0.31.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab"
|
||||
checksum = "2b92e0bdf838cbc1c4c9ba14f9c97a7ec6cdcd1ae66b10e1e42775a25553f45d"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@ -3062,9 +3062,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401"
|
||||
checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
@ -3094,9 +3094,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic-build"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964"
|
||||
checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
|
16
Cargo.toml
16
Cargo.toml
@ -18,7 +18,7 @@ members = [
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.19"
|
||||
version = "0.0.21"
|
||||
homepage = "https://krata.dev"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/edera-dev/krata"
|
||||
@ -70,24 +70,24 @@ prost-reflect-build = "0.14.0"
|
||||
prost-types = "0.13.1"
|
||||
pty-process = "0.4.0"
|
||||
rand = "0.8.5"
|
||||
ratatui = "0.28.0"
|
||||
redb = "2.1.1"
|
||||
ratatui = "0.28.1"
|
||||
redb = "2.1.2"
|
||||
regex = "1.10.6"
|
||||
rtnetlink = "0.14.1"
|
||||
scopeguard = "1.2.0"
|
||||
serde_json = "1.0.125"
|
||||
serde_json = "1.0.127"
|
||||
serde_yaml = "0.9"
|
||||
sha256 = "1.5.0"
|
||||
signal-hook = "0.3.17"
|
||||
slice-copy = "0.3.0"
|
||||
smoltcp = "0.11.0"
|
||||
sysinfo = "0.31.2"
|
||||
sysinfo = "0.31.3"
|
||||
termtree = "0.5.1"
|
||||
thiserror = "1.0"
|
||||
tokio-tun = "0.11.5"
|
||||
tokio-util = "0.7.11"
|
||||
toml = "0.8.19"
|
||||
tonic-build = "0.12.1"
|
||||
tonic-build = "0.12.2"
|
||||
tower = "0.5.0"
|
||||
udp-stream = "0.0.12"
|
||||
url = "2.5.2"
|
||||
@ -108,7 +108,7 @@ default-features = false
|
||||
features = ["rustls-tls"]
|
||||
|
||||
[workspace.dependencies.serde]
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
features = ["derive"]
|
||||
|
||||
[workspace.dependencies.sys-mount]
|
||||
@ -124,7 +124,7 @@ version = "0.1"
|
||||
features = ["io-util", "net"]
|
||||
|
||||
[workspace.dependencies.tonic]
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
features = ["tls"]
|
||||
|
||||
[workspace.dependencies.uuid]
|
||||
|
@ -16,7 +16,7 @@ oci-spec = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
krata-oci = { path = "../oci", version = "^0.0.19" }
|
||||
krata-oci = { path = "../oci", version = "^0.0.21" }
|
||||
krata-tokio-tar = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
|
||||
|
@ -20,7 +20,7 @@ env_logger = { workspace = true }
|
||||
fancy-duration = { workspace = true }
|
||||
human_bytes = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
krata = { path = "../krata", version = "^0.0.19" }
|
||||
krata = { path = "../krata", version = "^0.0.21" }
|
||||
log = { workspace = true }
|
||||
prost-reflect = { workspace = true, features = ["serde"] }
|
||||
prost-types = { workspace = true }
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod device;
|
||||
pub mod host;
|
||||
pub mod image;
|
||||
pub mod network;
|
||||
pub mod zone;
|
||||
|
||||
use crate::cli::device::DeviceCommand;
|
||||
@ -14,6 +15,7 @@ use krata::{
|
||||
events::EventStream,
|
||||
v1::control::{control_service_client::ControlServiceClient, ResolveZoneIdRequest},
|
||||
};
|
||||
use network::NetworkCommand;
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
#[derive(Parser)]
|
||||
@ -36,6 +38,7 @@ pub struct ControlCommand {
|
||||
pub enum ControlCommands {
|
||||
Zone(ZoneCommand),
|
||||
Image(ImageCommand),
|
||||
Network(NetworkCommand),
|
||||
Device(DeviceCommand),
|
||||
Host(HostCommand),
|
||||
}
|
||||
@ -57,6 +60,8 @@ impl ControlCommands {
|
||||
match self {
|
||||
ControlCommands::Zone(zone) => zone.run(client, events).await,
|
||||
|
||||
ControlCommands::Network(network) => network.run(client, events).await,
|
||||
|
||||
ControlCommands::Image(image) => image.run(client, events).await,
|
||||
|
||||
ControlCommands::Device(device) => device.run(client, events).await,
|
||||
|
43
crates/ctl/src/cli/network/mod.rs
Normal file
43
crates/ctl/src/cli/network/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use reservation::NetworkReservationCommand;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use krata::events::EventStream;
|
||||
use krata::v1::control::control_service_client::ControlServiceClient;
|
||||
|
||||
pub mod reservation;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "Manage the network on the isolation engine")]
|
||||
pub struct NetworkCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: NetworkCommands,
|
||||
}
|
||||
|
||||
impl NetworkCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
self.subcommand.run(client, events).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum NetworkCommands {
|
||||
Reservation(NetworkReservationCommand),
|
||||
}
|
||||
|
||||
impl NetworkCommands {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
NetworkCommands::Reservation(reservation) => reservation.run(client, events).await,
|
||||
}
|
||||
}
|
||||
}
|
125
crates/ctl/src/cli/network/reservation/list.rs
Normal file
125
crates/ctl/src/cli/network/reservation/list.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use comfy_table::{presets::UTF8_FULL_CONDENSED, Cell, Table};
|
||||
use krata::{
|
||||
events::EventStream,
|
||||
v1::{
|
||||
common::NetworkReservation,
|
||||
control::{control_service_client::ControlServiceClient, ListNetworkReservationsRequest},
|
||||
},
|
||||
};
|
||||
|
||||
use serde_json::Value;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use crate::format::{kv2line, proto2dynamic, proto2kv};
|
||||
|
||||
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
|
||||
enum NetworkReservationListFormat {
|
||||
Table,
|
||||
Json,
|
||||
JsonPretty,
|
||||
Jsonl,
|
||||
Yaml,
|
||||
KeyValue,
|
||||
Simple,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "List network reservation information")]
|
||||
pub struct NetworkReservationListCommand {
|
||||
#[arg(short, long, default_value = "table", help = "Output format")]
|
||||
format: NetworkReservationListFormat,
|
||||
}
|
||||
|
||||
impl NetworkReservationListCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
mut client: ControlServiceClient<Channel>,
|
||||
_events: EventStream,
|
||||
) -> Result<()> {
|
||||
let reply = client
|
||||
.list_network_reservations(ListNetworkReservationsRequest {})
|
||||
.await?
|
||||
.into_inner();
|
||||
let mut reservations = reply.reservations;
|
||||
|
||||
reservations.sort_by(|a, b| a.uuid.cmp(&b.uuid));
|
||||
|
||||
match self.format {
|
||||
NetworkReservationListFormat::Table => {
|
||||
self.print_reservations_table(reservations)?;
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Simple => {
|
||||
for reservation in reservations {
|
||||
println!(
|
||||
"{}\t{}\t{}\t{}",
|
||||
reservation.uuid, reservation.ipv4, reservation.ipv6, reservation.mac
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Json
|
||||
| NetworkReservationListFormat::JsonPretty
|
||||
| NetworkReservationListFormat::Yaml => {
|
||||
let mut values = Vec::new();
|
||||
for device in reservations {
|
||||
let message = proto2dynamic(device)?;
|
||||
values.push(serde_json::to_value(message)?);
|
||||
}
|
||||
let value = Value::Array(values);
|
||||
let encoded = if self.format == NetworkReservationListFormat::JsonPretty {
|
||||
serde_json::to_string_pretty(&value)?
|
||||
} else if self.format == NetworkReservationListFormat::Yaml {
|
||||
serde_yaml::to_string(&value)?
|
||||
} else {
|
||||
serde_json::to_string(&value)?
|
||||
};
|
||||
println!("{}", encoded.trim());
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::Jsonl => {
|
||||
for device in reservations {
|
||||
let message = proto2dynamic(device)?;
|
||||
println!("{}", serde_json::to_string(&message)?);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkReservationListFormat::KeyValue => {
|
||||
self.print_key_value(reservations)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_reservations_table(&self, reservations: Vec<NetworkReservation>) -> Result<()> {
|
||||
let mut table = Table::new();
|
||||
table.load_preset(UTF8_FULL_CONDENSED);
|
||||
table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
|
||||
table.set_header(vec!["uuid", "ipv4", "ipv6", "mac"]);
|
||||
for reservation in reservations {
|
||||
table.add_row(vec![
|
||||
Cell::new(reservation.uuid),
|
||||
Cell::new(reservation.ipv4),
|
||||
Cell::new(reservation.ipv6),
|
||||
Cell::new(reservation.mac),
|
||||
]);
|
||||
}
|
||||
if table.is_empty() {
|
||||
println!("no network reservations found");
|
||||
} else {
|
||||
println!("{}", table);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_key_value(&self, reservations: Vec<NetworkReservation>) -> Result<()> {
|
||||
for reservation in reservations {
|
||||
let kvs = proto2kv(reservation)?;
|
||||
println!("{}", kv2line(kvs));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
43
crates/ctl/src/cli/network/reservation/mod.rs
Normal file
43
crates/ctl/src/cli/network/reservation/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use list::NetworkReservationListCommand;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
use krata::events::EventStream;
|
||||
use krata::v1::control::control_service_client::ControlServiceClient;
|
||||
|
||||
pub mod list;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about = "Manage network reservations")]
|
||||
pub struct NetworkReservationCommand {
|
||||
#[command(subcommand)]
|
||||
subcommand: NetworkReservationCommands,
|
||||
}
|
||||
|
||||
impl NetworkReservationCommand {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
self.subcommand.run(client, events).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum NetworkReservationCommands {
|
||||
List(NetworkReservationListCommand),
|
||||
}
|
||||
|
||||
impl NetworkReservationCommands {
|
||||
pub async fn run(
|
||||
self,
|
||||
client: ControlServiceClient<Channel>,
|
||||
events: EventStream,
|
||||
) -> Result<()> {
|
||||
match self {
|
||||
NetworkReservationCommands::List(list) => list.run(client, events).await,
|
||||
}
|
||||
}
|
||||
}
|
@ -3,11 +3,13 @@ use std::collections::HashMap;
|
||||
use anyhow::Result;
|
||||
|
||||
use clap::Parser;
|
||||
use crossterm::tty::IsTty;
|
||||
use krata::v1::{
|
||||
common::{ZoneTaskSpec, ZoneTaskSpecEnvVar},
|
||||
common::{TerminalSize, ZoneTaskSpec, ZoneTaskSpecEnvVar},
|
||||
control::{control_service_client::ControlServiceClient, ExecInsideZoneRequest},
|
||||
};
|
||||
|
||||
use tokio::io::stdin;
|
||||
use tonic::{transport::Channel, Request};
|
||||
|
||||
use crate::console::StdioConsoleStream;
|
||||
@ -36,6 +38,7 @@ pub struct ZoneExecCommand {
|
||||
impl ZoneExecCommand {
|
||||
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
|
||||
let zone_id: String = resolve_zone(&mut client, &self.zone).await?;
|
||||
let should_map_tty = self.tty && stdin().is_tty();
|
||||
let initial = ExecInsideZoneRequest {
|
||||
zone_id,
|
||||
task: Some(ZoneTaskSpec {
|
||||
@ -52,16 +55,25 @@ impl ZoneExecCommand {
|
||||
}),
|
||||
stdin: vec![],
|
||||
stdin_closed: false,
|
||||
terminal_size: if should_map_tty {
|
||||
let size = crossterm::terminal::size().ok();
|
||||
size.map(|(columns, rows)| TerminalSize {
|
||||
rows: rows as u32,
|
||||
columns: columns as u32,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let stream = StdioConsoleStream::stdin_stream_exec(initial).await;
|
||||
let stream = StdioConsoleStream::input_stream_exec(initial, should_map_tty).await;
|
||||
|
||||
let response = client
|
||||
.exec_inside_zone(Request::new(stream))
|
||||
.await?
|
||||
.into_inner();
|
||||
|
||||
let code = StdioConsoleStream::exec_output(response, self.tty).await?;
|
||||
let code = StdioConsoleStream::exec_output(response, should_map_tty).await?;
|
||||
std::process::exit(code);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use crossterm::{
|
||||
use krata::v1::common::ZoneState;
|
||||
use krata::{
|
||||
events::EventStream,
|
||||
v1::common::TerminalSize,
|
||||
v1::control::{
|
||||
watch_events_reply::Event, ExecInsideZoneReply, ExecInsideZoneRequest, ZoneConsoleReply,
|
||||
ZoneConsoleRequest,
|
||||
@ -15,6 +16,7 @@ use krata::{
|
||||
use log::debug;
|
||||
use tokio::{
|
||||
io::{stderr, stdin, stdout, AsyncReadExt, AsyncWriteExt},
|
||||
select,
|
||||
task::JoinHandle,
|
||||
};
|
||||
use tokio_stream::{Stream, StreamExt};
|
||||
@ -22,6 +24,11 @@ use tonic::Streaming;
|
||||
|
||||
pub struct StdioConsoleStream;
|
||||
|
||||
enum ExecStdinSelect {
|
||||
DataRead(std::io::Result<usize>),
|
||||
TerminalResize,
|
||||
}
|
||||
|
||||
impl StdioConsoleStream {
|
||||
pub async fn stdin_stream(
|
||||
zone: String,
|
||||
@ -49,30 +56,106 @@ impl StdioConsoleStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stdin_stream_exec(
|
||||
#[cfg(unix)]
|
||||
pub async fn input_stream_exec(
|
||||
initial: ExecInsideZoneRequest,
|
||||
tty: bool,
|
||||
) -> impl Stream<Item = ExecInsideZoneRequest> {
|
||||
let mut stdin = stdin();
|
||||
stream! {
|
||||
yield initial;
|
||||
|
||||
let mut buffer = vec![0u8; 60];
|
||||
let mut terminal_size_change = if tty {
|
||||
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::window_change()).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut stdin_closed = false;
|
||||
loop {
|
||||
let size = match stdin.read(&mut buffer).await {
|
||||
Ok(size) => size,
|
||||
Err(error) => {
|
||||
debug!("failed to read stdin: {}", error);
|
||||
break;
|
||||
let selected = if let Some(ref mut terminal_size_change) = terminal_size_change {
|
||||
if stdin_closed {
|
||||
select! {
|
||||
_ = terminal_size_change.recv() => ExecStdinSelect::TerminalResize,
|
||||
}
|
||||
} else {
|
||||
select! {
|
||||
result = stdin.read(&mut buffer) => ExecStdinSelect::DataRead(result),
|
||||
_ = terminal_size_change.recv() => ExecStdinSelect::TerminalResize,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
select! {
|
||||
result = stdin.read(&mut buffer) => ExecStdinSelect::DataRead(result),
|
||||
}
|
||||
};
|
||||
let stdin = buffer[0..size].to_vec();
|
||||
if size == 1 && buffer[0] == 0x1d {
|
||||
break;
|
||||
|
||||
match selected {
|
||||
ExecStdinSelect::DataRead(result) => {
|
||||
match result {
|
||||
Ok(size) => {
|
||||
let stdin = buffer[0..size].to_vec();
|
||||
if size == 1 && buffer[0] == 0x1d {
|
||||
break;
|
||||
}
|
||||
stdin_closed = size == 0;
|
||||
yield ExecInsideZoneRequest { zone_id: String::default(), task: None, terminal_size: None, stdin, stdin_closed, };
|
||||
},
|
||||
Err(error) => {
|
||||
debug!("failed to read stdin: {}", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
ExecStdinSelect::TerminalResize => {
|
||||
if let Ok((columns, rows)) = crossterm::terminal::size() {
|
||||
yield ExecInsideZoneRequest { zone_id: String::default(), task: None, terminal_size: Some(TerminalSize {
|
||||
rows: rows as u32,
|
||||
columns: columns as u32,
|
||||
}), stdin: vec![], stdin_closed: false, };
|
||||
}
|
||||
}
|
||||
}
|
||||
let stdin_closed = size == 0;
|
||||
yield ExecInsideZoneRequest { zone_id: String::default(), task: None, stdin, stdin_closed, };
|
||||
if stdin_closed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub async fn input_stream_exec(
|
||||
initial: ExecInsideZoneRequest,
|
||||
_tty: bool,
|
||||
) -> impl Stream<Item = ExecInsideZoneRequest> {
|
||||
let mut stdin = stdin();
|
||||
stream! {
|
||||
yield initial;
|
||||
|
||||
let mut buffer = vec![0u8; 60];
|
||||
let mut stdin_closed = false;
|
||||
loop {
|
||||
let selected = select! {
|
||||
result = stdin.read(&mut buffer) => ExecStdinSelect::DataRead(result),
|
||||
};
|
||||
|
||||
match selected {
|
||||
ExecStdinSelect::DataRead(result) => {
|
||||
match result {
|
||||
Ok(size) => {
|
||||
let stdin = buffer[0..size].to_vec();
|
||||
if size == 1 && buffer[0] == 0x1d {
|
||||
break;
|
||||
}
|
||||
stdin_closed = size == 0;
|
||||
yield ExecInsideZoneRequest { zone_id: String::default(), task: None, terminal_size: None, stdin, stdin_closed, };
|
||||
},
|
||||
Err(error) => {
|
||||
debug!("failed to read stdin: {}", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,7 +179,7 @@ impl StdioConsoleStream {
|
||||
}
|
||||
|
||||
pub async fn exec_output(mut stream: Streaming<ExecInsideZoneReply>, raw: bool) -> Result<i32> {
|
||||
if raw && stdin().is_tty() {
|
||||
if raw {
|
||||
enable_raw_mode()?;
|
||||
StdioConsoleStream::register_terminal_restore_hook()?;
|
||||
}
|
||||
|
@ -19,9 +19,9 @@ clap = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
krata = { path = "../krata", version = "^0.0.19" }
|
||||
krata-oci = { path = "../oci", version = "^0.0.19" }
|
||||
krata-runtime = { path = "../runtime", version = "^0.0.19" }
|
||||
krata = { path = "../krata", version = "^0.0.21" }
|
||||
krata-oci = { path = "../oci", version = "^0.0.21" }
|
||||
krata-runtime = { path = "../runtime", version = "^0.0.21" }
|
||||
log = { workspace = true }
|
||||
prost = { workspace = true }
|
||||
redb = { workspace = true }
|
||||
|
@ -13,7 +13,8 @@ use krata::{
|
||||
idm::internal::{
|
||||
exec_stream_request_update::Update, request::Request as IdmRequestType,
|
||||
response::Response as IdmResponseType, ExecEnvVar, ExecStreamRequestStart,
|
||||
ExecStreamRequestStdin, ExecStreamRequestUpdate, Request as IdmRequest,
|
||||
ExecStreamRequestStdin, ExecStreamRequestTerminalSize, ExecStreamRequestUpdate,
|
||||
Request as IdmRequest,
|
||||
},
|
||||
v1::control::{ExecInsideZoneReply, ExecInsideZoneRequest},
|
||||
};
|
||||
@ -61,6 +62,12 @@ impl ExecInsideZoneRpc {
|
||||
command: task.command,
|
||||
working_directory: task.working_directory,
|
||||
tty: task.tty,
|
||||
terminal_size: request.terminal_size.map(|size| {
|
||||
ExecStreamRequestTerminalSize {
|
||||
rows: size.rows,
|
||||
columns: size.columns,
|
||||
}
|
||||
}),
|
||||
})),
|
||||
})),
|
||||
};
|
||||
@ -87,6 +94,16 @@ impl ExecInsideZoneRpc {
|
||||
})),
|
||||
}))}).await;
|
||||
}
|
||||
|
||||
if let Some(ref terminal_size) = update.terminal_size {
|
||||
let _ = handle.update(IdmRequest {
|
||||
request: Some(IdmRequestType::ExecStream(ExecStreamRequestUpdate {
|
||||
update: Some(Update::TerminalResize(ExecStreamRequestTerminalSize {
|
||||
rows: terminal_size.rows,
|
||||
columns: terminal_size.columns,
|
||||
})),
|
||||
}))}).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
x = handle.receiver.recv() => match x {
|
||||
|
@ -1,21 +1,21 @@
|
||||
use crate::command::DaemonCommand;
|
||||
use crate::ip::assignment::IpAssignment;
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
use crate::zlt::ZoneLookupTable;
|
||||
use anyhow::Result;
|
||||
use krata::v1::control::{GetHostStatusReply, GetHostStatusRequest};
|
||||
|
||||
pub struct GetHostStatusRpc {
|
||||
ip: IpAssignment,
|
||||
network: NetworkAssignment,
|
||||
zlt: ZoneLookupTable,
|
||||
}
|
||||
|
||||
impl GetHostStatusRpc {
|
||||
pub fn new(ip: IpAssignment, zlt: ZoneLookupTable) -> Self {
|
||||
Self { ip, zlt }
|
||||
pub fn new(ip: NetworkAssignment, zlt: ZoneLookupTable) -> Self {
|
||||
Self { network: ip, zlt }
|
||||
}
|
||||
|
||||
pub async fn process(self, _request: GetHostStatusRequest) -> Result<GetHostStatusReply> {
|
||||
let host_reservation = self.ip.retrieve(self.zlt.host_uuid()).await?;
|
||||
let host_reservation = self.network.retrieve(self.zlt.host_uuid()).await?;
|
||||
Ok(GetHostStatusReply {
|
||||
host_domid: self.zlt.host_domid(),
|
||||
host_uuid: self.zlt.host_uuid().to_string(),
|
||||
|
28
crates/daemon/src/control/list_network_reservations.rs
Normal file
28
crates/daemon/src/control/list_network_reservations.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use krata::v1::{
|
||||
common::NetworkReservation,
|
||||
control::{ListNetworkReservationsReply, ListNetworkReservationsRequest},
|
||||
};
|
||||
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
|
||||
pub struct ListNetworkReservationsRpc {
|
||||
network: NetworkAssignment,
|
||||
}
|
||||
|
||||
impl ListNetworkReservationsRpc {
|
||||
pub fn new(network: NetworkAssignment) -> Self {
|
||||
Self { network }
|
||||
}
|
||||
|
||||
pub async fn process(
|
||||
self,
|
||||
_request: ListNetworkReservationsRequest,
|
||||
) -> Result<ListNetworkReservationsReply> {
|
||||
let state = self.network.read_reservations().await?;
|
||||
let reservations: Vec<NetworkReservation> =
|
||||
state.into_values().map(|x| x.into()).collect::<Vec<_>>();
|
||||
Ok(ListNetworkReservationsReply { reservations })
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ use std::pin::Pin;
|
||||
|
||||
use anyhow::Error;
|
||||
use futures::Stream;
|
||||
use list_network_reservations::ListNetworkReservationsRpc;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tonic::{Request, Response, Status, Streaming};
|
||||
use uuid::Uuid;
|
||||
@ -17,8 +18,8 @@ use krata::v1::control::{
|
||||
WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest,
|
||||
};
|
||||
use krata::v1::control::{
|
||||
GetZoneReply, GetZoneRequest, SetHostPowerManagementPolicyReply,
|
||||
SetHostPowerManagementPolicyRequest,
|
||||
GetZoneReply, GetZoneRequest, ListNetworkReservationsReply, ListNetworkReservationsRequest,
|
||||
SetHostPowerManagementPolicyReply, SetHostPowerManagementPolicyRequest,
|
||||
};
|
||||
use krataoci::packer::service::OciPackerService;
|
||||
use kratart::Runtime;
|
||||
@ -41,7 +42,7 @@ use crate::control::snoop_idm::SnoopIdmRpc;
|
||||
use crate::control::update_zone_resources::UpdateZoneResourcesRpc;
|
||||
use crate::control::watch_events::WatchEventsRpc;
|
||||
use crate::db::zone::ZoneStore;
|
||||
use crate::ip::assignment::IpAssignment;
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
use crate::{
|
||||
console::DaemonConsoleHandle, devices::DaemonDeviceManager, event::DaemonEventContext,
|
||||
idm::DaemonIdmHandle, zlt::ZoneLookupTable,
|
||||
@ -55,6 +56,7 @@ pub mod get_host_cpu_topology;
|
||||
pub mod get_host_status;
|
||||
pub mod get_zone;
|
||||
pub mod list_devices;
|
||||
pub mod list_network_reservations;
|
||||
pub mod list_zones;
|
||||
pub mod pull_image;
|
||||
pub mod read_hypervisor_console;
|
||||
@ -91,7 +93,7 @@ pub struct DaemonControlService {
|
||||
console: DaemonConsoleHandle,
|
||||
idm: DaemonIdmHandle,
|
||||
zones: ZoneStore,
|
||||
ip: IpAssignment,
|
||||
network: NetworkAssignment,
|
||||
zone_reconciler_notify: Sender<Uuid>,
|
||||
packer: OciPackerService,
|
||||
runtime: Runtime,
|
||||
@ -106,7 +108,7 @@ impl DaemonControlService {
|
||||
console: DaemonConsoleHandle,
|
||||
idm: DaemonIdmHandle,
|
||||
zones: ZoneStore,
|
||||
ip: IpAssignment,
|
||||
network: NetworkAssignment,
|
||||
zone_reconciler_notify: Sender<Uuid>,
|
||||
packer: OciPackerService,
|
||||
runtime: Runtime,
|
||||
@ -118,7 +120,7 @@ impl DaemonControlService {
|
||||
console,
|
||||
idm,
|
||||
zones,
|
||||
ip,
|
||||
network,
|
||||
zone_reconciler_notify,
|
||||
packer,
|
||||
runtime,
|
||||
@ -134,7 +136,7 @@ impl ControlService for DaemonControlService {
|
||||
) -> Result<Response<GetHostStatusReply>, Status> {
|
||||
let request = request.into_inner();
|
||||
adapt(
|
||||
GetHostStatusRpc::new(self.ip.clone(), self.zlt.clone())
|
||||
GetHostStatusRpc::new(self.network.clone(), self.zlt.clone())
|
||||
.process(request)
|
||||
.await,
|
||||
)
|
||||
@ -191,6 +193,18 @@ impl ControlService for DaemonControlService {
|
||||
)
|
||||
}
|
||||
|
||||
async fn list_network_reservations(
|
||||
&self,
|
||||
request: Request<ListNetworkReservationsRequest>,
|
||||
) -> Result<Response<ListNetworkReservationsReply>, Status> {
|
||||
let request = request.into_inner();
|
||||
adapt(
|
||||
ListNetworkReservationsRpc::new(self.network.clone())
|
||||
.process(request)
|
||||
.await,
|
||||
)
|
||||
}
|
||||
|
||||
type PullImageStream =
|
||||
Pin<Box<dyn Stream<Item = Result<PullImageReply, Status>> + Send + 'static>>;
|
||||
|
||||
|
@ -3,7 +3,7 @@ use redb::Database;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod ip;
|
||||
pub mod network;
|
||||
pub mod zone;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::db::KrataDatabase;
|
||||
use advmac::MacAddr6;
|
||||
use anyhow::Result;
|
||||
use krata::v1::common::NetworkReservation as ApiNetworkReservation;
|
||||
use log::error;
|
||||
use redb::{ReadableTable, TableDefinition};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -8,24 +9,25 @@ use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use uuid::Uuid;
|
||||
|
||||
const IP_RESERVATION_TABLE: TableDefinition<u128, &[u8]> = TableDefinition::new("ip-reservation");
|
||||
const NETWORK_RESERVATION_TABLE: TableDefinition<u128, &[u8]> =
|
||||
TableDefinition::new("network-reservation");
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IpReservationStore {
|
||||
pub struct NetworkReservationStore {
|
||||
db: KrataDatabase,
|
||||
}
|
||||
|
||||
impl IpReservationStore {
|
||||
impl NetworkReservationStore {
|
||||
pub fn open(db: KrataDatabase) -> Result<Self> {
|
||||
let write = db.database.begin_write()?;
|
||||
let _ = write.open_table(IP_RESERVATION_TABLE);
|
||||
let _ = write.open_table(NETWORK_RESERVATION_TABLE);
|
||||
write.commit()?;
|
||||
Ok(IpReservationStore { db })
|
||||
Ok(NetworkReservationStore { db })
|
||||
}
|
||||
|
||||
pub async fn read(&self, id: Uuid) -> Result<Option<IpReservation>> {
|
||||
pub async fn read(&self, id: Uuid) -> Result<Option<NetworkReservation>> {
|
||||
let read = self.db.database.begin_read()?;
|
||||
let table = read.open_table(IP_RESERVATION_TABLE)?;
|
||||
let table = read.open_table(NETWORK_RESERVATION_TABLE)?;
|
||||
let Some(entry) = table.get(id.to_u128_le())? else {
|
||||
return Ok(None);
|
||||
};
|
||||
@ -33,26 +35,26 @@ impl IpReservationStore {
|
||||
Ok(Some(serde_json::from_slice(bytes)?))
|
||||
}
|
||||
|
||||
pub async fn list(&self) -> Result<HashMap<Uuid, IpReservation>> {
|
||||
pub async fn list(&self) -> Result<HashMap<Uuid, NetworkReservation>> {
|
||||
enum ListEntry {
|
||||
Valid(Uuid, IpReservation),
|
||||
Valid(Uuid, NetworkReservation),
|
||||
Invalid(Uuid),
|
||||
}
|
||||
let mut reservations: HashMap<Uuid, IpReservation> = HashMap::new();
|
||||
let mut reservations: HashMap<Uuid, NetworkReservation> = HashMap::new();
|
||||
|
||||
let corruptions = {
|
||||
let read = self.db.database.begin_read()?;
|
||||
let table = read.open_table(IP_RESERVATION_TABLE)?;
|
||||
let table = read.open_table(NETWORK_RESERVATION_TABLE)?;
|
||||
table
|
||||
.iter()?
|
||||
.flat_map(|result| {
|
||||
result.map(|(key, value)| {
|
||||
let uuid = Uuid::from_u128_le(key.value());
|
||||
match serde_json::from_slice::<IpReservation>(value.value()) {
|
||||
match serde_json::from_slice::<NetworkReservation>(value.value()) {
|
||||
Ok(reservation) => ListEntry::Valid(uuid, reservation),
|
||||
Err(error) => {
|
||||
error!(
|
||||
"found invalid ip reservation in database for uuid {}: {}",
|
||||
"found invalid network reservation in database for uuid {}: {}",
|
||||
uuid, error
|
||||
);
|
||||
ListEntry::Invalid(uuid)
|
||||
@ -73,7 +75,7 @@ impl IpReservationStore {
|
||||
|
||||
if !corruptions.is_empty() {
|
||||
let write = self.db.database.begin_write()?;
|
||||
let mut table = write.open_table(IP_RESERVATION_TABLE)?;
|
||||
let mut table = write.open_table(NETWORK_RESERVATION_TABLE)?;
|
||||
for corruption in corruptions {
|
||||
table.remove(corruption.to_u128_le())?;
|
||||
}
|
||||
@ -82,10 +84,10 @@ impl IpReservationStore {
|
||||
Ok(reservations)
|
||||
}
|
||||
|
||||
pub async fn update(&self, id: Uuid, entry: IpReservation) -> Result<()> {
|
||||
pub async fn update(&self, id: Uuid, entry: NetworkReservation) -> Result<()> {
|
||||
let write = self.db.database.begin_write()?;
|
||||
{
|
||||
let mut table = write.open_table(IP_RESERVATION_TABLE)?;
|
||||
let mut table = write.open_table(NETWORK_RESERVATION_TABLE)?;
|
||||
let bytes = serde_json::to_vec(&entry)?;
|
||||
table.insert(id.to_u128_le(), bytes.as_slice())?;
|
||||
}
|
||||
@ -96,7 +98,7 @@ impl IpReservationStore {
|
||||
pub async fn remove(&self, id: Uuid) -> Result<()> {
|
||||
let write = self.db.database.begin_write()?;
|
||||
{
|
||||
let mut table = write.open_table(IP_RESERVATION_TABLE)?;
|
||||
let mut table = write.open_table(NETWORK_RESERVATION_TABLE)?;
|
||||
table.remove(id.to_u128_le())?;
|
||||
}
|
||||
write.commit()?;
|
||||
@ -105,7 +107,7 @@ impl IpReservationStore {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct IpReservation {
|
||||
pub struct NetworkReservation {
|
||||
pub uuid: String,
|
||||
pub ipv4: Ipv4Addr,
|
||||
pub ipv6: Ipv6Addr,
|
||||
@ -116,3 +118,17 @@ pub struct IpReservation {
|
||||
pub gateway_ipv6: Ipv6Addr,
|
||||
pub gateway_mac: MacAddr6,
|
||||
}
|
||||
|
||||
impl From<NetworkReservation> for ApiNetworkReservation {
|
||||
fn from(val: NetworkReservation) -> Self {
|
||||
ApiNetworkReservation {
|
||||
uuid: val.uuid,
|
||||
ipv4: format!("{}/{}", val.ipv4, val.ipv4_prefix),
|
||||
ipv6: format!("{}/{}", val.ipv6, val.ipv6_prefix),
|
||||
mac: val.mac.to_string().to_lowercase().replace('-', ":"),
|
||||
gateway_ipv4: format!("{}/{}", val.gateway_ipv4, val.ipv4_prefix),
|
||||
gateway_ipv6: format!("{}/{}", val.gateway_ipv6, val.ipv6_prefix),
|
||||
gateway_mac: val.gateway_mac.to_string().to_lowercase().replace('-', ":"),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use crate::db::ip::IpReservationStore;
|
||||
use crate::db::network::NetworkReservationStore;
|
||||
use crate::db::zone::ZoneStore;
|
||||
use crate::db::KrataDatabase;
|
||||
use crate::ip::assignment::IpAssignment;
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
use anyhow::{anyhow, Result};
|
||||
use config::DaemonConfig;
|
||||
use console::{DaemonConsole, DaemonConsoleHandle};
|
||||
@ -37,18 +37,19 @@ pub mod db;
|
||||
pub mod devices;
|
||||
pub mod event;
|
||||
pub mod idm;
|
||||
pub mod ip;
|
||||
pub mod metrics;
|
||||
pub mod network;
|
||||
pub mod oci;
|
||||
pub mod reconcile;
|
||||
pub mod zlt;
|
||||
|
||||
pub struct Daemon {
|
||||
store: String,
|
||||
_config: Arc<DaemonConfig>,
|
||||
zlt: ZoneLookupTable,
|
||||
devices: DaemonDeviceManager,
|
||||
zones: ZoneStore,
|
||||
ip: IpAssignment,
|
||||
network: NetworkAssignment,
|
||||
events: DaemonEventContext,
|
||||
zone_reconciler_task: JoinHandle<()>,
|
||||
zone_reconciler_notify: Sender<Uuid>,
|
||||
@ -127,9 +128,14 @@ impl Daemon {
|
||||
let runtime_for_reconciler = runtime.dupe().await?;
|
||||
let ipv4_network = Ipv4Network::from_str(&config.network.ipv4.subnet)?;
|
||||
let ipv6_network = Ipv6Network::from_str(&config.network.ipv6.subnet)?;
|
||||
let ip_reservation_store = IpReservationStore::open(database)?;
|
||||
let ip =
|
||||
IpAssignment::new(host_uuid, ipv4_network, ipv6_network, ip_reservation_store).await?;
|
||||
let network_reservation_store = NetworkReservationStore::open(database)?;
|
||||
let network = NetworkAssignment::new(
|
||||
host_uuid,
|
||||
ipv4_network,
|
||||
ipv6_network,
|
||||
network_reservation_store,
|
||||
)
|
||||
.await?;
|
||||
debug!("initializing zone reconciler");
|
||||
let zone_reconciler = ZoneReconciler::new(
|
||||
devices.clone(),
|
||||
@ -142,7 +148,7 @@ impl Daemon {
|
||||
kernel_path,
|
||||
initrd_path,
|
||||
addons_path,
|
||||
ip.clone(),
|
||||
network.clone(),
|
||||
config.clone(),
|
||||
)?;
|
||||
|
||||
@ -165,7 +171,7 @@ impl Daemon {
|
||||
zlt,
|
||||
devices,
|
||||
zones,
|
||||
ip,
|
||||
network,
|
||||
events,
|
||||
zone_reconciler_task,
|
||||
zone_reconciler_notify,
|
||||
@ -186,7 +192,7 @@ impl Daemon {
|
||||
self.console.clone(),
|
||||
self.idm.clone(),
|
||||
self.zones.clone(),
|
||||
self.ip.clone(),
|
||||
self.network.clone(),
|
||||
self.zone_reconciler_notify.clone(),
|
||||
self.packer.clone(),
|
||||
self.runtime.clone(),
|
||||
|
@ -9,37 +9,37 @@ use std::{
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::db::ip::{IpReservation, IpReservationStore};
|
||||
use crate::db::network::{NetworkReservation, NetworkReservationStore};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct IpAssignmentState {
|
||||
pub ipv4: HashMap<Ipv4Addr, IpReservation>,
|
||||
pub ipv6: HashMap<Ipv6Addr, IpReservation>,
|
||||
pub struct NetworkAssignmentState {
|
||||
pub ipv4: HashMap<Ipv4Addr, NetworkReservation>,
|
||||
pub ipv6: HashMap<Ipv6Addr, NetworkReservation>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IpAssignment {
|
||||
pub struct NetworkAssignment {
|
||||
ipv4_network: Ipv4Network,
|
||||
ipv6_network: Ipv6Network,
|
||||
gateway_ipv4: Ipv4Addr,
|
||||
gateway_ipv6: Ipv6Addr,
|
||||
gateway_mac: MacAddr6,
|
||||
store: IpReservationStore,
|
||||
state: Arc<RwLock<IpAssignmentState>>,
|
||||
store: NetworkReservationStore,
|
||||
state: Arc<RwLock<NetworkAssignmentState>>,
|
||||
}
|
||||
|
||||
impl IpAssignment {
|
||||
impl NetworkAssignment {
|
||||
pub async fn new(
|
||||
host_uuid: Uuid,
|
||||
ipv4_network: Ipv4Network,
|
||||
ipv6_network: Ipv6Network,
|
||||
store: IpReservationStore,
|
||||
store: NetworkReservationStore,
|
||||
) -> Result<Self> {
|
||||
let mut state = IpAssignment::fetch_current_state(&store).await?;
|
||||
let mut state = NetworkAssignment::fetch_current_state(&store).await?;
|
||||
let gateway_reservation = if let Some(reservation) = store.read(Uuid::nil()).await? {
|
||||
reservation
|
||||
} else {
|
||||
IpAssignment::allocate(
|
||||
NetworkAssignment::allocate(
|
||||
&mut state,
|
||||
&store,
|
||||
Uuid::nil(),
|
||||
@ -53,7 +53,7 @@ impl IpAssignment {
|
||||
};
|
||||
|
||||
if store.read(host_uuid).await?.is_none() {
|
||||
let _ = IpAssignment::allocate(
|
||||
let _ = NetworkAssignment::allocate(
|
||||
&mut state,
|
||||
&store,
|
||||
host_uuid,
|
||||
@ -66,7 +66,7 @@ impl IpAssignment {
|
||||
.await?;
|
||||
}
|
||||
|
||||
let assignment = IpAssignment {
|
||||
let assignment = NetworkAssignment {
|
||||
ipv4_network,
|
||||
ipv6_network,
|
||||
gateway_ipv4: gateway_reservation.ipv4,
|
||||
@ -78,9 +78,11 @@ impl IpAssignment {
|
||||
Ok(assignment)
|
||||
}
|
||||
|
||||
async fn fetch_current_state(store: &IpReservationStore) -> Result<IpAssignmentState> {
|
||||
async fn fetch_current_state(
|
||||
store: &NetworkReservationStore,
|
||||
) -> Result<NetworkAssignmentState> {
|
||||
let reservations = store.list().await?;
|
||||
let mut state = IpAssignmentState::default();
|
||||
let mut state = NetworkAssignmentState::default();
|
||||
for reservation in reservations.values() {
|
||||
state.ipv4.insert(reservation.ipv4, reservation.clone());
|
||||
state.ipv6.insert(reservation.ipv6, reservation.clone());
|
||||
@ -90,15 +92,15 @@ impl IpAssignment {
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn allocate(
|
||||
state: &mut IpAssignmentState,
|
||||
store: &IpReservationStore,
|
||||
state: &mut NetworkAssignmentState,
|
||||
store: &NetworkReservationStore,
|
||||
uuid: Uuid,
|
||||
ipv4_network: Ipv4Network,
|
||||
ipv6_network: Ipv6Network,
|
||||
gateway_ipv4: Option<Ipv4Addr>,
|
||||
gateway_ipv6: Option<Ipv6Addr>,
|
||||
gateway_mac: Option<MacAddr6>,
|
||||
) -> Result<IpReservation> {
|
||||
) -> Result<NetworkReservation> {
|
||||
let found_ipv4: Option<Ipv4Addr> = ipv4_network
|
||||
.iter()
|
||||
.filter(|ip| {
|
||||
@ -136,7 +138,7 @@ impl IpAssignment {
|
||||
mac.set_local(true);
|
||||
mac.set_multicast(false);
|
||||
|
||||
let reservation = IpReservation {
|
||||
let reservation = NetworkReservation {
|
||||
uuid: uuid.to_string(),
|
||||
ipv4,
|
||||
ipv6,
|
||||
@ -153,9 +155,9 @@ impl IpAssignment {
|
||||
Ok(reservation)
|
||||
}
|
||||
|
||||
pub async fn assign(&self, uuid: Uuid) -> Result<IpReservation> {
|
||||
pub async fn assign(&self, uuid: Uuid) -> Result<NetworkReservation> {
|
||||
let mut state = self.state.write().await;
|
||||
let reservation = IpAssignment::allocate(
|
||||
let reservation = NetworkAssignment::allocate(
|
||||
&mut state,
|
||||
&self.store,
|
||||
uuid,
|
||||
@ -181,18 +183,22 @@ impl IpAssignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn retrieve(&self, uuid: Uuid) -> Result<Option<IpReservation>> {
|
||||
pub async fn retrieve(&self, uuid: Uuid) -> Result<Option<NetworkReservation>> {
|
||||
self.store.read(uuid).await
|
||||
}
|
||||
|
||||
pub async fn reload(&self) -> Result<()> {
|
||||
let mut state = self.state.write().await;
|
||||
let intermediate = IpAssignment::fetch_current_state(&self.store).await?;
|
||||
let intermediate = NetworkAssignment::fetch_current_state(&self.store).await?;
|
||||
*state = intermediate;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn read(&self) -> Result<IpAssignmentState> {
|
||||
pub async fn read(&self) -> Result<NetworkAssignmentState> {
|
||||
Ok(self.state.read().await.clone())
|
||||
}
|
||||
|
||||
pub async fn read_reservations(&self) -> Result<HashMap<Uuid, NetworkReservation>> {
|
||||
self.store.list().await
|
||||
}
|
||||
}
|
@ -14,8 +14,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::config::{DaemonConfig, DaemonPciDeviceRdmReservePolicy};
|
||||
use crate::devices::DaemonDeviceManager;
|
||||
use crate::ip::assignment::IpAssignment;
|
||||
use crate::reconcile::zone::ip_reservation_to_network_status;
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
use crate::reconcile::zone::network_reservation_to_network_status;
|
||||
use crate::{reconcile::zone::ZoneReconcilerResult, zlt::ZoneLookupTable};
|
||||
use krata::v1::common::zone_image_spec::Image;
|
||||
use tokio::fs::{self, File};
|
||||
@ -29,7 +29,7 @@ pub struct ZoneCreator<'a> {
|
||||
pub initrd_path: &'a Path,
|
||||
pub addons_path: &'a Path,
|
||||
pub packer: &'a OciPackerService,
|
||||
pub ip_assignment: &'a IpAssignment,
|
||||
pub network_assignment: &'a NetworkAssignment,
|
||||
pub zlt: &'a ZoneLookupTable,
|
||||
pub runtime: &'a Runtime,
|
||||
pub config: &'a DaemonConfig,
|
||||
@ -174,7 +174,7 @@ impl ZoneCreator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
let reservation = self.ip_assignment.assign(uuid).await?;
|
||||
let reservation = self.network_assignment.assign(uuid).await?;
|
||||
|
||||
let mut initial_resources = spec.initial_resources.unwrap_or_default();
|
||||
if initial_resources.target_cpus < 1 {
|
||||
@ -236,7 +236,7 @@ impl ZoneCreator<'_> {
|
||||
info!("created zone {}", uuid);
|
||||
zone.status = Some(ZoneStatus {
|
||||
state: ZoneState::Created.into(),
|
||||
network_status: Some(ip_reservation_to_network_status(&reservation)),
|
||||
network_status: Some(network_reservation_to_network_status(&reservation)),
|
||||
exit_status: None,
|
||||
error_status: None,
|
||||
resource_status: Some(ZoneResourceStatus {
|
||||
|
@ -7,8 +7,8 @@ use std::{
|
||||
|
||||
use self::create::ZoneCreator;
|
||||
use crate::config::DaemonConfig;
|
||||
use crate::db::ip::IpReservation;
|
||||
use crate::ip::assignment::IpAssignment;
|
||||
use crate::db::network::NetworkReservation;
|
||||
use crate::network::assignment::NetworkAssignment;
|
||||
use crate::{
|
||||
db::zone::ZoneStore,
|
||||
devices::DaemonDeviceManager,
|
||||
@ -62,7 +62,7 @@ pub struct ZoneReconciler {
|
||||
tasks: Arc<RwLock<HashMap<Uuid, ZoneReconcilerEntry>>>,
|
||||
zone_reconciler_notify: Sender<Uuid>,
|
||||
zone_reconcile_lock: Arc<RwLock<()>>,
|
||||
ip_assignment: IpAssignment,
|
||||
ip_assignment: NetworkAssignment,
|
||||
config: Arc<DaemonConfig>,
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ impl ZoneReconciler {
|
||||
kernel_path: PathBuf,
|
||||
initrd_path: PathBuf,
|
||||
modules_path: PathBuf,
|
||||
ip_assignment: IpAssignment,
|
||||
ip_assignment: NetworkAssignment,
|
||||
config: Arc<DaemonConfig>,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
@ -195,7 +195,7 @@ impl ZoneReconciler {
|
||||
|
||||
if let Some(reservation) = self.ip_assignment.retrieve(uuid).await? {
|
||||
status.network_status =
|
||||
Some(ip_reservation_to_network_status(&reservation));
|
||||
Some(network_reservation_to_network_status(&reservation));
|
||||
}
|
||||
stored_zone.status = Some(status);
|
||||
}
|
||||
@ -286,7 +286,7 @@ impl ZoneReconciler {
|
||||
initrd_path: &self.initrd_path,
|
||||
addons_path: &self.addons_path,
|
||||
packer: &self.packer,
|
||||
ip_assignment: &self.ip_assignment,
|
||||
network_assignment: &self.ip_assignment,
|
||||
zlt: &self.zlt,
|
||||
runtime: &self.runtime,
|
||||
config: &self.config,
|
||||
@ -369,7 +369,7 @@ impl ZoneReconciler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ip_reservation_to_network_status(ip: &IpReservation) -> ZoneNetworkStatus {
|
||||
pub fn network_reservation_to_network_status(ip: &NetworkReservation) -> ZoneNetworkStatus {
|
||||
ZoneNetworkStatus {
|
||||
zone_ipv4: format!("{}/{}", ip.ipv4, ip.ipv4_prefix),
|
||||
zone_ipv6: format!("{}/{}", ip.ipv6, ip.ipv6_prefix),
|
||||
|
@ -46,6 +46,7 @@ message ExecStreamRequestStart {
|
||||
repeated string command = 2;
|
||||
string working_directory = 3;
|
||||
bool tty = 4;
|
||||
ExecStreamRequestTerminalSize terminal_size = 5;
|
||||
}
|
||||
|
||||
message ExecStreamRequestStdin {
|
||||
@ -53,10 +54,16 @@ message ExecStreamRequestStdin {
|
||||
bool closed = 2;
|
||||
}
|
||||
|
||||
message ExecStreamRequestTerminalSize {
|
||||
uint32 rows = 1;
|
||||
uint32 columns = 2;
|
||||
}
|
||||
|
||||
message ExecStreamRequestUpdate {
|
||||
oneof update {
|
||||
ExecStreamRequestStart start = 1;
|
||||
ExecStreamRequestStdin stdin = 2;
|
||||
ExecStreamRequestTerminalSize terminal_resize = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,3 +134,18 @@ enum ZoneMetricFormat {
|
||||
ZONE_METRIC_FORMAT_INTEGER = 2;
|
||||
ZONE_METRIC_FORMAT_DURATION_SECONDS = 3;
|
||||
}
|
||||
|
||||
message TerminalSize {
|
||||
uint32 rows = 1;
|
||||
uint32 columns = 2;
|
||||
}
|
||||
|
||||
message NetworkReservation {
|
||||
string uuid = 1;
|
||||
string ipv4 = 2;
|
||||
string ipv6 = 3;
|
||||
string mac = 4;
|
||||
string gateway_ipv4 = 5;
|
||||
string gateway_ipv6 = 6;
|
||||
string gateway_mac = 7;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ service ControlService {
|
||||
|
||||
rpc ListDevices(ListDevicesRequest) returns (ListDevicesReply);
|
||||
|
||||
rpc ListNetworkReservations(ListNetworkReservationsRequest) returns (ListNetworkReservationsReply);
|
||||
|
||||
rpc PullImage(PullImageRequest) returns (stream PullImageReply);
|
||||
|
||||
rpc CreateZone(CreateZoneRequest) returns (CreateZoneReply);
|
||||
@ -91,6 +93,7 @@ message ExecInsideZoneRequest {
|
||||
krata.v1.common.ZoneTaskSpec task = 2;
|
||||
bytes stdin = 3;
|
||||
bool stdin_closed = 4;
|
||||
krata.v1.common.TerminalSize terminal_size = 5;
|
||||
}
|
||||
|
||||
message ExecInsideZoneReply {
|
||||
@ -264,3 +267,9 @@ message ReadHypervisorConsoleRequest {}
|
||||
message ReadHypervisorConsoleReply {
|
||||
string data = 1;
|
||||
}
|
||||
|
||||
message ListNetworkReservationsRequest {}
|
||||
|
||||
message ListNetworkReservationsReply {
|
||||
repeated krata.v1.common.NetworkReservation reservations = 1;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ clap = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
etherparse = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
krata = { path = "../krata", version = "^0.0.19" }
|
||||
krata = { path = "../krata", version = "^0.0.21" }
|
||||
krata-advmac = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
@ -12,20 +12,20 @@ resolver = "2"
|
||||
anyhow = { workspace = true }
|
||||
backhand = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
krata = { path = "../krata", version = "^0.0.19" }
|
||||
krata = { path = "../krata", version = "^0.0.21" }
|
||||
krata-advmac = { workspace = true }
|
||||
krata-oci = { path = "../oci", version = "^0.0.19" }
|
||||
krata-oci = { path = "../oci", version = "^0.0.21" }
|
||||
log = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
krata-loopdev = { path = "../loopdev", version = "^0.0.19" }
|
||||
krata-xencall = { path = "../xen/xencall", version = "^0.0.19" }
|
||||
krata-xenclient = { path = "../xen/xenclient", version = "^0.0.19" }
|
||||
krata-xenevtchn = { path = "../xen/xenevtchn", version = "^0.0.19" }
|
||||
krata-xengnt = { path = "../xen/xengnt", version = "^0.0.19" }
|
||||
krata-xenplatform = { path = "../xen/xenplatform", version = "^0.0.19" }
|
||||
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.19" }
|
||||
krata-loopdev = { path = "../loopdev", version = "^0.0.21" }
|
||||
krata-xencall = { path = "../xen/xencall", version = "^0.0.21" }
|
||||
krata-xenclient = { path = "../xen/xenclient", version = "^0.0.21" }
|
||||
krata-xenevtchn = { path = "../xen/xenevtchn", version = "^0.0.21" }
|
||||
krata-xengnt = { path = "../xen/xengnt", version = "^0.0.21" }
|
||||
krata-xenplatform = { path = "../xen/xenplatform", version = "^0.0.21" }
|
||||
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.21" }
|
||||
walkdir = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
|
||||
|
@ -13,9 +13,9 @@ async-trait = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
krata-xencall = { path = "../xencall", version = "^0.0.19" }
|
||||
krata-xenplatform = { path = "../xenplatform", version = "^0.0.19" }
|
||||
krata-xenstore = { path = "../xenstore", version = "^0.0.19" }
|
||||
krata-xencall = { path = "../xencall", version = "^0.0.21" }
|
||||
krata-xenplatform = { path = "../xenplatform", version = "^0.0.21" }
|
||||
krata-xenstore = { path = "../xenstore", version = "^0.0.21" }
|
||||
regex = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
@ -16,7 +16,7 @@ flate2 = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
krata-xencall = { path = "../xencall", version = "^0.0.19" }
|
||||
krata-xencall = { path = "../xencall", version = "^0.0.21" }
|
||||
memchr = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
|
@ -14,8 +14,8 @@ cgroups-rs = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
krata = { path = "../krata", version = "^0.0.19" }
|
||||
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.19" }
|
||||
krata = { path = "../krata", version = "^0.0.21" }
|
||||
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.21" }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
nix = { workspace = true, features = ["ioctl", "process", "fs"] }
|
||||
|
@ -70,7 +70,11 @@ impl ZoneExecTask {
|
||||
let code: c_int;
|
||||
if start.tty {
|
||||
let pty = Pty::new().map_err(|error| anyhow!("unable to allocate pty: {}", error))?;
|
||||
pty.resize(Size::new(24, 80))?;
|
||||
let size = start
|
||||
.terminal_size
|
||||
.map(|x| Size::new(x.rows as u16, x.columns as u16))
|
||||
.unwrap_or_else(|| Size::new(24, 80));
|
||||
pty.resize(size)?;
|
||||
let pts = pty
|
||||
.pts()
|
||||
.map_err(|error| anyhow!("unable to allocate pts: {}", error))?;
|
||||
@ -130,16 +134,24 @@ impl ZoneExecTask {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(Update::Stdin(update)) = update.update else {
|
||||
continue;
|
||||
};
|
||||
match update.update {
|
||||
Some(Update::Stdin(update)) => {
|
||||
if !update.data.is_empty()
|
||||
&& write.write_all(&update.data).await.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if !update.data.is_empty() && write.write_all(&update.data).await.is_err() {
|
||||
break;
|
||||
}
|
||||
|
||||
if update.closed {
|
||||
break;
|
||||
if update.closed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Some(Update::TerminalResize(size)) => {
|
||||
let _ = write.resize(Size::new(size.rows as u16, size.columns as u16));
|
||||
}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -94,10 +94,10 @@ It is possible to copy these options into a `.config` file and then use
|
||||
`make olddefconfig` to build the rest of the kernel configuration, which
|
||||
you can then use to build a kernel as desired.
|
||||
|
||||
The [kernels][edera-kernels] repository provides some example configurations
|
||||
The [linux-kernel-oci][edera-linux-kernel-oci] repository provides some example configurations
|
||||
and can generate a Dockerfile which will build a kernel image.
|
||||
|
||||
[edera-kernels]: https://github.com/edera-dev/kernels
|
||||
[edera-linux-kernel-oci]: https://github.com/edera-dev/linux-kernel-oci
|
||||
|
||||
Minimum requirements for a host kernel
|
||||
--------------------------------------
|
||||
|
@ -16,4 +16,4 @@ fi
|
||||
|
||||
export TARGET_ARCH
|
||||
TARGET_ARCH="" TARGET_LIBC="" RUST_TARGET="${HOST_RUST_TARGET}" ./hack/build/cargo.sh build -q --bin build-fetch-kernel
|
||||
exec "target/${HOST_RUST_TARGET}/debug/build-fetch-kernel" "ghcr.io/edera-dev/kernels:latest"
|
||||
exec "target/${HOST_RUST_TARGET}/debug/build-fetch-kernel" "ghcr.io/edera-dev/linux-kernel:latest"
|
||||
|
Reference in New Issue
Block a user