Skip to content

Commit 76e9eb8

Browse files
authored
Delete disk metrics endpoint (#8721)
Closes #8720 We'll have to confirm no one is relying on this endpoint, but as far as I know, the only thing relying on it was the instance disk metrics page in console, and that was switched to OxQL in February in oxidecomputer/console#2654.
1 parent b7da921 commit 76e9eb8

File tree

7 files changed

+9
-422
lines changed

7 files changed

+9
-422
lines changed

nexus/external-api/output/nexus_tags.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ disk_create POST /v1/disks
3535
disk_delete DELETE /v1/disks/{disk}
3636
disk_finalize_import POST /v1/disks/{disk}/finalize
3737
disk_list GET /v1/disks
38-
disk_metrics_list GET /v1/disks/{disk}/metrics/{metric}
3938
disk_view GET /v1/disks/{disk}
4039

4140
API operations found with tag "experimental"

nexus/external-api/src/lib.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,24 +1048,6 @@ pub trait NexusExternalApi {
10481048
query_params: Query<params::OptionalProjectSelector>,
10491049
) -> Result<HttpResponseDeleted, HttpError>;
10501050

1051-
/// Fetch disk metrics
1052-
#[endpoint {
1053-
method = GET,
1054-
path = "/v1/disks/{disk}/metrics/{metric}",
1055-
tags = ["disks"],
1056-
}]
1057-
async fn disk_metrics_list(
1058-
rqctx: RequestContext<Self::Context>,
1059-
path_params: Path<params::DiskMetricsPath>,
1060-
query_params: Query<
1061-
PaginationParams<params::ResourceMetrics, params::ResourceMetrics>,
1062-
>,
1063-
selector_params: Query<params::OptionalProjectSelector>,
1064-
) -> Result<
1065-
HttpResponseOk<ResultsPage<oximeter_types::Measurement>>,
1066-
HttpError,
1067-
>;
1068-
10691051
/// Start importing blocks into disk
10701052
///
10711053
/// Start the process of importing blocks into a disk

nexus/src/external_api/http_entrypoints.rs

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,52 +1921,6 @@ impl NexusExternalApi for NexusExternalApiImpl {
19211921
.await
19221922
}
19231923

