Add support for Dell ECS (S3-compatible host) to Jira

XMLWordPrintable

    • 0
    • 3

      Issue Summary

      Jira Data Center can store avatars and attachments in Amazon S3 (AWS). As a Jira administrator, I would like to use Dell ECS Enterprise Object Storage to store avatars and attachments. This is a third-party appliance that exposes an S3-compatible interface. Currently, Atlassian only officially supports Amazon S3.

      Steps to Reproduce

      1. Connect Jira DC to ECS, following the instructions:

      Expected Results

      Jira DC stores and retrieves avatars and attachments as designed. All health checks pass.

      Actual Results

      Errors are logged to the atlassian-jira.log file, and avatars/attachments fail to save.

      Startup:

      2025-01-08 16:00:00,000-0000 JIRA-Bootstrap WARN      [c.a.jira.health.HealthChecks] Unable to connect to the avatar and attachment storage.
      2025-01-08 16:00:00,000-0000 JIRA-Bootstrap WARN      [c.a.jira.health.HealthChecks] The Content-SHA256 you specified did not match what we received (Service: S3, Status Code: 400, Request ID: ..., Extended Request ID: ...)
      

      During the health check job:

      2025-01-08 16:00:00,000-0000 Caesium-1-1 WARN      [c.a.t.healthcheck.concurrent.SupportHealthCheckProcess] Health check 'Avatar Storage' failed with severity 'warning': 'Unable to write to avatar storage.'
      2025-01-08 16:00:00,000-0000 Caesium-1-1 ERROR      [c.a.t.healthcheck.concurrent.SupportHealthCheckProcess] Health check 'Attachment Storage' failed with severity 'major': 'Unable to write to attachment storage.'
      

      When attempting to upload an avatar (or attachment):

      2025-01-08 16:00:00,000-0000 http-nio-8080-exec-1 ERROR user 1x1x1 abcdef 0.0.0.0 /rest/api/latest/user/avatar [c.a.jira.avatar.AvatarPickerHelperImpl] Unable to create avatar.
      com.atlassian.dc.filestore.api.exception.FileStoreAccessDeniedException: The Content-SHA256 you specified did not match what we received (Service: S3, Status Code: 400, Request ID: ..., Extended Request ID: ...)
      	at com.atlassian.dc.filestore.impl.s3.OperationExecutorImpl.performOperation(OperationExecutorImpl.java:46)
      	at com.atlassian.dc.filestore.impl.s3.S3Path.put(S3Path.java:232)
      	at com.atlassian.dc.filestore.api.FileStore$Writer.write(FileStore.java:336)
      	at com.atlassian.dc.filestore.api.FileStore$Writer.write(FileStore.java:351)
      	at com.atlassian.jira.avatar.AvatarManagerImpl.processImage(AvatarManagerImpl.java:290)
      	at com.atlassian.jira.avatar.AvatarManagerImpl.create(AvatarManagerImpl.java:167)
      	at com.atlassian.jira.avatar.AvatarPickerHelperImpl.convertTemporaryToReal(AvatarPickerHelperImpl.java:170)
      	[trimmed Spring resolution]
      	at jdk.proxy156/jdk.proxy156.$Proxy2932.convertTemporaryToReal(Unknown Source)
      	at com.atlassian.jira.rest.v2.issue.AvatarResourceHelper.createAvatarFromTemporary(AvatarResourceHelper.java:194)
      	at com.atlassian.jira.rest.v2.issue.UserResource.createAvatarFromTemporary(UserResource.java:1131)
      	[trimmed Servlet filters]
      Caused by: java.util.concurrent.CompletionException: software.amazon.awssdk.services.s3.model.S3Exception: The Content-SHA256 you specified did not match what we received (Service: S3, Status Code: 400, Request ID: ..., Extended Request ID: ...)
      	at software.amazon.awssdk.utils.CompletableFutureUtils.errorAsCompletionException(CompletableFutureUtils.java:64)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncExecutionFailureExceptionReportingStage.lambda$execute$0(AsyncExecutionFailureExceptionReportingStage.java:51)
      	at java.base/java.util.concurrent.CompletableFuture.uniHandle(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(Unknown Source)
      	at software.amazon.awssdk.utils.CompletableFutureUtils.lambda$forwardExceptionTo$0(CompletableFutureUtils.java:78)
      	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(Unknown Source)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.maybeAttemptExecute(AsyncRetryableStage2.java:135)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.maybeRetryExecute(AsyncRetryableStage2.java:152)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage2$RetryingExecutor.lambda$attemptExecute$1(AsyncRetryableStage2.java:123)
      	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.complete(Unknown Source)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage.lambda$execute$0(MakeAsyncHttpRequestStage.java:110)
      	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.complete(Unknown Source)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage.completeResponseFuture(MakeAsyncHttpRequestStage.java:253)
      	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage.lambda$executeHttpRequest$3(MakeAsyncHttpRequestStage.java:167)
      	at java.base/java.util.concurrent.CompletableFuture.uniHandle(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture$Completion.run(Unknown Source)
      	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
      	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
      	... 1 more
      Caused by: software.amazon.awssdk.services.s3.model.S3Exception: The Content-SHA256 you specified did not match what we received (Service: S3, Status Code: 400, Request ID: ..., Extended Request ID: ...)
      	at software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler.handleErrorResponse(AwsXmlPredicatedResponseHandler.java:156)
      	at software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler.handleResponse(AwsXmlPredicatedResponseHandler.java:108)
      	at software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler.handle(AwsXmlPredicatedResponseHandler.java:85)
      	at software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler.handle(AwsXmlPredicatedResponseHandler.java:43)
      	at software.amazon.awssdk.core.internal.handler.BaseClientHandler.lambda$successTransformationResponseHandler$7(BaseClientHandler.java:279)
      	at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler.lambda$prepare$0(AsyncResponseHandler.java:92)
      	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.complete(Unknown Source)
      	at software.amazon.awssdk.core.internal.http.async.AsyncResponseHandler$BaosSubscriber.onComplete(AsyncResponseHandler.java:135)
      	at software.amazon.awssdk.core.internal.metrics.BytesReadTrackingPublisher$BytesReadTracker.onComplete(BytesReadTrackingPublisher.java:74)
      	at software.amazon.awssdk.utils.async.SimplePublisher.doProcessQueue(SimplePublisher.java:275)
      	at software.amazon.awssdk.utils.async.SimplePublisher.processEventQueue(SimplePublisher.java:224)
      	at software.amazon.awssdk.utils.async.SimplePublisher.complete(SimplePublisher.java:157)
      	at java.base/java.util.concurrent.CompletableFuture.uniRunNow(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.uniRunStage(Unknown Source)
      	at java.base/java.util.concurrent.CompletableFuture.thenRun(Unknown Source)
      	at software.amazon.awssdk.services.s3.internal.crt.S3CrtResponseHandlerAdapter.onErrorResponseComplete(S3CrtResponseHandlerAdapter.java:200)
      	at software.amazon.awssdk.services.s3.internal.crt.S3CrtResponseHandlerAdapter.handleError(S3CrtResponseHandlerAdapter.java:179)
      	at software.amazon.awssdk.services.s3.internal.crt.S3CrtResponseHandlerAdapter.onFinished(S3CrtResponseHandlerAdapter.java:148)
      	at software.amazon.awssdk.crt.s3.S3MetaRequestResponseHandlerNativeAdapter.onFinished(S3MetaRequestResponseHandlerNativeAdapter.java:25)
      

      Atlassian Support understands this because ECS implements the S3 API differently, requiring special accommodations.

      Workaround

      Currently, there is no known workaround for this behavior. A workaround will be added here when available.

            Assignee:
            Unassigned
            Reporter:
            Benjamin S
            Votes:
            6 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: