Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server: consolidate VM creation APIs #806

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
05689d0
[WIP] instance spec ensure to rule them all, part 1
gjcolombo Oct 29, 2024
643f10a
[WIP] small build fixes
gjcolombo Oct 31, 2024
fc062df
[WIP] make the spec in InstanceSpecGetResponse optional
gjcolombo Oct 31, 2024
29f2388
[WIP] clarify how Crucible backends are identified
gjcolombo Oct 31, 2024
20ffee3
[WIP] rework instance ensure state machine to handle init from source
gjcolombo Oct 31, 2024
e5bdfa2
[WIP] produce target instance specs from the migration preamble
gjcolombo Oct 31, 2024
b0e24fc
openapi update
gjcolombo Oct 31, 2024
9be75f1
[WIP] post-openapi cleanup, part the first
gjcolombo Oct 31, 2024
bfa2efc
[WIP] make clients responsible for (most) config TOML parsing
gjcolombo Oct 31, 2024
5511b53
[WIP] fix PHD to use new client APIs
gjcolombo Nov 1, 2024
8340378
[WIP] eliminate server config TOMLs, pass bootrom path instead
gjcolombo Nov 1, 2024
f64ed92
[WIP] fix import failure PHD test
gjcolombo Nov 4, 2024
6359663
rename propolis-server-config to propolis-config-toml
gjcolombo Nov 4, 2024
3d4df20
change propolis-config-toml to depend on propolis-client
gjcolombo Nov 4, 2024
9c29e6a
adapt CLI to new ensure API
gjcolombo Nov 4, 2024
00fd7fb
README updates
gjcolombo Nov 4, 2024
04da33d
kick bootrom out of the config toml
gjcolombo Nov 4, 2024
99e4355
allow bootrom version to be specified on the command line
gjcolombo Nov 4, 2024
c88be87
client: add helper type to create new specs
gjcolombo Nov 4, 2024
d5e1a7c
client: re-export VolumeConstructionRequest
gjcolombo Nov 7, 2024
e98eab1
fix up some TODOs
gjcolombo Nov 11, 2024
6a3d688
fix SoftNPU port specifications
gjcolombo Nov 11, 2024
bc65532
remove dead code
gjcolombo Nov 11, 2024
14c3e95
derive JsonSchema for SpecKey and add From for String
gjcolombo Nov 11, 2024
90352e1
don't archive nonexistent TOML files
gjcolombo Nov 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/buildomat/phd-run-with-args.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ failcount=$?
set -e

