Skip to content

Commit 10d5f7e

Browse files
merge main into multicast-e2e + update latest mcast dendrite/mags
2 parents df36929 + 985304a commit 10d5f7e

112 files changed

Lines changed: 4365 additions & 2399 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 96 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ members = [
163163
"sled-storage",
164164
"sled-storage/zfs-test-harness",
165165
"sp-sim",
166+
"support-bundle-collection",
166167
"test-utils",
167168
"trust-quorum",
168169
"trust-quorum/gfss",
@@ -351,6 +352,7 @@ default-members = [
351352
"sled-storage",
352353
"sled-storage/zfs-test-harness",
353354
"sp-sim",
355+
"support-bundle-collection",
354356
"trust-quorum",
355357
"trust-quorum/gfss",
356358
"trust-quorum/protocol",
@@ -484,7 +486,7 @@ crucible-common = { git = "https://github.com/oxidecomputer/crucible", rev = "3c
484486
# NOTE: See above!
485487
csv = "1.3.1"
486488
curve25519-dalek = "4"
487-
daft = { version = "0.1.4", features = ["derive", "newtype-uuid1", "oxnet01", "uuid1"] }
489+
daft = { version = "0.1.7", features = ["derive", "newtype-uuid1", "oxnet01", "uuid1"] }
488490
display-error-chain = "0.2.2"
489491
omicron-ddm-admin-client = { path = "clients/ddm-admin-client" }
490492
datatest-stable = "0.3.2"
@@ -501,10 +503,10 @@ digest = "0.10.7"
501503
dns-server = { path = "dns-server" }
502504
dns-server-api = { path = "dns-server-api" }
503505
dns-service-client = { path = "clients/dns-service-client" }
504-
dpd-client = { git = "https://github.com/oxidecomputer/dendrite", rev = "b6d8ba7957c8ed1e6b29fa4b2d85ad2c2248565e" }
506+
dpd-client = { git = "https://github.com/oxidecomputer/dendrite", rev = "90efdc6cf618523320bc403f1b9484dbd7f762be" }
505507
dropshot = { version = "0.17.0", features = [ "usdt-probes" ] }
506-
dropshot-api-manager = "0.7.1"
507-
dropshot-api-manager-types = "0.7.1"
508+
dropshot-api-manager = "0.7.2"
509+
dropshot-api-manager-types = "0.7.2"
508510
dyn-clone = "1.0.20"
509511
either = "1.15.0"
510512
ereport-types = { path = "ereport/types" }
@@ -611,9 +613,9 @@ ntp-admin-client = { path = "clients/ntp-admin-client" }
611613
ntp-admin-v1-client = { path = "clients/ntp-admin-v1-client" }
612614
ntp-admin-types = { path = "ntp-admin/types" }
613615
ntp-admin-types-versions = { path = "ntp-admin/types/versions" }
614-
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "864e0e150a90fd838199ceb38c2ad8a2be92a270" }
615-
mg-api-types = { git = "https://github.com/oxidecomputer/maghemite", rev = "864e0e150a90fd838199ceb38c2ad8a2be92a270" }
616-
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "864e0e150a90fd838199ceb38c2ad8a2be92a270" }
616+
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "5060d5864df864741dac8a0a4078fa4ecc3c73c8" }
617+
mg-api-types = { git = "https://github.com/oxidecomputer/maghemite", rev = "5060d5864df864741dac8a0a4078fa4ecc3c73c8" }
618+
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "5060d5864df864741dac8a0a4078fa4ecc3c73c8" }
617619
multimap = "0.10.1"
618620
nexus-auth = { path = "nexus/auth" }
619621
nexus-background-task-interface = { path = "nexus/background-task-interface" }
@@ -830,6 +832,7 @@ strum = { version = "0.27.2", features = [ "derive" ] }
830832
subprocess = "0.2.9"
831833
subtle = "2.6.1"
832834
supports-color = "3.0.2"
835+
support-bundle-collection = { path = "support-bundle-collection" }
833836
support-bundle-viewer = "0.1.2"
834837
swrite = "0.1.0"
835838
sync-ptr = "0.1.4"

clickhouse-admin/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ serde_json.workspace = true
4848
slog-term.workspace = true
4949
subprocess.workspace = true
5050
url.workspace = true
51+
uuid.workspace = true
52+
chrono-tz.workspace = true
5153

