Skip to content

Commit 62ae8e5

Browse files
committed
feat: S3 DeleteObjects implementation
1 parent 57eb4b7 commit 62ae8e5

1 file changed

Lines changed: 104 additions & 1 deletion

File tree

components/data_proxy/src/s3_frontend/s3service.rs

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,106 @@ impl S3 for ArunaS3Service {
13711371
};
13721372
}
13731373

1374+
#[tracing::instrument(err)]
1375+
#[allow(clippy::blocks_in_conditions)]
1376+
async fn delete_objects(
1377+
&self,
1378+
req: S3Request<DeleteObjectsInput>,
1379+
) -> S3Result<S3Response<DeleteObjectsOutput>> {
1380+
let CheckAccessResult {
1381+
user_state,
1382+
headers,
1383+
..
1384+
} = req
1385+
.extensions
1386+
.get::<CheckAccessResult>()
1387+
.cloned()
1388+
.ok_or_else(|| {
1389+
error!(error = "Missing data context");
1390+
s3_error!(UnexpectedContent, "Missing data context")
1391+
})?;
1392+
1393+
let mut objects = Vec::new();
1394+
let lock = self.cache.auth.read().await;
1395+
let auth = match lock.as_ref() {
1396+
Some(auth) => auth,
1397+
None => {
1398+
return Err(s3_error!(
1399+
InternalError,
1400+
"Could not access authorization handler"
1401+
));
1402+
}
1403+
};
1404+
// One loop for authorization
1405+
for ObjectIdentifier { key, .. } in &req.input.delete.objects {
1406+
let CheckAccessResult { objects_state, .. } = auth
1407+
.handle_object(
1408+
&req.input.bucket,
1409+
key,
1410+
&http::Method::DELETE,
1411+
req.credentials.as_ref(),
1412+
&req.headers,
1413+
)
1414+
.await?;
1415+
1416+
let (states, _) = objects_state.require_regular()?;
1417+
let all = states.to_new_or_existing()?;
1418+
trace!(?all);
1419+
let (_, _, _, object, _) = all;
1420+
objects.push(object);
1421+
}
1422+
1423+
drop(lock);
1424+
1425+
let impersonating_token =
1426+
user_state.sign_impersonating_token(self.cache.auth.read().await.as_ref());
1427+
1428+
for object in objects {
1429+
match object {
1430+
NewOrExistingObject::Missing(_) => {
1431+
//Do nothing.
1432+
}
1433+
NewOrExistingObject::Existing(object) => {
1434+
if let Some(handler) = self.cache.aruna_client.read().await.as_ref() {
1435+
if let Some(token) = &impersonating_token {
1436+
handler
1437+
.delete_object(&object.id, token)
1438+
.await
1439+
.map_err(|e| {
1440+
error!("Object deletion failed: {e}");
1441+
s3_error!(InternalError, "Object deletion failed")
1442+
})?;
1443+
1444+
self.cache.delete_object(object.id).await.map_err(|e| {
1445+
error!("Object cache deletion failed: {e}");
1446+
s3_error!(InternalError, "Object cache deletion failed")
1447+
})?;
1448+
}
1449+
}
1450+
}
1451+
NewOrExistingObject::None => {
1452+
return Err(s3_error!(
1453+
InvalidObjectState,
1454+
"Object in invalid state: None"
1455+
))
1456+
}
1457+
}
1458+
}
1459+
1460+
let mut resp = S3Response::new(DeleteObjectsOutput::default());
1461+
if let Some(headers) = headers {
1462+
for (k, v) in headers {
1463+
resp.headers.insert(
1464+
HeaderName::from_bytes(k.as_bytes())
1465+
.map_err(|_| s3_error!(InternalError, "Unable to parse header name"))?,
1466+
HeaderValue::from_str(&v)
1467+
.map_err(|_| s3_error!(InternalError, "Unable to parse header value"))?,
1468+
);
1469+
}
1470+
}
1471+
Ok(resp)
1472+
}
1473+
13741474
#[tracing::instrument(err)]
13751475
#[allow(clippy::blocks_in_conditions)]
13761476
async fn delete_object(
@@ -1395,7 +1495,10 @@ impl S3 for ArunaS3Service {
13951495

13961496
let (states, _) = objects_state.require_regular()?;
13971497

1398-
let (_, _, _, object, _) = states.to_new_or_existing()?;
1498+
//let (_, _, _, object, _) = states.to_new_or_existing()?;
1499+
let all = states.to_new_or_existing()?;
1500+
trace!(?all);
1501+
let (_, _, _, object, _) = all;
13991502

14001503
match object {
14011504
NewOrExistingObject::Missing(_) => {

0 commit comments

Comments
 (0)