diff --git a/control-plane/agents/src/bin/core/controller/resources/operations.rs b/control-plane/agents/src/bin/core/controller/resources/operations.rs index 3999e8055..cd4bcf5c2 100644 --- a/control-plane/agents/src/bin/core/controller/resources/operations.rs +++ b/control-plane/agents/src/bin/core/controller/resources/operations.rs @@ -181,6 +181,19 @@ pub(crate) trait ResourceReplicas { ) -> Result; } +/// Resource Property Operations. +#[async_trait::async_trait] +pub(crate) trait ResourceProperty { + type Request: Sync + Send; + + /// Set property values for the resource. + async fn set_property( + &mut self, + registry: &Registry, + request: &Self::Request, + ) -> Result<(), SvcError>; +} + /// Resource Children/Offspring Operations. #[async_trait::async_trait] pub(crate) trait ResourceOffspring { diff --git a/control-plane/agents/src/bin/core/volume/operations.rs b/control-plane/agents/src/bin/core/volume/operations.rs index e928a4c22..05f31a5c4 100644 --- a/control-plane/agents/src/bin/core/volume/operations.rs +++ b/control-plane/agents/src/bin/core/volume/operations.rs @@ -5,8 +5,8 @@ use crate::{ resources::{ operations::{ ResourceLifecycle, ResourceLifecycleExt, ResourceLifecycleWithLifetime, - ResourceOwnerUpdate, ResourcePublishing, ResourceReplicas, ResourceResize, - ResourceSharing, ResourceShutdownOperations, + ResourceOwnerUpdate, ResourceProperty, ResourcePublishing, ResourceReplicas, + ResourceResize, ResourceSharing, ResourceShutdownOperations, }, operations_helper::{ GuardedOperationsHelper, OnCreateFail, OperationSequenceGuard, ResourceSpecsLocked, @@ -37,8 +37,8 @@ use stor_port::{ transport::{ CreateVolume, DestroyNexus, DestroyReplica, DestroyShutdownTargets, DestroyVolume, Protocol, PublishVolume, Replica, ReplicaId, ReplicaOwners, RepublishVolume, - ResizeVolume, SetVolumeReplica, ShareNexus, ShareVolume, ShutdownNexus, - UnpublishVolume, UnshareNexus, UnshareVolume, Volume, + ResizeVolume, SetVolumeProperty, SetVolumeReplica, ShareNexus, ShareVolume, + ShutdownNexus, UnpublishVolume, UnshareNexus, UnshareVolume, Volume, }, }, }; @@ -645,6 +645,23 @@ impl ResourceReplicas for OperationGuardArc { } } +#[async_trait::async_trait] +impl ResourceProperty for OperationGuardArc { + type Request = SetVolumeProperty; + + async fn set_property( + &mut self, + registry: &Registry, + request: &Self::Request, + ) -> Result<(), SvcError> { + let state = registry.volume_state(&request.uuid).await?; + let operation = VolumeOperation::SetVolumeProperty(request.property.clone()); + let spec_clone = self.start_update(registry, &state, operation).await?; + + self.complete_update(registry, Ok(()), spec_clone).await?; + Ok(()) + } +} #[async_trait::async_trait] impl ResourceShutdownOperations for OperationGuardArc { type RemoveShutdownTargets = DestroyShutdownTargets; diff --git a/control-plane/agents/src/bin/core/volume/specs.rs b/control-plane/agents/src/bin/core/volume/specs.rs index 776d18ae3..271889da3 100644 --- a/control-plane/agents/src/bin/core/volume/specs.rs +++ b/control-plane/agents/src/bin/core/volume/specs.rs @@ -1113,6 +1113,7 @@ impl SpecOperationsHelper for VolumeSpec { VolumeOperation::CreateSnapshot(_) => Ok(()), VolumeOperation::DestroySnapshot(_) => Ok(()), VolumeOperation::Resize(_) => Ok(()), + VolumeOperation::SetVolumeProperty(_) => Ok(()), }?; self.start_op(operation); Ok(()) diff --git a/control-plane/stor-port/src/types/v0/store/volume.rs b/control-plane/stor-port/src/types/v0/store/volume.rs index b3834088e..d268e284a 100644 --- a/control-plane/stor-port/src/types/v0/store/volume.rs +++ b/control-plane/stor-port/src/types/v0/store/volume.rs @@ -9,26 +9,16 @@ use crate::{ }, transport::{ self, AffinityGroup, CreateVolume, HostNqn, NexusId, NexusNvmfConfig, NodeId, - ReplicaId, SnapshotId, Topology, VolumeId, VolumeLabels, VolumePolicy, + ReplicaId, SnapshotId, Topology, VolumeId, VolumeLabels, VolumePolicy, VolumeProperty, VolumeShareProtocol, VolumeStatus, }, }, IntoOption, }; + use pstor::ApiVersion; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use strum_macros::{EnumCount as EnumCountMacro, EnumIter, EnumString}; - -/// Volume properties. -#[derive( - Serialize, Deserialize, EnumString, Debug, EnumCountMacro, EnumIter, PartialEq, Clone, Copy, -)] -pub enum VolumeAttr { - /// Max number of snapshots allowed per volume. - #[strum(serialize = "max_snapshots")] - MaxSnapshots, -} /// Key used by the store to uniquely identify a VolumeState structure. pub struct VolumeStateKey(VolumeId); @@ -519,6 +509,11 @@ impl SpecTransaction for VolumeSpec { VolumeOperation::Resize(size) => { self.size = size; } + VolumeOperation::SetVolumeProperty(property) => match property { + VolumeProperty::MaxSnapshots(max_snapshots) => { + self.max_snapshots = Some(max_snapshots); + } + }, } } self.clear_op(); @@ -583,6 +578,7 @@ pub enum VolumeOperation { CreateSnapshot(SnapshotId), DestroySnapshot(SnapshotId), Resize(u64), + SetVolumeProperty(VolumeProperty), } #[test] @@ -681,6 +677,9 @@ impl From for models::volume_spec_operation::Operation { VolumeOperation::DestroySnapshot(_) => { models::volume_spec_operation::Operation::DestroySnapshot } + VolumeOperation::SetVolumeProperty(_) => { + todo!() + } VolumeOperation::Resize(_) => todo!(), } } diff --git a/control-plane/stor-port/src/types/v0/transport/volume.rs b/control-plane/stor-port/src/types/v0/transport/volume.rs index c7c7079d2..14679a35d 100644 --- a/control-plane/stor-port/src/types/v0/transport/volume.rs +++ b/control-plane/stor-port/src/types/v0/transport/volume.rs @@ -72,6 +72,13 @@ pub struct VolumeState { pub usage: Option, } +/// Volume properties. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub enum VolumeProperty { + /// Max number of snapshots allowed per volume. + MaxSnapshots(u32), +} + #[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct VolumeUsage { /// Capacity of the volume in bytes. @@ -703,6 +710,22 @@ impl SetVolumeReplica { } } +/// Set the volume property. +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SetVolumeProperty { + /// The uuid of the volume. + pub uuid: VolumeId, + /// The property to set. + pub property: VolumeProperty, +} +impl SetVolumeProperty { + /// Create new `Self` based on the provided arguments. + pub fn new(uuid: VolumeId, property: VolumeProperty) -> Self { + Self { uuid, property } + } +} + /// Delete volume request. #[derive(Serialize, Deserialize, Default, Debug, Clone)] #[serde(rename_all = "camelCase")]