From 5b4d5865f5306b3aefc9351f53230c2866465e76 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Tue, 14 Feb 2017 12:30:09 -0800 Subject: [PATCH 01/17] Added quota contoll without the service control client library --- contrib/endpoints/src/api_manager/BUILD | 2 + .../src/api_manager/check_workflow.cc | 3 + .../api_manager/context/request_context.cc | 17 ++ .../src/api_manager/context/request_context.h | 3 + .../src/api_manager/proto/server_config.proto | 18 ++ .../src/api_manager/quota_control.cc | 72 ++++++++ .../endpoints/src/api_manager/quota_control.h | 33 ++++ .../api_manager/service_control/aggregated.cc | 153 +++++++++++++-- .../api_manager/service_control/aggregated.h | 14 +- .../src/api_manager/service_control/info.h | 14 +- .../api_manager/service_control/interface.h | 11 ++ .../src/api_manager/service_control/proto.cc | 174 ++++++++++++++++++ .../src/api_manager/service_control/proto.h | 9 + .../src/api_manager/service_control/url.cc | 2 + .../src/api_manager/service_control/url.h | 2 + 15 files changed, 508 insertions(+), 19 deletions(-) create mode 100644 contrib/endpoints/src/api_manager/quota_control.cc create mode 100644 contrib/endpoints/src/api_manager/quota_control.h diff --git a/contrib/endpoints/src/api_manager/BUILD b/contrib/endpoints/src/api_manager/BUILD index e3d54b46eac..76416aea90e 100644 --- a/contrib/endpoints/src/api_manager/BUILD +++ b/contrib/endpoints/src/api_manager/BUILD @@ -81,6 +81,8 @@ cc_library( "method_impl.cc", "path_matcher.cc", "path_matcher_node.cc", + "quota_control.cc", + "quota_control.h", "request_handler.cc", ], linkopts = select({ diff --git a/contrib/endpoints/src/api_manager/check_workflow.cc b/contrib/endpoints/src/api_manager/check_workflow.cc index 8335d779142..27b9fba60da 100644 --- a/contrib/endpoints/src/api_manager/check_workflow.cc +++ b/contrib/endpoints/src/api_manager/check_workflow.cc @@ -18,6 +18,7 @@ #include "contrib/endpoints/src/api_manager/check_auth.h" #include "contrib/endpoints/src/api_manager/check_service_control.h" #include "contrib/endpoints/src/api_manager/fetch_metadata.h" +#include "contrib/endpoints/src/api_manager/quota_control.h" using ::google::api_manager::utils::Status; @@ -33,6 +34,8 @@ void CheckWorkflow::RegisterAll() { Register(CheckAuth); // Checks service control. Register(CheckServiceControl); + // Quota control + Register(QuotaControl); } void CheckWorkflow::Register(CheckHandler handler) { diff --git a/contrib/endpoints/src/api_manager/context/request_context.cc b/contrib/endpoints/src/api_manager/context/request_context.cc index 59cc7c3d53f..0e31e24f2fd 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.cc +++ b/contrib/endpoints/src/api_manager/context/request_context.cc @@ -226,6 +226,23 @@ void RequestContext::FillCheckRequestInfo( info->allow_unregistered_calls = method()->allow_unregistered_calls(); } +void RequestContext::FillAllocateQuotaRequestInfo( + service_control::QuotaRequestInfo *info) { + FillOperationInfo(info); + + info->client_ip = request_->GetClientIP(); + info->method_name = this->method_call_.method_info->name(); + + info->labels["servicecontrol.googleapis.com/caller_ip"] = + request_->GetClientIP(); + info->labels["servicecontrol.googleapis.com/referer"] = this->http_referer_; + info->labels["servicecontrol.googleapis.com/user"] = "integration_test_user"; + + // TODO(jaebong) need to set quota rule and metric rule + info->quota_rule_ = nullptr; + info->metric_rule_ = nullptr; +} + void RequestContext::FillReportRequestInfo( Response *response, service_control::ReportRequestInfo *info) { FillOperationInfo(info); diff --git a/contrib/endpoints/src/api_manager/context/request_context.h b/contrib/endpoints/src/api_manager/context/request_context.h index 5b29c271aad..8832b38fc3e 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.h +++ b/contrib/endpoints/src/api_manager/context/request_context.h @@ -66,6 +66,9 @@ class RequestContext { // Fill CheckRequestInfo void FillCheckRequestInfo(service_control::CheckRequestInfo *info); + // FillAllocateQuotaRequestInfo + void FillAllocateQuotaRequestInfo(service_control::QuotaRequestInfo *info); + // Fill ReportRequestInfo void FillReportRequestInfo(Response *response, service_control::ReportRequestInfo *info); diff --git a/contrib/endpoints/src/api_manager/proto/server_config.proto b/contrib/endpoints/src/api_manager/proto/server_config.proto index 1fe04af6d07..7f18460c10b 100644 --- a/contrib/endpoints/src/api_manager/proto/server_config.proto +++ b/contrib/endpoints/src/api_manager/proto/server_config.proto @@ -66,6 +66,13 @@ message ServiceControlConfig { // The intermediate reports for streaming calls should not be more frequent // than this value (in seconds) int32 intermediate_report_min_interval = 7; + + // Quota aggregator config + QuotaAggregatorConfig quota_aggregator_config = 8; + + // Timeout in milliseconds on service control allocate quota requests. + // If the value is <= 0, default timeout is 5000 milliseconds. + int32 quota_timeout_ms = 9; } // Check aggregator config @@ -82,6 +89,17 @@ message CheckAggregatorConfig { int32 response_expiration_ms = 3; } +// Quota aggregator config +message QuotaAggregatorConfig { + // The maximum number of cache entries that can be kept in the aggregation + // cache. Cache is disabled when entries <= 0. + int32 cache_entries = 1; + + // The maximum milliseconds before aggregated quota requests are refreshed to + // the server. + int32 refresh_interval_ms = 2; +} + // Report aggregator config message ReportAggregatorConfig { // The maximum number of cache entries that can be kept in the aggregation diff --git a/contrib/endpoints/src/api_manager/quota_control.cc b/contrib/endpoints/src/api_manager/quota_control.cc new file mode 100644 index 00000000000..04e2f974aef --- /dev/null +++ b/contrib/endpoints/src/api_manager/quota_control.cc @@ -0,0 +1,72 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// +// +#include + +#include "contrib/endpoints/src/api_manager/cloud_trace/cloud_trace.h" +#include "contrib/endpoints/src/api_manager/quota_control.h" +#include "google/protobuf/stubs/status.h" + +using ::google::api_manager::utils::Status; +using ::google::protobuf::util::error::Code; + +namespace google { +namespace api_manager { + +void QuotaControl(std::shared_ptr context, + std::function continuation) { + std::shared_ptr trace_span( + CreateSpan(context->cloud_trace(), "QuotaControl")); + + if (!context->service_context()->service_control()) { + TRACE(trace_span) << "Service control check is not needed"; + continuation(Status::OK); + return; + } + + if (context->api_key().empty()) { + if (context->method()->allow_unregistered_calls()) { + // Not need to call Check. + TRACE(trace_span) << "Service control check is not needed"; + continuation(Status::OK); + return; + } + + TRACE(trace_span) << "Failed at checking caller identity."; + continuation( + Status(Code::UNAUTHENTICATED, + "Method doesn't allow unregistered callers (callers without " + "established identity). Please use API Key or other form of " + "API consumer identity to call this API.", + Status::SERVICE_CONTROL)); + return; + } + + service_control::QuotaRequestInfo info; + context->FillAllocateQuotaRequestInfo(&info); + context->service_context()->service_control()->Quota( + info, trace_span.get(), + [context, continuation, trace_span](utils::Status status) { + + TRACE(trace_span) << "Quota service control request returned with " + << "status " << status.ToString(); + + continuation(status); + }); +} + +} // namespace service_control_client +} // namespace google diff --git a/contrib/endpoints/src/api_manager/quota_control.h b/contrib/endpoints/src/api_manager/quota_control.h new file mode 100644 index 00000000000..e4f94d6ac93 --- /dev/null +++ b/contrib/endpoints/src/api_manager/quota_control.h @@ -0,0 +1,33 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// +// +#ifndef API_MANAGER_QUOTA_CONTROL_H_ +#define API_MANAGER_QUOTA_CONTROL_H_ + +#include "contrib/endpoints/include/api_manager/utils/status.h" +#include "contrib/endpoints/src/api_manager/context/request_context.h" + +namespace google { +namespace api_manager { + +// Call service control quota. +void QuotaControl(std::shared_ptr, + std::function); + +} // namespace api_manager +} // namespace google + +#endif // API_MANAGER_QUOTA_CONTROL_H_ diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index d2754d69dbd..05ac5c7a49a 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -22,6 +22,8 @@ using ::google::api::servicecontrol::v1::CheckRequest; using ::google::api::servicecontrol::v1::CheckResponse; +using ::google::api::servicecontrol::v1::AllocateQuotaRequest; +using ::google::api::servicecontrol::v1::AllocateQuotaResponse; using ::google::api::servicecontrol::v1::ReportRequest; using ::google::api::servicecontrol::v1::ReportResponse; using ::google::api_manager::proto::ServerConfig; @@ -29,6 +31,7 @@ using ::google::api_manager::utils::Status; using ::google::protobuf::util::error::Code; using ::google::service_control_client::CheckAggregationOptions; +using ::google::service_control_client::QuotaAggregationOptions; using ::google::service_control_client::ReportAggregationOptions; using ::google::service_control_client::ServiceControlClient; using ::google::service_control_client::ServiceControlClientOptions; @@ -40,6 +43,9 @@ namespace service_control { namespace { +const int kQuotaAggregationEntries = 10000; +const int kQuotaAggregationRefreshMs = 1000; + // Default config for check aggregator const int kCheckAggregationEntries = 10000; // Check doesn't support quota yet. It is safe to increase @@ -54,6 +60,8 @@ const int kReportAggregationFlushIntervalMs = 1000; // The default connection timeout for check requests. const int kCheckDefaultTimeoutInMs = 5000; +// The default connection timeout for allocate quota requests. +const int kAllocateQuotaDefaultTimeoutInMs = 5000; // The default connection timeout for report requests. const int kReportDefaultTimeoutInMs = 15000; @@ -69,6 +77,10 @@ const char application_proto[] = "application/x-protobuf"; const char servicecontrol_service[] = "/google.api.servicecontrol.v1.ServiceController"; +// The quota_control service name. used for as audience to generate JWT token. +const char quotacontrol_service[] = + "/google.api.servicecontrol.v1.QuotaController"; + // Generates CheckAggregationOptions. CheckAggregationOptions GetCheckAggregationOptions( const ServerConfig* server_config) { @@ -85,6 +97,26 @@ CheckAggregationOptions GetCheckAggregationOptions( kCheckAggregationExpirationMs); } +// TODO(jaebong): - need to add quota configuration +// Generate QuotaAggregationOptions +QuotaAggregationOptions GetQuotaAggregationOptions( + const ServerConfig* server_config, + const ::google::api::Service* service_config) { + QuotaAggregationOptions option = QuotaAggregationOptions( + kQuotaAggregationEntries, kQuotaAggregationRefreshMs); + + if (server_config && server_config->has_service_control_config() && + server_config->service_control_config().has_quota_aggregator_config()) { + const auto& quota_config = + server_config->service_control_config().quota_aggregator_config(); + + option.num_entries = quota_config.cache_entries(); + option.refresh_interval_ms = quota_config.refresh_interval_ms(); + } + + return option; +} + // Generates ReportAggregationOptions. ReportAggregationOptions GetReportAggregationOptions( const ServerConfig* server_config) { @@ -133,6 +165,7 @@ Aggregated::Aggregated(const ::google::api::Service& service, server_config_(server_config), env_(env), sa_token_(sa_token), + sa_token_quota_(nullptr), service_control_proto_(logs, metrics, labels, service.name(), service.id()), url_(service_, server_config), @@ -144,6 +177,13 @@ Aggregated::Aggregated(const ::google::api::Service& service, auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL, url_.service_control() + servicecontrol_service); } + + sa_token_quota_ = new auth::ServiceAccountToken(env); + sa_token_quota_->SetClientAuthSecret( + server_config->google_authentication_secret()); + sa_token_quota_->SetAudience( + auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL, + url_.service_control() + quotacontrol_service); } Aggregated::Aggregated(const std::set& logs, @@ -153,12 +193,13 @@ Aggregated::Aggregated(const std::set& logs, server_config_(nullptr), env_(env), sa_token_(nullptr), + sa_token_quota_(nullptr), service_control_proto_(logs, "", ""), url_(service_, server_config_), client_(std::move(client)), max_report_size_(0) {} -Aggregated::~Aggregated() {} +Aggregated::~Aggregated() { delete sa_token_quota_; } Status Aggregated::Init() { // Init() can be called repeatedly. @@ -171,6 +212,7 @@ Status Aggregated::Init() { // env->StartPeriodicTimer doens't work at constructor. ServiceControlClientOptions options( GetCheckAggregationOptions(server_config_), + GetQuotaAggregationOptions(server_config_, service_), GetReportAggregationOptions(server_config_)); std::stringstream ss; @@ -186,6 +228,11 @@ Status Aggregated::Init() { options.check_transport = [this]( const CheckRequest& request, CheckResponse* response, TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); }; + + options.quota_transport = [this]( + const AllocateQuotaRequest& request, AllocateQuotaResponse* response, + TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); }; + options.report_transport = [this]( const ReportRequest& request, ReportResponse* response, TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); }; @@ -193,10 +240,10 @@ Status Aggregated::Init() { options.periodic_timer = [this](int interval_ms, std::function callback) -> std::unique_ptr<::google::service_control_client::PeriodicTimer> { - return std::unique_ptr<::google::service_control_client::PeriodicTimer>( - new ApiManagerPeriodicTimer(env_->StartPeriodicTimer( - std::chrono::milliseconds(interval_ms), callback))); - }; + return std::unique_ptr<::google::service_control_client::PeriodicTimer>( + new ApiManagerPeriodicTimer(env_->StartPeriodicTimer( + std::chrono::milliseconds(interval_ms), callback))); + }; client_ = ::google::service_control_client::CreateServiceControlClient( service_->name(), service_->id(), options); return Status::OK; @@ -317,6 +364,60 @@ void Aggregated::Check( check_pool_.Free(std::move(request)); } +void Aggregated::Quota(const QuotaRequestInfo& info, + cloud_trace::CloudTraceSpan* parent_span, + std::function on_done) { + std::shared_ptr trace_span( + CreateChildSpan(parent_span, "QuotaServiceControlCache")); + + if (!client_) { + on_done(Status(Code::INTERNAL, "Missing service control client")); + return; + } + + auto request = quota_pool_.Alloc(); + + Status status = + service_control_proto_.FillAllocateQuotaRequest(info, request.get()); + if (!status.ok()) { + on_done(status); + quota_pool_.Free(std::move(request)); + return; + } + + AllocateQuotaResponse* response = new AllocateQuotaResponse(); + + auto check_on_done = [this, response, on_done, trace_span]( + const ::google::protobuf::util::Status& status) { + if (status.ok()) { + utils::Status status = Proto::ConvertAllocateQuotaResponse( + *response, service_control_proto_.service_name()); + on_done(utils::Status::OK); + } else { + on_done(Status(status.error_code(), status.error_message(), + Status::SERVICE_CONTROL)); + } + + delete response; + }; + + AllocateQuotaRequest* quota_request_copy = new AllocateQuotaRequest(*request); + + // TODO(jaebong) Temporarily call Chemist directly instead of using service + // control client library + Call(*request, response, + [this, quota_request_copy, response, + check_on_done](::google::protobuf::util::Status status) { + delete quota_request_copy; + check_on_done(status); + }, + trace_span.get()); + + // There is no reference to request anymore at this point and it is safe to + // free request now. + quota_pool_.Free(std::move(request)); +} + Status Aggregated::GetStatistics(Statistics* esp_stat) const { if (!client_) { return Status(Code::INTERNAL, "Missing service control client"); @@ -358,9 +459,11 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, Status(Code::INVALID_ARGUMENT, std::string("Invalid response")); } } else { - const std::string& url = typeid(RequestType) == typeid(CheckRequest) - ? url_.check_url() - : url_.report_url(); + const std::string& url = + typeid(RequestType) == typeid(CheckRequest) + ? url_.check_url() + : typeid(RequestType) == typeid(ReportRequest) ? url_.report_url() + : url_.quota_url(); env_->LogError(std::string("Failed to call ") + url + ", Error: " + status.ToString() + ", Response body: " + body); @@ -378,36 +481,52 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, on_done(status.ToProto()); })); - bool is_check = (typeid(RequestType) == typeid(CheckRequest)); - const std::string& url = is_check ? url_.check_url() : url_.report_url(); + const std::string& url = (typeid(RequestType) == typeid(CheckRequest)) + ? url_.check_url() + : typeid(RequestType) == typeid(ReportRequest) + ? url_.report_url() + : url_.quota_url(); + TRACE(trace_span) << "Http request URL: " << url; std::string request_body; request.SerializeToString(&request_body); - if (!is_check && (request_body.size() > max_report_size_)) { + if ((typeid(RequestType) == typeid(ReportRequest)) && + (request_body.size() > max_report_size_)) { max_report_size_ = request_body.size(); } + auto token = (typeid(RequestType) == typeid(AllocateQuotaRequest)) + ? sa_token_quota_ + : sa_token_; + http_request->set_url(url) .set_method("POST") - .set_auth_token(GetAuthToken()) + .set_auth_token(GetAuthToken(token)) .set_header("Content-Type", application_proto) .set_body(request_body); // Set timeout on the request if it was so configured. - if (is_check) { + if (typeid(RequestType) == typeid(CheckRequest)) { http_request->set_timeout_ms(kCheckDefaultTimeoutInMs); + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + http_request->set_timeout_ms(kAllocateQuotaDefaultTimeoutInMs); } else { http_request->set_timeout_ms(kReportDefaultTimeoutInMs); } + if (server_config_ != nullptr && server_config_->has_service_control_config()) { const auto& config = server_config_->service_control_config(); - if (is_check) { + if (typeid(RequestType) == typeid(CheckRequest)) { if (config.check_timeout_ms() > 0) { http_request->set_timeout_ms(config.check_timeout_ms()); } + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + if (config.quota_timeout_ms() > 0) { + http_request->set_timeout_ms(config.quota_timeout_ms()); + } } else { if (config.report_timeout_ms() > 0) { http_request->set_timeout_ms(config.report_timeout_ms()); @@ -418,9 +537,9 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, env_->RunHTTPRequest(std::move(http_request)); } -const std::string& Aggregated::GetAuthToken() { - if (sa_token_) { - return sa_token_->GetAuthToken( +const std::string& Aggregated::GetAuthToken(auth::ServiceAccountToken* token) { + if (token) { + return token->GetAuthToken( auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); } else { static std::string empty; diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.h b/contrib/endpoints/src/api_manager/service_control/aggregated.h index 27e42833dbe..1113f84a129 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.h +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.h @@ -49,6 +49,10 @@ class Aggregated : public Interface { const CheckRequestInfo& info, cloud_trace::CloudTraceSpan* parent_span, std::function on_done); + virtual void Quota(const QuotaRequestInfo& info, + cloud_trace::CloudTraceSpan* parent_span, + std::function on_done); + virtual utils::Status Init(); virtual utils::Status Close(); @@ -112,7 +116,7 @@ class Aggregated : public Interface { cloud_trace::CloudTraceSpan* parent_span); // Gets the auth token to access service control server. - const std::string& GetAuthToken(); + const std::string& GetAuthToken(auth::ServiceAccountToken* token); // the sevice config. const ::google::api::Service* service_; @@ -125,6 +129,9 @@ class Aggregated : public Interface { // service account token. auth::ServiceAccountToken* sa_token_; + // TODO(jaebong) quota service account token. + auth::ServiceAccountToken* sa_token_quota_; + // The object to fill service control Check and Report protobuf. Proto service_control_proto_; @@ -134,6 +141,11 @@ class Aggregated : public Interface { // The service control client instance. std::unique_ptr<::google::service_control_client::ServiceControlClient> client_; + + // The protobuf pool to reuse AllocateQuotaRequest protobuf. + ProtoPool<::google::api::servicecontrol::v1::AllocateQuotaRequest> + quota_pool_; + // The protobuf pool to reuse CheckRequest protobuf. ProtoPool<::google::api::servicecontrol::v1::CheckRequest> check_pool_; // The protobuf pool to reuse ReportRequest protobuf. diff --git a/contrib/endpoints/src/api_manager/service_control/info.h b/contrib/endpoints/src/api_manager/service_control/info.h index f203057cc9e..50000a264fb 100644 --- a/contrib/endpoints/src/api_manager/service_control/info.h +++ b/contrib/endpoints/src/api_manager/service_control/info.h @@ -17,7 +17,8 @@ #include "google/protobuf/stubs/stringpiece.h" -#include +#include "google/api/quota.pb.h" + #include #include #include @@ -89,6 +90,17 @@ struct CheckResponseInfo { CheckResponseInfo() : is_api_key_valid(true), service_is_activated(true) {} }; +struct QuotaRequestInfo : public OperationInfo { + std::string method_name; + // The client IP address. + std::string client_ip; + + std::unordered_map labels; + + ::google::api::QuotaRule* quota_rule_; + ::google::api::MetricRule* metric_rule_; +}; + // Information to fill Report request protobuf. struct ReportRequestInfo : public OperationInfo { // The HTTP response code. diff --git a/contrib/endpoints/src/api_manager/service_control/interface.h b/contrib/endpoints/src/api_manager/service_control/interface.h index 708acc56a88..a6188e0f73b 100644 --- a/contrib/endpoints/src/api_manager/service_control/interface.h +++ b/contrib/endpoints/src/api_manager/service_control/interface.h @@ -70,6 +70,17 @@ class Interface { const CheckRequestInfo& info, cloud_trace::CloudTraceSpan* parent_span, std::function on_done) = 0; + // on_done() function will be called once it is completed. + // utils::Status in the on_done callback: + // If status.code is more than 100, it is the HTTP response status + // from the service control server. + // If status code is less than 20, within the ranges defined by + // google/protobuf/stubs/status.h, is from parsing error response + // body. + virtual void Quota(const QuotaRequestInfo& info, + cloud_trace::CloudTraceSpan* parent_span, + std::function on_done) = 0; + // Get statistics of ServiceControl library. virtual utils::Status GetStatistics(Statistics* stat) const = 0; }; diff --git a/contrib/endpoints/src/api_manager/service_control/proto.cc b/contrib/endpoints/src/api_manager/service_control/proto.cc index 3e7eba64d21..4e8fbd5c306 100644 --- a/contrib/endpoints/src/api_manager/service_control/proto.cc +++ b/contrib/endpoints/src/api_manager/service_control/proto.cc @@ -30,6 +30,7 @@ #include "utils/distribution_helper.h" using ::google::api::servicecontrol::v1::CheckError; +using ::google::api::servicecontrol::v1::QuotaError; using ::google::api::servicecontrol::v1::CheckRequest; using ::google::api::servicecontrol::v1::CheckResponse; using ::google::api::servicecontrol::v1::Distribution; @@ -49,6 +50,11 @@ namespace google { namespace api_manager { namespace service_control { +const char kConsumerQuotaUsedCount[] = + "serviceruntime.googleapis.com/api/consumer/quota_used_count"; + +const char kQuotaName[] = "/quota_name"; + struct SupportedMetric { const char* name; ::google::api::MetricDescriptor_MetricKind metric_kind; @@ -905,6 +911,83 @@ Proto::Proto(const std::set& logs, service_name_(service_name), service_config_id_(service_config_id) {} +utils::Status Proto::FillAllocateQuotaRequest( + const QuotaRequestInfo& info, + ::google::api::servicecontrol::v1::AllocateQuotaRequest* request) { + ::google::api::servicecontrol::v1::QuotaOperation* operation = + request->mutable_allocate_operation(); + + // service_name + request->set_service_name(service_name_); + // service_config_id + request->set_service_config_id(service_config_id_); + + // allocate_operation.operation_id + if (!info.operation_id.empty()) { + operation->set_operation_id(info.operation_id); + } + // allocate_operation.method_name + if (!info.method_name.empty()) { + operation->set_method_name(info.method_name); + } + // allocate_operation.consumer_id + if (!info.api_key.empty()) { + operation->set_consumer_id(std::string(kConsumerIdApiKey) + + std::string(info.api_key)); + } + + // TODO(jaebong) - Read from service conf? + // allocate_operation.quota_mode + operation->set_quota_mode( + ::google::api::servicecontrol::v1::QuotaOperation_QuotaMode:: + QuotaOperation_QuotaMode_NORMAL); + + // allocate_operation.labels + auto* labels = operation->mutable_labels(); + if (!info.client_ip.empty()) { + (*labels)[kServiceControlCallerIp] = info.client_ip; + } + + if (!info.referer.empty()) { + (*labels)[kServiceControlReferer] = info.referer; + } + (*labels)[kServiceControlUserAgent] = kUserAgent; + (*labels)[kServiceControlServiceAgent] = + kServiceAgentPrefix + utils::Version::instance().get(); + + // allocate_operation.quota_metrics + // TODO(jaebong) need to update after the configuration module change + // handle group rules + if (info.quota_rule_ != nullptr) { + MetricValueSet* value_set = operation->add_quota_metrics(); + value_set->set_metric_name(kConsumerQuotaUsedCount); + + for (const auto& group : info.quota_rule_->groups()) { + MetricValue* value = value_set->add_metric_values(); + (*value->mutable_labels())[kQuotaName] = group.group(); + // Quota cost should be always larger than 0. Default to 1 if not. + // When super quota (go/pollux-detailed-design) is ready, negative value + // should not happen due to validation. + value->set_int64_value(group.cost() <= 0 ? 1 : group.cost()); + } + + return Status::OK; + } + + // handle metric rules + if (info.metric_rule_ != nullptr) { + for (const auto& metric_and_cost : info.metric_rule_->metric_costs()) { + MetricValueSet* value_set = operation->add_quota_metrics(); + value_set->set_metric_name(metric_and_cost.first); + MetricValue* value = value_set->add_metric_values(); + const auto& cost = metric_and_cost.second; + value->set_int64_value(cost <= 0 ? 1 : cost); + } + } + + return Status::OK; +} + Status Proto::FillCheckRequest(const CheckRequestInfo& info, CheckRequest* request) { Status status = VerifyRequiredCheckFields(info); @@ -993,6 +1076,97 @@ Status Proto::FillReportRequest(const ReportRequestInfo& info, return Status::OK; } +Status Proto::ConvertAllocateQuotaResponse( + const ::google::api::servicecontrol::v1::AllocateQuotaResponse& response, + const std::string& service_name) { + // response.operation_id() + if (response.allocate_errors().size() == 0) { + return Status::OK; + } + + const ::google::api::servicecontrol::v1::QuotaError& error = + response.allocate_errors().Get(0); + + switch (error.code()) { + case ::google::api::servicecontrol::v1::QuotaError::UNSPECIFIED: + // This is never used. + break; + + case ::google::api::servicecontrol::v1::QuotaError::RESOURCE_EXHAUSTED: + // Quota allocation failed. + // Same as [google.rpc.Code.RESOURCE_EXHAUSTED][]. + return Status(Code::PERMISSION_DENIED, "Quota allocation failed."); + + case ::google::api::servicecontrol::v1::QuotaError::PROJECT_SUSPENDED: + // Consumer project has been suspended. + return Status(Code::PERMISSION_DENIED, "Project suspended."); + + case ::google::api::servicecontrol::v1::QuotaError::SERVICE_NOT_ENABLED: + // Consumer has not enabled the service. + return Status(Code::PERMISSION_DENIED, + std::string("API ") + service_name + + " is not enabled for the project."); + + case ::google::api::servicecontrol::v1::QuotaError::BILLING_NOT_ACTIVE: + // Consumer cannot access the service because billing is disabled. + return Status(Code::PERMISSION_DENIED, + std::string("API ") + service_name + + " has billing disabled. Please enable it."); + + case ::google::api::servicecontrol::v1::QuotaError::PROJECT_DELETED: + // Consumer's project has been marked as deleted (soft deletion). + case ::google::api::servicecontrol::v1::QuotaError::PROJECT_INVALID: + // Consumer's project number or ID does not represent a valid project. + return Status(Code::INVALID_ARGUMENT, + "Client project not valid. Please pass a valid project."); + + case ::google::api::servicecontrol::v1::QuotaError::IP_ADDRESS_BLOCKED: + // IP address of the consumer is invalid for the specific consumer + // project. + return Status(Code::PERMISSION_DENIED, "IP address blocked."); + + case ::google::api::servicecontrol::v1::QuotaError::REFERER_BLOCKED: + // Referer address of the consumer request is invalid for the specific + // consumer project. + return Status(Code::PERMISSION_DENIED, "Referer blocked."); + + case ::google::api::servicecontrol::v1::QuotaError::CLIENT_APP_BLOCKED: + // Client application of the consumer request is invalid for the + // specific consumer project. + return Status(Code::PERMISSION_DENIED, "Client app blocked."); + + case ::google::api::servicecontrol::v1::QuotaError::API_KEY_INVALID: + // Specified API key is invalid. + return Status(Code::INVALID_ARGUMENT, + "API key not valid. Please pass a valid API key."); + + case ::google::api::servicecontrol::v1::QuotaError::API_KEY_EXPIRED: + // Specified API Key has expired. + return Status(Code::INVALID_ARGUMENT, + "API key expired. Please renew the API key."); + + case ::google::api::servicecontrol::v1::QuotaError:: + PROJECT_STATUS_UNVAILABLE: + // The backend server for looking up project id/number is unavailable. + case ::google::api::servicecontrol::v1::QuotaError:: + SERVICE_STATUS_UNAVAILABLE: + // The backend server for checking service status is unavailable. + case ::google::api::servicecontrol::v1::QuotaError:: + BILLING_STATUS_UNAVAILABLE: + // The backend server for checking billing status is unavailable. + // Fail open for internal server errors per recommendation + return Status::OK; + + default: + return Status( + Code::INTERNAL, + std::string("Request blocked due to unsupported error code: ") + + std::to_string(error.code())); + } + + return Status::OK; +} + Status Proto::ConvertCheckResponse(const CheckResponse& check_response, const std::string& service_name, CheckResponseInfo* check_response_info) { diff --git a/contrib/endpoints/src/api_manager/service_control/proto.h b/contrib/endpoints/src/api_manager/service_control/proto.h index bea2a948b63..d4fa09592c9 100644 --- a/contrib/endpoints/src/api_manager/service_control/proto.h +++ b/contrib/endpoints/src/api_manager/service_control/proto.h @@ -19,6 +19,7 @@ #include "contrib/endpoints/src/api_manager/service_control/info.h" #include "google/api/label.pb.h" #include "google/api/metric.pb.h" +#include "google/api/servicecontrol/v1/quota_controller.pb.h" #include "google/api/servicecontrol/v1/service_controller.pb.h" namespace google { @@ -48,6 +49,10 @@ class Proto final { const CheckRequestInfo& info, ::google::api::servicecontrol::v1::CheckRequest* request); + utils::Status FillAllocateQuotaRequest( + const QuotaRequestInfo& info, + ::google::api::servicecontrol::v1::AllocateQuotaRequest* request); + // Fills the CheckRequest protobuf from info. // FillReportRequest function should copy the strings pointed by info. // These buffers may be freed after the FillReportRequest call. @@ -64,6 +69,10 @@ class Proto final { const ::google::api::servicecontrol::v1::CheckResponse& response, const std::string& service_name, CheckResponseInfo* check_response_info); + static utils::Status ConvertAllocateQuotaResponse( + const ::google::api::servicecontrol::v1::AllocateQuotaResponse& response, + const std::string& service_name); + static bool IsMetricSupported(const ::google::api::MetricDescriptor& metric); static bool IsLabelSupported(const ::google::api::LabelDescriptor& label); const std::string& service_name() const { return service_name_; } diff --git a/contrib/endpoints/src/api_manager/service_control/url.cc b/contrib/endpoints/src/api_manager/service_control/url.cc index d113d402d1f..f106ccd40fa 100644 --- a/contrib/endpoints/src/api_manager/service_control/url.cc +++ b/contrib/endpoints/src/api_manager/service_control/url.cc @@ -27,6 +27,7 @@ namespace { // /v1/services/{service}:report const char v1_services_path[] = "/v1/services/"; const char check_verb[] = ":check"; +const char quota_verb[] = ":allocateQuota"; const char report_verb[] = ":report"; const char http[] = "http://"; const char https[] = "https://"; @@ -66,6 +67,7 @@ Url::Url(const ::google::api::Service* service, std::string path = service_control_ + v1_services_path + service->name(); check_url_ = path + check_verb; report_url_ = path + report_verb; + quota_url_ = path + quota_verb; } } diff --git a/contrib/endpoints/src/api_manager/service_control/url.h b/contrib/endpoints/src/api_manager/service_control/url.h index 4615864bbdd..fb17aa5e006 100644 --- a/contrib/endpoints/src/api_manager/service_control/url.h +++ b/contrib/endpoints/src/api_manager/service_control/url.h @@ -31,12 +31,14 @@ class Url { // Pre-computed url for service control. const std::string& service_control() const { return service_control_; } const std::string& check_url() const { return check_url_; } + const std::string& quota_url() const { return quota_url_; } const std::string& report_url() const { return report_url_; } private: // Pre-computed url for service control methods. std::string service_control_; std::string check_url_; + std::string quota_url_; std::string report_url_; }; From 60f5d0721c893062352c29b0df2b6660b9fcfd04 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Tue, 14 Feb 2017 16:57:54 -0800 Subject: [PATCH 02/17] Applied code review --- .../api_manager/auth/service_account_token.h | 1 + .../api_manager/context/request_context.cc | 5 - .../src/api_manager/quota_control.cc | 18 -- .../api_manager/service_control/aggregated.cc | 157 +++++++++--------- .../api_manager/service_control/aggregated.h | 13 +- .../src/api_manager/service_control/info.h | 2 - 6 files changed, 90 insertions(+), 106 deletions(-) diff --git a/contrib/endpoints/src/api_manager/auth/service_account_token.h b/contrib/endpoints/src/api_manager/auth/service_account_token.h index 211377449f4..eca3e148f68 100644 --- a/contrib/endpoints/src/api_manager/auth/service_account_token.h +++ b/contrib/endpoints/src/api_manager/auth/service_account_token.h @@ -64,6 +64,7 @@ class ServiceAccountToken { enum JWT_TOKEN_TYPE { JWT_TOKEN_FOR_SERVICE_CONTROL = 0, JWT_TOKEN_FOR_CLOUD_TRACING, + JWT_TOKEN_FOR_QUOTA_CONTROL, JWT_TOKEN_TYPE_MAX, }; // Set audience. Only calcualtes JWT token with specified audience. diff --git a/contrib/endpoints/src/api_manager/context/request_context.cc b/contrib/endpoints/src/api_manager/context/request_context.cc index 0e31e24f2fd..3d26d191b97 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.cc +++ b/contrib/endpoints/src/api_manager/context/request_context.cc @@ -233,11 +233,6 @@ void RequestContext::FillAllocateQuotaRequestInfo( info->client_ip = request_->GetClientIP(); info->method_name = this->method_call_.method_info->name(); - info->labels["servicecontrol.googleapis.com/caller_ip"] = - request_->GetClientIP(); - info->labels["servicecontrol.googleapis.com/referer"] = this->http_referer_; - info->labels["servicecontrol.googleapis.com/user"] = "integration_test_user"; - // TODO(jaebong) need to set quota rule and metric rule info->quota_rule_ = nullptr; info->metric_rule_ = nullptr; diff --git a/contrib/endpoints/src/api_manager/quota_control.cc b/contrib/endpoints/src/api_manager/quota_control.cc index 04e2f974aef..58568ec6fdb 100644 --- a/contrib/endpoints/src/api_manager/quota_control.cc +++ b/contrib/endpoints/src/api_manager/quota_control.cc @@ -37,24 +37,6 @@ void QuotaControl(std::shared_ptr context, return; } - if (context->api_key().empty()) { - if (context->method()->allow_unregistered_calls()) { - // Not need to call Check. - TRACE(trace_span) << "Service control check is not needed"; - continuation(Status::OK); - return; - } - - TRACE(trace_span) << "Failed at checking caller identity."; - continuation( - Status(Code::UNAUTHENTICATED, - "Method doesn't allow unregistered callers (callers without " - "established identity). Please use API Key or other form of " - "API consumer identity to call this API.", - Status::SERVICE_CONTROL)); - return; - } - service_control::QuotaRequestInfo info; context->FillAllocateQuotaRequestInfo(&info); context->service_context()->service_control()->Quota( diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index 05ac5c7a49a..4d37990c0b1 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -100,8 +100,7 @@ CheckAggregationOptions GetCheckAggregationOptions( // TODO(jaebong): - need to add quota configuration // Generate QuotaAggregationOptions QuotaAggregationOptions GetQuotaAggregationOptions( - const ServerConfig* server_config, - const ::google::api::Service* service_config) { + const ServerConfig* server_config) { QuotaAggregationOptions option = QuotaAggregationOptions( kQuotaAggregationEntries, kQuotaAggregationRefreshMs); @@ -165,7 +164,6 @@ Aggregated::Aggregated(const ::google::api::Service& service, server_config_(server_config), env_(env), sa_token_(sa_token), - sa_token_quota_(nullptr), service_control_proto_(logs, metrics, labels, service.name(), service.id()), url_(service_, server_config), @@ -176,14 +174,10 @@ Aggregated::Aggregated(const ::google::api::Service& service, sa_token_->SetAudience( auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL, url_.service_control() + servicecontrol_service); + sa_token_->SetAudience( + auth::ServiceAccountToken::JWT_TOKEN_FOR_QUOTA_CONTROL, + url_.service_control() + quotacontrol_service); } - - sa_token_quota_ = new auth::ServiceAccountToken(env); - sa_token_quota_->SetClientAuthSecret( - server_config->google_authentication_secret()); - sa_token_quota_->SetAudience( - auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL, - url_.service_control() + quotacontrol_service); } Aggregated::Aggregated(const std::set& logs, @@ -193,13 +187,12 @@ Aggregated::Aggregated(const std::set& logs, server_config_(nullptr), env_(env), sa_token_(nullptr), - sa_token_quota_(nullptr), service_control_proto_(logs, "", ""), url_(service_, server_config_), client_(std::move(client)), max_report_size_(0) {} -Aggregated::~Aggregated() { delete sa_token_quota_; } +Aggregated::~Aggregated() {} Status Aggregated::Init() { // Init() can be called repeatedly. @@ -212,7 +205,7 @@ Status Aggregated::Init() { // env->StartPeriodicTimer doens't work at constructor. ServiceControlClientOptions options( GetCheckAggregationOptions(server_config_), - GetQuotaAggregationOptions(server_config_, service_), + GetQuotaAggregationOptions(server_config_), GetReportAggregationOptions(server_config_)); std::stringstream ss; @@ -387,12 +380,14 @@ void Aggregated::Quota(const QuotaRequestInfo& info, AllocateQuotaResponse* response = new AllocateQuotaResponse(); - auto check_on_done = [this, response, on_done, trace_span]( + auto quota_on_done = [this, response, on_done, trace_span]( const ::google::protobuf::util::Status& status) { + TRACE(trace_span) << "AllocateQuotaRequst returned with status: " + << status.ToString(); + if (status.ok()) { - utils::Status status = Proto::ConvertAllocateQuotaResponse( - *response, service_control_proto_.service_name()); - on_done(utils::Status::OK); + on_done(Proto::ConvertAllocateQuotaResponse( + *response, service_control_proto_.service_name())); } else { on_done(Status(status.error_code(), status.error_message(), Status::SERVICE_CONTROL)); @@ -401,15 +396,11 @@ void Aggregated::Quota(const QuotaRequestInfo& info, delete response; }; - AllocateQuotaRequest* quota_request_copy = new AllocateQuotaRequest(*request); - // TODO(jaebong) Temporarily call Chemist directly instead of using service // control client library Call(*request, response, - [this, quota_request_copy, response, - check_on_done](::google::protobuf::util::Status status) { - delete quota_request_copy; - check_on_done(status); + [quota_on_done](::google::protobuf::util::Status status) { + quota_on_done(status); }, trace_span.get()); @@ -442,13 +433,75 @@ Status Aggregated::GetStatistics(Statistics* esp_stat) const { return Status::OK; } +template +const std::string& Aggregated::GetApiReqeustUrl(const RequestType& request) { + if (typeid(request) == typeid(CheckRequest)) { + return url_.check_url(); + } else if (typeid(request) == typeid(AllocateQuotaRequest)) { + return url_.quota_url(); + } else { + return url_.report_url(); + } +} + +template +void Aggregated::SetHttpRequestTimeout( + const RequestType& request, std::unique_ptr& http_request) { + // Set timeout on the request if it was so configured. + if (typeid(RequestType) == typeid(CheckRequest)) { + http_request->set_timeout_ms(kCheckDefaultTimeoutInMs); + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + http_request->set_timeout_ms(kAllocateQuotaDefaultTimeoutInMs); + } else { + http_request->set_timeout_ms(kReportDefaultTimeoutInMs); + } + + if (server_config_ != nullptr && + server_config_->has_service_control_config()) { + const auto& config = server_config_->service_control_config(); + if (typeid(RequestType) == typeid(CheckRequest)) { + if (config.check_timeout_ms() > 0) { + http_request->set_timeout_ms(config.check_timeout_ms()); + } + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + if (config.quota_timeout_ms() > 0) { + http_request->set_timeout_ms(config.quota_timeout_ms()); + } + } else { + if (config.report_timeout_ms() > 0) { + http_request->set_timeout_ms(config.report_timeout_ms()); + } + } + } +} + +template +const std::string& Aggregated::GetAuthToken(const RequestType& request) { + if (typeid(request) == typeid(AllocateQuotaRequest)) { + return sa_token_->GetAuthToken( + auth::ServiceAccountToken::JWT_TOKEN_FOR_QUOTA_CONTROL); + } else if (typeid(request) == typeid(CheckRequest) || + typeid(request) == typeid(ReportRequest)) { + return sa_token_->GetAuthToken( + auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); + } else { + static std::string empty; + return empty; + } +} + template void Aggregated::Call(const RequestType& request, ResponseType* response, TransportDoneFunc on_done, cloud_trace::CloudTraceSpan* parent_span) { std::shared_ptr trace_span( CreateChildSpan(parent_span, "Call ServiceControl server")); - std::unique_ptr http_request(new HTTPRequest([response, on_done, + + const std::string& url = GetApiReqeustUrl(request); + TRACE(trace_span) << "Http request URL: " << url; + + std::unique_ptr http_request(new HTTPRequest([url, response, + on_done, trace_span, this]( Status status, std::map&&, std::string&& body) { TRACE(trace_span) << "HTTP response status: " << status.ToString(); @@ -459,11 +512,6 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, Status(Code::INVALID_ARGUMENT, std::string("Invalid response")); } } else { - const std::string& url = - typeid(RequestType) == typeid(CheckRequest) - ? url_.check_url() - : typeid(RequestType) == typeid(ReportRequest) ? url_.report_url() - : url_.quota_url(); env_->LogError(std::string("Failed to call ") + url + ", Error: " + status.ToString() + ", Response body: " + body); @@ -481,14 +529,6 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, on_done(status.ToProto()); })); - const std::string& url = (typeid(RequestType) == typeid(CheckRequest)) - ? url_.check_url() - : typeid(RequestType) == typeid(ReportRequest) - ? url_.report_url() - : url_.quota_url(); - - TRACE(trace_span) << "Http request URL: " << url; - std::string request_body; request.SerializeToString(&request_body); @@ -497,56 +537,17 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, max_report_size_ = request_body.size(); } - auto token = (typeid(RequestType) == typeid(AllocateQuotaRequest)) - ? sa_token_quota_ - : sa_token_; - http_request->set_url(url) .set_method("POST") - .set_auth_token(GetAuthToken(token)) + .set_auth_token(GetAuthToken(request)) .set_header("Content-Type", application_proto) .set_body(request_body); - // Set timeout on the request if it was so configured. - if (typeid(RequestType) == typeid(CheckRequest)) { - http_request->set_timeout_ms(kCheckDefaultTimeoutInMs); - } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { - http_request->set_timeout_ms(kAllocateQuotaDefaultTimeoutInMs); - } else { - http_request->set_timeout_ms(kReportDefaultTimeoutInMs); - } - - if (server_config_ != nullptr && - server_config_->has_service_control_config()) { - const auto& config = server_config_->service_control_config(); - if (typeid(RequestType) == typeid(CheckRequest)) { - if (config.check_timeout_ms() > 0) { - http_request->set_timeout_ms(config.check_timeout_ms()); - } - } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { - if (config.quota_timeout_ms() > 0) { - http_request->set_timeout_ms(config.quota_timeout_ms()); - } - } else { - if (config.report_timeout_ms() > 0) { - http_request->set_timeout_ms(config.report_timeout_ms()); - } - } - } + SetHttpRequestTimeout(request, http_request); env_->RunHTTPRequest(std::move(http_request)); } -const std::string& Aggregated::GetAuthToken(auth::ServiceAccountToken* token) { - if (token) { - return token->GetAuthToken( - auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); - } else { - static std::string empty; - return empty; - } -} - Interface* Aggregated::Create(const ::google::api::Service& service, const ServerConfig* server_config, ApiManagerEnvInterface* env, diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.h b/contrib/endpoints/src/api_manager/service_control/aggregated.h index 1113f84a129..534431befa2 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.h +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.h @@ -115,6 +115,16 @@ class Aggregated : public Interface { ::google::service_control_client::TransportDoneFunc on_done, cloud_trace::CloudTraceSpan* parent_span); + template + const std::string& GetApiReqeustUrl(const RequestType& request); + + template + void SetHttpRequestTimeout(const RequestType& request, + std::unique_ptr& http_request); + + template + const std::string& GetAuthToken(const RequestType& request); + // Gets the auth token to access service control server. const std::string& GetAuthToken(auth::ServiceAccountToken* token); @@ -129,9 +139,6 @@ class Aggregated : public Interface { // service account token. auth::ServiceAccountToken* sa_token_; - // TODO(jaebong) quota service account token. - auth::ServiceAccountToken* sa_token_quota_; - // The object to fill service control Check and Report protobuf. Proto service_control_proto_; diff --git a/contrib/endpoints/src/api_manager/service_control/info.h b/contrib/endpoints/src/api_manager/service_control/info.h index 50000a264fb..f517c283f15 100644 --- a/contrib/endpoints/src/api_manager/service_control/info.h +++ b/contrib/endpoints/src/api_manager/service_control/info.h @@ -95,8 +95,6 @@ struct QuotaRequestInfo : public OperationInfo { // The client IP address. std::string client_ip; - std::unordered_map labels; - ::google::api::QuotaRule* quota_rule_; ::google::api::MetricRule* metric_rule_; }; From 8ee01ed527b3354effc86c9a52740715bcb1ba76 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Wed, 15 Feb 2017 14:19:27 -0800 Subject: [PATCH 03/17] Applied code review --- contrib/endpoints/repositories.bzl | 18 +++--- contrib/endpoints/src/api_manager/config.h | 1 + .../api_manager/service_control/aggregated.cc | 63 ++++++++++--------- .../api_manager/service_control/aggregated.h | 7 +-- .../src/api_manager/service_control/info.h | 2 - 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index bae14e92d61..fef87b195b1 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -290,33 +290,33 @@ cc_proto_library( ) """.format(protobuf_repo) - - native.new_git_repository( + # TODO(jaebong) This is temporary repository change introduced by protobuf + # files hack. It needs to be rollback after the googapis repository update + native.git_repository( name = "googleapis_git", - commit = "db1d4547dc56a798915e0eb2c795585385922165", - remote = "https://github.com/googleapis/googleapis.git", - build_file_content = BUILD, + commit = "069bc7156d92a2d84929309d69610c76f6b8dab9", + remote = "https://github.com/cloudendpoints/service-control-client-cxx.git", ) if bind: native.bind( name = "servicecontrol", - actual = "@googleapis_git//:servicecontrol", + actual = "@googleapis_git//proto:servicecontrol", ) native.bind( name = "servicecontrol_genproto", - actual = "@googleapis_git//:servicecontrol_genproto", + actual = "@googleapis_git//proto:servicecontrol_genproto", ) native.bind( name = "service_config", - actual = "@googleapis_git//:service_config", + actual = "@googleapis_git//proto:service_config", ) native.bind( name = "cloud_trace", - actual = "@googleapis_git//:cloud_trace", + actual = "@googleapis_git//proto:cloud_trace", ) def servicecontrol_client_repositories(bind=True): diff --git a/contrib/endpoints/src/api_manager/config.h b/contrib/endpoints/src/api_manager/config.h index 9a56d16d745..436a5f6e016 100644 --- a/contrib/endpoints/src/api_manager/config.h +++ b/contrib/endpoints/src/api_manager/config.h @@ -25,6 +25,7 @@ #include "contrib/endpoints/src/api_manager/method_impl.h" #include "contrib/endpoints/src/api_manager/path_matcher.h" #include "contrib/endpoints/src/api_manager/proto/server_config.pb.h" +#include "google/api/quota.pb.h" #include "google/api/service.pb.h" namespace google { diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index 4d37990c0b1..c38a935ba6c 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -31,7 +31,8 @@ using ::google::api_manager::utils::Status; using ::google::protobuf::util::error::Code; using ::google::service_control_client::CheckAggregationOptions; -using ::google::service_control_client::QuotaAggregationOptions; +// TODO(jaebong) enable this after service_control_client library is updated +// using ::google::service_control_client::QuotaAggregationOptions; using ::google::service_control_client::ReportAggregationOptions; using ::google::service_control_client::ServiceControlClient; using ::google::service_control_client::ServiceControlClientOptions; @@ -97,6 +98,8 @@ CheckAggregationOptions GetCheckAggregationOptions( kCheckAggregationExpirationMs); } +// TODO(jaebong) enable this after service_control_client library is updated +/* // TODO(jaebong): - need to add quota configuration // Generate QuotaAggregationOptions QuotaAggregationOptions GetQuotaAggregationOptions( @@ -115,6 +118,7 @@ QuotaAggregationOptions GetQuotaAggregationOptions( return option; } +*/ // Generates ReportAggregationOptions. ReportAggregationOptions GetReportAggregationOptions( @@ -205,7 +209,9 @@ Status Aggregated::Init() { // env->StartPeriodicTimer doens't work at constructor. ServiceControlClientOptions options( GetCheckAggregationOptions(server_config_), - GetQuotaAggregationOptions(server_config_), + // TODO(jaebong) enable this after service_control_client library is + // updated + // GetQuotaAggregationOptions(server_config_), GetReportAggregationOptions(server_config_)); std::stringstream ss; @@ -222,9 +228,13 @@ Status Aggregated::Init() { const CheckRequest& request, CheckResponse* response, TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); }; - options.quota_transport = [this]( - const AllocateQuotaRequest& request, AllocateQuotaResponse* response, - TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); }; + /* + // TODO(jaebong) enable this after service_control_client library is updated + options.quota_transport = [this]( + const AllocateQuotaRequest& request, AllocateQuotaResponse* response, + TransportDoneFunc on_done) { Call(request, response, on_done, nullptr); + }; + */ options.report_transport = [this]( const ReportRequest& request, ReportResponse* response, @@ -398,11 +408,7 @@ void Aggregated::Quota(const QuotaRequestInfo& info, // TODO(jaebong) Temporarily call Chemist directly instead of using service // control client library - Call(*request, response, - [quota_on_done](::google::protobuf::util::Status status) { - quota_on_done(status); - }, - trace_span.get()); + Call(*request, response, quota_on_done, trace_span.get()); // There is no reference to request anymore at this point and it is safe to // free request now. @@ -445,48 +451,47 @@ const std::string& Aggregated::GetApiReqeustUrl(const RequestType& request) { } template -void Aggregated::SetHttpRequestTimeout( - const RequestType& request, std::unique_ptr& http_request) { +int Aggregated::GetHttpRequestTimeout(const RequestType& request) { + int timeout_ms = 0; + // Set timeout on the request if it was so configured. - if (typeid(RequestType) == typeid(CheckRequest)) { - http_request->set_timeout_ms(kCheckDefaultTimeoutInMs); - } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { - http_request->set_timeout_ms(kAllocateQuotaDefaultTimeoutInMs); + if (typeid(request) == typeid(CheckRequest)) { + timeout_ms = kCheckDefaultTimeoutInMs; + } else if (typeid(request) == typeid(AllocateQuotaRequest)) { + timeout_ms = kAllocateQuotaDefaultTimeoutInMs; } else { - http_request->set_timeout_ms(kReportDefaultTimeoutInMs); + timeout_ms = kReportDefaultTimeoutInMs; } if (server_config_ != nullptr && server_config_->has_service_control_config()) { const auto& config = server_config_->service_control_config(); - if (typeid(RequestType) == typeid(CheckRequest)) { + if (typeid(request) == typeid(CheckRequest)) { if (config.check_timeout_ms() > 0) { - http_request->set_timeout_ms(config.check_timeout_ms()); + timeout_ms = config.check_timeout_ms(); } - } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + } else if (typeid(request) == typeid(AllocateQuotaRequest)) { if (config.quota_timeout_ms() > 0) { - http_request->set_timeout_ms(config.quota_timeout_ms()); + timeout_ms = config.quota_timeout_ms(); } } else { if (config.report_timeout_ms() > 0) { - http_request->set_timeout_ms(config.report_timeout_ms()); + timeout_ms = config.report_timeout_ms(); } } } + + return timeout_ms; } template const std::string& Aggregated::GetAuthToken(const RequestType& request) { - if (typeid(request) == typeid(AllocateQuotaRequest)) { + if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { return sa_token_->GetAuthToken( auth::ServiceAccountToken::JWT_TOKEN_FOR_QUOTA_CONTROL); - } else if (typeid(request) == typeid(CheckRequest) || - typeid(request) == typeid(ReportRequest)) { + } else { return sa_token_->GetAuthToken( auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); - } else { - static std::string empty; - return empty; } } @@ -543,7 +548,7 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, .set_header("Content-Type", application_proto) .set_body(request_body); - SetHttpRequestTimeout(request, http_request); + http_request->set_timeout_ms(GetHttpRequestTimeout(request)); env_->RunHTTPRequest(std::move(http_request)); } diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.h b/contrib/endpoints/src/api_manager/service_control/aggregated.h index 534431befa2..363bc4ccd2e 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.h +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.h @@ -23,6 +23,7 @@ #include "contrib/endpoints/src/api_manager/service_control/proto.h" #include "contrib/endpoints/src/api_manager/service_control/url.h" #include "google/api/service.pb.h" +#include "google/api/servicecontrol/v1/quota_controller.pb.h" #include "google/api/servicecontrol/v1/service_controller.pb.h" #include "include/service_control_client.h" @@ -119,15 +120,11 @@ class Aggregated : public Interface { const std::string& GetApiReqeustUrl(const RequestType& request); template - void SetHttpRequestTimeout(const RequestType& request, - std::unique_ptr& http_request); + int GetHttpRequestTimeout(const RequestType& request); template const std::string& GetAuthToken(const RequestType& request); - // Gets the auth token to access service control server. - const std::string& GetAuthToken(auth::ServiceAccountToken* token); - // the sevice config. const ::google::api::Service* service_; // the server config. diff --git a/contrib/endpoints/src/api_manager/service_control/info.h b/contrib/endpoints/src/api_manager/service_control/info.h index f517c283f15..f6517af01d4 100644 --- a/contrib/endpoints/src/api_manager/service_control/info.h +++ b/contrib/endpoints/src/api_manager/service_control/info.h @@ -92,8 +92,6 @@ struct CheckResponseInfo { struct QuotaRequestInfo : public OperationInfo { std::string method_name; - // The client IP address. - std::string client_ip; ::google::api::QuotaRule* quota_rule_; ::google::api::MetricRule* metric_rule_; From 74ed244810af809adbf57006232c55c1f19b00fd Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Wed, 15 Feb 2017 14:25:38 -0800 Subject: [PATCH 04/17] Resolve conflicts --- contrib/endpoints/repositories.bzl | 136 +++-------------------------- 1 file changed, 11 insertions(+), 125 deletions(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index fef87b195b1..d07064cedf8 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -32,11 +32,8 @@ def zlib_repositories(bind=True): # ################################################################################ # - licenses(["notice"]) - exports_files(["README"]) - cc_library( name = "zlib", srcs = [ @@ -105,11 +102,8 @@ def nanopb_repositories(bind=True): # ################################################################################ # - licenses(["notice"]) - exports_files(["LICENSE.txt"]) - cc_library( name = "nanopb", srcs = [ @@ -126,7 +120,6 @@ cc_library( "//visibility:public", ], ) - genrule( name = "includes", srcs = [ @@ -193,143 +186,36 @@ def grpc_repositories(bind=True): actual = "@grpc_git//:grpc++_codegen_proto", ) -def googleapis_repositories(protobuf_repo="@protobuf_git//", bind=True): - BUILD = """ -# Copyright 2016 Google Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -################################################################################ -# - -licenses(["notice"]) - -load("{}:protobuf.bzl", "cc_proto_library") - -exports_files(glob(["google/**"])) - -cc_proto_library( - name = "servicecontrol", - srcs = [ - "google/api/servicecontrol/v1/check_error.proto", - "google/api/servicecontrol/v1/distribution.proto", - "google/api/servicecontrol/v1/log_entry.proto", - "google/api/servicecontrol/v1/metric_value.proto", - "google/api/servicecontrol/v1/operation.proto", - "google/api/servicecontrol/v1/service_controller.proto", - "google/logging/type/http_request.proto", - "google/logging/type/log_severity.proto", - "google/rpc/error_details.proto", - "google/rpc/status.proto", - "google/type/money.proto", - ], - include = ".", - visibility = ["//visibility:public"], - deps = [ - ":service_config", - ], - protoc = "//external:protoc", - default_runtime = "//external:protobuf", -) - -cc_proto_library( - name = "service_config", - srcs = [ - "google/api/annotations.proto", - "google/api/auth.proto", - "google/api/backend.proto", - "google/api/billing.proto", - "google/api/consumer.proto", - "google/api/context.proto", - "google/api/control.proto", - "google/api/documentation.proto", - "google/api/endpoint.proto", - "google/api/http.proto", - "google/api/label.proto", - "google/api/log.proto", - "google/api/logging.proto", - "google/api/metric.proto", - "google/api/monitored_resource.proto", - "google/api/monitoring.proto", - "google/api/service.proto", - "google/api/system_parameter.proto", - "google/api/usage.proto", - ], - include = ".", - visibility = ["//visibility:public"], - deps = [ - "//external:cc_wkt_protos", - ], - protoc = "//external:protoc", - default_runtime = "//external:protobuf", -) -cc_proto_library( - name = "cloud_trace", - srcs = [ - "google/devtools/cloudtrace/v1/trace.proto", - ], - include = ".", - default_runtime = "//external:protobuf", - protoc = "//external:protoc", - visibility = ["//visibility:public"], - deps = [ - ":service_config", - "//external:cc_wkt_protos", - ], -) -""".format(protobuf_repo) +def servicecontrol_client_repositories(bind=True): - # TODO(jaebong) This is temporary repository change introduced by protobuf - # files hack. It needs to be rollback after the googapis repository update native.git_repository( - name = "googleapis_git", + name = "servicecontrol_client_git", commit = "069bc7156d92a2d84929309d69610c76f6b8dab9", remote = "https://github.com/cloudendpoints/service-control-client-cxx.git", ) if bind: + native.bind( + name = "servicecontrol_client", + actual = "@servicecontrol_client_git//:service_control_client_lib", + ) native.bind( name = "servicecontrol", - actual = "@googleapis_git//proto:servicecontrol", + actual = "@servicecontrol_client_git//proto:servicecontrol", ) native.bind( name = "servicecontrol_genproto", - actual = "@googleapis_git//proto:servicecontrol_genproto", + actual = "@servicecontrol_client_git//proto:servicecontrol_genproto", ) native.bind( name = "service_config", - actual = "@googleapis_git//proto:service_config", + actual = "@servicecontrol_client_git//proto:service_config", ) native.bind( name = "cloud_trace", - actual = "@googleapis_git//proto:cloud_trace", - ) - -def servicecontrol_client_repositories(bind=True): - googleapis_repositories(bind=bind) - - native.git_repository( - name = "servicecontrol_client_git", - commit = "d739d755365c6a13d0b4164506fd593f53932f5d", - remote = "https://github.com/cloudendpoints/service-control-client-cxx.git", - ) - - if bind: - native.bind( - name = "servicecontrol_client", - actual = "@servicecontrol_client_git//:service_control_client_lib", - ) + actual = "@servicecontrol_client_git//proto:cloud_trace", + ) \ No newline at end of file From a40535747823537112cdf0ae700c8f8a28423be1 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Wed, 15 Feb 2017 14:30:22 -0800 Subject: [PATCH 05/17] Resolve conflicts --- contrib/endpoints/repositories.bzl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index d07064cedf8..3aebfb83bc8 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -32,8 +32,11 @@ def zlib_repositories(bind=True): # ################################################################################ # + licenses(["notice"]) + exports_files(["README"]) + cc_library( name = "zlib", srcs = [ @@ -102,8 +105,11 @@ def nanopb_repositories(bind=True): # ################################################################################ # + licenses(["notice"]) + exports_files(["LICENSE.txt"]) + cc_library( name = "nanopb", srcs = [ @@ -120,6 +126,7 @@ cc_library( "//visibility:public", ], ) + genrule( name = "includes", srcs = [ @@ -218,4 +225,4 @@ def servicecontrol_client_repositories(bind=True): native.bind( name = "cloud_trace", actual = "@servicecontrol_client_git//proto:cloud_trace", - ) \ No newline at end of file + ) From 13a4e2d87d637a8a6f7b86eeb196ebb75be746d7 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Wed, 15 Feb 2017 15:12:16 -0800 Subject: [PATCH 06/17] Fixed format error reported by script/check-style --- .../src/api_manager/service_control/aggregated.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index c38a935ba6c..cb96ac7efd0 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -243,10 +243,10 @@ Status Aggregated::Init() { options.periodic_timer = [this](int interval_ms, std::function callback) -> std::unique_ptr<::google::service_control_client::PeriodicTimer> { - return std::unique_ptr<::google::service_control_client::PeriodicTimer>( - new ApiManagerPeriodicTimer(env_->StartPeriodicTimer( - std::chrono::milliseconds(interval_ms), callback))); - }; + return std::unique_ptr<::google::service_control_client::PeriodicTimer>( + new ApiManagerPeriodicTimer(env_->StartPeriodicTimer( + std::chrono::milliseconds(interval_ms), callback))); + }; client_ = ::google::service_control_client::CreateServiceControlClient( service_->name(), service_->id(), options); return Status::OK; From 7fade41db73b6b2bf5aeaea5b6e80d4dfa5fb5e5 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Wed, 15 Feb 2017 15:54:36 -0800 Subject: [PATCH 07/17] Fixed a bug at Aggregated::GetAuthToken that causes Segmentation Fault --- .../src/api_manager/service_control/aggregated.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index cb96ac7efd0..e58c3d559dd 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -486,12 +486,17 @@ int Aggregated::GetHttpRequestTimeout(const RequestType& request) { template const std::string& Aggregated::GetAuthToken(const RequestType& request) { - if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { - return sa_token_->GetAuthToken( - auth::ServiceAccountToken::JWT_TOKEN_FOR_QUOTA_CONTROL); + if (sa_token_) { + if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { + return sa_token_->GetAuthToken( + auth::ServiceAccountToken::JWT_TOKEN_FOR_QUOTA_CONTROL); + } else { + return sa_token_->GetAuthToken( + auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); + } } else { - return sa_token_->GetAuthToken( - auth::ServiceAccountToken::JWT_TOKEN_FOR_SERVICE_CONTROL); + static std::string empty; + return empty; } } From 02dcb856594b109445c46f0562b9487a4e6434b8 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 11:06:36 -0800 Subject: [PATCH 08/17] Changed usage of template funcion --- .../api_manager/service_control/aggregated.cc | 24 +++++++++---------- .../api_manager/service_control/aggregated.h | 6 ++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.cc b/contrib/endpoints/src/api_manager/service_control/aggregated.cc index e58c3d559dd..8c0907934d3 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.cc +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.cc @@ -440,10 +440,10 @@ Status Aggregated::GetStatistics(Statistics* esp_stat) const { } template -const std::string& Aggregated::GetApiReqeustUrl(const RequestType& request) { - if (typeid(request) == typeid(CheckRequest)) { +const std::string& Aggregated::GetApiReqeustUrl() { + if (typeid(RequestType) == typeid(CheckRequest)) { return url_.check_url(); - } else if (typeid(request) == typeid(AllocateQuotaRequest)) { + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { return url_.quota_url(); } else { return url_.report_url(); @@ -451,13 +451,13 @@ const std::string& Aggregated::GetApiReqeustUrl(const RequestType& request) { } template -int Aggregated::GetHttpRequestTimeout(const RequestType& request) { +int Aggregated::GetHttpRequestTimeout() { int timeout_ms = 0; // Set timeout on the request if it was so configured. - if (typeid(request) == typeid(CheckRequest)) { + if (typeid(RequestType) == typeid(CheckRequest)) { timeout_ms = kCheckDefaultTimeoutInMs; - } else if (typeid(request) == typeid(AllocateQuotaRequest)) { + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { timeout_ms = kAllocateQuotaDefaultTimeoutInMs; } else { timeout_ms = kReportDefaultTimeoutInMs; @@ -466,11 +466,11 @@ int Aggregated::GetHttpRequestTimeout(const RequestType& request) { if (server_config_ != nullptr && server_config_->has_service_control_config()) { const auto& config = server_config_->service_control_config(); - if (typeid(request) == typeid(CheckRequest)) { + if (typeid(RequestType) == typeid(CheckRequest)) { if (config.check_timeout_ms() > 0) { timeout_ms = config.check_timeout_ms(); } - } else if (typeid(request) == typeid(AllocateQuotaRequest)) { + } else if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { if (config.quota_timeout_ms() > 0) { timeout_ms = config.quota_timeout_ms(); } @@ -485,7 +485,7 @@ int Aggregated::GetHttpRequestTimeout(const RequestType& request) { } template -const std::string& Aggregated::GetAuthToken(const RequestType& request) { +const std::string& Aggregated::GetAuthToken() { if (sa_token_) { if (typeid(RequestType) == typeid(AllocateQuotaRequest)) { return sa_token_->GetAuthToken( @@ -507,7 +507,7 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, std::shared_ptr trace_span( CreateChildSpan(parent_span, "Call ServiceControl server")); - const std::string& url = GetApiReqeustUrl(request); + const std::string& url = GetApiReqeustUrl(); TRACE(trace_span) << "Http request URL: " << url; std::unique_ptr http_request(new HTTPRequest([url, response, @@ -549,11 +549,11 @@ void Aggregated::Call(const RequestType& request, ResponseType* response, http_request->set_url(url) .set_method("POST") - .set_auth_token(GetAuthToken(request)) + .set_auth_token(GetAuthToken()) .set_header("Content-Type", application_proto) .set_body(request_body); - http_request->set_timeout_ms(GetHttpRequestTimeout(request)); + http_request->set_timeout_ms(GetHttpRequestTimeout()); env_->RunHTTPRequest(std::move(http_request)); } diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.h b/contrib/endpoints/src/api_manager/service_control/aggregated.h index 363bc4ccd2e..fbee2b48619 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.h +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.h @@ -117,13 +117,13 @@ class Aggregated : public Interface { cloud_trace::CloudTraceSpan* parent_span); template - const std::string& GetApiReqeustUrl(const RequestType& request); + const std::string& GetApiReqeustUrl(); template - int GetHttpRequestTimeout(const RequestType& request); + int GetHttpRequestTimeout(); template - const std::string& GetAuthToken(const RequestType& request); + const std::string& GetAuthToken(); // the sevice config. const ::google::api::Service* service_; From 628987abfb56987ce2f0fc8fc39da44bc5772115 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 11:11:48 -0800 Subject: [PATCH 09/17] Applied latest changes from the repo --- contrib/endpoints/repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index 3aebfb83bc8..653fde9a85f 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -225,4 +225,4 @@ def servicecontrol_client_repositories(bind=True): native.bind( name = "cloud_trace", actual = "@servicecontrol_client_git//proto:cloud_trace", - ) + ) \ No newline at end of file From aec3b3586b20f369bfdfc116dbdcb9d708438fd4 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 11:24:04 -0800 Subject: [PATCH 10/17] Applied latest changes from the repo --- contrib/endpoints/repositories.bzl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index 653fde9a85f..ea53dae29e8 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -225,4 +225,5 @@ def servicecontrol_client_repositories(bind=True): native.bind( name = "cloud_trace", actual = "@servicecontrol_client_git//proto:cloud_trace", - ) \ No newline at end of file + ) + From 9c9de97ad6137ec053d59efbb53ce35a473a7961 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 11:25:27 -0800 Subject: [PATCH 11/17] Applied latest changes from the repo --- contrib/endpoints/repositories.bzl | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index ea53dae29e8..3aebfb83bc8 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -226,4 +226,3 @@ def servicecontrol_client_repositories(bind=True): name = "cloud_trace", actual = "@servicecontrol_client_git//proto:cloud_trace", ) - From bf01f8894be0c1fb91c9e5717d06f6a38f73cc14 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 13:05:40 -0800 Subject: [PATCH 12/17] Adde comments --- contrib/endpoints/src/api_manager/service_control/aggregated.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/endpoints/src/api_manager/service_control/aggregated.h b/contrib/endpoints/src/api_manager/service_control/aggregated.h index fbee2b48619..759cdbb41fd 100644 --- a/contrib/endpoints/src/api_manager/service_control/aggregated.h +++ b/contrib/endpoints/src/api_manager/service_control/aggregated.h @@ -116,12 +116,15 @@ class Aggregated : public Interface { ::google::service_control_client::TransportDoneFunc on_done, cloud_trace::CloudTraceSpan* parent_span); + // Returns API request url based on RequestType template const std::string& GetApiReqeustUrl(); + // Returns API request timeout in ms based on RequestType template int GetHttpRequestTimeout(); + // Returns API request auth token based on RequestType template const std::string& GetAuthToken(); From f6c4a8d15c6fde042284fa66c1358da50352a6fb Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Thu, 16 Feb 2017 16:03:19 -0800 Subject: [PATCH 13/17] Updated log information --- contrib/endpoints/src/api_manager/quota_control.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/endpoints/src/api_manager/quota_control.cc b/contrib/endpoints/src/api_manager/quota_control.cc index 58568ec6fdb..0811b311f69 100644 --- a/contrib/endpoints/src/api_manager/quota_control.cc +++ b/contrib/endpoints/src/api_manager/quota_control.cc @@ -32,7 +32,7 @@ void QuotaControl(std::shared_ptr context, CreateSpan(context->cloud_trace(), "QuotaControl")); if (!context->service_context()->service_control()) { - TRACE(trace_span) << "Service control check is not needed"; + TRACE(trace_span) << "Quota control check is not needed"; continuation(Status::OK); return; } From 625696808473eb7197e7c638fab13330cd69f5f6 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Fri, 17 Feb 2017 10:35:54 -0800 Subject: [PATCH 14/17] Applied #101 --- .../endpoints/include/api_manager/method.h | 4 +++ .../api_manager/context/request_context.cc | 3 +- .../src/api_manager/quota_control.cc | 2 +- .../src/api_manager/service_control/info.h | 3 +- .../src/api_manager/service_control/proto.cc | 28 +++---------------- 5 files changed, 11 insertions(+), 29 deletions(-) diff --git a/contrib/endpoints/include/api_manager/method.h b/contrib/endpoints/include/api_manager/method.h index 6b7c01072b8..1680b6950ff 100644 --- a/contrib/endpoints/include/api_manager/method.h +++ b/contrib/endpoints/include/api_manager/method.h @@ -89,6 +89,10 @@ class MethodInfo { // Get the names of url system parameters virtual const std::set &system_query_parameter_names() const = 0; + + // Get quota metric cost vector + virtual const std::vector> &metric_cost_vector() + const = 0; }; } // namespace api_manager diff --git a/contrib/endpoints/src/api_manager/context/request_context.cc b/contrib/endpoints/src/api_manager/context/request_context.cc index 3d26d191b97..15f5a96b49d 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.cc +++ b/contrib/endpoints/src/api_manager/context/request_context.cc @@ -234,8 +234,7 @@ void RequestContext::FillAllocateQuotaRequestInfo( info->method_name = this->method_call_.method_info->name(); // TODO(jaebong) need to set quota rule and metric rule - info->quota_rule_ = nullptr; - info->metric_rule_ = nullptr; + info->metric_cost_map = &this->method_call_.method_info->metric_cost_vector(); } void RequestContext::FillReportRequestInfo( diff --git a/contrib/endpoints/src/api_manager/quota_control.cc b/contrib/endpoints/src/api_manager/quota_control.cc index 0811b311f69..29fdb3fae1e 100644 --- a/contrib/endpoints/src/api_manager/quota_control.cc +++ b/contrib/endpoints/src/api_manager/quota_control.cc @@ -31,7 +31,7 @@ void QuotaControl(std::shared_ptr context, std::shared_ptr trace_span( CreateSpan(context->cloud_trace(), "QuotaControl")); - if (!context->service_context()->service_control()) { + if (context->method()->metric_cost_vector().size() == 0) { TRACE(trace_span) << "Quota control check is not needed"; continuation(Status::OK); return; diff --git a/contrib/endpoints/src/api_manager/service_control/info.h b/contrib/endpoints/src/api_manager/service_control/info.h index f6517af01d4..4d2f696bcf9 100644 --- a/contrib/endpoints/src/api_manager/service_control/info.h +++ b/contrib/endpoints/src/api_manager/service_control/info.h @@ -93,8 +93,7 @@ struct CheckResponseInfo { struct QuotaRequestInfo : public OperationInfo { std::string method_name; - ::google::api::QuotaRule* quota_rule_; - ::google::api::MetricRule* metric_rule_; + const std::vector>* metric_cost_map; }; // Information to fill Report request protobuf. diff --git a/contrib/endpoints/src/api_manager/service_control/proto.cc b/contrib/endpoints/src/api_manager/service_control/proto.cc index 4e8fbd5c306..4daf98fa144 100644 --- a/contrib/endpoints/src/api_manager/service_control/proto.cc +++ b/contrib/endpoints/src/api_manager/service_control/proto.cc @@ -955,32 +955,12 @@ utils::Status Proto::FillAllocateQuotaRequest( (*labels)[kServiceControlServiceAgent] = kServiceAgentPrefix + utils::Version::instance().get(); - // allocate_operation.quota_metrics - // TODO(jaebong) need to update after the configuration module change - // handle group rules - if (info.quota_rule_ != nullptr) { - MetricValueSet* value_set = operation->add_quota_metrics(); - value_set->set_metric_name(kConsumerQuotaUsedCount); - - for (const auto& group : info.quota_rule_->groups()) { - MetricValue* value = value_set->add_metric_values(); - (*value->mutable_labels())[kQuotaName] = group.group(); - // Quota cost should be always larger than 0. Default to 1 if not. - // When super quota (go/pollux-detailed-design) is ready, negative value - // should not happen due to validation. - value->set_int64_value(group.cost() <= 0 ? 1 : group.cost()); - } - - return Status::OK; - } - - // handle metric rules - if (info.metric_rule_ != nullptr) { - for (const auto& metric_and_cost : info.metric_rule_->metric_costs()) { + if (info.metric_cost_map) { + for (auto metric : *info.metric_cost_map) { MetricValueSet* value_set = operation->add_quota_metrics(); - value_set->set_metric_name(metric_and_cost.first); + value_set->set_metric_name(metric.first); MetricValue* value = value_set->add_metric_values(); - const auto& cost = metric_and_cost.second; + const auto& cost = metric.second; value->set_int64_value(cost <= 0 ? 1 : cost); } } From 9a2bda25c866c4aa69679221388dca03c4f4bc21 Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Fri, 17 Feb 2017 11:11:27 -0800 Subject: [PATCH 15/17] Changed metric_cost_map to metric_cost_vector --- contrib/endpoints/src/api_manager/context/request_context.cc | 5 ++--- contrib/endpoints/src/api_manager/service_control/info.h | 2 +- contrib/endpoints/src/api_manager/service_control/proto.cc | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/contrib/endpoints/src/api_manager/context/request_context.cc b/contrib/endpoints/src/api_manager/context/request_context.cc index 15f5a96b49d..5bc40f69645 100644 --- a/contrib/endpoints/src/api_manager/context/request_context.cc +++ b/contrib/endpoints/src/api_manager/context/request_context.cc @@ -232,9 +232,8 @@ void RequestContext::FillAllocateQuotaRequestInfo( info->client_ip = request_->GetClientIP(); info->method_name = this->method_call_.method_info->name(); - - // TODO(jaebong) need to set quota rule and metric rule - info->metric_cost_map = &this->method_call_.method_info->metric_cost_vector(); + info->metric_cost_vector = + &this->method_call_.method_info->metric_cost_vector(); } void RequestContext::FillReportRequestInfo( diff --git a/contrib/endpoints/src/api_manager/service_control/info.h b/contrib/endpoints/src/api_manager/service_control/info.h index 4d2f696bcf9..78c528f126b 100644 --- a/contrib/endpoints/src/api_manager/service_control/info.h +++ b/contrib/endpoints/src/api_manager/service_control/info.h @@ -93,7 +93,7 @@ struct CheckResponseInfo { struct QuotaRequestInfo : public OperationInfo { std::string method_name; - const std::vector>* metric_cost_map; + const std::vector>* metric_cost_vector; }; // Information to fill Report request protobuf. diff --git a/contrib/endpoints/src/api_manager/service_control/proto.cc b/contrib/endpoints/src/api_manager/service_control/proto.cc index 4daf98fa144..2c7ef893864 100644 --- a/contrib/endpoints/src/api_manager/service_control/proto.cc +++ b/contrib/endpoints/src/api_manager/service_control/proto.cc @@ -955,8 +955,8 @@ utils::Status Proto::FillAllocateQuotaRequest( (*labels)[kServiceControlServiceAgent] = kServiceAgentPrefix + utils::Version::instance().get(); - if (info.metric_cost_map) { - for (auto metric : *info.metric_cost_map) { + if (info.metric_cost_vector) { + for (auto metric : *info.metric_cost_vector) { MetricValueSet* value_set = operation->add_quota_metrics(); value_set->set_metric_name(metric.first); MetricValue* value = value_set->add_metric_values(); From 5f016a46a5ef451360812d358cbb768035bdd6bb Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Fri, 17 Feb 2017 14:37:59 -0800 Subject: [PATCH 16/17] Fixed test case compilation error --- contrib/endpoints/src/grpc/transcoding/transcoder_test.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/endpoints/src/grpc/transcoding/transcoder_test.cc b/contrib/endpoints/src/grpc/transcoding/transcoder_test.cc index eb2a38eaf5d..5ba4fc6370d 100644 --- a/contrib/endpoints/src/grpc/transcoding/transcoder_test.cc +++ b/contrib/endpoints/src/grpc/transcoding/transcoder_test.cc @@ -90,6 +90,10 @@ class TestMethodInfo : public MethodInfo { return dummy; }; + const std::vector> &metric_cost_vector() const { + return metric_cost_vector_; + } + // Methods that the Transcoder does use const std::string &request_type_url() const { return request_type_url_; } bool request_streaming() const { return request_streaming_; } @@ -104,6 +108,7 @@ class TestMethodInfo : public MethodInfo { bool response_streaming_; std::string body_field_path_; std::string empty_; + std::vector> metric_cost_vector_; }; class TranscoderTest : public ::testing::Test { From b7d4a42421a5e417113b6accd256bb3df5127b3b Mon Sep 17 00:00:00 2001 From: Jae Kim Date: Fri, 17 Feb 2017 14:49:53 -0800 Subject: [PATCH 17/17] Fixed test case compilation error --- contrib/endpoints/src/api_manager/mock_method_info.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/endpoints/src/api_manager/mock_method_info.h b/contrib/endpoints/src/api_manager/mock_method_info.h index a7de28e3422..6b78e86228b 100644 --- a/contrib/endpoints/src/api_manager/mock_method_info.h +++ b/contrib/endpoints/src/api_manager/mock_method_info.h @@ -48,6 +48,8 @@ class MockMethodInfo : public MethodInfo { MOCK_CONST_METHOD0(response_streaming, bool()); MOCK_CONST_METHOD0(system_query_parameter_names, const std::set&()); + MOCK_CONST_METHOD0(metric_cost_vector, + const std::vector>&()); }; } // namespace api_manager