Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
233dc6d
Test impl of new endpoint format
just-be-dev Nov 17, 2022
0be1778
ResourceIdentifier -> NameOrId
just-be-dev Nov 17, 2022
6e3210f
Add docs, remove unneeded chunk
just-be-dev Nov 17, 2022
a2681b9
Use v1 prefix, convert instance delete
just-be-dev Nov 17, 2022
18bc9cf
Push up diplay error
just-be-dev Nov 17, 2022
07ec450
ReferenceIdentifer -> NameOrId in nexus.json
just-be-dev Nov 17, 2022
5b2f217
Update nexus.json to fix build issues
just-be-dev Nov 17, 2022
8631e9f
Change v1 to a prefix instead of postfix
just-be-dev Nov 17, 2022
41672aa
Normalize id lookups and path selection
just-be-dev Nov 19, 2022
954ffdb
Add v1 create instance api
just-be-dev Nov 20, 2022
c8d191b
Add instance list endpoint
just-be-dev Nov 21, 2022
6708bac
Add instance migrate endpoint
just-be-dev Nov 22, 2022
26b5651
Add instance reboot endpoint
just-be-dev Nov 22, 2022
f70f84f
Add instance start endpoint
just-be-dev Nov 22, 2022
e6374fe
Add instance stop endpoint
just-be-dev Nov 22, 2022
cdaa977
Add serial console endpoints
just-be-dev Nov 22, 2022
d0a19c6
Workaround for multiple emits
just-be-dev Nov 22, 2022
f439f59
Implement NameOrId for display to try resolve dropshot error
just-be-dev Nov 22, 2022
b4e818a
Flip the order of id/name in the NameOrId enum
just-be-dev Nov 23, 2022
7bdfeb0
Add untagged to NameOrId
just-be-dev Nov 25, 2022
cf5f540
Update NameOrId to be labeled
just-be-dev Nov 29, 2022
8c7ce21
RFD-322 PoC Revision 2 (#1995)
just-be-dev Nov 30, 2022
87f4d25
Move version to postfix
just-be-dev Nov 30, 2022
1596ed2
Add v1 disk list endpoint
just-be-dev Dec 1, 2022
393283d
Merge main int rfd-322-poc
just-be-dev Dec 1, 2022
ae73d95
Merge branch 'rfd-322-poc' into rfd-322-poc-disks
just-be-dev Dec 1, 2022
3d69694
Add new disk create endpoint
just-be-dev Dec 1, 2022
57549c7
Add disk view
just-be-dev Dec 2, 2022
2a87558
Always do a lookup, even when only handling UUID
just-be-dev Dec 2, 2022
0b227b0
Merge branch 'main' into rfd-322-poc
just-be-dev Dec 2, 2022
8f64dd7
Merge branch 'rfd-322-poc' into rfd-322-poc-disks
just-be-dev Dec 2, 2022
df8f5bf
Add disk delete
just-be-dev Dec 2, 2022
548a4d0
Add disk metrics
just-be-dev Dec 5, 2022
78962c2
Merge branch 'main' into rfd-322-poc
just-be-dev Dec 5, 2022
ce7da01
Fix clippy failures
just-be-dev Dec 6, 2022
2092012
Merge branch 'main' into rfd-322-poc
just-be-dev Dec 6, 2022
96165f5
Update unauthz coverage
just-be-dev Dec 6, 2022
e616c03
Fix up some failed testcases
just-be-dev Dec 6, 2022
3c13edc
Add view by id to skip list
just-be-dev Dec 7, 2022
67ebcd8
Merge branch 'rfd-322-poc' into rfd-322-poc-disks
just-be-dev Dec 7, 2022
f26c18a
Merge branch 'main' into rfd-322-poc
just-be-dev Dec 7, 2022
12bc365
Update lookups to return authz refs instead of uuids
just-be-dev Dec 7, 2022
9b75d90
Merge branch 'rfd-322-poc' into rfd-322-poc-disks
just-be-dev Dec 7, 2022
c94d0d9
Update disk lookups to use authz objects
just-be-dev Dec 7, 2022
31cc6b1
Fix invalid path name
just-be-dev Dec 7, 2022
a59c346
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 8, 2022
39fcf37
Add the ability to filter disks by instance
just-be-dev Dec 8, 2022
9a4c6da
Fix clippy issues
just-be-dev Dec 8, 2022
9187fcc
Update nexus.json
just-be-dev Dec 8, 2022
9c74e88
Add attach and detach methods
just-be-dev Dec 8, 2022
ff14b9b
Fix some of the failing tests
just-be-dev Dec 8, 2022
afbda07
Update instance lookup to return lookups instead of authz refs
just-be-dev Dec 9, 2022
eb9335d
Convert project lookup to return lookup::Project
just-be-dev Dec 9, 2022
1784353
Merge branch 'return-lookup' into rfd-322-poc-disks
just-be-dev Dec 12, 2022
69c7dcb
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 12, 2022
1033683
Deprecate old endpoints, fix missing v1 prefix, update disk lookups
just-be-dev Dec 12, 2022
9dbfed6
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 12, 2022
8d51dbb
Revamp selectors (again), convert organizations
just-be-dev Dec 13, 2022
129011e
Add project APIs, update routes
just-be-dev Dec 13, 2022
c29c67d
Fix clippy failures
just-be-dev Dec 14, 2022
599e6eb
Require less conversions when going from NameOrId to name
just-be-dev Dec 14, 2022
114d39a
Revamp selectors (again x2), convert projects
just-be-dev Dec 14, 2022
6ae7da3
Update nexus.json
just-be-dev Dec 14, 2022
63eddd7
Skip deprecated endpoints in auth check; update test to assert contents
just-be-dev Dec 14, 2022
8db8fa2
Fix authz test
just-be-dev Dec 14, 2022
c14cf71
Merge branch 'rfd-322-orgs-n-projs' into rfd-322-poc-disks
just-be-dev Dec 14, 2022
3a68689
Fixup disk params
just-be-dev Dec 14, 2022
143b1b7
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 14, 2022
33f09b5
WIP
just-be-dev Dec 14, 2022
bd1fafe
Merge branch 'main' into rfd-322-orgs-n-projs
just-be-dev Dec 14, 2022
f949c6c
Update nexus.json
just-be-dev Dec 14, 2022
bd033a0
format -_-
just-be-dev Dec 15, 2022
b1e1cde
Merge branch 'rfd-322-orgs-n-projs' into rfd-322-poc-disks
just-be-dev Dec 15, 2022
8eb8fca
Update implementation to match project/org setup
just-be-dev Dec 15, 2022
ae4ddcd
Merge branch 'main' into rfd-322-orgs-n-projs
just-be-dev Dec 15, 2022
69ac008
Add expanded error checking
just-be-dev Dec 15, 2022
1176211
Update nexus.json
just-be-dev Dec 16, 2022
81d58ae
Merge branch 'rfd-322-orgs-n-projs' into rfd-322-poc-disks
just-be-dev Dec 19, 2022
4065a3a
Fix type failures, fix some failing tests
just-be-dev Dec 19, 2022
3e88bbc
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 20, 2022
d5e6c42
Minor touch-ups after merge
just-be-dev Dec 20, 2022
30f83fd
Fix authz tests for disk
just-be-dev Dec 20, 2022
e02cd60
Fix final failing tests
just-be-dev Dec 20, 2022
ded1119
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Dec 21, 2022
4e602d2
Move back to old pattern of working with disks attached to instances
just-be-dev Dec 21, 2022
8f79dc6
Add checks to ensure disk from different project can be attached to i…
just-be-dev Dec 21, 2022
2f75756
Update nexus/types/src/external_api/params.rs
just-be-dev Dec 21, 2022
5c2366d
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Jan 3, 2023
8ca6b35
Revert "Update nexus/types/src/external_api/params.rs"
just-be-dev Jan 4, 2023
898002d
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Jan 4, 2023
072c389
Merge branch 'main' into rfd-322-poc-disks
just-be-dev Jan 11, 2023
7f608d1
Drop metrics for v1; update disk integration tests; update pagination
just-be-dev Jan 12, 2023
2b9369a
Fix unauth test
just-be-dev Jan 13, 2023
f357742
Restore disk metrics coverage
just-be-dev Jan 17, 2023
178e86c
Revert pub change
just-be-dev Jan 17, 2023
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
109 changes: 58 additions & 51 deletions nexus/src/app/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::authn;
use crate::authz;
use crate::context::OpContext;
use crate::db;
use crate::db::lookup;
use crate::db::lookup::LookupPath;
use crate::db::model::Name;
use crate::external_api::params;
Expand All @@ -20,26 +21,58 @@ use omicron_common::api::external::Error;
use omicron_common::api::external::InternalContext;
use omicron_common::api::external::ListResultVec;
use omicron_common::api::external::LookupResult;
use omicron_common::api::external::NameOrId;
use omicron_common::api::internal::nexus::DiskRuntimeState;
use ref_cast::RefCast;
use sled_agent_client::Client as SledAgentClient;
use std::sync::Arc;
use uuid::Uuid;

impl super::Nexus {
// Disks
pub fn disk_lookup<'a>(
&'a self,
opctx: &'a OpContext,
disk_selector: &'a params::DiskSelector,
) -> LookupResult<lookup::Disk<'a>> {
match disk_selector {
params::DiskSelector {
disk: NameOrId::Id(id),
project_selector: None,
} => {
let disk =
LookupPath::new(opctx, &self.db_datastore).disk_id(*id);
Ok(disk)
}
params::DiskSelector {
disk: NameOrId::Name(name),
project_selector: Some(project_selector),
} => {
let disk = self
.project_lookup(opctx, project_selector)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering, how much work will be involved to change project_lookup to work without organizations?

Should the implementation change much? If so, how much effort would including organization in the lookup now and removing it almost immediately after take?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be too much work. It's fairly formulaic.

.disk_name(Name::ref_cast(name));
Ok(disk)
}
params::DiskSelector {
disk: NameOrId::Id(_),
project_selector: Some(_),
} => Err(Error::invalid_request(
"when providing disk as an ID, project should not be specified",
)),
_ => Err(Error::invalid_request(
"disk should either be UUID or project should be specified",
)),
}
}

