public override async Task<Response> ProcessRequest(Request request) { var fanoutRequest = request.HasInputBody ? await request.ReadInputBody<TieredRequest>() : null; if (request.HasInputBody && fanoutRequest == null) { // This indicates failed deserialization return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not read input body"); } // aggregation servers should fanout automagically. we honor filters for machine function and datacenter. if ((fanoutRequest == null || fanoutRequest.Sources == null || fanoutRequest.Sources.Count == 0) && this.server.EnableQueryAggregation) { if (fanoutRequest == null) { fanoutRequest = new TieredRequest(); } fanoutRequest.Sources = this.SelectSourceServers(request.QueryParameters).ToList(); } var queryParameters = new DimensionSpecification(request.QueryParameters); var endOfName = request.Path.LastIndexOf('/'); if (endOfName < 0) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "No command provided."); } var counterName = request.Path.Substring(0, endOfName); if (string.IsNullOrEmpty(counterName)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "No counter pattern provided."); } var commandName = request.Path.Substring(endOfName + 1); if (RestCommands.CounterInfoCommand.Equals(commandName, StringComparison.OrdinalIgnoreCase)) { return await this.Info(request, fanoutRequest, counterName, queryParameters); } if (RestCommands.CounterQueryCommand.Equals(commandName, StringComparison.OrdinalIgnoreCase)) { var response = await this.Query(counterName, fanoutRequest, queryParameters); return Response.Create(request, (HttpStatusCode)response.HttpResponseCode, response); } return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Unknown command: " + commandName); }
public override async Task<Response> ProcessRequest(Request request) { if (!request.HasInputBody) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "no input body provided."); } var registrationMessage = await request.ReadInputBody<ServerRegistration>(); if (registrationMessage != null) { var server = this.serverList.InsertOrUpdate(registrationMessage); server.ProcessRegistrationMessage(registrationMessage); return new Response(request, HttpStatusCode.OK, "Registered."); } return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid data."); }
public override async Task<Response> ProcessRequest(Request request) { if (!request.HasInputBody) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "No input body provided for write."); } if (string.IsNullOrEmpty(request.Path)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Counter name must be specified."); } var counter = this.server.DataManager.GetCounter<Counter>(request.Path); if (counter == null) { return request.CreateErrorResponse(HttpStatusCode.NotFound, "Unknown counter name provided."); } var input = await request.ReadInputBody<CounterWriteRequest>(); if (input == null) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not deserialize input."); } if (input.Writes.Count == 0) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "No write operations were provided."); } // We want to do two passes here because if any of the operations are invalid we want to reject the entire // transaction. if (input.Writes.Any(operation => operation.Count < 1)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Operation counts must be greater than zero."); } foreach (var operation in input.Writes) { RunOperation(counter, operation); } return new Response(request, HttpStatusCode.Accepted, "Accepted"); }
public override async Task<Response> ProcessRequest(Request request) { var counterName = request.Path; if (string.IsNullOrEmpty(counterName)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Path or command is invalid."); } if (request.QueryParameters.Count != 2 || !request.QueryParameters.ContainsKey(ReservedDimensions.StartTimeDimension) || !request.QueryParameters.ContainsKey(ReservedDimensions.EndTimeDimension)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid query parameters. Must specify only start and end time."); } DateTime start, end; if (!DateTime.TryParse(request.QueryParameters[ReservedDimensions.StartTimeDimension], out start)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid start time."); } if (!DateTime.TryParse(request.QueryParameters[ReservedDimensions.EndTimeDimension], out end)) { return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid end time."); } var message = new TransferRequest(); if (request.HasInputBody) { message = await request.ReadInputBody<TransferRequest>(); } var ms = request.GetStream(); // This is a tiered aggregation request, handle it separately. if (message.Sources != null && message.Sources.Count > 1) { try { using (var aggregator = PersistedDataProtocol.CreateAggregatorForSampleType(message.DataType, counterName, message.Sources, start, end, dataManager.MemoryStreamManager)) { if (message.Timeout > 0) { aggregator.Timeout = TimeSpan.FromSeconds(message.Timeout); } if (message.MaxFanout > 0) { aggregator.MaxFanout = (int)message.MaxFanout; } // This shouldn't happen, given that one of the servers we want to talk to is.. us. if (!await aggregator.Run()) { ms.Dispose(); return request.CreateErrorResponse(HttpStatusCode.InternalServerError, "All child requests failed."); } if (!aggregator.WriteToStream(ms)) { // TODO: If we have no results but none of our queries failed we can definitively 404, // for now lazy. ms.Dispose(); return request.CreateErrorResponse(HttpStatusCode.InternalServerError, "No cntent matched."); } } } catch (ArgumentException) { ms.Dispose(); return request.CreateErrorResponse(HttpStatusCode.BadRequest, "Request parameters are invalid."); } } else { var counter = this.dataManager.GetCounter<Counter>(counterName); if (counter == null || !counter.SerializeData(start, end, ms)) { ms.Dispose(); return request.CreateErrorResponse(HttpStatusCode.NotFound, "The requested data is not available."); } } // after writing the response the server will handle disposing the stream for us. return new Response(request, HttpStatusCode.OK, ms) {ContentType = ResponseType}; }