Skip to content

Commit 5663728

Browse files
authored
Implement CAS support in Azure test fixture (#117104)
Closes ES-5680
1 parent e54c7cf commit 5663728

File tree

14 files changed

+800
-117
lines changed

14 files changed

+800
-117
lines changed

modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.repositories.azure;
1010

1111
import fixture.azure.AzureHttpHandler;
12+
import fixture.azure.MockAzureBlobStore;
1213

1314
import com.azure.storage.common.policy.RequestRetryOptions;
1415
import com.azure.storage.common.policy.RetryPolicyType;
@@ -184,7 +185,12 @@ long getUploadBlockSize() {
184185
@SuppressForbidden(reason = "this test uses a HttpHandler to emulate an Azure endpoint")
185186
private static class AzureBlobStoreHttpHandler extends AzureHttpHandler implements BlobStoreHttpHandler {
186187
AzureBlobStoreHttpHandler(final String account, final String container) {
187-
super(account, container, null /* no auth header validation - sometimes it's omitted in these tests (TODO why?) */);
188+
super(
189+
account,
190+
container,
191+
null /* no auth header validation - sometimes it's omitted in these tests (TODO why?) */,
192+
MockAzureBlobStore.LeaseExpiryPredicate.NEVER_EXPIRE
193+
);
188194
}
189195
}
190196

modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureStorageCleanupThirdPartyTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.repositories.azure;
1111

1212
import fixture.azure.AzureHttpFixture;
13+
import fixture.azure.MockAzureBlobStore;
1314

1415
import com.azure.core.exception.HttpResponseException;
1516
import com.azure.storage.blob.BlobContainerClient;
@@ -60,7 +61,8 @@ public class AzureStorageCleanupThirdPartyTests extends AbstractThirdPartyReposi
6061
System.getProperty("test.azure.container"),
6162
System.getProperty("test.azure.tenant_id"),
6263
System.getProperty("test.azure.client_id"),
63-
AzureHttpFixture.sharedKeyForAccountPredicate(AZURE_ACCOUNT)
64+
AzureHttpFixture.sharedKeyForAccountPredicate(AZURE_ACCOUNT),
65+
MockAzureBlobStore.LeaseExpiryPredicate.NEVER_EXPIRE
6466
);
6567

6668
@Override

modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureBlobContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ protected String buildKey(String blobName) {
180180
}
181181

182182
private boolean skipRegisterOperation(ActionListener<?> listener) {
183-
return skipCas(listener) || skipIfNotPrimaryOnlyLocationMode(listener);
183+
return skipIfNotPrimaryOnlyLocationMode(listener);
184184
}
185185

186186
private boolean skipIfNotPrimaryOnlyLocationMode(ActionListener<?> listener) {

modules/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureBlobStore.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.azure.storage.blob.models.ListBlobsOptions;
4141
import com.azure.storage.blob.options.BlobParallelUploadOptions;
4242
import com.azure.storage.blob.options.BlockBlobSimpleUploadOptions;
43+
import com.azure.storage.blob.specialized.BlobLeaseClient;
4344
import com.azure.storage.blob.specialized.BlobLeaseClientBuilder;
4445
import com.azure.storage.blob.specialized.BlockBlobAsyncClient;
4546

@@ -1010,7 +1011,7 @@ private static BytesReference innerCompareAndExchangeRegister(
10101011
}
10111012
return currentValue;
10121013
} finally {
1013-
leaseClient.releaseLease();
1014+
bestEffortRelease(leaseClient);
10141015
}
10151016
} else {
10161017
if (expected.length() == 0) {
@@ -1020,6 +1021,29 @@ private static BytesReference innerCompareAndExchangeRegister(
10201021
}
10211022
}
10221023

1024+
/**
1025+
* Release the lease, ignoring conflicts due to expiry
1026+
*
1027+
* @see <a href="https://learn.microsoft.com/en-us/rest/api/storageservices/lease-blob?outcomes-of-lease-operations-on-blobs-by-lease-state">Outcomes of lease operations by lease state</a>
1028+
* @param leaseClient The client for the lease
1029+
*/
1030+
private static void bestEffortRelease(BlobLeaseClient leaseClient) {
1031+
try {
1032+
leaseClient.releaseLease();
1033+
} catch (BlobStorageException blobStorageException) {
1034+
if (blobStorageException.getStatusCode() == RestStatus.CONFLICT.getStatus()) {
1035+
// This is OK, we tried to release a lease that was expired/re-acquired
1036+
logger.debug(
1037+
"Ignored conflict on release: errorCode={}, message={}",
1038+
blobStorageException.getErrorCode(),
1039+
blobStorageException.getMessage()
1040+
);
1041+
} else {
1042+
throw blobStorageException;
1043+
}
1044+
}
1045+
}
1046+
10231047
private static BytesReference downloadRegisterBlob(
10241048
String containerPath,
10251049
String blobKey,

modules/repository-azure/src/test/java/org/elasticsearch/repositories/azure/AzureBlobContainerStatsTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.repositories.azure;
1111

1212
import fixture.azure.AzureHttpHandler;
13+
import fixture.azure.MockAzureBlobStore;
1314

1415
import org.elasticsearch.common.blobstore.OperationPurpose;
1516
import org.elasticsearch.common.bytes.BytesReference;
@@ -26,7 +27,7 @@ public class AzureBlobContainerStatsTests extends AbstractAzureServerTestCase {
2627
@SuppressForbidden(reason = "use a http server")
2728
@Before
2829
public void configureAzureHandler() {
29-
httpServer.createContext("/", new AzureHttpHandler(ACCOUNT, CONTAINER, null));
30+
httpServer.createContext("/", new AzureHttpHandler(ACCOUNT, CONTAINER, null, MockAzureBlobStore.LeaseExpiryPredicate.NEVER_EXPIRE));
3031
}
3132

3233
public void testOperationPurposeIsReflectedInBlobStoreStats() throws IOException {

modules/repository-azure/src/yamlRestTest/java/org/elasticsearch/repositories/azure/RepositoryAzureClientYamlTestSuiteIT.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.repositories.azure;
1111

1212
import fixture.azure.AzureHttpFixture;
13+
import fixture.azure.MockAzureBlobStore;
1314

1415
import com.carrotsearch.randomizedtesting.annotations.Name;
1516
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
@@ -47,7 +48,8 @@ public class RepositoryAzureClientYamlTestSuiteIT extends ESClientYamlSuiteTestC
4748
AZURE_TEST_CONTAINER,
4849
AZURE_TEST_TENANT_ID,
4950
AZURE_TEST_CLIENT_ID,
50-
decideAuthHeaderPredicate()
51+
decideAuthHeaderPredicate(),
52+
MockAzureBlobStore.LeaseExpiryPredicate.NEVER_EXPIRE
5153
);
5254

5355
private static Predicate<String> decideAuthHeaderPredicate() {

modules/repository-azure/src/yamlRestTest/resources/rest-api-spec/test/repository_azure/20_repository.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ setup:
193193
container: zHHkfSqlbnBsbpSgvCYtxrEfFLqghXtyPvvvKPNBnRCicNHQLE
194194
client: integration_test
195195

196+
---
197+
"Register a read-only repository with a non existing container":
198+
199+
- do:
200+
catch: /repository_verification_exception/
201+
snapshot.create_repository:
202+
repository: repository
203+
body:
204+
type: azure
205+
settings:
206+
container: zHHkfSqlbnBsbpSgvCYtxrEfFLqghXtyPvvvKPNBnRCicNHQLE
207+
client: integration_test
208+
readonly: true
209+
196210
---
197211
"Register a repository with a non existing client":
198212

test/fixtures/azure-fixture/src/main/java/fixture/azure/AzureHttpFixture.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class AzureHttpFixture extends ExternalResource {
4545
private final String clientId;
4646
private final String tenantId;
4747
private final Predicate<String> authHeaderPredicate;
48+
private final MockAzureBlobStore.LeaseExpiryPredicate leaseExpiryPredicate;
4849

4950
private HttpServer server;
5051
private HttpServer metadataServer;
@@ -116,7 +117,8 @@ public AzureHttpFixture(
116117
String container,
117118
@Nullable String rawTenantId,
118119
@Nullable String rawClientId,
119-
Predicate<String> authHeaderPredicate
120+
Predicate<String> authHeaderPredicate,
121+
MockAzureBlobStore.LeaseExpiryPredicate leaseExpiryPredicate
120122
) {
121123
final var tenantId = Strings.hasText(rawTenantId) ? rawTenantId : null;
122124
final var clientId = Strings.hasText(rawClientId) ? rawClientId : null;
@@ -135,6 +137,7 @@ public AzureHttpFixture(
135137
this.tenantId = tenantId;
136138
this.clientId = clientId;
137139
this.authHeaderPredicate = authHeaderPredicate;
140+
this.leaseExpiryPredicate = leaseExpiryPredicate;
138141
}
139142

140143
private String scheme() {
@@ -193,7 +196,10 @@ protected void before() {
193196
}
194197
case HTTP -> {
195198
server = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
196-
server.createContext("/" + account, new AzureHttpHandler(account, container, actualAuthHeaderPredicate));
199+
server.createContext(
200+
"/" + account,
201+
new AzureHttpHandler(account, container, actualAuthHeaderPredicate, leaseExpiryPredicate)
202+
);
197203
server.start();
198204

199205
oauthTokenServiceServer = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
@@ -222,7 +228,10 @@ protected void before() {
222228
final var httpsServer = HttpsServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
223229
this.server = httpsServer;
224230
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
225-
httpsServer.createContext("/" + account, new AzureHttpHandler(account, container, actualAuthHeaderPredicate));
231+
httpsServer.createContext(
232+
"/" + account,
233+
new AzureHttpHandler(account, container, actualAuthHeaderPredicate, leaseExpiryPredicate)
234+
);
226235
httpsServer.start();
227236
}
228237
{

0 commit comments

Comments
 (0)