Search in sources :

Example 1 with GetBlobOptions

use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.

the class RestUtilsTest method doBuildGetBlobOptionsTestForSubResource.

/**
 * Test that {@link RestUtils#buildGetBlobOptions(Map, RestUtils.SubResource, GetOption, int)} works correctly with given args and a
 * specified sub-resource.
 * @param args the map of args for the method call.
 * @param subResource the sub-resource for the call.
 * @param expectedRange the {@link ByteRange} expected to be parsed if the call should succeed, or {@code null} if no
 *                      range is expected.
 * @param expectedOpType the {@link OperationType} expected to be set in the {@link GetBlobOptions}
 *                       object.
 * @param expectedResolveRangeOnEmptyBlob the expected value of {@link GetBlobOptions#resolveRangeOnEmptyBlob}.
 * @param shouldSucceed {@code true} if the call should succeed.
 * @throws RestServiceException
 */
private void doBuildGetBlobOptionsTestForSubResource(Map<String, Object> args, RestUtils.SubResource subResource, ByteRange expectedRange, OperationType expectedOpType, boolean expectedResolveRangeOnEmptyBlob, boolean shouldSucceed) throws RestServiceException {
    if (shouldSucceed) {
        GetBlobOptions options = RestUtils.buildGetBlobOptions(args, subResource, GetOption.None, null, NO_BLOB_SEGMENT_IDX_SPECIFIED);
        assertEquals("Unexpected range for args=" + args + " and subResource=" + subResource, expectedRange, options.getRange());
        assertEquals("Unexpected operation type for args=" + args + " and subResource=" + subResource, expectedOpType, options.getOperationType());
        assertEquals("Unexpected get options type for args=" + args + " and subResource=" + subResource, GetOption.None, options.getGetOption());
        assertEquals("Unexpected resolveRangeOnEmptyBlob for args=" + args + " and subResource=" + subResource, expectedResolveRangeOnEmptyBlob, options.resolveRangeOnEmptyBlob());
    } else {
        try {
            RestUtils.buildGetBlobOptions(args, subResource, GetOption.None, null, NO_BLOB_SEGMENT_IDX_SPECIFIED);
            fail("buildGetBlobOptions should not have succeeded with args=" + args + "and subResource=" + subResource);
        } catch (RestServiceException expected) {
            assertEquals("Unexpected error code.", RestServiceErrorCode.InvalidArgs, expected.getErrorCode());
        }
    }
}
Also used : GetBlobOptions(com.github.ambry.router.GetBlobOptions)

Example 2 with GetBlobOptions

use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.

the class RestUtilsTest method doBuildGetBlobOptionsTestForSubResource.

/**
 * Test that {@link RestUtils#buildGetBlobOptions(Map, RestUtils.SubResource, GetOption)} works correctly with given args and a
 * specified sub-resource.
 * @param args the map of args for the method call.
 * @param subResource the sub-resource for the call.
 * @param expectedRange the {@link ByteRange} expected to be parsed if the call should succeed, or {@code null} if no
 *                      range is expected.
 * @param expectedOpType the {@link GetBlobOptions.OperationType} expected to be set in the {@link GetBlobOptions}
 *                       object.
 * @param shouldSucceed {@code true} if the call should succeed.
 * @throws RestServiceException
 */
private void doBuildGetBlobOptionsTestForSubResource(Map<String, Object> args, RestUtils.SubResource subResource, ByteRange expectedRange, GetBlobOptions.OperationType expectedOpType, boolean shouldSucceed) throws RestServiceException {
    if (shouldSucceed) {
        GetBlobOptions options = RestUtils.buildGetBlobOptions(args, subResource, GetOption.None);
        assertEquals("Unexpected range for args=" + args + " and subResource=" + subResource, expectedRange, options.getRange());
        assertEquals("Unexpected operation type for args=" + args + " and subResource=" + subResource, expectedOpType, options.getOperationType());
        assertEquals("Unexpected get options type for args=" + args + " and subResource=" + subResource, GetOption.None, options.getGetOption());
    } else {
        try {
            RestUtils.buildGetBlobOptions(args, subResource, GetOption.None);
            fail("buildGetBlobOptions should not have succeeded with args=" + args + "and subResource=" + subResource);
        } catch (RestServiceException expected) {
            assertEquals("Unexpected error code.", RestServiceErrorCode.InvalidArgs, expected.getErrorCode());
        }
    }
}
Also used : GetBlobOptions(com.github.ambry.router.GetBlobOptions)