5254
[lints]
5355
workspace = true

clickhouse-admin/src/context.rs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,12 +783,19 @@ mod tests {
783783
use crate::context::ServerContext;
784784
use crate::context::USAGE_UPDATE_INTERVAL;
785785
use camino::Utf8PathBuf;
786+
use chrono::NaiveDate;
787+
use chrono::TimeZone;
788+
use chrono_tz::Tz;
786789
use clickhouse_admin_types::CLICKHOUSE_SERVER_CONFIG_FILE;
787790
use clickhouse_admin_types::retention::Days;
788791
use clickhouse_admin_types::retention::RetentionPolicyRequest;
789792
use dropshot::ErrorStatusCode;
790793
use omicron_common::api::external::Generation;
791794
use omicron_test_utils::dev;
795+
use oximeter_db::native::block::Block;
796+
use oximeter_db::native::block::Column;
797+
use oximeter_db::native::block::Precision;
798+
use oximeter_db::native::block::ValueArray;
792799
use slog::info;
793800
use std::str::FromStr;
794801

@@ -967,12 +974,15 @@ mod tests {
967974
assert!(usage.last_success.is_some());
968975

969976
// Wait until we actually do compute the usage again.
977+
//
978+
// From `grep -c "CREATE TABLE" oximeter/db/schema/single-node/db-init.sql`.
979+
const N_EXPECTED_TABLES: usize = 39;
970980
let usage = dev::poll::wait_for_condition(
971981
|| async {
972982
let usage = context.database_usage();
973983
match &usage.last_success {
974984
Some(success) => {
975-
if success.tables.is_empty() {
985+
if success.tables.len() < N_EXPECTED_TABLES {
976986
Err(dev::poll::CondCheckError::<()>::NotYet)
977987
} else {
978988
Ok(usage)
@@ -998,7 +1008,74 @@ mod tests {
9981008
assert!(
9991009
tables.contains_key(&String::from("oximeter.measurements_f64"))
10001010
);
1001-
assert!(tables.contains_key(&String::from("oximeter.version")));
1011+
1012+
// Insert some rows in the version table, so we can see it updated.
1013+
let version_table = String::from("oximeter.version");
1014+
let version_usage =
1015+
tables.get(&version_table).expect("Should have this table");
1016+
let naive_dt = NaiveDate::from_ymd_opt(2020, 1, 1)
1017+
.unwrap()
1018+
.and_hms_opt(12, 12, 12)
1019+
.unwrap();
1020+
let timestamp = Tz::UTC.from_local_datetime(&naive_dt).unwrap();
1021+
oximeter_db::native::Connection::new(
1022+
clickhouse.native_address().into(),
1023+
)
1024+
.await
1025+
.expect("Should be able to make client")
1026+
.insert(
1027+
uuid::Uuid::new_v4(),
1028+
"INSERT INTO oximeter.version FORMAT NATIVE",
1029+
Block {
1030+
name: String::new(),
1031+
info: Default::default(),
1032+
columns: [
1033+
(
1034+
"value".to_string(),
1035+
Column::from(ValueArray::UInt64(vec![1, 2, 3])),
1036+
),
1037+
(
1038+
"timestamp".to_string(),
1039+
Column::from(ValueArray::DateTime64 {
1040+
precision: Precision::new(9).unwrap(),
1041+
tz: Tz::UTC,
1042+
values: vec![timestamp; 3],
1043+
}),
1044+
),
1045+
]
1046+
.into(),
1047+
},
1048+
)
1049+
.await
1050+
.expect("Should be able to insert data");
1051+
1052+
// Check again, waiting until we get more than the previous usage.
1053+
let usage = dev::poll::wait_for_condition(
1054+
|| async {
1055+
let usage = context.database_usage();
1056+
match &usage.last_success {
1057+
Some(success) => {
1058+
let Some(usage) = success.tables.get(&version_table)
1059+
else {
1060+
return Err(
1061+
dev::poll::CondCheckError::<()>::NotYet,
1062+
);
1063+
};
1064+
if usage.n_rows > version_usage.n_rows {
1065+
Ok(usage.clone())
1066+
} else {
1067+
Err(dev::poll::CondCheckError::<()>::NotYet)
1068+
}
1069+
}
1070+
None => Err(dev::poll::CondCheckError::<()>::NotYet),
1071+
}
1072+
},
1073+
&std::time::Duration::from_millis(50),
1074+
&(2 * USAGE_UPDATE_INTERVAL),
1075+
)
1076+
.await
1077+
.expect("New rows didn't show up on time");
1078+
assert_eq!(usage.n_rows, 4);
10021079

10031080
// Kill the database, and wait for another collection. This one should
10041081
// fail.

common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ dropshot.workspace = true
2626
futures.workspace = true
2727
hex.workspace = true
2828
http.workspace = true
29+
humantime.workspace = true
2930
iddqd.workspace = true
3031
ipnetwork.workspace = true
3132
itertools.workspace = true

common/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ pub fn now_db_precision() -> chrono::DateTime<chrono::Utc> {
6969
ts - std::time::Duration::from_nanos(u64::from(only_nanos))
7070
}
7171

72+
/// Format a [`std::time::Duration`] as a human-readable string
73+
/// (e.g. `"1h 5m 23ms"`), truncated to millisecond precision.
74+
pub fn format_duration_ms(duration: std::time::Duration) -> String {
75+
// Ignore units smaller than a millisecond.
76+
let elapsed = std::time::Duration::from_millis(
77+
u64::try_from(duration.as_millis()).unwrap_or(u64::MAX),
78+
);
79+
humantime::format_duration(elapsed).to_string()
80+
}
81+
82+
/// Format a [`chrono::TimeDelta`] as a human-readable string (see
83+
/// [`format_duration_ms`]).
84+
pub fn format_time_delta(time_delta: chrono::TimeDelta) -> String {
85+
match time_delta.to_std() {
86+
Ok(d) => format_duration_ms(d),
87+
Err(_) => String::from("<time delta out of range>"),
88+
}
89+
}
90+
7291
pub const OMICRON_DPD_TAG: &str = "omicron";
7392

7493
/// A wrapper struct that does nothing other than elide the inner value from

common/src/zpool_name.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ pub enum ZpoolName {
5151
Internal(InternalZpoolUuid),
5252
}
5353

54+
impl fmt::Display for ZpoolKind {
55+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
match self {
57+
ZpoolKind::External => write!(f, "external"),
58+
ZpoolKind::Internal => write!(f, "internal"),
59+
}
60+
}
61+
}
62+
5463
const ZPOOL_NAME_REGEX: &str = r"^ox[ip]_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$";
5564

5665
/// Custom JsonSchema implementation to encode the constraints on Name.

dev-tools/ls-apis/tests/api_dependencies.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Management Gateway Service (client: gateway-client)
4949
consumed by: dpd (dendrite/dpd) via 1 path
5050
consumed by: lldpd (lldp/lldpd) via 1 path
5151
consumed by: mgd (maghemite/mgd) via 1 path
52-
consumed by: omicron-nexus (omicron/nexus) via 5 paths
52+
consumed by: omicron-nexus (omicron/nexus) via 6 paths
5353
consumed by: omicron-sled-agent (omicron/sled-agent) via 1 path
5454
consumed by: wicketd (omicron/wicketd) via 3 paths
5555

@@ -99,7 +99,7 @@ Repo Depot API (client: repo-depot-client)
9999
consumed by: omicron-sled-agent (omicron/sled-agent) via 1 path
100100

101101
Sled Agent (client: sled-agent-client)
102-
consumed by: omicron-nexus (omicron/nexus) via 8 paths
102+
consumed by: omicron-nexus (omicron/nexus) via 9 paths
103103

104104
Wicketd (client: wicketd-client)
105105

dev-tools/omdb/src/bin/omdb/nexus/quiesce.rs

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@
77
use crate::Omdb;
88
use crate::check_allow_destructive::DestructiveOperationToken;
99
use anyhow::Context;
10-
use chrono::TimeDelta;
1110
use chrono::Utc;
1211
use clap::Args;
1312
use clap::Subcommand;
1413
use nexus_lockstep_client::types::PendingRecovery;
1514
use nexus_lockstep_client::types::QuiesceState;
1615
use nexus_lockstep_client::types::QuiesceStatus;
1716
use nexus_lockstep_client::types::SagaQuiesceStatus;
18-
use std::time::Duration;
1917

2018
#[derive(Debug, Args)]
2119
pub struct QuiesceArgs {
@@ -77,7 +75,7 @@ async fn quiesce_show(
7775
println!(
7876
"quiescing since {} ({} ago)",
7977
humantime::format_rfc3339_millis(time_requested.into()),
80-
format_time_delta(now - time_requested),
78+
omicron_common::format_time_delta(now - time_requested),
8179
);
8280
println!("details: waiting for running sagas to finish");
8381
}
@@ -89,14 +87,16 @@ async fn quiesce_show(
8987
println!(
9088
"quiescing since {} ({} ago)",
9189
humantime::format_rfc3339_millis(time_requested.into()),
92-
format_time_delta(now - time_requested),
90+
omicron_common::format_time_delta(now - time_requested),
9391
);
9492
println!(
9593
"details: waiting for database connections to be released"
9694
);
9795
println!(
9896
" previously: waiting for sagas took {}",
99-
format_duration_ms(duration_draining_sagas.into()),
97+
omicron_common::format_duration_ms(
98+
duration_draining_sagas.into()
99+
),
100100
);
101101
}
102102
QuiesceState::RecordingQuiesce {
@@ -108,15 +108,17 @@ async fn quiesce_show(
108108
println!(
109109
"quiescing since {} ({} ago)",
110110
humantime::format_rfc3339_millis(time_requested.into()),
111-
format_time_delta(now - time_requested),
111+
omicron_common::format_time_delta(now - time_requested),
112112
);
113113
println!(
114114
" waiting for sagas took {}",
115-
format_duration_ms(duration_draining_sagas.into()),
115+
omicron_common::format_duration_ms(
116+
duration_draining_sagas.into()
117+
),
116118
);
117119
println!(
118120
" waiting for db quiesce took {}",
119-
format_duration_ms(duration_draining_db.into()),
121+
omicron_common::format_duration_ms(duration_draining_db.into()),
120122
);
121123
}
122124
QuiesceState::Quiesced {
@@ -130,23 +132,27 @@ async fn quiesce_show(
130132
println!(
131133
"quiesced since {} ({} ago)",
132134
humantime::format_rfc3339_millis(time_quiesced.into()),
133-
format_time_delta(now - time_quiesced),
135+
omicron_common::format_time_delta(now - time_quiesced),
134136
);
135137
println!(
136138
" waiting for sagas took {}",
137-
format_duration_ms(duration_draining_sagas.into()),
139+
omicron_common::format_duration_ms(
140+
duration_draining_sagas.into()
141+
),
138142
);
139143
println!(
140144
" waiting for db quiesce took {}",
141-
format_duration_ms(duration_draining_db.into()),
145+
omicron_common::format_duration_ms(duration_draining_db.into()),
142146
);
143147
println!(
144148
" recording quiesce took {}",
145-
format_duration_ms(duration_recording_quiesce.into()),
149+
omicron_common::format_duration_ms(
150+
duration_recording_quiesce.into()
151+
),
146152
);
147153
println!(
148154
" total quiesce time: {}",
149-
format_duration_ms(duration_total.into()),
155+
omicron_common::format_duration_ms(duration_total.into()),
150156
);
151157
}
152158
}
@@ -225,7 +231,7 @@ async fn quiesce_show(
225231
" claim {} held since {} ({} ago)",
226232
claim.id,
227233
claim.held_since,
228-
format_time_delta(Utc::now() - claim.held_since),
234+
omicron_common::format_time_delta(Utc::now() - claim.held_since),
229235
);
230236
if args.stacks {
231237
println!(" acquired by:");
@@ -243,18 +249,3 @@ async fn quiesce_start(
243249
client.quiesce_start().await.context("quiescing Nexus")?;
244250
quiesce_show(client, &QuiesceShowArgs { stacks: false }).await
245251
}
246-
247-
fn format_duration_ms(duration: Duration) -> String {
248-
// Ignore units smaller than a millisecond.
249-
let elapsed = Duration::from_millis(
250-
u64::try_from(duration.as_millis()).unwrap_or(u64::MAX),
251-
);
252-
humantime::format_duration(elapsed).to_string()
253-
}
254-
255-
fn format_time_delta(time_delta: TimeDelta) -> String {
256-
match time_delta.to_std() {
257-
Ok(d) => format_duration_ms(d),
258-
Err(_) => String::from("<time delta out of range>"),
259-
}
260-
}

0 commit comments

Comments
 (0)