tar -czvf /tmp/phd-tmp-files.tar.gz \
-C /tmp/propolis-phd /tmp/propolis-phd/*.log \
-C /tmp/propolis-phd /tmp/propolis-phd/*.toml
-C /tmp/propolis-phd /tmp/propolis-phd/*.log

exitcode=0
if [ $failcount -eq 0 ]; then
Expand Down
40 changes: 23 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ bhyve_api_sys = { path = "crates/bhyve-api/sys" }
cpuid_utils = { path = "crates/cpuid-utils" }
cpuid_profile_config = { path = "crates/cpuid-profile-config" }
dladm = { path = "crates/dladm" }
propolis-server-config = { path = "crates/propolis-server-config" }
propolis-config-toml = { path = "crates/propolis-config-toml" }
propolis_api_types = { path = "crates/propolis-api-types" }
propolis_types = { path = "crates/propolis-types" }
rfb = { path = "crates/rfb" }
Expand Down Expand Up @@ -145,6 +145,7 @@ serde_arrays = "0.1"
serde_derive = "1.0"
serde_json = "1.0"
serde_test = "1.0.138"
serde_with = "3.11.0"
slog = "2.7"
slog-async = "2.8"
slog-bunyan = "2.4.0"
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ implementation details, consumed by Propolis components.

- bhyve-api: API (ioctls & structs) for the illumos bhyve kernel VMM
- dladm: Some thin wrappers around `dladm` queries
- propolis-server-config: Type definitions for `propolis-server` config file
- propolis-config-toml: Type definitions for expressing static Propolis server
configurations in TOML format
- propolis-types: Publically exposed (via `propolis-server`) types, intergral
to the `propolis` library
- viona-api: API (ioctls & structs) for the illumos viona driver
Expand Down
1 change: 0 additions & 1 deletion bin/mock-server/src/lib/api_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ impl TryFrom<types::PciPath> for propolis_types::PciPath {
.map_err(|e| e.to_string())
}
}
pub use propolis_types::PciPath;

// Duplicate the parameter types for the endpoints related to the serial console

Expand Down
60 changes: 0 additions & 60 deletions bin/mock-server/src/lib/copied.rs

This file was deleted.

68 changes: 3 additions & 65 deletions bin/mock-server/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,24 @@

//! Implementation of a mock Propolis server

use std::io::{Error as IoError, ErrorKind};
use std::sync::Arc;

use base64::Engine;
use dropshot::{
channel, endpoint, ApiDescription, HttpError, HttpResponseCreated,
HttpResponseOk, HttpResponseUpdatedNoContent, Query, RequestContext,
TypedBody, WebsocketConnection,
};
use futures::SinkExt;
use slog::{error, info, Logger};
use slog::{error, Logger};
use thiserror::Error;
use tokio::sync::{watch, Mutex};
use tokio_tungstenite::tungstenite::protocol::{Role, WebSocketConfig};
use tokio_tungstenite::tungstenite::Message;
use tokio_tungstenite::WebSocketStream;

mod api_types;
mod copied;

use crate::copied::{slot_to_pci_path, SlotType};
use api_types::types as api;
use api_types::types::{self as api, InstanceEnsureRequest};

#[derive(Debug, Eq, PartialEq, Error)]
pub enum Error {
Expand Down Expand Up @@ -140,13 +136,7 @@ async fn instance_ensure(
request: TypedBody<api::InstanceEnsureRequest>,
) -> Result<HttpResponseCreated<api::InstanceEnsureResponse>, HttpError> {
let server_context = rqctx.context();
let request = request.into_inner();
let (properties, nics, disks, cloud_init_bytes) = (
request.properties,
request.nics,
request.disks,
request.cloud_init_bytes,
);
let InstanceEnsureRequest { properties, .. } = request.into_inner();

// Handle an already-initialized instance
let mut instance = server_context.instance.lock().await;
Expand All @@ -160,58 +150,6 @@ async fn instance_ensure(
migrate: None,
}));
}

// Perform some basic validation of the requested properties
for nic in &nics {
info!(server_context.log, "Creating NIC: {:#?}", nic);
slot_to_pci_path(nic.slot, SlotType::Nic).map_err(|e| {
let err = IoError::new(
ErrorKind::InvalidData,
format!("Cannot parse vnic PCI: {}", e),
);
HttpError::for_internal_error(format!(
"Cannot build instance: {}",
err
))
})?;
}

for disk in &disks {
info!(server_context.log, "Creating Disk: {:#?}", disk);
slot_to_pci_path(disk.slot, SlotType::Disk).map_err(|e| {
let err = IoError::new(
ErrorKind::InvalidData,
format!("Cannot parse disk PCI: {}", e),
);
HttpError::for_internal_error(format!(
"Cannot build instance: {}",
err
))
})?;
info!(server_context.log, "Disk {} created successfully", disk.name);
}

if let Some(cloud_init_bytes) = &cloud_init_bytes {
info!(server_context.log, "Creating cloud-init disk");
slot_to_pci_path(api::Slot(0), SlotType::CloudInit).map_err(|e| {
let err = IoError::new(ErrorKind::InvalidData, e.to_string());
HttpError::for_internal_error(format!(
"Cannot build instance: {}",
err
))
})?;
base64::engine::general_purpose::STANDARD
.decode(cloud_init_bytes)
.map_err(|e| {
let err = IoError::new(ErrorKind::InvalidInput, e.to_string());
HttpError::for_internal_error(format!(
"Cannot build instance: {}",
err
))
})?;
info!(server_context.log, "cloud-init disk created");
}

*instance = Some(InstanceContext::new(properties, &server_context.log));
Ok(HttpResponseCreated(api::InstanceEnsureResponse { migrate: None }))
}
Expand Down
2 changes: 2 additions & 0 deletions bin/propolis-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ edition = "2021"
[dependencies]
anyhow.workspace = true
clap = { workspace = true, features = ["derive"] }
crucible-client-types.workspace = true
futures.workspace = true
libc.workspace = true
newtype-uuid.workspace = true
propolis-config-toml.workspace = true
propolis-client.workspace = true
slog.workspace = true
slog-async.workspace = true
Expand Down
43 changes: 43 additions & 0 deletions bin/propolis-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Propolis CLI

The `propolis-cli` utility provides a user-friendly frontend to the
[`propolis-server`](../propolis-server) REST API.

## Getting started

The easiest way to launch a VM via the CLI is to write a TOML file describing
the VM's configuration. An example of such a file might be the following:

```toml
bootrom = "/path/to/bootrom/OVMF_CODE.fd"

[block_dev.alpine_iso]
type = "file"
path = "/path/to/alpine-extended-3.12.0-x86_64.iso"

[dev.block0]
driver = "pci-virtio-block"
block_dev = "alpine_iso"
pci-path = "0.4.0"

[dev.net0]
driver = "pci-virtio-viona"
vnic = "vnic_name"
pci-path = "0.5.0"
```

To create and run a Propolis VM using this configuration:

```
# propolis-cli -s <server ip> -p <port> new --config-toml <path> <VM name>
# propolis-cli -s <server ip> -p <port> state run
```

To connect to the VM's serial console:

```
# propolis-cli -s <server ip> -p <port> serial
```

Run `propolis-cli --help` to see the full list of supported commands and their
arguments.
Loading
Loading