Compare commits

...

6 Commits

Author SHA1 Message Date
3cb0e214e9 chore: release (#362)
Co-authored-by: edera-cultivation[bot] <165992271+edera-cultivation[bot]@users.noreply.github.com>
2024-08-29 01:50:12 +00:00
0e0c5264eb build(deps): bump the dep-updates group with 2 updates (#367)
Bumps the dep-updates group with 2 updates: [tonic-build](https://github.com/hyperium/tonic) and [tonic](https://github.com/hyperium/tonic).


Updates `tonic-build` from 0.12.1 to 0.12.2
- [Release notes](https://github.com/hyperium/tonic/releases)
- [Changelog](https://github.com/hyperium/tonic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/tonic/compare/v0.12.1...v0.12.2)

Updates `tonic` from 0.12.1 to 0.12.2
- [Release notes](https://github.com/hyperium/tonic/releases)
- [Changelog](https://github.com/hyperium/tonic/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/tonic/compare/v0.12.1...v0.12.2)

---
updated-dependencies:
- dependency-name: tonic-build
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: tonic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-27 19:23:26 +00:00
19f35ef20a feature(krata): implement network reservation list (#366) 2024-08-26 19:05:57 +00:00
79e27256e6 build(deps): bump the dep-updates group with 6 updates (#365)
Bumps the dep-updates group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [flate2](https://github.com/rust-lang/flate2-rs) | `1.0.32` | `1.0.33` |
| [ratatui](https://github.com/ratatui/ratatui) | `0.28.0` | `0.28.1` |
| [redb](https://github.com/cberner/redb) | `2.1.1` | `2.1.2` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.125` | `1.0.127` |
| [sysinfo](https://github.com/GuillaumeGomez/sysinfo) | `0.31.2` | `0.31.3` |
| [serde](https://github.com/serde-rs/serde) | `1.0.208` | `1.0.209` |


Updates `flate2` from 1.0.32 to 1.0.33
- [Release notes](https://github.com/rust-lang/flate2-rs/releases)
- [Changelog](https://github.com/rust-lang/flate2-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/flate2-rs/compare/1.0.32...1.0.33)

Updates `ratatui` from 0.28.0 to 0.28.1
- [Release notes](https://github.com/ratatui/ratatui/releases)
- [Changelog](https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ratatui/ratatui/compare/v0.28.0...v0.28.1)

Updates `redb` from 2.1.1 to 2.1.2
- [Release notes](https://github.com/cberner/redb/releases)
- [Changelog](https://github.com/cberner/redb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/cberner/redb/compare/v2.1.1...v2.1.2)

Updates `serde_json` from 1.0.125 to 1.0.127
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/1.0.125...1.0.127)

Updates `sysinfo` from 0.31.2 to 0.31.3
- [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.31.2...v0.31.3)

Updates `serde` from 1.0.208 to 1.0.209
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.208...v1.0.209)

---
updated-dependencies:
- dependency-name: flate2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: ratatui
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: redb
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: sysinfo
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dep-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex Zenla <alex@edera.dev>
2024-08-26 08:27:30 +00:00
b6c726e7aa feature(kernel): switch to linux-kernel-oci images (#364) 2024-08-26 06:18:56 +00:00
0d2b7a3ae3 feature(zone-exec): implement terminal resize support (#363) 2024-08-26 04:43:07 +00:00
34 changed files with 620 additions and 170 deletions

View File

@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [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 ## [0.0.19](https://github.com/edera-dev/krata/compare/v0.0.18...v0.0.19) - 2024-08-25
### Added ### Added

66
Cargo.lock generated
View File

@ -814,9 +814,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.32" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666" checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.0", "miniz_oxide 0.8.0",
@ -1297,7 +1297,7 @@ dependencies = [
[[package]] [[package]]
name = "krata" name = "krata"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1337,7 +1337,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-buildtools" name = "krata-buildtools"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"env_logger", "env_logger",
@ -1352,7 +1352,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-ctl" name = "krata-ctl"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1382,7 +1382,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-daemon" name = "krata-daemon"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1414,14 +1414,14 @@ dependencies = [
[[package]] [[package]]
name = "krata-loopdev" name = "krata-loopdev"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "krata-network" name = "krata-network"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -1445,7 +1445,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-oci" name = "krata-oci"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-compression", "async-compression",
@ -1472,7 +1472,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-runtime" name = "krata-runtime"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backhand", "backhand",
@ -1513,7 +1513,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xencall" name = "krata-xencall"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"libc", "libc",
@ -1526,7 +1526,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xenclient" name = "krata-xenclient"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"env_logger", "env_logger",
@ -1544,7 +1544,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xenevtchn" name = "krata-xenevtchn"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"libc", "libc",
@ -1556,7 +1556,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xengnt" name = "krata-xengnt"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"libc", "libc",
"nix 0.29.0", "nix 0.29.0",
@ -1565,7 +1565,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xenplatform" name = "krata-xenplatform"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"c2rust-bitfields", "c2rust-bitfields",
@ -1588,7 +1588,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-xenstore" name = "krata-xenstore"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"env_logger", "env_logger",
@ -1600,7 +1600,7 @@ dependencies = [
[[package]] [[package]]
name = "krata-zone" name = "krata-zone"
version = "0.0.19" version = "0.0.20"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cgroups-rs", "cgroups-rs",
@ -2304,9 +2304,9 @@ dependencies = [
[[package]] [[package]]
name = "ratatui" name = "ratatui"
version = "0.28.0" version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ba6a365afbe5615999275bea2446b970b10a41102500e27ce7678d50d978303" checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"cassowary", "cassowary",
@ -2345,9 +2345,9 @@ dependencies = [
[[package]] [[package]]
name = "redb" name = "redb"
version = "2.1.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6dd20d3cdeb9c7d2366a0b16b93b35b75aec15309fbeb7ce477138c9f68c8c0" checksum = "58323dc32ea52a8ae105ff94bc0460c5d906307533ba3401aa63db3cbe491fe5"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -2577,9 +2577,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.208" version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2596,9 +2596,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.208" version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2607,9 +2607,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.125" version = "1.0.127"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -2867,9 +2867,9 @@ dependencies = [
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.31.2" version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab" checksum = "2b92e0bdf838cbc1c4c9ba14f9c97a7ec6cdcd1ae66b10e1e42775a25553f45d"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -3062,9 +3062,9 @@ dependencies = [
[[package]] [[package]]
name = "tonic" name = "tonic"
version = "0.12.1" version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401" checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad"
dependencies = [ dependencies = [
"async-stream", "async-stream",
"async-trait", "async-trait",
@ -3094,9 +3094,9 @@ dependencies = [
[[package]] [[package]]
name = "tonic-build" name = "tonic-build"
version = "0.12.1" version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67"
dependencies = [ dependencies = [
"prettyplease", "prettyplease",
"proc-macro2", "proc-macro2",

View File

@ -18,7 +18,7 @@ members = [
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.0.19" version = "0.0.20"
homepage = "https://krata.dev" homepage = "https://krata.dev"
license = "Apache-2.0" license = "Apache-2.0"
repository = "https://github.com/edera-dev/krata" repository = "https://github.com/edera-dev/krata"
@ -70,24 +70,24 @@ prost-reflect-build = "0.14.0"
prost-types = "0.13.1" prost-types = "0.13.1"
pty-process = "0.4.0" pty-process = "0.4.0"
rand = "0.8.5" rand = "0.8.5"
ratatui = "0.28.0" ratatui = "0.28.1"
redb = "2.1.1" redb = "2.1.2"
regex = "1.10.6" regex = "1.10.6"
rtnetlink = "0.14.1" rtnetlink = "0.14.1"
scopeguard = "1.2.0" scopeguard = "1.2.0"
serde_json = "1.0.125" serde_json = "1.0.127"
serde_yaml = "0.9" serde_yaml = "0.9"
sha256 = "1.5.0" sha256 = "1.5.0"
signal-hook = "0.3.17" signal-hook = "0.3.17"
slice-copy = "0.3.0" slice-copy = "0.3.0"
smoltcp = "0.11.0" smoltcp = "0.11.0"
sysinfo = "0.31.2" sysinfo = "0.31.3"
termtree = "0.5.1" termtree = "0.5.1"
thiserror = "1.0" thiserror = "1.0"
tokio-tun = "0.11.5" tokio-tun = "0.11.5"
tokio-util = "0.7.11" tokio-util = "0.7.11"
toml = "0.8.19" toml = "0.8.19"
tonic-build = "0.12.1" tonic-build = "0.12.2"
tower = "0.5.0" tower = "0.5.0"
udp-stream = "0.0.12" udp-stream = "0.0.12"
url = "2.5.2" url = "2.5.2"
@ -108,7 +108,7 @@ default-features = false
features = ["rustls-tls"] features = ["rustls-tls"]
[workspace.dependencies.serde] [workspace.dependencies.serde]
version = "1.0.208" version = "1.0.209"
features = ["derive"] features = ["derive"]
[workspace.dependencies.sys-mount] [workspace.dependencies.sys-mount]
@ -124,7 +124,7 @@ version = "0.1"
features = ["io-util", "net"] features = ["io-util", "net"]
[workspace.dependencies.tonic] [workspace.dependencies.tonic]
version = "0.12.1" version = "0.12.2"
features = ["tls"] features = ["tls"]
[workspace.dependencies.uuid] [workspace.dependencies.uuid]

View File

@ -16,7 +16,7 @@ oci-spec = { workspace = true }
scopeguard = { workspace = true } scopeguard = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
tokio-stream = { workspace = true } tokio-stream = { workspace = true }
krata-oci = { path = "../oci", version = "^0.0.19" } krata-oci = { path = "../oci", version = "^0.0.20" }
krata-tokio-tar = { workspace = true } krata-tokio-tar = { workspace = true }
uuid = { workspace = true } uuid = { workspace = true }

View File

@ -20,7 +20,7 @@ env_logger = { workspace = true }
fancy-duration = { workspace = true } fancy-duration = { workspace = true }
human_bytes = { workspace = true } human_bytes = { workspace = true }
indicatif = { workspace = true } indicatif = { workspace = true }
krata = { path = "../krata", version = "^0.0.19" } krata = { path = "../krata", version = "^0.0.20" }
log = { workspace = true } log = { workspace = true }
prost-reflect = { workspace = true, features = ["serde"] } prost-reflect = { workspace = true, features = ["serde"] }
prost-types = { workspace = true } prost-types = { workspace = true }

View File

@ -1,6 +1,7 @@
pub mod device; pub mod device;
pub mod host; pub mod host;
pub mod image; pub mod image;
pub mod network;
pub mod zone; pub mod zone;
use crate::cli::device::DeviceCommand; use crate::cli::device::DeviceCommand;
@ -14,6 +15,7 @@ use krata::{
events::EventStream, events::EventStream,
v1::control::{control_service_client::ControlServiceClient, ResolveZoneIdRequest}, v1::control::{control_service_client::ControlServiceClient, ResolveZoneIdRequest},
}; };
use network::NetworkCommand;
use tonic::{transport::Channel, Request}; use tonic::{transport::Channel, Request};
#[derive(Parser)] #[derive(Parser)]
@ -36,6 +38,7 @@ pub struct ControlCommand {
pub enum ControlCommands { pub enum ControlCommands {
Zone(ZoneCommand), Zone(ZoneCommand),
Image(ImageCommand), Image(ImageCommand),
Network(NetworkCommand),
Device(DeviceCommand), Device(DeviceCommand),
Host(HostCommand), Host(HostCommand),
} }
@ -57,6 +60,8 @@ impl ControlCommands {
match self { match self {
ControlCommands::Zone(zone) => zone.run(client, events).await, 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::Image(image) => image.run(client, events).await,
ControlCommands::Device(device) => device.run(client, events).await, ControlCommands::Device(device) => device.run(client, events).await,

View 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,
}
}
}

View 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(())
}
}

View 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,
}
}
}

View File

@ -3,11 +3,13 @@ use std::collections::HashMap;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use crossterm::tty::IsTty;
use krata::v1::{ use krata::v1::{
common::{ZoneTaskSpec, ZoneTaskSpecEnvVar}, common::{TerminalSize, ZoneTaskSpec, ZoneTaskSpecEnvVar},
control::{control_service_client::ControlServiceClient, ExecInsideZoneRequest}, control::{control_service_client::ControlServiceClient, ExecInsideZoneRequest},
}; };
use tokio::io::stdin;
use tonic::{transport::Channel, Request}; use tonic::{transport::Channel, Request};
use crate::console::StdioConsoleStream; use crate::console::StdioConsoleStream;
@ -36,6 +38,7 @@ pub struct ZoneExecCommand {
impl ZoneExecCommand { impl ZoneExecCommand {
pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> { pub async fn run(self, mut client: ControlServiceClient<Channel>) -> Result<()> {
let zone_id: String = resolve_zone(&mut client, &self.zone).await?; let zone_id: String = resolve_zone(&mut client, &self.zone).await?;
let should_map_tty = self.tty && stdin().is_tty();
let initial = ExecInsideZoneRequest { let initial = ExecInsideZoneRequest {
zone_id, zone_id,
task: Some(ZoneTaskSpec { task: Some(ZoneTaskSpec {
@ -52,16 +55,25 @@ impl ZoneExecCommand {
}), }),
stdin: vec![], stdin: vec![],
stdin_closed: false, 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 let response = client
.exec_inside_zone(Request::new(stream)) .exec_inside_zone(Request::new(stream))
.await? .await?
.into_inner(); .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); std::process::exit(code);
} }
} }

View File

@ -7,6 +7,7 @@ use crossterm::{
use krata::v1::common::ZoneState; use krata::v1::common::ZoneState;
use krata::{ use krata::{
events::EventStream, events::EventStream,
v1::common::TerminalSize,
v1::control::{ v1::control::{
watch_events_reply::Event, ExecInsideZoneReply, ExecInsideZoneRequest, ZoneConsoleReply, watch_events_reply::Event, ExecInsideZoneReply, ExecInsideZoneRequest, ZoneConsoleReply,
ZoneConsoleRequest, ZoneConsoleRequest,
@ -15,6 +16,7 @@ use krata::{
use log::debug; use log::debug;
use tokio::{ use tokio::{
io::{stderr, stdin, stdout, AsyncReadExt, AsyncWriteExt}, io::{stderr, stdin, stdout, AsyncReadExt, AsyncWriteExt},
select,
task::JoinHandle, task::JoinHandle,
}; };
use tokio_stream::{Stream, StreamExt}; use tokio_stream::{Stream, StreamExt};
@ -22,6 +24,11 @@ use tonic::Streaming;
pub struct StdioConsoleStream; pub struct StdioConsoleStream;
enum ExecStdinSelect {
DataRead(std::io::Result<usize>),
TerminalResize,
}
impl StdioConsoleStream { impl StdioConsoleStream {
pub async fn stdin_stream( pub async fn stdin_stream(
zone: String, zone: String,
@ -49,30 +56,106 @@ impl StdioConsoleStream {
} }
} }
pub async fn stdin_stream_exec( #[cfg(unix)]
pub async fn input_stream_exec(
initial: ExecInsideZoneRequest, initial: ExecInsideZoneRequest,
tty: bool,
) -> impl Stream<Item = ExecInsideZoneRequest> { ) -> impl Stream<Item = ExecInsideZoneRequest> {
let mut stdin = stdin(); let mut stdin = stdin();
stream! { stream! {
yield initial; yield initial;
let mut buffer = vec![0u8; 60]; 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 { loop {
let size = match stdin.read(&mut buffer).await { let selected = if let Some(ref mut terminal_size_change) = terminal_size_change {
Ok(size) => size, if stdin_closed {
Err(error) => { select! {
debug!("failed to read stdin: {}", error); _ = terminal_size_change.recv() => ExecStdinSelect::TerminalResize,
break; }
} 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 { match selected {
break; 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> { pub async fn exec_output(mut stream: Streaming<ExecInsideZoneReply>, raw: bool) -> Result<i32> {
if raw && stdin().is_tty() { if raw {
enable_raw_mode()?; enable_raw_mode()?;
StdioConsoleStream::register_terminal_restore_hook()?; StdioConsoleStream::register_terminal_restore_hook()?;
} }

View File

@ -19,9 +19,9 @@ clap = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
ipnetwork = { workspace = true } ipnetwork = { workspace = true }
krata = { path = "../krata", version = "^0.0.19" } krata = { path = "../krata", version = "^0.0.20" }
krata-oci = { path = "../oci", version = "^0.0.19" } krata-oci = { path = "../oci", version = "^0.0.20" }
krata-runtime = { path = "../runtime", version = "^0.0.19" } krata-runtime = { path = "../runtime", version = "^0.0.20" }
log = { workspace = true } log = { workspace = true }
prost = { workspace = true } prost = { workspace = true }
redb = { workspace = true } redb = { workspace = true }

View File

@ -13,7 +13,8 @@ use krata::{
idm::internal::{ idm::internal::{
exec_stream_request_update::Update, request::Request as IdmRequestType, exec_stream_request_update::Update, request::Request as IdmRequestType,
response::Response as IdmResponseType, ExecEnvVar, ExecStreamRequestStart, response::Response as IdmResponseType, ExecEnvVar, ExecStreamRequestStart,
ExecStreamRequestStdin, ExecStreamRequestUpdate, Request as IdmRequest, ExecStreamRequestStdin, ExecStreamRequestTerminalSize, ExecStreamRequestUpdate,
Request as IdmRequest,
}, },
v1::control::{ExecInsideZoneReply, ExecInsideZoneRequest}, v1::control::{ExecInsideZoneReply, ExecInsideZoneRequest},
}; };
@ -61,6 +62,12 @@ impl ExecInsideZoneRpc {
command: task.command, command: task.command,
working_directory: task.working_directory, working_directory: task.working_directory,
tty: task.tty, tty: task.tty,
terminal_size: request.terminal_size.map(|size| {
ExecStreamRequestTerminalSize {
rows: size.rows,
columns: size.columns,
}
}),
})), })),
})), })),
}; };
@ -87,6 +94,16 @@ impl ExecInsideZoneRpc {
})), })),
}))}).await; }))}).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 { x = handle.receiver.recv() => match x {

View File

@ -1,21 +1,21 @@
use crate::command::DaemonCommand; use crate::command::DaemonCommand;
use crate::ip::assignment::IpAssignment; use crate::network::assignment::NetworkAssignment;
use crate::zlt::ZoneLookupTable; use crate::zlt::ZoneLookupTable;
use anyhow::Result; use anyhow::Result;
use krata::v1::control::{GetHostStatusReply, GetHostStatusRequest}; use krata::v1::control::{GetHostStatusReply, GetHostStatusRequest};
pub struct GetHostStatusRpc { pub struct GetHostStatusRpc {
ip: IpAssignment, network: NetworkAssignment,
zlt: ZoneLookupTable, zlt: ZoneLookupTable,
} }
impl GetHostStatusRpc { impl GetHostStatusRpc {
pub fn new(ip: IpAssignment, zlt: ZoneLookupTable) -> Self { pub fn new(ip: NetworkAssignment, zlt: ZoneLookupTable) -> Self {
Self { ip, zlt } Self { network: ip, zlt }
} }
pub async fn process(self, _request: GetHostStatusRequest) -> Result<GetHostStatusReply> { 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 { Ok(GetHostStatusReply {
host_domid: self.zlt.host_domid(), host_domid: self.zlt.host_domid(),
host_uuid: self.zlt.host_uuid().to_string(), host_uuid: self.zlt.host_uuid().to_string(),

View 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 })
}
}

View File

@ -2,6 +2,7 @@ use std::pin::Pin;
use anyhow::Error; use anyhow::Error;
use futures::Stream; use futures::Stream;
use list_network_reservations::ListNetworkReservationsRpc;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tonic::{Request, Response, Status, Streaming}; use tonic::{Request, Response, Status, Streaming};
use uuid::Uuid; use uuid::Uuid;
@ -17,8 +18,8 @@ use krata::v1::control::{
WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest, WatchEventsRequest, ZoneConsoleReply, ZoneConsoleRequest,
}; };
use krata::v1::control::{ use krata::v1::control::{
GetZoneReply, GetZoneRequest, SetHostPowerManagementPolicyReply, GetZoneReply, GetZoneRequest, ListNetworkReservationsReply, ListNetworkReservationsRequest,
SetHostPowerManagementPolicyRequest, SetHostPowerManagementPolicyReply, SetHostPowerManagementPolicyRequest,
}; };
use krataoci::packer::service::OciPackerService; use krataoci::packer::service::OciPackerService;
use kratart::Runtime; use kratart::Runtime;
@ -41,7 +42,7 @@ use crate::control::snoop_idm::SnoopIdmRpc;
use crate::control::update_zone_resources::UpdateZoneResourcesRpc; use crate::control::update_zone_resources::UpdateZoneResourcesRpc;
use crate::control::watch_events::WatchEventsRpc; use crate::control::watch_events::WatchEventsRpc;
use crate::db::zone::ZoneStore; use crate::db::zone::ZoneStore;
use crate::ip::assignment::IpAssignment; use crate::network::assignment::NetworkAssignment;
use crate::{ use crate::{
console::DaemonConsoleHandle, devices::DaemonDeviceManager, event::DaemonEventContext, console::DaemonConsoleHandle, devices::DaemonDeviceManager, event::DaemonEventContext,
idm::DaemonIdmHandle, zlt::ZoneLookupTable, idm::DaemonIdmHandle, zlt::ZoneLookupTable,
@ -55,6 +56,7 @@ pub mod get_host_cpu_topology;
pub mod get_host_status; pub mod get_host_status;
pub mod get_zone; pub mod get_zone;
pub mod list_devices; pub mod list_devices;
pub mod list_network_reservations;
pub mod list_zones; pub mod list_zones;
pub mod pull_image; pub mod pull_image;
pub mod read_hypervisor_console; pub mod read_hypervisor_console;
@ -91,7 +93,7 @@ pub struct DaemonControlService {
console: DaemonConsoleHandle, console: DaemonConsoleHandle,
idm: DaemonIdmHandle, idm: DaemonIdmHandle,
zones: ZoneStore, zones: ZoneStore,
ip: IpAssignment, network: NetworkAssignment,
zone_reconciler_notify: Sender<Uuid>, zone_reconciler_notify: Sender<Uuid>,
packer: OciPackerService, packer: OciPackerService,
runtime: Runtime, runtime: Runtime,
@ -106,7 +108,7 @@ impl DaemonControlService {
console: DaemonConsoleHandle, console: DaemonConsoleHandle,
idm: DaemonIdmHandle, idm: DaemonIdmHandle,
zones: ZoneStore, zones: ZoneStore,
ip: IpAssignment, network: NetworkAssignment,
zone_reconciler_notify: Sender<Uuid>, zone_reconciler_notify: Sender<Uuid>,
packer: OciPackerService, packer: OciPackerService,
runtime: Runtime, runtime: Runtime,
@ -118,7 +120,7 @@ impl DaemonControlService {
console, console,
idm, idm,
zones, zones,
ip, network,
zone_reconciler_notify, zone_reconciler_notify,
packer, packer,
runtime, runtime,
@ -134,7 +136,7 @@ impl ControlService for DaemonControlService {
) -> Result<Response<GetHostStatusReply>, Status> { ) -> Result<Response<GetHostStatusReply>, Status> {
let request = request.into_inner(); let request = request.into_inner();
adapt( adapt(
GetHostStatusRpc::new(self.ip.clone(), self.zlt.clone()) GetHostStatusRpc::new(self.network.clone(), self.zlt.clone())
.process(request) .process(request)
.await, .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 = type PullImageStream =
Pin<Box<dyn Stream<Item = Result<PullImageReply, Status>> + Send + 'static>>; Pin<Box<dyn Stream<Item = Result<PullImageReply, Status>> + Send + 'static>>;

View File

@ -3,7 +3,7 @@ use redb::Database;
use std::path::Path; use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
pub mod ip; pub mod network;
pub mod zone; pub mod zone;
#[derive(Clone)] #[derive(Clone)]

View File

@ -1,6 +1,7 @@
use crate::db::KrataDatabase; use crate::db::KrataDatabase;
use advmac::MacAddr6; use advmac::MacAddr6;
use anyhow::Result; use anyhow::Result;
use krata::v1::common::NetworkReservation as ApiNetworkReservation;
use log::error; use log::error;
use redb::{ReadableTable, TableDefinition}; use redb::{ReadableTable, TableDefinition};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,24 +9,25 @@ use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use uuid::Uuid; 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)] #[derive(Clone)]
pub struct IpReservationStore { pub struct NetworkReservationStore {
db: KrataDatabase, db: KrataDatabase,
} }
impl IpReservationStore { impl NetworkReservationStore {
pub fn open(db: KrataDatabase) -> Result<Self> { pub fn open(db: KrataDatabase) -> Result<Self> {
let write = db.database.begin_write()?; let write = db.database.begin_write()?;
let _ = write.open_table(IP_RESERVATION_TABLE); let _ = write.open_table(NETWORK_RESERVATION_TABLE);
write.commit()?; 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 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 { let Some(entry) = table.get(id.to_u128_le())? else {
return Ok(None); return Ok(None);
}; };
@ -33,26 +35,26 @@ impl IpReservationStore {
Ok(Some(serde_json::from_slice(bytes)?)) 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 { enum ListEntry {
Valid(Uuid, IpReservation), Valid(Uuid, NetworkReservation),
Invalid(Uuid), Invalid(Uuid),
} }
let mut reservations: HashMap<Uuid, IpReservation> = HashMap::new(); let mut reservations: HashMap<Uuid, NetworkReservation> = HashMap::new();
let corruptions = { let corruptions = {
let read = self.db.database.begin_read()?; let read = self.db.database.begin_read()?;
let table = read.open_table(IP_RESERVATION_TABLE)?; let table = read.open_table(NETWORK_RESERVATION_TABLE)?;
table table
.iter()? .iter()?
.flat_map(|result| { .flat_map(|result| {
result.map(|(key, value)| { result.map(|(key, value)| {
let uuid = Uuid::from_u128_le(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), Ok(reservation) => ListEntry::Valid(uuid, reservation),
Err(error) => { Err(error) => {
error!( error!(
"found invalid ip reservation in database for uuid {}: {}", "found invalid network reservation in database for uuid {}: {}",
uuid, error uuid, error
); );
ListEntry::Invalid(uuid) ListEntry::Invalid(uuid)
@ -73,7 +75,7 @@ impl IpReservationStore {
if !corruptions.is_empty() { if !corruptions.is_empty() {
let write = self.db.database.begin_write()?; 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 { for corruption in corruptions {
table.remove(corruption.to_u128_le())?; table.remove(corruption.to_u128_le())?;
} }
@ -82,10 +84,10 @@ impl IpReservationStore {
Ok(reservations) 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 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)?; let bytes = serde_json::to_vec(&entry)?;
table.insert(id.to_u128_le(), bytes.as_slice())?; table.insert(id.to_u128_le(), bytes.as_slice())?;
} }
@ -96,7 +98,7 @@ impl IpReservationStore {
pub async fn remove(&self, id: Uuid) -> Result<()> { pub async fn remove(&self, id: Uuid) -> Result<()> {
let write = self.db.database.begin_write()?; 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())?; table.remove(id.to_u128_le())?;
} }
write.commit()?; write.commit()?;
@ -105,7 +107,7 @@ impl IpReservationStore {
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct IpReservation { pub struct NetworkReservation {
pub uuid: String, pub uuid: String,
pub ipv4: Ipv4Addr, pub ipv4: Ipv4Addr,
pub ipv6: Ipv6Addr, pub ipv6: Ipv6Addr,
@ -116,3 +118,17 @@ pub struct IpReservation {
pub gateway_ipv6: Ipv6Addr, pub gateway_ipv6: Ipv6Addr,
pub gateway_mac: MacAddr6, 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('-', ":"),
}
}
}

View File

@ -1,7 +1,7 @@
use crate::db::ip::IpReservationStore; use crate::db::network::NetworkReservationStore;
use crate::db::zone::ZoneStore; use crate::db::zone::ZoneStore;
use crate::db::KrataDatabase; use crate::db::KrataDatabase;
use crate::ip::assignment::IpAssignment; use crate::network::assignment::NetworkAssignment;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use config::DaemonConfig; use config::DaemonConfig;
use console::{DaemonConsole, DaemonConsoleHandle}; use console::{DaemonConsole, DaemonConsoleHandle};
@ -37,18 +37,19 @@ pub mod db;
pub mod devices; pub mod devices;
pub mod event; pub mod event;
pub mod idm; pub mod idm;
pub mod ip;
pub mod metrics; pub mod metrics;
pub mod network;
pub mod oci; pub mod oci;
pub mod reconcile; pub mod reconcile;
pub mod zlt; pub mod zlt;
pub struct Daemon { pub struct Daemon {
store: String, store: String,
_config: Arc<DaemonConfig>, _config: Arc<DaemonConfig>,
zlt: ZoneLookupTable, zlt: ZoneLookupTable,
devices: DaemonDeviceManager, devices: DaemonDeviceManager,
zones: ZoneStore, zones: ZoneStore,
ip: IpAssignment, network: NetworkAssignment,
events: DaemonEventContext, events: DaemonEventContext,
zone_reconciler_task: JoinHandle<()>, zone_reconciler_task: JoinHandle<()>,
zone_reconciler_notify: Sender<Uuid>, zone_reconciler_notify: Sender<Uuid>,
@ -127,9 +128,14 @@ impl Daemon {
let runtime_for_reconciler = runtime.dupe().await?; let runtime_for_reconciler = runtime.dupe().await?;
let ipv4_network = Ipv4Network::from_str(&config.network.ipv4.subnet)?; let ipv4_network = Ipv4Network::from_str(&config.network.ipv4.subnet)?;
let ipv6_network = Ipv6Network::from_str(&config.network.ipv6.subnet)?; let ipv6_network = Ipv6Network::from_str(&config.network.ipv6.subnet)?;
let ip_reservation_store = IpReservationStore::open(database)?; let network_reservation_store = NetworkReservationStore::open(database)?;
let ip = let network = NetworkAssignment::new(
IpAssignment::new(host_uuid, ipv4_network, ipv6_network, ip_reservation_store).await?; host_uuid,
ipv4_network,
ipv6_network,
network_reservation_store,
)
.await?;
debug!("initializing zone reconciler"); debug!("initializing zone reconciler");
let zone_reconciler = ZoneReconciler::new( let zone_reconciler = ZoneReconciler::new(
devices.clone(), devices.clone(),
@ -142,7 +148,7 @@ impl Daemon {
kernel_path, kernel_path,
initrd_path, initrd_path,
addons_path, addons_path,
ip.clone(), network.clone(),
config.clone(), config.clone(),
)?; )?;
@ -165,7 +171,7 @@ impl Daemon {
zlt, zlt,
devices, devices,
zones, zones,
ip, network,
events, events,
zone_reconciler_task, zone_reconciler_task,
zone_reconciler_notify, zone_reconciler_notify,
@ -186,7 +192,7 @@ impl Daemon {
self.console.clone(), self.console.clone(),
self.idm.clone(), self.idm.clone(),
self.zones.clone(), self.zones.clone(),
self.ip.clone(), self.network.clone(),
self.zone_reconciler_notify.clone(), self.zone_reconciler_notify.clone(),
self.packer.clone(), self.packer.clone(),
self.runtime.clone(), self.runtime.clone(),

View File

@ -9,37 +9,37 @@ use std::{
use tokio::sync::RwLock; use tokio::sync::RwLock;
use uuid::Uuid; use uuid::Uuid;
use crate::db::ip::{IpReservation, IpReservationStore}; use crate::db::network::{NetworkReservation, NetworkReservationStore};
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct IpAssignmentState { pub struct NetworkAssignmentState {
pub ipv4: HashMap<Ipv4Addr, IpReservation>, pub ipv4: HashMap<Ipv4Addr, NetworkReservation>,
pub ipv6: HashMap<Ipv6Addr, IpReservation>, pub ipv6: HashMap<Ipv6Addr, NetworkReservation>,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct IpAssignment { pub struct NetworkAssignment {
ipv4_network: Ipv4Network, ipv4_network: Ipv4Network,
ipv6_network: Ipv6Network, ipv6_network: Ipv6Network,
gateway_ipv4: Ipv4Addr, gateway_ipv4: Ipv4Addr,
gateway_ipv6: Ipv6Addr, gateway_ipv6: Ipv6Addr,
gateway_mac: MacAddr6, gateway_mac: MacAddr6,
store: IpReservationStore, store: NetworkReservationStore,
state: Arc<RwLock<IpAssignmentState>>, state: Arc<RwLock<NetworkAssignmentState>>,
} }
impl IpAssignment { impl NetworkAssignment {
pub async fn new( pub async fn new(
host_uuid: Uuid, host_uuid: Uuid,
ipv4_network: Ipv4Network, ipv4_network: Ipv4Network,
ipv6_network: Ipv6Network, ipv6_network: Ipv6Network,
store: IpReservationStore, store: NetworkReservationStore,
) -> Result<Self> { ) -> 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? { let gateway_reservation = if let Some(reservation) = store.read(Uuid::nil()).await? {
reservation reservation
} else { } else {
IpAssignment::allocate( NetworkAssignment::allocate(
&mut state, &mut state,
&store, &store,
Uuid::nil(), Uuid::nil(),
@ -53,7 +53,7 @@ impl IpAssignment {
}; };
if store.read(host_uuid).await?.is_none() { if store.read(host_uuid).await?.is_none() {
let _ = IpAssignment::allocate( let _ = NetworkAssignment::allocate(
&mut state, &mut state,
&store, &store,
host_uuid, host_uuid,
@ -66,7 +66,7 @@ impl IpAssignment {
.await?; .await?;
} }
let assignment = IpAssignment { let assignment = NetworkAssignment {
ipv4_network, ipv4_network,
ipv6_network, ipv6_network,
gateway_ipv4: gateway_reservation.ipv4, gateway_ipv4: gateway_reservation.ipv4,
@ -78,9 +78,11 @@ impl IpAssignment {
Ok(assignment) 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 reservations = store.list().await?;
let mut state = IpAssignmentState::default(); let mut state = NetworkAssignmentState::default();
for reservation in reservations.values() { for reservation in reservations.values() {
state.ipv4.insert(reservation.ipv4, reservation.clone()); state.ipv4.insert(reservation.ipv4, reservation.clone());
state.ipv6.insert(reservation.ipv6, reservation.clone()); state.ipv6.insert(reservation.ipv6, reservation.clone());
@ -90,15 +92,15 @@ impl IpAssignment {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
async fn allocate( async fn allocate(
state: &mut IpAssignmentState, state: &mut NetworkAssignmentState,
store: &IpReservationStore, store: &NetworkReservationStore,
uuid: Uuid, uuid: Uuid,
ipv4_network: Ipv4Network, ipv4_network: Ipv4Network,
ipv6_network: Ipv6Network, ipv6_network: Ipv6Network,
gateway_ipv4: Option<Ipv4Addr>, gateway_ipv4: Option<Ipv4Addr>,
gateway_ipv6: Option<Ipv6Addr>, gateway_ipv6: Option<Ipv6Addr>,
gateway_mac: Option<MacAddr6>, gateway_mac: Option<MacAddr6>,
) -> Result<IpReservation> { ) -> Result<NetworkReservation> {
let found_ipv4: Option<Ipv4Addr> = ipv4_network let found_ipv4: Option<Ipv4Addr> = ipv4_network
.iter() .iter()
.filter(|ip| { .filter(|ip| {
@ -136,7 +138,7 @@ impl IpAssignment {
mac.set_local(true); mac.set_local(true);
mac.set_multicast(false); mac.set_multicast(false);
let reservation = IpReservation { let reservation = NetworkReservation {
uuid: uuid.to_string(), uuid: uuid.to_string(),
ipv4, ipv4,
ipv6, ipv6,
@ -153,9 +155,9 @@ impl IpAssignment {
Ok(reservation) 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 mut state = self.state.write().await;
let reservation = IpAssignment::allocate( let reservation = NetworkAssignment::allocate(
&mut state, &mut state,
&self.store, &self.store,
uuid, uuid,
@ -181,18 +183,22 @@ impl IpAssignment {
Ok(()) 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 self.store.read(uuid).await
} }
pub async fn reload(&self) -> Result<()> { pub async fn reload(&self) -> Result<()> {
let mut state = self.state.write().await; 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; *state = intermediate;
Ok(()) Ok(())
} }
pub async fn read(&self) -> Result<IpAssignmentState> { pub async fn read(&self) -> Result<NetworkAssignmentState> {
Ok(self.state.read().await.clone()) Ok(self.state.read().await.clone())
} }
pub async fn read_reservations(&self) -> Result<HashMap<Uuid, NetworkReservation>> {
self.store.list().await
}
} }

View File

@ -14,8 +14,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use crate::config::{DaemonConfig, DaemonPciDeviceRdmReservePolicy}; use crate::config::{DaemonConfig, DaemonPciDeviceRdmReservePolicy};
use crate::devices::DaemonDeviceManager; use crate::devices::DaemonDeviceManager;
use crate::ip::assignment::IpAssignment; use crate::network::assignment::NetworkAssignment;
use crate::reconcile::zone::ip_reservation_to_network_status; use crate::reconcile::zone::network_reservation_to_network_status;
use crate::{reconcile::zone::ZoneReconcilerResult, zlt::ZoneLookupTable}; use crate::{reconcile::zone::ZoneReconcilerResult, zlt::ZoneLookupTable};
use krata::v1::common::zone_image_spec::Image; use krata::v1::common::zone_image_spec::Image;
use tokio::fs::{self, File}; use tokio::fs::{self, File};
@ -29,7 +29,7 @@ pub struct ZoneCreator<'a> {
pub initrd_path: &'a Path, pub initrd_path: &'a Path,
pub addons_path: &'a Path, pub addons_path: &'a Path,
pub packer: &'a OciPackerService, pub packer: &'a OciPackerService,
pub ip_assignment: &'a IpAssignment, pub network_assignment: &'a NetworkAssignment,
pub zlt: &'a ZoneLookupTable, pub zlt: &'a ZoneLookupTable,
pub runtime: &'a Runtime, pub runtime: &'a Runtime,
pub config: &'a DaemonConfig, 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(); let mut initial_resources = spec.initial_resources.unwrap_or_default();
if initial_resources.target_cpus < 1 { if initial_resources.target_cpus < 1 {
@ -236,7 +236,7 @@ impl ZoneCreator<'_> {
info!("created zone {}", uuid); info!("created zone {}", uuid);
zone.status = Some(ZoneStatus { zone.status = Some(ZoneStatus {
state: ZoneState::Created.into(), 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, exit_status: None,
error_status: None, error_status: None,
resource_status: Some(ZoneResourceStatus { resource_status: Some(ZoneResourceStatus {

View File

@ -7,8 +7,8 @@ use std::{
use self::create::ZoneCreator; use self::create::ZoneCreator;
use crate::config::DaemonConfig; use crate::config::DaemonConfig;
use crate::db::ip::IpReservation; use crate::db::network::NetworkReservation;
use crate::ip::assignment::IpAssignment; use crate::network::assignment::NetworkAssignment;
use crate::{ use crate::{
db::zone::ZoneStore, db::zone::ZoneStore,
devices::DaemonDeviceManager, devices::DaemonDeviceManager,
@ -62,7 +62,7 @@ pub struct ZoneReconciler {
tasks: Arc<RwLock<HashMap<Uuid, ZoneReconcilerEntry>>>, tasks: Arc<RwLock<HashMap<Uuid, ZoneReconcilerEntry>>>,
zone_reconciler_notify: Sender<Uuid>, zone_reconciler_notify: Sender<Uuid>,
zone_reconcile_lock: Arc<RwLock<()>>, zone_reconcile_lock: Arc<RwLock<()>>,
ip_assignment: IpAssignment, ip_assignment: NetworkAssignment,
config: Arc<DaemonConfig>, config: Arc<DaemonConfig>,
} }
@ -79,7 +79,7 @@ impl ZoneReconciler {
kernel_path: PathBuf, kernel_path: PathBuf,
initrd_path: PathBuf, initrd_path: PathBuf,
modules_path: PathBuf, modules_path: PathBuf,
ip_assignment: IpAssignment, ip_assignment: NetworkAssignment,
config: Arc<DaemonConfig>, config: Arc<DaemonConfig>,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self { Ok(Self {
@ -195,7 +195,7 @@ impl ZoneReconciler {
if let Some(reservation) = self.ip_assignment.retrieve(uuid).await? { if let Some(reservation) = self.ip_assignment.retrieve(uuid).await? {
status.network_status = status.network_status =
Some(ip_reservation_to_network_status(&reservation)); Some(network_reservation_to_network_status(&reservation));
} }
stored_zone.status = Some(status); stored_zone.status = Some(status);
} }
@ -286,7 +286,7 @@ impl ZoneReconciler {
initrd_path: &self.initrd_path, initrd_path: &self.initrd_path,
addons_path: &self.addons_path, addons_path: &self.addons_path,
packer: &self.packer, packer: &self.packer,
ip_assignment: &self.ip_assignment, network_assignment: &self.ip_assignment,
zlt: &self.zlt, zlt: &self.zlt,
runtime: &self.runtime, runtime: &self.runtime,
config: &self.config, 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 { ZoneNetworkStatus {
zone_ipv4: format!("{}/{}", ip.ipv4, ip.ipv4_prefix), zone_ipv4: format!("{}/{}", ip.ipv4, ip.ipv4_prefix),
zone_ipv6: format!("{}/{}", ip.ipv6, ip.ipv6_prefix), zone_ipv6: format!("{}/{}", ip.ipv6, ip.ipv6_prefix),

View File

@ -46,6 +46,7 @@ message ExecStreamRequestStart {
repeated string command = 2; repeated string command = 2;
string working_directory = 3; string working_directory = 3;
bool tty = 4; bool tty = 4;
ExecStreamRequestTerminalSize terminal_size = 5;
} }
message ExecStreamRequestStdin { message ExecStreamRequestStdin {
@ -53,10 +54,16 @@ message ExecStreamRequestStdin {
bool closed = 2; bool closed = 2;
} }
message ExecStreamRequestTerminalSize {
uint32 rows = 1;
uint32 columns = 2;
}
message ExecStreamRequestUpdate { message ExecStreamRequestUpdate {
oneof update { oneof update {
ExecStreamRequestStart start = 1; ExecStreamRequestStart start = 1;
ExecStreamRequestStdin stdin = 2; ExecStreamRequestStdin stdin = 2;
ExecStreamRequestTerminalSize terminal_resize = 3;
} }
} }

View File

@ -134,3 +134,18 @@ enum ZoneMetricFormat {
ZONE_METRIC_FORMAT_INTEGER = 2; ZONE_METRIC_FORMAT_INTEGER = 2;
ZONE_METRIC_FORMAT_DURATION_SECONDS = 3; 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;
}

View File

@ -17,6 +17,8 @@ service ControlService {
rpc ListDevices(ListDevicesRequest) returns (ListDevicesReply); rpc ListDevices(ListDevicesRequest) returns (ListDevicesReply);
rpc ListNetworkReservations(ListNetworkReservationsRequest) returns (ListNetworkReservationsReply);
rpc PullImage(PullImageRequest) returns (stream PullImageReply); rpc PullImage(PullImageRequest) returns (stream PullImageReply);
rpc CreateZone(CreateZoneRequest) returns (CreateZoneReply); rpc CreateZone(CreateZoneRequest) returns (CreateZoneReply);
@ -91,6 +93,7 @@ message ExecInsideZoneRequest {
krata.v1.common.ZoneTaskSpec task = 2; krata.v1.common.ZoneTaskSpec task = 2;
bytes stdin = 3; bytes stdin = 3;
bool stdin_closed = 4; bool stdin_closed = 4;
krata.v1.common.TerminalSize terminal_size = 5;
} }
message ExecInsideZoneReply { message ExecInsideZoneReply {
@ -264,3 +267,9 @@ message ReadHypervisorConsoleRequest {}
message ReadHypervisorConsoleReply { message ReadHypervisorConsoleReply {
string data = 1; string data = 1;
} }
message ListNetworkReservationsRequest {}
message ListNetworkReservationsReply {
repeated krata.v1.common.NetworkReservation reservations = 1;
}

View File

@ -16,7 +16,7 @@ clap = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
etherparse = { workspace = true } etherparse = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
krata = { path = "../krata", version = "^0.0.19" } krata = { path = "../krata", version = "^0.0.20" }
krata-advmac = { workspace = true } krata-advmac = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true } log = { workspace = true }

View File

@ -12,20 +12,20 @@ resolver = "2"
anyhow = { workspace = true } anyhow = { workspace = true }
backhand = { workspace = true } backhand = { workspace = true }
ipnetwork = { workspace = true } ipnetwork = { workspace = true }
krata = { path = "../krata", version = "^0.0.19" } krata = { path = "../krata", version = "^0.0.20" }
krata-advmac = { workspace = true } krata-advmac = { workspace = true }
krata-oci = { path = "../oci", version = "^0.0.19" } krata-oci = { path = "../oci", version = "^0.0.20" }
log = { workspace = true } log = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
uuid = { workspace = true } uuid = { workspace = true }
krata-loopdev = { path = "../loopdev", version = "^0.0.19" } krata-loopdev = { path = "../loopdev", version = "^0.0.20" }
krata-xencall = { path = "../xen/xencall", version = "^0.0.19" } krata-xencall = { path = "../xen/xencall", version = "^0.0.20" }
krata-xenclient = { path = "../xen/xenclient", version = "^0.0.19" } krata-xenclient = { path = "../xen/xenclient", version = "^0.0.20" }
krata-xenevtchn = { path = "../xen/xenevtchn", version = "^0.0.19" } krata-xenevtchn = { path = "../xen/xenevtchn", version = "^0.0.20" }
krata-xengnt = { path = "../xen/xengnt", version = "^0.0.19" } krata-xengnt = { path = "../xen/xengnt", version = "^0.0.20" }
krata-xenplatform = { path = "../xen/xenplatform", version = "^0.0.19" } krata-xenplatform = { path = "../xen/xenplatform", version = "^0.0.20" }
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.19" } krata-xenstore = { path = "../xen/xenstore", version = "^0.0.20" }
walkdir = { workspace = true } walkdir = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }

View File

@ -13,9 +13,9 @@ async-trait = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true } log = { workspace = true }
krata-xencall = { path = "../xencall", version = "^0.0.19" } krata-xencall = { path = "../xencall", version = "^0.0.20" }
krata-xenplatform = { path = "../xenplatform", version = "^0.0.19" } krata-xenplatform = { path = "../xenplatform", version = "^0.0.20" }
krata-xenstore = { path = "../xenstore", version = "^0.0.19" } krata-xenstore = { path = "../xenstore", version = "^0.0.20" }
regex = { workspace = true } regex = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }

View File

@ -16,7 +16,7 @@ flate2 = { workspace = true }
indexmap = { workspace = true } indexmap = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true } log = { workspace = true }
krata-xencall = { path = "../xencall", version = "^0.0.19" } krata-xencall = { path = "../xencall", version = "^0.0.20" }
memchr = { workspace = true } memchr = { workspace = true }
nix = { workspace = true } nix = { workspace = true }
regex = { workspace = true } regex = { workspace = true }

View File

@ -14,8 +14,8 @@ cgroups-rs = { workspace = true }
env_logger = { workspace = true } env_logger = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
ipnetwork = { workspace = true } ipnetwork = { workspace = true }
krata = { path = "../krata", version = "^0.0.19" } krata = { path = "../krata", version = "^0.0.20" }
krata-xenstore = { path = "../xen/xenstore", version = "^0.0.19" } krata-xenstore = { path = "../xen/xenstore", version = "^0.0.20" }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true } log = { workspace = true }
nix = { workspace = true, features = ["ioctl", "process", "fs"] } nix = { workspace = true, features = ["ioctl", "process", "fs"] }

View File

@ -70,7 +70,11 @@ impl ZoneExecTask {
let code: c_int; let code: c_int;
if start.tty { if start.tty {
let pty = Pty::new().map_err(|error| anyhow!("unable to allocate pty: {}", error))?; 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 let pts = pty
.pts() .pts()
.map_err(|error| anyhow!("unable to allocate pts: {}", error))?; .map_err(|error| anyhow!("unable to allocate pts: {}", error))?;
@ -130,16 +134,24 @@ impl ZoneExecTask {
continue; continue;
}; };
let Some(Update::Stdin(update)) = update.update else { match update.update {
continue; 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() { if update.closed {
break; break;
} }
}
if update.closed { Some(Update::TerminalResize(size)) => {
break; let _ = write.resize(Size::new(size.rows as u16, size.columns as u16));
}
_ => {
continue;
}
} }
} }
}); });

View File

@ -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 `make olddefconfig` to build the rest of the kernel configuration, which
you can then use to build a kernel as desired. 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. 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 Minimum requirements for a host kernel
-------------------------------------- --------------------------------------

View File

@ -16,4 +16,4 @@ fi
export TARGET_ARCH export TARGET_ARCH
TARGET_ARCH="" TARGET_LIBC="" RUST_TARGET="${HOST_RUST_TARGET}" ./hack/build/cargo.sh build -q --bin build-fetch-kernel 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"