use of com.github.ambry.utils.Pair in project ambry by linkedin.
the class AmbrySecurityServiceTest method testGetSubResource.
/**
* Tests GET of sub-resources.
* @param subResource the {@link RestUtils.SubResource} to test.
* @throws Exception
*/
private void testGetSubResource(BlobInfo blobInfo, RestUtils.SubResource subResource) throws Exception {
MockRestResponseChannel restResponseChannel = new MockRestResponseChannel();
RestRequest restRequest = createRestRequest(RestMethod.GET, "/sampleId/" + subResource, null);
Pair<Account, Container> accountAndContainer = getAccountAndContainer(blobInfo.getBlobProperties());
insertAccountAndContainer(restRequest, accountAndContainer.getFirst(), accountAndContainer.getSecond());
securityService.processResponse(restRequest, restResponseChannel, blobInfo).get();
Assert.assertEquals("ProcessResponse status should have been set ", ResponseStatus.Ok, restResponseChannel.getStatus());
Assert.assertNotNull("Date has not been set", restResponseChannel.getHeader(RestUtils.Headers.DATE));
Assert.assertEquals("Last Modified does not match creation time", RestUtils.toSecondsPrecisionInMs(blobInfo.getBlobProperties().getCreationTimeInMs()), RestUtils.getTimeFromDateString(restResponseChannel.getHeader(RestUtils.Headers.LAST_MODIFIED)).longValue());
if (subResource.equals(RestUtils.SubResource.BlobInfo)) {
verifyBlobPropertiesHeaders(blobInfo.getBlobProperties(), restResponseChannel);
verifyAccountAndContainerHeaders(restResponseChannel, accountAndContainer.getFirst(), accountAndContainer.getSecond());
Assert.assertEquals("LifeVersion mismatch", Short.toString(blobInfo.getLifeVersion()), restResponseChannel.getHeader(RestUtils.Headers.LIFE_VERSION));
} else {
verifyAbsenceOfHeaders(restResponseChannel, RestUtils.Headers.PRIVATE, RestUtils.Headers.TTL, RestUtils.Headers.SERVICE_ID, RestUtils.Headers.OWNER_ID, RestUtils.Headers.AMBRY_CONTENT_TYPE, RestUtils.Headers.CREATION_TIME, RestUtils.Headers.BLOB_SIZE, RestUtils.Headers.ACCEPT_RANGES, RestUtils.Headers.CONTENT_RANGE, RestUtils.Headers.LIFE_VERSION);
}
Map<String, String> userMetadata = blobInfo.getUserMetadata() != null ? RestUtils.buildUserMetadata(blobInfo.getUserMetadata()) : null;
if (userMetadata == null && !(blobInfo.getUserMetadata().length == 0)) {
Assert.assertTrue("Internal key " + RestUtils.InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY + " should be set", (Boolean) restRequest.getArgs().get(RestUtils.InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY));
} else if (!(blobInfo.getUserMetadata().length == 0)) {
USER_METADATA.forEach((key, value) -> Assert.assertEquals("Value of " + key + " not as expected", value, restResponseChannel.getHeader(key)));
}
}
use of com.github.ambry.utils.Pair in project ambry by linkedin.
the class AmbrySecurityServiceTest method getAccountAndContainer.
/**
* @param blobProperties the {@link BlobProperties} to read.
* @return the {@link Account} and {@link Container} objects corresponding to the IDs in the {@link BlobProperties}.
*/
private Pair<Account, Container> getAccountAndContainer(BlobProperties blobProperties) {
Account account = ACCOUNT_SERVICE.getAccountById(blobProperties.getAccountId());
Container container = account.getContainerById(blobProperties.getContainerId());
return new Pair<>(account, container);
}
use of com.github.ambry.utils.Pair in project ambry by linkedin.
the class FrontendIntegrationTest method uploadDataChunksAndVerify.
/**
* Upload data chunks using chunk upload signed URL.
* @param account the {@link Account} to upload into.
* @param container the {@link Container} to upload into.
* @param chunkSizes The sizes for each data chunk to upload.
* @return the list of signed chunk IDs for the uploaded chunks and an array containing the concatenated content of
* the data chunks.
* @throws Exception
*/
private Pair<List<String>, byte[]> uploadDataChunksAndVerify(Account account, Container container, int... chunkSizes) throws Exception {
IdSigningService idSigningService = new AmbryIdSigningService();
HttpHeaders chunkUploadHeaders = new DefaultHttpHeaders();
chunkUploadHeaders.add(RestUtils.Headers.URL_TYPE, RestMethod.POST.name());
chunkUploadHeaders.add(RestUtils.Headers.CHUNK_UPLOAD, "true");
setAmbryHeadersForPut(chunkUploadHeaders, TTL_SECS, !container.isCacheable(), "chunkUploader", "application/octet-stream", "stitchedUploadTest", account.getName(), container.getName());
// POST
// Get signed URL
FullHttpRequest httpRequest = buildRequest(HttpMethod.GET, Operations.GET_SIGNED_URL, chunkUploadHeaders, null);
ResponseParts responseParts = nettyClient.sendRequest(httpRequest, null, null).get();
HttpResponse response = getHttpResponse(responseParts);
assertEquals("Unexpected response status", HttpResponseStatus.OK, response.status());
verifyTrackingHeaders(response);
String signedPostUrl = response.headers().get(RestUtils.Headers.SIGNED_URL);
assertNotNull("Did not get a signed POST URL", signedPostUrl);
assertNoContent(responseParts.queue, 1);
List<String> signedChunkIds = new ArrayList<>();
ByteArrayOutputStream fullContentStream = new ByteArrayOutputStream();
URI uri = new URI(signedPostUrl);
for (int chunkSize : chunkSizes) {
byte[] contentArray = TestUtils.getRandomBytes(chunkSize);
ByteBuffer content = ByteBuffer.wrap(contentArray);
// Use signed URL to POST
httpRequest = buildRequest(HttpMethod.POST, uri.getPath() + "?" + uri.getQuery(), null, content);
responseParts = nettyClient.sendRequest(httpRequest, null, null).get();
String signedId = verifyPostAndReturnBlobId(responseParts, chunkSize, false);
assertTrue("Blob ID for chunk upload must be signed", idSigningService.isIdSigned(signedId.substring(1)));
Pair<String, Map<String, String>> idAndMetadata = idSigningService.parseSignedId(signedId.substring(1));
// Inspect metadata fields
String chunkUploadSession = idAndMetadata.getSecond().get(RestUtils.Headers.SESSION);
assertNotNull("x-ambry-chunk-upload-session should be present in signed ID", chunkUploadSession);
String blobSize = idAndMetadata.getSecond().get(RestUtils.Headers.BLOB_SIZE);
assertNotNull("x-ambry-blob-size should be present in signed ID", blobSize);
assertEquals("wrong size value in signed id", content.capacity(), Long.parseLong(blobSize));
HttpHeaders expectedGetHeaders = new DefaultHttpHeaders().add(chunkUploadHeaders);
// Use signed ID and blob ID for GET request
expectedGetHeaders.add(RestUtils.Headers.BLOB_SIZE, content.capacity());
// Blob TTL for chunk upload is fixed
expectedGetHeaders.set(RestUtils.Headers.TTL, FRONTEND_CONFIG.chunkUploadInitialChunkTtlSecs);
expectedGetHeaders.set(RestUtils.Headers.LIFE_VERSION, "0");
for (String id : new String[] { signedId, idAndMetadata.getFirst() }) {
getBlobAndVerify(id, null, GetOption.None, false, expectedGetHeaders, !container.isCacheable(), content, account.getName(), container.getName());
getBlobInfoAndVerify(id, GetOption.None, expectedGetHeaders, !container.isCacheable(), account.getName(), container.getName(), null);
}
signedChunkIds.add(addClusterPrefix ? "/" + CLUSTER_NAME + signedId : signedId);
fullContentStream.write(contentArray);
}
return new Pair<>(signedChunkIds, fullContentStream.toByteArray());
}
use of com.github.ambry.utils.Pair in project ambry by linkedin.
the class SignedIdSerDe method fromJson.
/**
* @param jsonString the JSON string to deserialize.
* @return a {@link Pair} that contains the blob ID and additional metadata parsed from the JSON string.
* @throws JSONException
*/
public static Pair<String, Map<String, String>> fromJson(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
String blobId = jsonObject.getString(BLOB_ID_FIELD);
JSONObject metadataJson = jsonObject.optJSONObject(METADATA_FIELD);
Map<String, String> metadata = new HashMap<>();
if (metadataJson != null) {
for (String key : metadataJson.keySet()) {
metadata.put(key, metadataJson.getString(key));
}
}
return new Pair<>(blobId, metadata);
}
use of com.github.ambry.utils.Pair in project ambry by linkedin.
the class StorageQuotaEnforcer method getQuotaAndUsage.
/**
* Return quota and current usage for the account/container carried in the given {@code restRequest}.
* If there is no account and container found in the {@code restRequest}, this method would return -1
* for quota. If there is no quota found for the account/container, this method would return -1 for
* quota as well.
* @param restRequest the {@link RestRequest} that carries account and container in the header.
* @return A {@link Pair} whose first element is quota the second element is current storage usage.
*/
Pair<Long, Long> getQuotaAndUsage(RestRequest restRequest) {
long quotaValue = -1L;
long currentUsage = 0L;
try {
Account account = RestUtils.getAccountFromArgs(restRequest.getArgs());
Container container = RestUtils.getContainerFromArgs(restRequest.getArgs());
QuotaResource quotaResource = account.getQuotaResourceType() == QuotaResourceType.ACCOUNT ? QuotaResource.fromAccount(account) : QuotaResource.fromContainer(container);
quotaValue = getQuotaValueForResource(quotaResource);
if (quotaValue != -1L) {
currentUsage = storageUsages.getOrDefault(quotaResource, 0L);
}
} catch (Exception e) {
logger.error("Failed to getQuotaAndUsage for RestRequest {}", restRequest, e);
}
return new Pair<>(quotaValue, currentUsage);
}
Aggregations