pub async fn project_create_disk(
self: &Arc<Self>,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
project_lookup: &lookup::Project<'_>,
params: &params::DiskCreate,
) -> CreateResult<db::model::Disk> {
let (.., authz_project) = LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.lookup_for(authz::Action::CreateChild)
.await?;
let (.., authz_project) =
project_lookup.lookup_for(authz::Action::CreateChild).await?;

match &params.disk_source {
params::DiskSource::Blank { block_size } => {
Expand Down Expand Up @@ -225,49 +258,30 @@ impl super::Nexus {
Ok(disk_created)
}

pub async fn project_list_disks(
pub async fn project_list_disks_by_id(
&self,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
pagparams: &DataPageParams<'_, Name>,
project_lookup: &lookup::Project<'_>,
pagparams: &DataPageParams<'_, Uuid>,
) -> ListResultVec<db::model::Disk> {
let (.., authz_project) = LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.lookup_for(authz::Action::ListChildren)
.await?;
let (.., authz_project) =
project_lookup.lookup_for(authz::Action::ListChildren).await?;
self.db_datastore
.project_list_disks(opctx, &authz_project, pagparams)
.project_list_disks_by_id(opctx, &authz_project, pagparams)
.await
}

pub async fn disk_fetch(
&self,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
disk_name: &Name,
) -> LookupResult<db::model::Disk> {
let (.., db_disk) = LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.disk_name(disk_name)
.fetch()
.await?;
Ok(db_disk)
}

pub async fn disk_fetch_by_id(
pub async fn project_list_disks_by_name(
&self,
opctx: &OpContext,
disk_id: &Uuid,
) -> LookupResult<db::model::Disk> {
let (.., db_disk) = LookupPath::new(opctx, &self.db_datastore)
.disk_id(*disk_id)
.fetch()
.await?;
Ok(db_disk)
project_lookup: &lookup::Project<'_>,
pagparams: &DataPageParams<'_, Name>,
) -> ListResultVec<db::model::Disk> {
let (.., authz_project) =
project_lookup.lookup_for(authz::Action::ListChildren).await?;
self.db_datastore
.project_list_disks_by_name(opctx, &authz_project, pagparams)
.await
}

/// Modifies the runtime state of the Disk as requested. This generally
Expand Down Expand Up @@ -372,17 +386,10 @@ impl super::Nexus {

pub async fn project_delete_disk(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit and kind of a general comment: these used to be called project_$action_$subresource because they were nested under the Project, but that's no longer really true. It seems like all of these could now just be called $resource_$action (i.e., disk_delete() here). That probably applies to a bunch of other functions too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a note in the parent issue to tackle this as a follow up.

self: &Arc<Self>,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
disk_name: &Name,
disk_lookup: &lookup::Disk<'_>,
) -> DeleteResult {
let (.., authz_disk) = LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.disk_name(disk_name)
.lookup_for(authz::Action::Delete)
.await?;
let (.., authz_disk) =
disk_lookup.lookup_for(authz::Action::Delete).await?;

let saga_params =
sagas::disk_delete::Params { disk_id: authz_disk.id() };
Expand Down
111 changes: 63 additions & 48 deletions nexus/src/app/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl super::Nexus {
// Gather disk information and turn that into DiskRequests
let disks = self
.db_datastore
.instance_list_disks(
.instance_list_disks_by_name(
&opctx,
&authz_instance,
&DataPageParams {
Expand Down Expand Up @@ -699,48 +699,66 @@ impl super::Nexus {
}
}

/// Lists disks attached to the instance.
pub async fn instance_list_disks(
/// Lists disks attached to the instance by id.
pub async fn instance_list_disks_by_id(
&self,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
instance_name: &Name,
instance_lookup: &lookup::Instance<'_>,
pagparams: &DataPageParams<'_, Uuid>,
) -> ListResultVec<db::model::Disk> {
let (.., authz_instance) =
instance_lookup.lookup_for(authz::Action::ListChildren).await?;
self.db_datastore
.instance_list_disks_by_id(opctx, &authz_instance, pagparams)
.await
}

/// Lists disks attached to the instance by name.
pub async fn instance_list_disks_by_name(
&self,
opctx: &OpContext,
instance_lookup: &lookup::Instance<'_>,
pagparams: &DataPageParams<'_, Name>,
) -> ListResultVec<db::model::Disk> {
let (.., authz_instance) = LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.instance_name(instance_name)
.lookup_for(authz::Action::ListChildren)
.await?;
let (.., authz_instance) =
instance_lookup.lookup_for(authz::Action::ListChildren).await?;
self.db_datastore
.instance_list_disks(opctx, &authz_instance, pagparams)
.instance_list_disks_by_name(opctx, &authz_instance, pagparams)
.await
}

/// Attach a disk to an instance.
pub async fn instance_attach_disk(
&self,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
instance_name: &Name,
disk_name: &Name,
instance_lookup: &lookup::Instance<'_>,
disk: NameOrId,
) -> UpdateResult<db::model::Disk> {
let (.., authz_project, authz_disk, _) =
LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.disk_name(disk_name)
.fetch()
.await?;
let (.., authz_instance, _) =
LookupPath::new(opctx, &self.db_datastore)
.project_id(authz_project.id())
.instance_name(instance_name)
.fetch()
.await?;
let (.., authz_project, authz_instance) =
instance_lookup.lookup_for(authz::Action::Modify).await?;
let (.., authz_project_disk, authz_disk) = self
.disk_lookup(
opctx,
&params::DiskSelector::new(
None,
Some(authz_project.id().into()),
disk,
),
)?
.lookup_for(authz::Action::Modify)
.await?;

// TODO-v1: Write test to verify this case
// Because both instance and disk can be provided by ID it's possible for someone
// to specify resources from different projects. The lookups would resolve the resources
// (assuming the user had sufficient permissions on both) without verifying the shared hierarchy.
// To mitigate that we verify that their parent projects have the same ID.
if authz_project.id() != authz_project_disk.id() {
return Err(Error::InvalidRequest {
message: "disk must be in the same project as the instance"
.to_string(),
});
}

// TODO(https://github.com/oxidecomputer/omicron/issues/811):
// Disk attach is only implemented for instances that are not
Expand Down Expand Up @@ -771,25 +789,22 @@ impl super::Nexus {
pub async fn instance_detach_disk(
&self,
opctx: &OpContext,
organization_name: &Name,
project_name: &Name,
instance_name: &Name,
disk_name: &Name,
instance_lookup: &lookup::Instance<'_>,
disk: NameOrId,
) -> UpdateResult<db::model::Disk> {
let (.., authz_project, authz_disk, _) =
LookupPath::new(opctx, &self.db_datastore)
.organization_name(organization_name)
.project_name(project_name)
.disk_name(disk_name)
.fetch()
.await?;
let (.., authz_instance, _) =
LookupPath::new(opctx, &self.db_datastore)
.project_id(authz_project.id())
.instance_name(instance_name)
.fetch()
.await?;

let (.., authz_project, authz_instance) =
instance_lookup.lookup_for(authz::Action::Modify).await?;
let (.., authz_disk) = self
.disk_lookup(
opctx,
&params::DiskSelector::new(
None,
Some(authz_project.id().into()),
disk,
),
)?
.lookup_for(authz::Action::Modify)
.await?;
// TODO(https://github.com/oxidecomputer/omicron/issues/811):
// Disk detach is only implemented for instances that are not
// currently running. This operation therefore can operate exclusively
Expand Down
22 changes: 8 additions & 14 deletions nexus/src/app/sagas/disk_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ pub(crate) mod test {
use crate::{
app::saga::create_saga_dag, app::sagas::disk_create::Params,
app::sagas::disk_create::SagaDiskCreate, authn::saga::Serialized,
context::OpContext, db, db::datastore::DataStore, external_api::params,
context::OpContext, db::datastore::DataStore, external_api::params,
};
use async_bb8_diesel::{AsyncRunQueryDsl, OptionalExtension};
use diesel::{ExpressionMethods, QueryDsl, SelectableHelper};
Expand All @@ -599,7 +599,6 @@ pub(crate) mod test {
use omicron_common::api::external::IdentityMetadataCreateParams;
use omicron_common::api::external::Name;
use omicron_sled_agent::sim::SledAgent;
use ref_cast::RefCast;
use std::num::NonZeroU32;
use uuid::Uuid;

Expand Down Expand Up @@ -863,20 +862,15 @@ pub(crate) mod test {
async fn destroy_disk(cptestctx: &ControlPlaneTestContext) {
let nexus = &cptestctx.server.apictx.nexus;
let opctx = test_opctx(&cptestctx);
let disk_selector = params::DiskSelector::new(
Some(Name::try_from(ORG_NAME.to_string()).unwrap().into()),
Some(Name::try_from(PROJECT_NAME.to_string()).unwrap().into()),
Name::try_from(DISK_NAME.to_string()).unwrap().into(),
);
let disk_lookup = nexus.disk_lookup(&opctx, &disk_selector).unwrap();

nexus
.project_delete_disk(
&opctx,
db::model::Name::ref_cast(
&Name::try_from(ORG_NAME.to_string()).unwrap(),
),
db::model::Name::ref_cast(
&Name::try_from(PROJECT_NAME.to_string()).unwrap(),
),
db::model::Name::ref_cast(
&Name::try_from(DISK_NAME.to_string()).unwrap(),
),
)
.project_delete_disk(&disk_lookup)
.await
.expect("Failed to delete disk");
}
Expand Down
18 changes: 10 additions & 8 deletions nexus/src/app/sagas/disk_delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ async fn sdd_delete_volume(
pub(crate) mod test {
use crate::{
app::saga::create_saga_dag, app::sagas::disk_delete::Params,
app::sagas::disk_delete::SagaDiskDelete, context::OpContext, db,
app::sagas::disk_delete::SagaDiskDelete, context::OpContext,
};
use dropshot::test_util::ClientTestContext;
use nexus_test_utils::resource_helpers::create_ip_pool;
use nexus_test_utils::resource_helpers::create_organization;
use nexus_test_utils::resource_helpers::create_project;
use nexus_test_utils::resource_helpers::DiskTest;
use nexus_test_utils_macros::nexus_test;
use nexus_types::external_api::params;
use omicron_common::api::external::Name;
use ref_cast::RefCast;
use std::num::NonZeroU32;
use uuid::Uuid;

Expand Down Expand Up @@ -125,15 +125,17 @@ pub(crate) mod test {
let nexus = &cptestctx.server.apictx.nexus;
let opctx = test_opctx(&cptestctx);

let project_selector = params::ProjectSelector::new(
Some(Name::try_from(ORG_NAME.to_string()).unwrap().into()),
Name::try_from(PROJECT_NAME.to_string()).unwrap().into(),
);
let project_lookup =
nexus.project_lookup(&opctx, &project_selector).unwrap();

nexus
.project_create_disk(
&opctx,
db::model::Name::ref_cast(
&Name::try_from(ORG_NAME.to_string()).unwrap(),
),
db::model::Name::ref_cast(
&Name::try_from(PROJECT_NAME.to_string()).unwrap(),
),
&project_lookup,
&crate::app::sagas::disk_create::test::new_disk_create_params(),
)
.await
Expand Down
Loading