1924-
async fn disk_metrics_list(
1925-
rqctx: RequestContext<ApiContext>,
1926-
path_params: Path<params::DiskMetricsPath>,
1927-
query_params: Query<
1928-
PaginationParams<params::ResourceMetrics, params::ResourceMetrics>,
1929-
>,
1930-
selector_params: Query<params::OptionalProjectSelector>,
1931-
) -> Result<HttpResponseOk<ResultsPage<oximeter_db::Measurement>>, HttpError>
1932-
{
1933-
let apictx = rqctx.context();
1934-
let handler = async {
1935-
let nexus = &apictx.context.nexus;
1936-
let path = path_params.into_inner();
1937-
let query = query_params.into_inner();
1938-
1939-
let selector = selector_params.into_inner();
1940-
let limit = rqctx.page_limit(&query)?;
1941-
let disk_selector = params::DiskSelector {
1942-
disk: path.disk,
1943-
project: selector.project,
1944-
};
1945-
let opctx =
1946-
crate::context::op_context_for_external_api(&rqctx).await?;
1947-
let (.., authz_disk) = nexus
1948-
.disk_lookup(&opctx, disk_selector)?
1949-
.lookup_for(authz::Action::Read)
1950-
.await?;
1951-
1952-
let result = nexus
1953-
.select_timeseries(
1954-
&format!("crucible_upstairs:{}", path.metric),
1955-
&[&format!("upstairs_uuid=={}", authz_disk.id())],
1956-
query,
1957-
limit,
1958-
)
1959-
.await?;
1960-
1961-
Ok(HttpResponseOk(result))
1962-
};
1963-
apictx
1964-
.context
1965-
.external_latencies
1966-
.instrument_dropshot_handler(&rqctx, handler)
1967-
.await
1968-
}
1969-
19701924
async fn disk_bulk_write_import_start(
19711925
rqctx: RequestContext<ApiContext>,
19721926
path_params: Path<params::DiskPath>,

nexus/tests/integration_tests/disks.rs

Lines changed: 1 addition & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
//! Tests basic disk support in the API
66
77
use super::instances::instance_wait_for_state;
8-
use super::metrics_querier::MetricsNotYet;
9-
use super::metrics_querier::MetricsQuerier;
10-
use chrono::Utc;
118
use dropshot::HttpErrorResponseBody;
129
use dropshot::test_util::ClientTestContext;
1310
use http::StatusCode;
@@ -22,36 +19,30 @@ use nexus_db_queries::db::datastore::RegionAllocationParameters;
2219
use nexus_db_queries::db::fixed_data::FLEET_ID;
2320
use nexus_test_utils::SLED_AGENT_UUID;
2421
use nexus_test_utils::http_testing::AuthnMode;
25-
use nexus_test_utils::http_testing::Collection;
2622
use nexus_test_utils::http_testing::NexusRequest;
2723
use nexus_test_utils::http_testing::RequestBuilder;
2824
use nexus_test_utils::identity_eq;
2925
use nexus_test_utils::resource_helpers::create_default_ip_pool;
3026
use nexus_test_utils::resource_helpers::create_disk;
3127
use nexus_test_utils::resource_helpers::create_instance;
32-
use nexus_test_utils::resource_helpers::create_instance_with;
3328
use nexus_test_utils::resource_helpers::create_project;
34-
use nexus_test_utils::resource_helpers::objects_list_page_authz;
35-
use nexus_test_utils::wait_for_producer;
3629
use nexus_test_utils_macros::nexus_test;
3730
use nexus_types::external_api::params;
3831
use nexus_types::identity::Asset;
3932
use nexus_types::silo::DEFAULT_SILO_ID;
33+
use omicron_common::api::external::ByteCount;
4034
use omicron_common::api::external::Disk;
4135
use omicron_common::api::external::DiskState;
4236
use omicron_common::api::external::IdentityMetadataCreateParams;
4337
use omicron_common::api::external::Instance;
4438
use omicron_common::api::external::InstanceState;
4539
use omicron_common::api::external::Name;
4640
use omicron_common::api::external::NameOrId;
47-
use omicron_common::api::external::{ByteCount, SimpleIdentityOrName as _};
4841
use omicron_nexus::Nexus;
4942
use omicron_nexus::TestInterfaces as _;
5043
use omicron_nexus::app::{MAX_DISK_SIZE_BYTES, MIN_DISK_SIZE_BYTES};
5144
use omicron_uuid_kinds::VolumeUuid;
5245
use omicron_uuid_kinds::{GenericUuid, InstanceUuid};
53-
use oximeter::types::Datum;
54-
use oximeter::types::Measurement;
5546
use sled_agent_client::TestInterfaces as _;
5647
use std::collections::HashSet;
5748
use std::sync::Arc;
@@ -1752,193 +1743,6 @@ async fn test_multiple_disks_multiple_zpools(
17521743
.unwrap();
17531744
}
17541745

1755-
async fn create_instance_with_disk(client: &ClientTestContext) {
1756-
create_instance_with(
1757-
&client,
1758-
PROJECT_NAME,
1759-
INSTANCE_NAME,
1760-
&params::InstanceNetworkInterfaceAttachment::Default,
1761-
vec![params::InstanceDiskAttachment::Attach(
1762-
params::InstanceDiskAttach { name: DISK_NAME.parse().unwrap() },
1763-
)],
1764-
Vec::<params::ExternalIpCreate>::new(),
1765-
true,
1766-
Default::default(),
1767-
)
1768-
.await;
1769-
}
1770-
1771-
const ALL_METRICS: [&'static str; 6] =
1772-
["activated", "read", "write", "read_bytes", "write_bytes", "flush"];
1773-
1774-
#[nexus_test]
1775-
async fn test_disk_metrics(cptestctx: &ControlPlaneTestContext) {
1776-
let metrics_querier = MetricsQuerier::new(cptestctx);
1777-
let client = &cptestctx.external_client;
1778-
DiskTest::new(&cptestctx).await;
1779-
let project_id = create_project_and_pool(client).await;
1780-
let disk = create_disk(&client, PROJECT_NAME, DISK_NAME).await;
1781-
1782-
// When grabbing a metric, we look for data points going back to the
1783-
// start of this test all the way up to the current time.
1784-
let metric_url = |metric: &str| {
1785-
format!(
1786-
"/v1/disks/{}/metrics/{}?start_time={:?}&end_time={:?}&project={}",
1787-
DISK_NAME,
1788-
metric,
1789-
cptestctx.start_time,
1790-
Utc::now(),
1791-
PROJECT_NAME,
1792-
)
1793-
};
1794-
1795-
// Try accessing metrics before we attach the disk to an instance.
1796-
//
1797-
// Observe that no metrics exist yet; no "upstairs" should have been
1798-
// instantiated on a sled.
1799-
let measurements =
1800-
objects_list_page_authz::<Measurement>(client, &metric_url("read"))
1801-
.await;
1802-
assert!(measurements.items.is_empty());
1803-
1804-
metrics_querier
1805-
.wait_for_latest_silo_metric(
1806-
"virtual_disk_space_provisioned",
1807-
Some(project_id),
1808-
|measurement| {
1809-
if measurement == i64::from(disk.size) {
1810-
Ok(())
1811-
} else {
1812-
Err(MetricsNotYet::new(format!(
1813-
"waiting for virtual_disk_space_provisioned={} \
1814-
(currently {measurement})",
1815-
disk.size,
1816-
)))
1817-
}
1818-
},
1819-
)
1820-
.await;
1821-
1822-
// Create an instance, attach the disk to it.
1823-
create_instance_with_disk(client).await;
1824-
wait_for_producer(&cptestctx.oximeter, disk.id()).await;
1825-
1826-
for metric in &ALL_METRICS {
1827-
metrics_querier
1828-
.wait_for_disk_metric(PROJECT_NAME, DISK_NAME, metric, |items| {
1829-
if items.is_empty() {
1830-
return Err(MetricsNotYet::new(format!(
1831-
"waiting for at least one item for metric={metric}"
1832-
)));
1833-
}
1834-
for item in &items {
1835-
let cumulative = match item.datum() {
1836-
Datum::CumulativeI64(c) => c,
1837-
_ => panic!("Unexpected datum type {:?}", item.datum()),
1838-
};
1839-
assert!(cumulative.start_time() <= item.timestamp());
1840-
}
1841-
Ok(())
1842-
})
1843-
.await;
1844-
}
1845-
1846-
// Check the utilization info for the whole project too.
1847-
metrics_querier
1848-
.wait_for_latest_silo_metric(
1849-
"virtual_disk_space_provisioned",
1850-
Some(project_id),
1851-
|measurement| {
1852-
if measurement == i64::from(disk.size) {
1853-
Ok(())
1854-
} else {
1855-
Err(MetricsNotYet::new(format!(
1856-
"waiting for virtual_disk_space_provisioned={} \
1857-
(currently {measurement})",
1858-
disk.size,
1859-
)))
1860-
}
1861-
},
1862-
)
1863-
.await;
1864-
}
1865-
1866-
#[nexus_test]
1867-
async fn test_disk_metrics_paginated(cptestctx: &ControlPlaneTestContext) {
1868-
let client = &cptestctx.external_client;
1869-
DiskTest::new(&cptestctx).await;
1870-
create_project_and_pool(client).await;
1871-
let disk = create_disk(&client, PROJECT_NAME, DISK_NAME).await;
1872-
create_instance_with_disk(client).await;
1873-
wait_for_producer(&cptestctx.oximeter, disk.id()).await;
1874-
1875-
let metrics_querier = MetricsQuerier::new(cptestctx);
1876-
for metric in &ALL_METRICS {
1877-
// Wait until we have at least two measurements.
1878-
metrics_querier
1879-
.wait_for_disk_metric(
1880-
PROJECT_NAME,
1881-
DISK_NAME,
1882-
metric,
1883-
|measurements| {
1884-
let num_measurements = measurements.len();
1885-
if num_measurements >= 2 {
1886-
Ok(())
1887-
} else {
1888-
Err(MetricsNotYet::new(format!(
1889-
"waiting for at least 2 measurements \
1890-
(currently {num_measurements})"
1891-
)))
1892-
}
1893-
},
1894-
)
1895-
.await;
1896-
1897-
let collection_url = format!(
1898-
"/v1/disks/{}/metrics/{}?project={}",
1899-
DISK_NAME, metric, PROJECT_NAME
1900-
);
1901-
let initial_params = format!(
1902-
"start_time={:?}&end_time={:?}",
1903-
cptestctx.start_time,
1904-
Utc::now(),
1905-
);
1906-
1907-
let measurements_paginated: Collection<Measurement> =
1908-
NexusRequest::iter_collection_authn(
1909-
client,
1910-
&collection_url,
1911-
&initial_params,
1912-
Some(10),
1913-
)
1914-
.await
1915-
.expect("failed to iterate over metrics");
1916-
assert!(!measurements_paginated.all_items.is_empty());
1917-
1918-
let mut last_timestamp = None;
1919-
let mut last_value = None;
1920-
for item in &measurements_paginated.all_items {
1921-
let cumulative = match item.datum() {
1922-
Datum::CumulativeI64(c) => c,
1923-
_ => panic!("Unexpected datum type {:?}", item.datum()),
1924-
};
1925-
assert!(cumulative.start_time() <= item.timestamp());
1926-
1927-
// Validate that the timestamps are non-decreasing.
1928-
if let Some(last_ts) = last_timestamp {
1929-
assert!(last_ts <= item.timestamp());
1930-
}
1931-
// Validate that the values increase.
1932-
if let Some(last_value) = last_value {
1933-
assert!(last_value < cumulative.value());
1934-
}
1935-
1936-
last_timestamp = Some(item.timestamp());
1937-
last_value = Some(cumulative.value());
1938-
}
1939-
}
1940-
}
1941-
19421746
#[nexus_test]
19431747
async fn test_disk_create_for_importing(cptestctx: &ControlPlaneTestContext) {
19441748
let client = &cptestctx.external_client;

nexus/tests/integration_tests/endpoints.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -401,15 +401,6 @@ pub static DEMO_DISK_CREATE: LazyLock<params::DiskCreate> =
401401
),
402402
}
403403
});
404-
pub static DEMO_DISK_METRICS_URL: LazyLock<String> = LazyLock::new(|| {
405-
format!(
406-
"/v1/disks/{}/metrics/activated?start_time={:?}&end_time={:?}&{}",
407-
*DEMO_DISK_NAME,
408-
Utc::now(),
409-
Utc::now(),
410-
*DEMO_PROJECT_SELECTOR,
411-
)
412-
});
413404

