[ 
https://issues.apache.org/jira/browse/CAMEL-25760?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen updated CAMEL-25760:
--------------------------------
    Fix Version/s: 4.24.0

> camel-alibaba-oss, camel-huaweicloud-obs - one listed object that cannot be 
> got (access denied, archived) fails every poll, so the consumer stops 
> consuming the bucket (OSS: never again; OBS: the objects listed with it)
> --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25760
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25760
>             Project: Camel
>          Issue Type: Bug
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>             Fix For: 4.24.0
>
>
> The same defect in two object-store consumers (as CAMEL-25551 covered several 
> modules in one issue); one fix per module, two pull requests.
> h3. camel-alibaba-oss
> {{OSSConsumer.poll}} (main e13303ef1ef7, lines 72-107) lists one page of the 
> bucket ({{maxKeys}} = {{maxMessagesPerPoll}}, 10 by default) and gets every 
> listed object in {{createExchanges}} / {{addExchange}} (lines 152-203). An 
> object that no longer exists (404) is skipped since CAMEL-25551; any other 
> failure of the get is rethrown, the exchanges already created are released, 
> and the poll fails. The continuation token is only moved on after the batch 
> was processed (lines 101-105), so the next poll lists the same page again:
> {code:java}
> Queue<Exchange> exchanges = createExchanges(bucketName, listing.contents());
> int processed = processBatch(CastUtils.cast(exchanges));
> if (processed >= 0) {
>     continuationToken = nextToken;
> }
> {code}
> So one object whose get fails every time (access denied for that object, an 
> object of the Archive or Cold Archive storage class that is not restored, a 
> KMS key that was disabled) fails every poll: none of the other objects of its 
> page is consumed, and the consumer never reaches the following pages. If the 
> bucket fits in one page, the consumer consumes nothing at all. Nothing but a 
> WARN per poll ("Failed polling endpoint") says why, and it lasts until 
> someone removes or restores the object.
> camel-aws2-s3 had the same behaviour and CAMEL-25558 changed it: a listed 
> object whose get fails is skipped for that poll and reported to the exception 
> handler with its key, the other listed objects are consumed, and the poll 
> fails only when none of the listed objects could be got (expired credentials, 
> no permission to get objects); the marker of the listing is moved on before 
> the objects are got ({{AWS2S3Consumer}} lines 173-201, 340-356). 
> camel-huaweicloud-obs moves its marker on before the gets, but also fails the 
> poll for one object.
> *Fix*: the same in {{OSSConsumer}}: a failed get of one listed object is 
> collected, the object is skipped and reported to the consumer's exception 
> handler ("Error getting object <key> from bucket <bucket>. The object is 
> skipped for this poll."), and the other objects are consumed; when none of 
> the listed objects could be got, the poll fails with the first failure as 
> before. The continuation token is set from the listing before the objects are 
> got, so a page whose objects cannot be got does not hold the consumer back 
> (its objects are listed again when the listing starts over). An object 
> deleted after the listing is still skipped silently. Upgrade note in the 4.24 
> guide.
> *Tests*: new {{OSSConsumerObjectThatCannotBeGotTest}} (3 tests; a fake bucket 
> that lists keys in order, {{maxKeys}} at a time with a continuation token, 
> and answers the get of a forbidden object with 403). 
> {{objectThatCannotBeGotDoesNotBlockTheOtherObjects}} (a.txt, b.txt forbidden, 
> c.txt) and {{pageOfObjectsThatCannotBeGotDoesNotBlockTheNextPage}} 
> ({{maxMessagesPerPoll=1}}, a.txt forbidden) fail on main: no object is 
> received ({{mock://result Received message count. Expected: <2> but was: 
> <0>}}). {{pollFailsWhenNoListedObjectCanBeGot}} passes on main and with the 
> fix; it guards the case the fix must not swallow (no object can be got: the 
> poll fails). camel-alibaba-oss unit tests: 22 run, 0 failures.
> *How it was found*: differential reading of sibling consumers of object 
> stores against the same listing / get / commit model: camel-aws2-s3 (after 
> CAMEL-25558), camel-huaweicloud-obs and camel-alibaba-oss. camel-aws2-s3 
> skips the object; camel-huaweicloud-obs fails the poll but moves its marker 
> on, so it stops for good only when the bucket fits in one page (see below); 
> camel-alibaba-oss fails the poll and keeps its listing position, so it stops 
> for good whatever the size of the bucket. The JUnit tests above are the 
> evidence; the OSS status codes for archived and forbidden objects are from 
> the OSS documentation and were not run against OSS.
> Not changed here: camel-minio (a failed get in 
> {{MinioConsumer.processBatch}}, main lines 319-331, stops the rest of the 
> batch and fails the poll) and camel-google-storage 
> ({{GoogleCloudStorageConsumer.createExchanges}} / {{addExchange}}, lines 
> 166-208, fail the poll for one object) have the same kind of defect; they are 
> left as follow-ups.
> *Affected*: main, camel-4.23.x (the same lines; read, not run). The component 
> is new in 4.23.
> h3. camel-huaweicloud-obs
> {{OBSConsumer.poll}} (main e13303ef1ef7, lines 139-166) lists the bucket 
> ({{maxKeys}} = {{maxMessagesPerPoll}}, 10 by default) and gets every listed 
> object in {{createExchanges}} (lines 218-245). An object that no longer 
> exists (404) is skipped since CAMEL-25551; any other failure of the get is 
> rethrown, the exchanges already created are released, and the poll fails:
> {code:java}
> } catch (ObsException e) {
>     if (e.getResponseCode() == 404) { ... continue; }
>     throw e;
> }
> ...
> } catch (RuntimeException e) {
>     // none of the objects of this poll is processed
>     releaseNotProcessed(answer);
>     throw e;
> }
> {code}
> So one object whose get fails every time (access denied for that object, an 
> object of the Archive or Deep Archive storage class that is not restored, an 
> SSE-KMS key that was disabled) fails every poll that lists it, and the other 
> objects of that listing are not consumed either. The marker of a truncated 
> listing is moved on before the gets, but a listing that is not truncated sets 
> the marker back to {{null}}, so:
> * a bucket (or prefix) whose objects fit in one listing (10 objects with the 
> default {{maxMessagesPerPoll}}) is never consumed again: every poll lists the 
> same objects and fails on the same one;
> * in a larger bucket the objects that are listed together with it are skipped 
> at every pass over the bucket.
> Nothing but a WARN per poll ("Failed polling endpoint") says why, and it 
> lasts until someone removes or restores the object.
> camel-aws2-s3 had the same behaviour and CAMEL-25558 changed it: a listed 
> object whose get fails is skipped for that poll and reported to the exception 
> handler with its key, the other listed objects are consumed, and the poll 
> fails only when none of the listed objects could be got ({{AWS2S3Consumer}} 
> lines 340-356).
> *Fix*: the same in {{OBSConsumer.createExchanges}}: a failed get of one 
> listed object is collected, the object is skipped and reported to the 
> consumer's exception handler ("Error getting object <key> from bucket 
> <bucket>. The object is skipped for this poll."), and the other objects are 
> consumed; when none of the listed objects could be got, the poll fails with 
> the first failure as before. An object deleted after the listing is still 
> skipped silently; with the {{fileName}} option a failed get still fails the 
> poll. Upgrade note in the 4.24 guide.
> *Tests*: new {{OBSConsumerObjectThatCannotBeGotTest}} (3 tests; a fake bucket 
> that lists keys in order, {{maxKeys}} at a time with the last key as next 
> marker, and answers the get of a forbidden object with 403). 
> {{objectThatCannotBeGotDoesNotBlockTheOtherObjects}} (a.txt, b.txt forbidden, 
> c.txt, one listing) and 
> {{objectThatCannotBeGotDoesNotBlockTheObjectsOfItsPage}} 
> ({{maxMessagesPerPoll=2}}, a.txt forbidden, listed with b.txt) fail on main. 
> {{pollFailsWhenNoListedObjectCanBeGot}} passes on main and with the fix; it 
> guards the case the fix must not swallow (no object can be got: the poll 
> fails). camel-huaweicloud-obs unit tests: 47 run, 0 failures, 18 skipped 
> (functional tests that need OBS credentials).
> *How it was found*: differential reading of sibling consumers of object 
> stores against the same listing / get / commit model: camel-aws2-s3 (after 
> CAMEL-25558), camel-huaweicloud-obs and camel-alibaba-oss. camel-aws2-s3 
> skips the object; camel-huaweicloud-obs and camel-alibaba-oss fail the poll. 
> The JUnit tests above are the evidence; the OBS status codes for archived and 
> forbidden objects are from the OBS documentation and were not run against OBS.
> Not changed here: camel-minio (a failed get in 
> {{MinioConsumer.processBatch}}, main lines 319-331, stops the rest of the 
> batch and fails the poll) and camel-google-storage 
> ({{GoogleCloudStorageConsumer.createExchanges}} / {{addExchange}}, lines 
> 166-208, fail the poll for one object) have the same kind of defect; they are 
> left as follow-ups.
> *Affected*: main and camel-4.23.x (the same lines); camel-4.22.x, 
> camel-4.18.x and camel-4.14.x do not catch the get at all, so there every 
> failed get, also of an object deleted after the listing, fails the poll 
> (read, not run).
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to