Example 3 with GetBlobOptions

use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.

the class FrontendRestRequestService method handleGet.

@Override
public void handleGet(final RestRequest restRequest, final RestResponseChannel restResponseChannel) {
    ThrowingConsumer<RequestPath> routingAction = requestPath -> {
        if (requestPath.matchesOperation(Operations.GET_PEERS)) {
            getPeersHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
        } else if (requestPath.matchesOperation(Operations.GET_CLUSTER_MAP_SNAPSHOT)) {
            getClusterMapSnapshotHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
        } else if (requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
            getSignedUrlHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
        } else if (requestPath.matchesOperation(Operations.ACCOUNTS)) {
            getAccountsHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
        } else if (requestPath.matchesOperation(Operations.STATS_REPORT)) {
            getStatsReportHandler.handle(restRequest, restResponseChannel, (result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception));
        } else if (requestPath.matchesOperation(Operations.NAMED_BLOB) && NamedBlobPath.parse(requestPath, restRequest.getArgs()).getBlobName() == null) {
            listNamedBlobsHandler.handle(restRequest, restResponseChannel, ((result, exception) -> submitResponse(restRequest, restResponseChannel, result, exception)));
        } else {
            SubResource subResource = requestPath.getSubResource();
            GetBlobOptions options = buildGetBlobOptions(restRequest.getArgs(), subResource, getGetOption(restRequest, frontendConfig.defaultRouterGetOption), restRequest, requestPath.getBlobSegmentIdx());
            GetCallback routerCallback = new GetCallback(restRequest, restResponseChannel, subResource, options);
            SecurityProcessRequestCallback securityCallback = new SecurityProcessRequestCallback(restRequest, restResponseChannel, routerCallback);
            if (subResource == SubResource.Replicas) {
                securityCallback = new SecurityProcessRequestCallback(restRequest, restResponseChannel);
            }
            RestRequestMetricsGroup metricsGroup = getMetricsGroupForGet(frontendMetrics, subResource);
            RestRequestMetrics restRequestMetrics = metricsGroup.getRestRequestMetrics(restRequest.isSslUsed(), false);
            restRequest.getMetricsTracker().injectMetrics(restRequestMetrics);
            // named blob requests have their account/container in the URI, so checks can be done prior to ID conversion.
            if (requestPath.matchesOperation(Operations.NAMED_BLOB)) {
                accountAndContainerInjector.injectAccountAndContainerForNamedBlob(restRequest, metricsGroup);
            }
            securityService.processRequest(restRequest, securityCallback);
        }
    };
    preProcessAndRouteRequest(restRequest, restResponseChannel, frontendMetrics.getPreProcessingMetrics, routingAction);
}
Also used : RequestPath(com.github.ambry.rest.RequestPath) Histogram(com.codahale.metrics.Histogram) GetOption(com.github.ambry.protocol.GetOption) FrontendConfig(com.github.ambry.config.FrontendConfig) ResponseStatus(com.github.ambry.rest.ResponseStatus) LoggerFactory(org.slf4j.LoggerFactory) ByteBufferReadableStreamChannel(com.github.ambry.commons.ByteBufferReadableStreamChannel) AccountService(com.github.ambry.account.AccountService) QuotaManager(com.github.ambry.quota.QuotaManager) ByteBuffer(java.nio.ByteBuffer) ThrowingConsumer(com.github.ambry.utils.ThrowingConsumer) RequestPath(com.github.ambry.rest.RequestPath) NamedBlobDb(com.github.ambry.named.NamedBlobDb) RestRequestService(com.github.ambry.rest.RestRequestService) RestRequestMetrics(com.github.ambry.rest.RestRequestMetrics) SystemTime(com.github.ambry.utils.SystemTime) Router(com.github.ambry.router.Router) RouterErrorCode(com.github.ambry.router.RouterErrorCode) RestResponseHandler(com.github.ambry.rest.RestResponseHandler) ReadableStreamChannel(com.github.ambry.router.ReadableStreamChannel) Logger(org.slf4j.Logger) GregorianCalendar(java.util.GregorianCalendar) RestMethod(com.github.ambry.rest.RestMethod) RestResponseChannel(com.github.ambry.rest.RestResponseChannel) RestServiceErrorCode(com.github.ambry.rest.RestServiceErrorCode) InternalKeys(com.github.ambry.rest.RestUtils.InternalKeys) ClusterMap(com.github.ambry.clustermap.ClusterMap) Utils(com.github.ambry.utils.Utils) IOException(java.io.IOException) GetBlobOptions(com.github.ambry.router.GetBlobOptions) RouterException(com.github.ambry.router.RouterException) BlobInfo(com.github.ambry.messageformat.BlobInfo) QuotaUtils(com.github.ambry.quota.QuotaUtils) AccountStatsStore(com.github.ambry.accountstats.AccountStatsStore) RestServiceException(com.github.ambry.rest.RestServiceException) GetBlobResult(com.github.ambry.router.GetBlobResult) Callback(com.github.ambry.commons.Callback) RestUtils(com.github.ambry.rest.RestUtils) AsyncOperationTracker(com.github.ambry.utils.AsyncOperationTracker) RestRequest(com.github.ambry.rest.RestRequest) GetBlobOptionsBuilder(com.github.ambry.router.GetBlobOptionsBuilder) BlobId(com.github.ambry.commons.BlobId) RestRequestMetrics(com.github.ambry.rest.RestRequestMetrics) GetBlobOptions(com.github.ambry.router.GetBlobOptions)

