Skip to content

Commit c075e9a

Browse files
authored
Compare request against existing region (#7845)
If the IDs match, the simulated Crucible agent should compare the CreateRegion request against the existing Region, and return a conflict error if the request differs. Also, correctly use the fields from the CreateRegion request when creating the region: encrypted, cert_pem, key_pem, and root_pem were not being set properly!
1 parent 364f344 commit c075e9a

File tree

2 files changed

+71
-12
lines changed

2 files changed

+71
-12
lines changed

sled-agent/src/sim/http_entrypoints_storage.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,7 @@ async fn region_create(
7777
let params = body.into_inner();
7878
let crucible = rc.context();
7979

80-
let region = crucible.create(params).map_err(|e| {
81-
HttpError::for_internal_error(
82-
format!("region create failure: {:?}", e,),
83-
)
84-
})?;
80+
let region = crucible.create(params)?;
8581

8682
Ok(HttpResponseOk(region))
8783
}

sled-agent/src/sim/storage.rs

+70-7
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,53 @@ struct CrucibleDataInner {
7171
used_ports: HashSet<u16>,
7272
}
7373

74+
/// Returns Some with a string if there's a mismatch
75+
pub fn mismatch(params: &CreateRegion, r: &Region) -> Option<String> {
76+
if params.block_size != r.block_size {
77+
Some(format!(
78+
"requested block size {} instead of {}",
79+
params.block_size, r.block_size
80+
))
81+
} else if params.extent_size != r.extent_size {
82+
Some(format!(
83+
"requested extent size {} instead of {}",
84+
params.extent_size, r.extent_size
85+
))
86+
} else if params.extent_count != r.extent_count {
87+
Some(format!(
88+
"requested extent count {} instead of {}",
89+
params.extent_count, r.extent_count
90+
))
91+
} else if params.encrypted != r.encrypted {
92+
Some(format!(
93+
"requested encrypted {} instead of {}",
94+
params.encrypted, r.encrypted
95+
))
96+
} else if params.cert_pem != r.cert_pem {
97+
Some(format!(
98+
"requested cert_pem {:?} instead of {:?}",
99+
params.cert_pem, r.cert_pem
100+
))
101+
} else if params.key_pem != r.key_pem {
102+
Some(format!(
103+
"requested key_pem {:?} instead of {:?}",
104+
params.key_pem, r.key_pem
105+
))
106+
} else if params.root_pem != r.root_pem {
107+
Some(format!(
108+
"requested root_pem {:?} instead of {:?}",
109+
params.root_pem, r.root_pem
110+
))
111+
} else if params.source != r.source {
112+
Some(format!(
113+
"requested source {:?} instead of {:?}",
114+
params.source, r.source
115+
))
116+
} else {
117+
None
118+
}
119+
}
120+
74121
impl CrucibleDataInner {
75122
fn new(log: Logger, start_port: u16, end_port: u16) -> Self {
76123
Self {
@@ -108,7 +155,7 @@ impl CrucibleDataInner {
108155
panic!("no free ports for simulated crucible agent!");
109156
}
110157

111-
fn create(&mut self, params: CreateRegion) -> Result<Region> {
158+
fn create(&mut self, params: CreateRegion) -> Result<Region, HttpError> {
112159
let id = Uuid::from_str(&params.id.0).unwrap();
113160

114161
let state = if let Some(on_create) = &self.on_create {
@@ -118,7 +165,23 @@ impl CrucibleDataInner {
118165
};
119166

120167
if self.region_creation_error {
121-
bail!("region creation error!");
168+
return Err(HttpError::for_internal_error(
169+
"region creation error!".to_string(),
170+
));
171+
}
172+
173+
if let Some(region) = self.regions.get(&id) {
174+
if let Some(mismatch) = mismatch(&params, &region) {
175+
let s = format!(
176+
"region {region:?} already exists as {params:?}: {mismatch}"
177+
);
178+
warn!(self.log, "{s}");
179+
return Err(HttpError::for_client_error(
180+
None,
181+
dropshot::ClientErrorStatusCode::CONFLICT,
182+
s,
183+
));
184+
}
122185
}
123186

124187
let read_only = params.source.is_some();
@@ -131,10 +194,10 @@ impl CrucibleDataInner {
131194
// NOTE: This is a lie - no server is running.
132195
port_number: self.get_free_port(),
133196
state,
134-
encrypted: false,
135-
cert_pem: None,
136-
key_pem: None,
137-
root_pem: None,
197+
encrypted: params.encrypted,
198+
cert_pem: params.cert_pem,
199+
key_pem: params.key_pem,
200+
root_pem: params.root_pem,
138201
source: params.source,
139202
read_only,
140203
};
@@ -933,7 +996,7 @@ impl CrucibleData {
933996
self.inner.lock().unwrap().list()
934997
}
935998

936-
pub fn create(&self, params: CreateRegion) -> Result<Region> {
999+
pub fn create(&self, params: CreateRegion) -> Result<Region, HttpError> {
9371000
self.inner.lock().unwrap().create(params)
9381001
}
9391002

0 commit comments

Comments
 (0)