Skip to content

Commit cf01401

Browse files
chore: add canonical pcie, add regex to stop non persistent devlinks
Signed-off-by: Abhinandan Purkait <[email protected]>
1 parent c5f1dbb commit cf01401

File tree

12 files changed

+112
-6
lines changed

12 files changed

+112
-6
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

control-plane/agents/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ tracing = "0.1.40"
5858
nix = { version = "0.29.0", default-features = false }
5959
prost-types = "0.13.3"
6060
url = "2.5.4"
61+
regex = "1.11.1"
6162

6263
grpc = { path = "../grpc" }
6364
shutdown = { path = "../../utils/shutdown" }

control-plane/agents/src/bin/core/controller/registry.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ pub(crate) struct RegistryInner<S: Store> {
114114
ha_disabled: bool,
115115
/// Etcd max page size.
116116
etcd_max_page_size: i64,
117+
/// Allow pool creation using non-persistent devlinks.
118+
allow_non_persistent_devlinks: bool,
117119
}
118120

119121
impl Registry {
@@ -140,6 +142,7 @@ impl Registry {
140142
ha_enabled: bool,
141143
etcd_max_page_size: i64,
142144
no_volume_health: bool,
145+
allow_non_persistent_devlinks: bool,
143146
) -> Result<Self, SvcError> {
144147
let store_endpoint = Self::format_store_endpoint(&store_url);
145148
tracing::info!("Connecting to persistent store at {}", store_endpoint);
@@ -199,6 +202,7 @@ impl Registry {
199202
thin_args,
200203
ha_disabled: ha_enabled,
201204
etcd_max_page_size,
205+
allow_non_persistent_devlinks,
202206
}),
203207
};
204208
registry.init().await?;
@@ -230,6 +234,11 @@ impl Registry {
230234
self.ha_disabled
231235
}
232236