Example 4 with GetBlobOptions

use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.

the class AmbrySecurityService method processResponse.

@Override
public void processResponse(RestRequest restRequest, RestResponseChannel responseChannel, BlobInfo blobInfo, Callback<Void> callback) {
    Exception exception = null;
    frontendMetrics.securityServiceProcessResponseRate.mark();
    long startTimeMs = System.currentTimeMillis();
    if (!isOpen) {
        exception = new RestServiceException("SecurityService is closed", RestServiceErrorCode.ServiceUnavailable);
    } else {
        if (restRequest == null || responseChannel == null) {
            throw new IllegalArgumentException("One of the required params is null");
        }
        RequestPath requestPath = RestUtils.getRequestPath(restRequest);
        RestMethod restMethod = restRequest.getRestMethod();
        if (blobInfo == null && !restMethod.equals(RestMethod.OPTIONS) && !restMethod.equals(RestMethod.PUT)) {
            if (!requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
                throw new IllegalArgumentException("BlobInfo is null");
            }
        }
        try {
            GetBlobOptions options;
            responseChannel.setHeader(RestUtils.Headers.DATE, new GregorianCalendar().getTime());
            switch(restMethod) {
                case HEAD:
                    options = RestUtils.buildGetBlobOptions(restRequest.getArgs(), null, GetOption.None, restRequest, NO_BLOB_SEGMENT_IDX_SPECIFIED);
                    responseChannel.setStatus(options.getRange() == null ? ResponseStatus.Ok : ResponseStatus.PartialContent);
                    responseChannel.setHeader(RestUtils.Headers.LAST_MODIFIED, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
                    setHeadResponseHeaders(blobInfo, options, restRequest, responseChannel);
                    break;
                case GET:
                    if (!requestPath.matchesOperation(Operations.GET_SIGNED_URL)) {
                        options = RestUtils.buildGetBlobOptions(restRequest.getArgs(), null, GetOption.None, restRequest, NO_BLOB_SEGMENT_IDX_SPECIFIED);
                        responseChannel.setStatus(ResponseStatus.Ok);
                        RestUtils.SubResource subResource = RestUtils.getRequestPath(restRequest).getSubResource();
                        responseChannel.setHeader(RestUtils.Headers.LAST_MODIFIED, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
                        if (subResource == null) {
                            Long ifModifiedSinceMs = getIfModifiedSinceMs(restRequest);
                            if (ifModifiedSinceMs != null && RestUtils.toSecondsPrecisionInMs(blobInfo.getBlobProperties().getCreationTimeInMs()) <= ifModifiedSinceMs) {
                                responseChannel.setStatus(ResponseStatus.NotModified);
                            } else {
                                if (options.getRange() != null) {
                                    responseChannel.setStatus(ResponseStatus.PartialContent);
                                }
                                setGetBlobResponseHeaders(blobInfo, options, responseChannel);
                                setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
                                setAccountAndContainerHeaders(restRequest, responseChannel);
                                setUserMetadataHeaders(blobInfo.getUserMetadata(), responseChannel);
                                responseChannel.setHeader(RestUtils.Headers.LIFE_VERSION, blobInfo.getLifeVersion());
                            }
                            setCacheHeaders(restRequest, responseChannel);
                        } else {
                            if (subResource.equals(RestUtils.SubResource.BlobInfo)) {
                                setBlobInfoHeaders(blobInfo.getBlobProperties(), responseChannel);
                                setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
                                setAccountAndContainerHeaders(restRequest, responseChannel);
                                responseChannel.setHeader(RestUtils.Headers.LIFE_VERSION, blobInfo.getLifeVersion());
                            } else if (subResource.equals(SubResource.Segment)) {
                                setGetBlobResponseHeaders(blobInfo, options, responseChannel);
                                setBlobPropertiesHeaders(blobInfo.getBlobProperties(), responseChannel);
                                setAccountAndContainerHeaders(restRequest, responseChannel);
                            }
                            if (!setUserMetadataHeaders(blobInfo.getUserMetadata(), responseChannel)) {
                                restRequest.setArg(InternalKeys.SEND_USER_METADATA_AS_RESPONSE_BODY, true);
                            }
                        }
                    }
                    break;
                case POST:
                    responseChannel.setStatus(ResponseStatus.Created);
                    responseChannel.setHeader(RestUtils.Headers.CONTENT_LENGTH, 0);
                    responseChannel.setHeader(RestUtils.Headers.CREATION_TIME, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
                    break;
                case OPTIONS:
                case PUT:
                    if (requestPath.matchesOperation(Operations.NAMED_BLOB)) {
                        responseChannel.setStatus(ResponseStatus.Created);
                        responseChannel.setHeader(RestUtils.Headers.CONTENT_LENGTH, 0);
                        responseChannel.setHeader(RestUtils.Headers.CREATION_TIME, new Date(blobInfo.getBlobProperties().getCreationTimeInMs()));
                    }
                    break;
                default:
                    exception = new RestServiceException("Cannot process response for request with method " + restMethod, RestServiceErrorCode.InternalServerError);
            }
        } catch (RestServiceException e) {
            exception = e;
        }
    }
    processRequestCharges(restRequest, responseChannel, blobInfo);
    frontendMetrics.securityServiceProcessResponseTimeInMs.update(System.currentTimeMillis() - startTimeMs);
    callback.onCompletion(null, exception);
}
Also used : RestServiceException(com.github.ambry.rest.RestServiceException) RequestPath(com.github.ambry.rest.RequestPath) GetBlobOptions(com.github.ambry.router.GetBlobOptions) GregorianCalendar(java.util.GregorianCalendar) RestUtils(com.github.ambry.rest.RestUtils) QuotaException(com.github.ambry.quota.QuotaException) RestServiceException(com.github.ambry.rest.RestServiceException) Date(java.util.Date) RestMethod(com.github.ambry.rest.RestMethod)

Example 5 with GetBlobOptions

use of com.github.ambry.router.GetBlobOptions in project ambry by linkedin.

the class GetManagerTest method testBadCallback.

/**
 * Test that a bad user defined callback will not crash the router.
 * @param getBlobCallback User defined callback to be called after getBlob operation.
 * @param getBlobCallbackCalled This latch should be at 0 after {@code getBlobCallback} has been called.
 * @param checkBadCallbackBlob {@code true} if the blob contents provided by the getBlob operation with the bad
 *                             callback should be inspected for correctness.
 * @throws Exception
 */
private void testBadCallback(Callback<GetBlobResult> getBlobCallback, CountDownLatch getBlobCallbackCalled, Boolean checkBadCallbackBlob) throws Exception {
    router = getNonBlockingRouter();
    setOperationParams(LARGE_BLOB_SIZE, new GetBlobOptionsBuilder().build());
    final CountDownLatch getBlobInfoCallbackCalled = new CountDownLatch(1);
    String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
    List<Future<GetBlobResult>> getBlobInfoFutures = new ArrayList<>();
    List<Future<GetBlobResult>> getBlobDataFutures = new ArrayList<>();
    GetBlobOptions infoOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.BlobInfo).build();
    GetBlobOptions dataOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.Data).build();
    for (int i = 0; i < 5; i++) {
        if (i == 1) {
            getBlobInfoFutures.add(router.getBlob(blobId, infoOptions, new Callback<GetBlobResult>() {

                @Override
                public void onCompletion(GetBlobResult result, Exception exception) {
                    getBlobInfoCallbackCalled.countDown();
                    throw new RuntimeException("Throwing an exception in the user callback");
                }
            }, quotaChargeCallback));
            getBlobDataFutures.add(router.getBlob(blobId, dataOptions, getBlobCallback, quotaChargeCallback));
        } else {
            getBlobInfoFutures.add(router.getBlob(blobId, infoOptions));
            getBlobDataFutures.add(router.getBlob(blobId, dataOptions));
        }
    }
    options = dataOptions;
    for (int i = 0; i < getBlobDataFutures.size(); i++) {
        if (i != 1 || checkBadCallbackBlob) {
            compareContent(getBlobDataFutures.get(i).get().getBlobDataChannel());
        }
    }
    options = infoOptions;
    for (Future<GetBlobResult> future : getBlobInfoFutures) {
        compareBlobInfo(future.get().getBlobInfo(), -1);
    }
    Assert.assertTrue("getBlobInfo callback not called.", getBlobInfoCallbackCalled.await(2, TimeUnit.SECONDS));
    Assert.assertTrue("getBlob callback not called.", getBlobCallbackCalled.await(2, TimeUnit.SECONDS));
    Assert.assertEquals("All operations should be finished.", 0, router.getOperationsCount());
    Assert.assertTrue("Router should not be closed", router.isOpen());
    // Test that GetManager is still operational
    setOperationParams(CHUNK_SIZE, new GetBlobOptionsBuilder().build());
    blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
    getBlobAndCompareContent(blobId, -1);
    this.options = infoOptions;
    getBlobAndCompareContent(blobId, -1);
    router.close();
}
Also used : ArrayList(java.util.ArrayList) GetBlobOptions(com.github.ambry.router.GetBlobOptions) CountDownLatch(java.util.concurrent.CountDownLatch) GeneralSecurityException(java.security.GeneralSecurityException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) QuotaChargeCallback(com.github.ambry.quota.QuotaChargeCallback) Callback(com.github.ambry.commons.Callback) Future(java.util.concurrent.Future)

Aggregations

GetBlobOptions (com.github.ambry.router.GetBlobOptions)5 Callback (com.github.ambry.commons.Callback)2 RequestPath (com.github.ambry.rest.RequestPath)2 RestMethod (com.github.ambry.rest.RestMethod)2 RestServiceException (com.github.ambry.rest.RestServiceException)2 RestUtils (com.github.ambry.rest.RestUtils)2 IOException (java.io.IOException)2 GregorianCalendar (java.util.GregorianCalendar)2 Histogram (com.codahale.metrics.Histogram)1 AccountService (com.github.ambry.account.AccountService)1 AccountStatsStore (com.github.ambry.accountstats.AccountStatsStore)1 ClusterMap (com.github.ambry.clustermap.ClusterMap)1 BlobId (com.github.ambry.commons.BlobId)1 ByteBufferReadableStreamChannel (com.github.ambry.commons.ByteBufferReadableStreamChannel)1 FrontendConfig (com.github.ambry.config.FrontendConfig)1 BlobInfo (com.github.ambry.messageformat.BlobInfo)1 NamedBlobDb (com.github.ambry.named.NamedBlobDb)1 GetOption (com.github.ambry.protocol.GetOption)1 QuotaChargeCallback (com.github.ambry.quota.QuotaChargeCallback)1 QuotaException (com.github.ambry.quota.QuotaException)1