From e3c52bff651a3cadc0872dc901ee4a84fa1b4f15 Mon Sep 17 00:00:00 2001 From: Abhinandan Purkait Date: Tue, 22 Aug 2023 08:18:42 +0000 Subject: [PATCH 1/4] refactor: snapshot listing based on query Signed-off-by: Abhinandan Purkait --- io-engine-tests/src/snapshot.rs | 3 +- .../bin/io-engine-client/v1/snapshot_cli.rs | 3 +- io-engine/src/grpc/v1/snapshot.rs | 63 +++++++------------ io-engine/tests/snapshot_nexus.rs | 18 +++--- rpc/mayastor-api | 2 +- 5 files changed, 35 insertions(+), 54 deletions(-) diff --git a/io-engine-tests/src/snapshot.rs b/io-engine-tests/src/snapshot.rs index f8ae8f294..261af23a8 100644 --- a/io-engine-tests/src/snapshot.rs +++ b/io-engine-tests/src/snapshot.rs @@ -10,7 +10,6 @@ use mayastor_api::v1::snapshot::{ // ListSnapshotsResponse, Replica, SnapshotInfo, - SnapshotQueryType, }; use tonic::Status; @@ -109,7 +108,7 @@ pub async fn list_snapshot( .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .map(|r| r.into_inner().snapshots) diff --git a/io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs b/io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs index e21199f65..e60794de9 100644 --- a/io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs +++ b/io-engine/src/bin/io-engine-client/v1/snapshot_cli.rs @@ -411,8 +411,7 @@ async fn list(mut ctx: Context, matches: &ArgMatches<'_>) -> crate::Result<()> { let request = v1_rpc::snapshot::ListSnapshotsRequest { source_uuid, snapshot_uuid, - snapshot_query_type: v1_rpc::snapshot::SnapshotQueryType::AllSnapshots - as i32, + query: None, }; let response = ctx diff --git a/io-engine/src/grpc/v1/snapshot.rs b/io-engine/src/grpc/v1/snapshot.rs index c6d3de44d..b88bd61ac 100644 --- a/io-engine/src/grpc/v1/snapshot.rs +++ b/io-engine/src/grpc/v1/snapshot.rs @@ -314,54 +314,38 @@ impl SnapshotService { } } -/// Filter snapshots based on snapshot_query_type came in gRPC request. +/// Filter snapshots based on query came in gRPC request. fn filter_snapshots_by_snapshot_query_type( snapshot_list: Vec, - snap_query_type: Option, + query: Option, ) -> Vec { - let Some(snap_query_type) = snap_query_type else { - return snapshot_list + let query = match query { + None => return snapshot_list, + Some(query) => query, }; + snapshot_list .into_iter() - .filter_map(|s| match snap_query_type { - // AllSnapshots - SnapshotQueryType::AllSnapshots => Some(s), - // AllSnapshotsExceptDiscardedSnapshots - SnapshotQueryType::AllSnapshotsExceptDiscardedSnapshots => { - if !s.discarded_snapshot { - Some(s) - } else { - None - } - } - // OnlyDiscardedSnapshots - SnapshotQueryType::OnlyDiscardedSnapshots => { - if s.discarded_snapshot { - Some(s) - } else { - None - } - } - // OnlyInvalidSnapshots - SnapshotQueryType::OnlyInvalidSnapshots => { - if !s.valid_snapshot { - Some(s) - } else { - None - } - } - // OnlyUsableSnapshots - SnapshotQueryType::OnlyUsableSnapshots => { - if !s.discarded_snapshot && s.valid_snapshot { - Some(s) - } else { - None + .filter(|snapshot| { + let query = &query; + + let query_fields = vec![ + (query.invalid, snapshot.valid_snapshot), + (query.discarded, snapshot.discarded_snapshot), + // ... add other fields here as needed + ]; + + query_fields.iter().all(|(query_field, snapshot_field)| { + match query_field { + Some(true) => *snapshot_field, + Some(false) => !(*snapshot_field), + None => true, } - } + }) }) .collect() } + #[tonic::async_trait] impl SnapshotRpc for SnapshotService { #[named] @@ -563,8 +547,7 @@ impl SnapshotRpc for SnapshotService { .collect(); } let snapshots = filter_snapshots_by_snapshot_query_type( - snapshots, - SnapshotQueryType::from_i32(args.snapshot_query_type), + snapshots, args.query, ); Ok(ListSnapshotsResponse { snapshots, diff --git a/io-engine/tests/snapshot_nexus.rs b/io-engine/tests/snapshot_nexus.rs index 0a74ae7e8..0a643a334 100755 --- a/io-engine/tests/snapshot_nexus.rs +++ b/io-engine/tests/snapshot_nexus.rs @@ -11,7 +11,7 @@ use common::{ bdev::ListBdevOptions, pool::CreatePoolRequest, replica::{CreateReplicaRequest, ListReplicaOptions}, - snapshot::{ListSnapshotsRequest, SnapshotInfo, SnapshotQueryType}, + snapshot::{ListSnapshotsRequest, SnapshotInfo}, GrpcConnect, }, Builder, @@ -250,7 +250,7 @@ async fn test_replica_handle_snapshot() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -293,7 +293,7 @@ async fn test_replica_handle_snapshot() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -375,7 +375,7 @@ async fn test_list_no_snapshots() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -458,7 +458,7 @@ async fn test_nexus_snapshot() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -501,7 +501,7 @@ async fn test_nexus_snapshot() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -589,7 +589,7 @@ async fn test_duplicated_snapshot_uuid_name() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -829,7 +829,7 @@ async fn test_snapshot_ancestor_usage() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") @@ -897,7 +897,7 @@ async fn test_snapshot_ancestor_usage() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - snapshot_query_type: SnapshotQueryType::AllSnapshots as i32, + query: None, }) .await .expect("Failed to list snapshots on replica node") diff --git a/rpc/mayastor-api b/rpc/mayastor-api index 984c2d414..396a0756c 160000 --- a/rpc/mayastor-api +++ b/rpc/mayastor-api @@ -1 +1 @@ -Subproject commit 984c2d414cdba1db3bee2bc886d6d3c2bf997206 +Subproject commit 396a0756cb4062eb32226ab37ebbfb9cf257bb98 From 9ddc0163217e4499d0cdfaa7567d36ced5ee5b15 Mon Sep 17 00:00:00 2001 From: Abhinandan Purkait Date: Wed, 23 Aug 2023 09:13:21 +0000 Subject: [PATCH 2/4] test: snapshot list based on query Signed-off-by: Abhinandan Purkait --- io-engine/tests/snapshot_nexus.rs | 166 ++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/io-engine/tests/snapshot_nexus.rs b/io-engine/tests/snapshot_nexus.rs index 0a643a334..9d7fe4625 100755 --- a/io-engine/tests/snapshot_nexus.rs +++ b/io-engine/tests/snapshot_nexus.rs @@ -40,6 +40,13 @@ use io_engine::{ use io_engine_tests::file_io::{test_write_to_file, DataSize}; use nix::errno::Errno; +use mayastor_api::v1::snapshot::{ + destroy_snapshot_request::Pool, + list_snapshots_request::Query, + CreateReplicaSnapshotRequest, + CreateSnapshotCloneRequest, + DestroySnapshotRequest, +}; use std::{pin::Pin, str}; use uuid::Uuid; @@ -915,3 +922,162 @@ async fn test_snapshot_ancestor_usage() { nvme_disconnect_all(); } + +/// This tests creates 2 replicas --> 2 snapshots --> 1 restore --> deletes snap +/// 1 --> Validates listing. +#[tokio::test] +async fn test_replica_snapshot_listing_with_query() { + let _ = get_ms(); + let (test, _urls) = launch_instance(true).await; + let conn = GrpcConnect::new(&test); + let snap1 = Uuid::new_v4(); + + let mut ms1 = conn + .grpc_handle("ms1") + .await + .expect("Can't connect to remote I/O agent"); + + ms1.snapshot + .create_replica_snapshot(CreateReplicaSnapshotRequest { + replica_uuid: replica1_uuid(), + snapshot_uuid: snap1.to_string(), + snapshot_name: "snaprep1/2".to_string(), + entity_id: "snaprep1".to_string(), + txn_id: "1".to_string(), + }) + .await + .expect("Should create replica snapshot"); + + ms1.snapshot + .create_replica_snapshot(CreateReplicaSnapshotRequest { + replica_uuid: replica2_uuid(), + snapshot_uuid: Uuid::new_v4().to_string(), + snapshot_name: "snaprep2/1".to_string(), + entity_id: "snaprep2".to_string(), + txn_id: "1".to_string(), + }) + .await + .expect("Should create replica snapshot"); + + // List only non discarded snapshots before restore. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: Some(Query { + invalid: None, + discarded: Some(false), + }), + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 2); + assert!(!snaps[0].discarded_snapshot); + assert!(!snaps[1].discarded_snapshot); + + ms1.snapshot + .create_snapshot_clone(CreateSnapshotCloneRequest { + snapshot_uuid: snap1.to_string(), + clone_name: "snaprep1clone".to_string(), + clone_uuid: Uuid::new_v4().to_string(), + }) + .await + .expect("Should create snapshot clone"); + + // List only non discarded snapshots after restore. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: Some(Query { + invalid: None, + discarded: Some(false), + }), + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 2); + assert!(!snaps[0].discarded_snapshot); + assert!(!snaps[1].discarded_snapshot); + + ms1.snapshot + .destroy_snapshot(DestroySnapshotRequest { + snapshot_uuid: snap1.to_string(), + pool: Some(Pool::PoolUuid(pool_uuid())), + }) + .await + .expect("Destroy should not fail"); + + // List only non discarded snapshots. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: Some(Query { + invalid: None, + discarded: Some(false), + }), + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 1); + assert!(!snaps[0].discarded_snapshot); + + // List only discarded snapshots. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: Some(Query { + invalid: None, + discarded: Some(true), + }), + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 1); + assert!(snaps[0].discarded_snapshot); + + // List all with query fields as None. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: Some(Query { + invalid: None, + discarded: None, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 2); + + // List all with query None. + let snaps = ms1 + .snapshot + .list_snapshot(ListSnapshotsRequest { + source_uuid: None, + snapshot_uuid: None, + query: None, + }) + .await + .expect("List should not fail") + .into_inner() + .snapshots; + assert_eq!(snaps.len(), 2); +} From 357a9fdbc7e747c8334066a38d04f31c434cba6f Mon Sep 17 00:00:00 2001 From: Abhinandan Purkait Date: Thu, 24 Aug 2023 07:08:00 +0000 Subject: [PATCH 3/4] refactor: replica listing based on query Signed-off-by: Abhinandan Purkait --- io-engine-tests/src/pool.rs | 4 +- io-engine-tests/src/replica.rs | 5 +- .../bin/io-engine-client/v1/replica_cli.rs | 2 +- io-engine/src/grpc/v1/replica.rs | 58 ++++++++----------- rpc/mayastor-api | 2 +- 5 files changed, 29 insertions(+), 42 deletions(-) diff --git a/io-engine-tests/src/pool.rs b/io-engine-tests/src/pool.rs index b58924de9..047e623b5 100644 --- a/io-engine-tests/src/pool.rs +++ b/io-engine-tests/src/pool.rs @@ -2,7 +2,7 @@ pub use super::compose::rpc::v1::pool::Pool; use super::{ compose::rpc::v1::{ pool::{CreatePoolRequest, ListPoolOptions}, - replica::{ListReplicaOptions, Replica, ReplicaType}, + replica::{ListReplicaOptions, Replica}, SharedRpcHandle, Status, }, @@ -104,7 +104,7 @@ impl PoolBuilder { poolname: None, uuid: None, pooluuid: self.uuid.clone(), - replicatype: ReplicaType::AllReplicas as i32, + query: None, }) .await .map(|r| r.into_inner().replicas) diff --git a/io-engine-tests/src/replica.rs b/io-engine-tests/src/replica.rs index 6b22d806d..60e0d4f64 100644 --- a/io-engine-tests/src/replica.rs +++ b/io-engine-tests/src/replica.rs @@ -11,7 +11,6 @@ use mayastor_api::v1::replica::{ DestroyReplicaRequest, ListReplicaOptions, Replica, - ReplicaType, ShareReplicaRequest, }; @@ -211,7 +210,7 @@ pub async fn list_replicas( poolname: None, uuid: None, pooluuid: None, - replicatype: ReplicaType::AllReplicas as i32, + query: None, }) .await .map(|r| r.into_inner().replicas) @@ -229,7 +228,7 @@ pub async fn find_replica_by_uuid( poolname: None, uuid: Some(uuid.to_owned()), pooluuid: None, - replicatype: ReplicaType::AllReplicas as i32, + query: None, }) .await .map(|r| r.into_inner().replicas)? diff --git a/io-engine/src/bin/io-engine-client/v1/replica_cli.rs b/io-engine/src/bin/io-engine-client/v1/replica_cli.rs index 913f9113c..2b3ec8fc2 100644 --- a/io-engine/src/bin/io-engine-client/v1/replica_cli.rs +++ b/io-engine/src/bin/io-engine-client/v1/replica_cli.rs @@ -271,7 +271,7 @@ async fn replica_list( poolname: None, uuid: None, pooluuid: None, - replicatype: v1_rpc::replica::ReplicaType::AllReplicas as i32, + query: None, }) .await .context(GrpcStatus)?; diff --git a/io-engine/src/grpc/v1/replica.rs b/io-engine/src/grpc/v1/replica.rs index 456418818..a6331b42e 100644 --- a/io-engine/src/grpc/v1/replica.rs +++ b/io-engine/src/grpc/v1/replica.rs @@ -125,41 +125,31 @@ impl ReplicaService { } } fn filter_replicas_by_replica_type( - replicas: Vec, - replica_type: Option, + replica_list: Vec, + query: Option, ) -> Vec { - let Some(replica_type) = replica_type else { - return replicas + let query = match query { + None => return replica_list, + Some(query) => query, }; - replicas + replica_list .into_iter() - .filter_map(|r| match replica_type { - // AllReplicas - ReplicaType::AllReplicas => Some(r), - // AllReplicasExceptSnapshots - ReplicaType::AllReplicasExceptSnapshots => { - if !r.is_snapshot { - Some(r) - } else { - None - } - } - // OnlySnapshotClones - ReplicaType::OnlySnapshotClones => { - if r.is_clone { - Some(r) - } else { - None - } - } - // OnlyReplicas - ReplicaType::OnlyReplicas => { - if !r.is_snapshot && !r.is_clone { - Some(r) - } else { - None + .filter(|replica| { + let query = &query; + + let query_fields = vec![ + (query.snapshot, replica.is_snapshot), + (query.clone, replica.is_clone), + // ... add other fields here as needed + ]; + + query_fields.iter().all(|(query_field, replica_field)| { + match query_field { + Some(true) => *replica_field, + Some(false) => !(*replica_field), + None => true, } - } + }) }) .collect() } @@ -353,10 +343,8 @@ impl ReplicaRpc for ReplicaService { } else if let Some(uuid) = args.uuid { replicas.retain(|r| r.uuid == uuid); } - let replicas = filter_replicas_by_replica_type( - replicas, - ReplicaType::from_i32(args.replicatype), - ); + let replicas = + filter_replicas_by_replica_type(replicas, args.query); Ok(ListReplicasResponse { replicas, }) diff --git a/rpc/mayastor-api b/rpc/mayastor-api index 396a0756c..2963fea7e 160000 --- a/rpc/mayastor-api +++ b/rpc/mayastor-api @@ -1 +1 @@ -Subproject commit 396a0756cb4062eb32226ab37ebbfb9cf257bb98 +Subproject commit 2963fea7e3ecde5f8e996edd9e82a279de6a158b From f9f9d820c7167106a969755b6be0083e300fb2f9 Mon Sep 17 00:00:00 2001 From: Abhinandan Purkait Date: Thu, 24 Aug 2023 08:16:24 +0000 Subject: [PATCH 4/4] test: add test to validate replica listing scenarios on query Signed-off-by: Abhinandan Purkait --- io-engine/src/grpc/v1/replica.rs | 8 +- io-engine/tests/snapshot_nexus.rs | 222 ++++++++++++++++++++++++++++-- rpc/mayastor-api | 2 +- 3 files changed, 216 insertions(+), 16 deletions(-) diff --git a/io-engine/src/grpc/v1/replica.rs b/io-engine/src/grpc/v1/replica.rs index a6331b42e..8eb1be698 100644 --- a/io-engine/src/grpc/v1/replica.rs +++ b/io-engine/src/grpc/v1/replica.rs @@ -138,16 +138,16 @@ fn filter_replicas_by_replica_type( let query = &query; let query_fields = vec![ + (query.replica, (!replica.is_snapshot && !replica.is_clone)), (query.snapshot, replica.is_snapshot), (query.clone, replica.is_clone), // ... add other fields here as needed ]; - query_fields.iter().all(|(query_field, replica_field)| { + query_fields.iter().any(|(query_field, replica_field)| { match query_field { - Some(true) => *replica_field, - Some(false) => !(*replica_field), - None => true, + true => *replica_field, + false => false, } }) }) diff --git a/io-engine/tests/snapshot_nexus.rs b/io-engine/tests/snapshot_nexus.rs index 9d7fe4625..7f08949f6 100755 --- a/io-engine/tests/snapshot_nexus.rs +++ b/io-engine/tests/snapshot_nexus.rs @@ -40,12 +40,15 @@ use io_engine::{ use io_engine_tests::file_io::{test_write_to_file, DataSize}; use nix::errno::Errno; -use mayastor_api::v1::snapshot::{ - destroy_snapshot_request::Pool, - list_snapshots_request::Query, - CreateReplicaSnapshotRequest, - CreateSnapshotCloneRequest, - DestroySnapshotRequest, +use mayastor_api::v1::{ + replica::list_replica_options, + snapshot::{ + destroy_snapshot_request::Pool, + list_snapshots_request, + CreateReplicaSnapshotRequest, + CreateSnapshotCloneRequest, + DestroySnapshotRequest, + }, }; use std::{pin::Pin, str}; use uuid::Uuid; @@ -965,7 +968,7 @@ async fn test_replica_snapshot_listing_with_query() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - query: Some(Query { + query: Some(list_snapshots_request::Query { invalid: None, discarded: Some(false), }), @@ -993,7 +996,7 @@ async fn test_replica_snapshot_listing_with_query() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - query: Some(Query { + query: Some(list_snapshots_request::Query { invalid: None, discarded: Some(false), }), @@ -1020,7 +1023,7 @@ async fn test_replica_snapshot_listing_with_query() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - query: Some(Query { + query: Some(list_snapshots_request::Query { invalid: None, discarded: Some(false), }), @@ -1038,7 +1041,7 @@ async fn test_replica_snapshot_listing_with_query() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - query: Some(Query { + query: Some(list_snapshots_request::Query { invalid: None, discarded: Some(true), }), @@ -1056,7 +1059,7 @@ async fn test_replica_snapshot_listing_with_query() { .list_snapshot(ListSnapshotsRequest { source_uuid: None, snapshot_uuid: None, - query: Some(Query { + query: Some(list_snapshots_request::Query { invalid: None, discarded: None, }), @@ -1081,3 +1084,200 @@ async fn test_replica_snapshot_listing_with_query() { .snapshots; assert_eq!(snaps.len(), 2); } + +/// This tests creates 2 replicas --> 2 snapshots --> 1 restore --> Validates +/// listing. +#[tokio::test] +async fn test_replica_listing_with_query() { + let _ = get_ms(); + let (test, _urls) = launch_instance(true).await; + let conn = GrpcConnect::new(&test); + let snap1 = Uuid::new_v4(); + + let mut ms1 = conn + .grpc_handle("ms1") + .await + .expect("Can't connect to remote I/O agent"); + + ms1.snapshot + .create_replica_snapshot(CreateReplicaSnapshotRequest { + replica_uuid: replica1_uuid(), + snapshot_uuid: snap1.to_string(), + snapshot_name: "snap1rep1/2".to_string(), + entity_id: "snap1rep1".to_string(), + txn_id: "1".to_string(), + }) + .await + .expect("Should create replica snapshot"); + + ms1.snapshot + .create_replica_snapshot(CreateReplicaSnapshotRequest { + replica_uuid: replica2_uuid(), + snapshot_uuid: Uuid::new_v4().to_string(), + snapshot_name: "snap2rep2/1".to_string(), + entity_id: "snap2rep2".to_string(), + txn_id: "1".to_string(), + }) + .await + .expect("Should create replica snapshot"); + + ms1.snapshot + .create_snapshot_clone(CreateSnapshotCloneRequest { + snapshot_uuid: snap1.to_string(), + clone_name: "snaprep1clone".to_string(), + clone_uuid: Uuid::new_v4().to_string(), + }) + .await + .expect("Should create snapshot clone"); + + // List all with query None, all replicas including snapshots and clones. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: None, + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 5); + + // List all replicas except snapshots. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: true, + snapshot: false, + clone: true, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 3); + assert!(!replicas[0].is_snapshot); + assert!(!replicas[1].is_snapshot); + assert!(!replicas[2].is_snapshot); + + // List all replicas except clones. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: true, + snapshot: true, + clone: false, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 4); + assert!(!replicas[0].is_clone); + assert!(!replicas[1].is_clone); + assert!(!replicas[2].is_clone); + assert!(!replicas[3].is_clone); + + // List only clones and snapshots. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: false, + snapshot: true, + clone: true, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 3); + assert!(replicas[0].is_clone || replicas[0].is_snapshot); + assert!(replicas[1].is_clone || replicas[1].is_snapshot); + assert!(replicas[2].is_clone || replicas[2].is_snapshot); + + // List only snapshots. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: false, + snapshot: true, + clone: false, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 2); + assert!(replicas[0].is_snapshot); + assert!(replicas[1].is_snapshot); + + // List only clones. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: false, + snapshot: false, + clone: true, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 1); + assert!(replicas[0].is_clone); + + // List all only replicas. + let replicas = ms1 + .replica + .list_replicas(ListReplicaOptions { + name: None, + poolname: None, + uuid: None, + pooluuid: None, + query: Some(list_replica_options::Query { + replica: true, + snapshot: false, + clone: false, + }), + }) + .await + .expect("List should not fail") + .into_inner() + .replicas; + assert_eq!(replicas.len(), 2); + assert!(!replicas[0].is_clone && !replicas[0].is_snapshot); + assert!(!replicas[1].is_clone && !replicas[1].is_snapshot); +} diff --git a/rpc/mayastor-api b/rpc/mayastor-api index 2963fea7e..0bbc1fe2f 160000 --- a/rpc/mayastor-api +++ b/rpc/mayastor-api @@ -1 +1 @@ -Subproject commit 2963fea7e3ecde5f8e996edd9e82a279de6a158b +Subproject commit 0bbc1fe2f185859b821777e8279c50df1ca6bf78