414405
// Related to importing blocks from an external source
415406
pub static DEMO_IMPORT_DISK_NAME: LazyLock<Name> =
@@ -2048,12 +2039,6 @@ pub static VERIFY_ENDPOINTS: LazyLock<Vec<VerifyEndpoint>> = LazyLock::new(
20482039
AllowedMethod::Delete,
20492040
],
20502041
},
2051-
VerifyEndpoint {
2052-
url: &DEMO_DISK_METRICS_URL,
2053-
visibility: Visibility::Protected,
2054-
unprivileged_access: UnprivilegedAccess::None,
2055-
allowed_methods: vec![AllowedMethod::Get],
2056-
},
20572042
VerifyEndpoint {
20582043
url: &DEMO_INSTANCE_DISKS_URL,
20592044
visibility: Visibility::Protected,

nexus/tests/integration_tests/metrics_querier.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -143,27 +143,6 @@ impl<'a, N> MetricsQuerier<'a, N> {
143143
self.wait_for_objects(|| endpoint.to_string(), cond).await
144144
}
145145

146-
/// Repeatedly fetch a specific disk metric until `cond` returns `Ok(_)`.
147-
pub async fn wait_for_disk_metric<F, T>(
148-
&self,
149-
project_name: &str,
150-
disk_name: &str,
151-
metric_name: &str,
152-
cond: F,
153-
) -> T
154-
where
155-
F: Fn(Vec<Measurement>) -> Result<T, MetricsNotYet>,
156-
{
157-
let endpoint = || {
158-
format!(
159-
"/v1/disks/{disk_name}/metrics/{metric_name}?start_time={:?}&end_time={:?}&project={project_name}",
160-
self.ctx.start_time,
161-
Utc::now(),
162-
)
163-
};
164-
self.wait_for_objects(endpoint, cond).await
165-
}
166-
167146
/// Repeatedly fetch the single newest system metric until `cond` returns
168147
/// `Ok(_)`.
169148
pub async fn wait_for_latest_system_metric<F, T>(

0 commit comments

Comments
 (0)