237+
/// Check if pool creation using non-persistent devlink is allowed.
238+
pub(crate) fn allow_non_persistent_devlinks(&self) -> bool {
239+
self.allow_non_persistent_devlinks
240+
}
241+
233242
/// Check if the partial rebuilds are disabled.
234243
pub(crate) fn partial_rebuild_disabled(&self) -> bool {
235244
self.disable_partial_rebuild

control-plane/agents/src/bin/core/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ pub(crate) struct CliArgs {
142142
/// Disable volume health reporting which uses pstor watchers.
143143
#[clap(long)]
144144
no_volume_health: bool,
145+
146+
/// Allow pools to be created using non persistent devlinks.
147+
#[clap(long)]
148+
allow_non_persistent_devlink: bool,
145149
}
146150
impl CliArgs {
147151
fn args() -> Self {
@@ -219,6 +223,7 @@ async fn server(cli_args: CliArgs) -> anyhow::Result<()> {
219223
cli_args.disable_ha,
220224
cli_args.etcd_page_limit as i64,
221225
cli_args.no_volume_health,
226+
cli_args.allow_non_persistent_devlink,
222227
)
223228
.await?;
224229

control-plane/agents/src/bin/core/pool/operations_helper.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use stor_port::types::v0::{
2424
};
2525

2626
use itertools::Itertools;
27+
use regex::Regex;
2728
use snafu::OptionExt;
2829
use std::collections::HashSet;
2930
use std::ops::Deref;
@@ -151,6 +152,22 @@ pub(crate) async fn devlink_preflight_checks(
151152
.map(|disk| utils::disk::normalize_disk(disk.as_str()))
152153
.collect();
153154

155+
if !registry.allow_non_persistent_devlinks() {
156+
fn is_persistent_devlink(pattern: &str) -> Result<bool, SvcError> {
157+
let re = Regex::new(utils::DEVLINK_REGEX).map_err(|_| SvcError::InvalidArguments {})?;
158+
Ok(re.is_match(pattern))
159+
}
160+
161+
if request_disks
162+
.iter()
163+
// Only attempt to validate if it starts with "/dev".
164+
.filter(|disk| disk.starts_with("/dev"))
165+
.any(|disk| !is_persistent_devlink(disk).is_ok_and(|val| val))
166+
{
167+
return Err(SvcError::InvalidDevlink {});
168+
}
169+
}
170+
154171
let node_pools = registry
155172
.get_node_opt_pools(Some(request.node.clone()))
156173
.await?;

control-plane/agents/src/bin/core/pool/pool_operations.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ impl ResourceLifecycle for OperationGuardArc<PoolSpec> {
4444
});
4545
}
4646

47-
if let Ok(pool) = registry.specs().pool(&request.id) {
47+
let pool_get_result = registry.specs().pool(&request.id);
48+
if let Ok(pool) = &pool_get_result {
4849
if pool.status.created() {
4950
return Err(SvcError::AlreadyExists {
5051
kind: ResourceKind::Pool,
@@ -61,8 +62,10 @@ impl ResourceLifecycle for OperationGuardArc<PoolSpec> {
6162
});
6263
}
6364

64-
// If the devlink for a device is used for multiple pools, reject new creation.
65-
devlink_preflight_checks(request, node.clone(), registry).await?;
65+
if pool_get_result.is_err() {
66+
// If the devlink for a device is used for multiple pools, reject new creation.
67+
devlink_preflight_checks(request, node.clone(), registry).await?
68+
}
6669

6770
let mut pool = specs
6871
.get_or_create_pool(request)

control-plane/agents/src/bin/core/tests/pool/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use grpc::{
77
},
88
};
99
use itertools::Itertools;
10+
use regex::Regex;
1011
use std::{collections::HashMap, convert::TryFrom, thread::sleep, time::Duration};
1112
use stor_port::types::v0::store::pool::{Encryption, EncryptionSecret};
1213
use stor_port::types::v0::transport::{GetBlockDevices, NodeStatus};
@@ -1347,3 +1348,34 @@ async fn reject_devlink_reuse() {
13471348
}
13481349
}
13491350
}
1351+
1352+
#[tokio::test]
1353+
async fn persistent_devlink_regex() {
1354+
fn is_persistent_devlink(pattern: &str) -> bool {
1355+
let re = Regex::new(utils::DEVLINK_REGEX).expect("DEVLINK_REGEX should be valid");
1356+
re.is_match(pattern)
1357+
}
1358+
1359+
let test_suite = [
1360+
("/dev/some/path", false),
1361+
("/dev/mapper/some/path", false),
1362+
("/dev/disk/some/path", false),
1363+
("/dev/disk/by-something/path", false),
1364+
("/devil/disk/by-something/path", false),
1365+
("/dev/diskxyz/by-something/path", false),
1366+
("/dev/disk/something-by/path", false),
1367+
("/dev/disk/by-/path", false),
1368+
("something", false),
1369+
("/dev/somevg/lv0", false), // LVM Paths are to be used via the /dev/mapper or by /dev/disk/by-id
1370+
("/dev/disk/by-id/somepath", true),
1371+
("/dev/disk/by-path/somepath", true),
1372+
("/dev/disk/by-label/somepath", true),
1373+
("/dev/disk/by-partuuid/somepath", true),
1374+
("/dev/disk/by-partlabel/somepath", true),
1375+
("/dev/mapper/dm0", true),
1376+
];
1377+
1378+
for test in test_suite {
1379+
assert_eq!(is_persistent_devlink(test.0), test.1);
1380+
}
1381+
}

control-plane/agents/src/common/errors.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ pub enum SvcError {
420420
replica: String,
421421
source: tonic::Status,
422422
},
423+
#[snafu(display("Invalid devlink, use a persistent devlink for pool creation"))]
424+
InvalidDevlink {},
423425
}
424426

425427
impl SvcError {
@@ -1111,6 +1113,12 @@ impl From<SvcError> for ReplyError {
11111113
source,
11121114
extra,
11131115
},
1116+
SvcError::InvalidDevlink { .. } => ReplyError {
1117+
kind: ReplyErrorKind::InvalidArgument,
1118+
resource: ResourceKind::Block,
1119+
source,
1120+
extra,
1121+
},
11141122
}
11151123
}
11161124
}

k8s/operators/src/pool/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,13 @@ mod test {
369369
"uring:///dev/null",
370370
"uring://dev/null", // this URL is invalid
371371
"pcie:///0000:01:00.0",
372+
"pcie:///00:01:00.0",
372373
];
373374

374375
assert_eq!(utils::disk::normalize_disk(disks[0]), "/dev/null");
375376
assert_eq!(utils::disk::normalize_disk(disks[1]), "/dev/null");
376377
assert_eq!(utils::disk::normalize_disk(disks[2]), "uring://dev/null");
377378
assert_eq!(utils::disk::normalize_disk(disks[3]), "/0000:01:00.0");
379+
assert_eq!(utils::disk::normalize_disk(disks[4]), "/0000:01:00.0");
378380
}
379381
}

tests/bdd/features/pool/create/test_disks.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ def disks():
125125

126126
@pytest.fixture
127127
def attempt_create_pool_nonexistent_disk(context, attempt_create_pool):
128-
context["attempt"] = attempt_create_pool(POOL_NAME, POOL_NODE, ["/dev/no_there"])
128+
context["attempt"] = attempt_create_pool(
129+
POOL_NAME, POOL_NODE, ["/dev/disk/by-id/no_there"]
130+
)
129131

130132

131133
@pytest.fixture

0 commit comments

Comments
 (0)