diff --git a/WORKSPACE b/WORKSPACE index 3bd9feb3245..bbafd205918 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -31,11 +31,14 @@ googletest_repositories() load( "//contrib/endpoints:repositories.bzl", "grpc_repositories", + "mixerapi_repositories", "servicecontrol_client_repositories", ) grpc_repositories() +mixerapi_repositories() + servicecontrol_client_repositories() load( diff --git a/contrib/endpoints/repositories.bzl b/contrib/endpoints/repositories.bzl index a14d7ce4dfd..f3df61722a2 100644 --- a/contrib/endpoints/repositories.bzl +++ b/contrib/endpoints/repositories.bzl @@ -333,3 +333,52 @@ def servicecontrol_client_repositories(bind=True): name = "servicecontrol_client", actual = "@servicecontrol_client_git//:service_control_client_lib", ) + +def mixerapi_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") + +cc_proto_library( + name = "mixer_api_cc_proto", + srcs = glob( + ["mixer/api/v1/*.proto"], + ), + default_runtime = "//external:protobuf", + protoc = "//external:protoc", + visibility = ["//visibility:public"], + deps = [ + "//external:cc_wkt_protos", + "//external:servicecontrol", + ], +) +""".format(protobuf_repo) + + native.new_git_repository( + name = "mixerapi_git", + commit = "fc5a396185edc72d06d1937f30a8148a37d4fc1b", + remote = "https://github.com/istio/api.git", + build_file_content = BUILD, + ) + if bind: + native.bind( + name = "mixer_api_cc_proto", + actual = "@mixerapi_git//:mixer_api_cc_proto", + ) diff --git a/contrib/endpoints/src/api_manager/mixer/BUILD b/contrib/endpoints/src/api_manager/mixer/BUILD new file mode 100644 index 00000000000..8082c61e201 --- /dev/null +++ b/contrib/endpoints/src/api_manager/mixer/BUILD @@ -0,0 +1,42 @@ +# 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. +# +################################################################################ +# +package(default_visibility = ["//contrib/endpoints/src/api_manager:__subpackages__"]) + +cc_library( + name = "mixer", + srcs = [ + "mixer.cc", + ], + hdrs = [ + "mixer.h", + ], + linkopts = select({ + "//:darwin": [], + "//conditions:default": [ + "-lm", + "-luuid", + ], + }), + deps = [ + "//external:grpc++", + "//external:mixer_api_cc_proto", + "//external:protobuf", + "//contrib/endpoints/src/api_manager:impl_headers", + "//contrib/endpoints/src/api_manager/service_control", + "//contrib/endpoints/src/api_manager/utils", + ], +) diff --git a/contrib/endpoints/src/api_manager/mixer/mixer.cc b/contrib/endpoints/src/api_manager/mixer/mixer.cc new file mode 100644 index 00000000000..c770df1d631 --- /dev/null +++ b/contrib/endpoints/src/api_manager/mixer/mixer.cc @@ -0,0 +1,229 @@ +/* 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. + */ +#include "contrib/endpoints/src/api_manager/mixer/mixer.h" + +#include +#include "mixer/api/v1/service.pb.h" + +using ::google::api_manager::utils::Status; +using ::google::protobuf::util::error::Code; +using ::google::protobuf::Map; + +namespace google { +namespace api_manager { +namespace mixer { +namespace { + +enum AttributeIndex { + ATTR_SERVICE_NAME = 0, + ATTR_PEER_ID, + ATTR_OPERATION_NAME, + ATTR_API_KEY, + ATTR_RESPONSE_CODE, + ATTR_URL, + ATTR_LOCATION, + ATTR_API_NAME, + ATTR_API_VERSION, + ATTR_API_METHOD, + ATTR_REQUEST_SIZE, + ATTR_RESPONSE_SIZE, + ATTR_LOG_MESSAGE, +}; + +struct AttributeDict { + int index; + std::string name; +} kAttributeNames[] = { + { + ATTR_SERVICE_NAME, "serviceName", + }, + { + ATTR_PEER_ID, "peerId", + }, + { + ATTR_OPERATION_NAME, "operationName", + }, + { + ATTR_API_KEY, "apiKey", + }, + { + ATTR_RESPONSE_CODE, "responseCode", + }, + { + ATTR_URL, "URL", + }, + { + ATTR_LOCATION, "location", + }, + { + ATTR_API_NAME, "apiName", + }, + { + ATTR_API_VERSION, "apiVersion", + }, + { + ATTR_API_METHOD, "apiMethod", + }, + { + ATTR_REQUEST_SIZE, "requestSize", + }, + { + ATTR_RESPONSE_SIZE, "responesSize", + }, + { + ATTR_LOG_MESSAGE, "logMessage", + }, +}; + +void SetAttributeDict(Map* dict) { + for (auto attr : kAttributeNames) { + (*dict)[attr.index] = attr.name; + } +} + +void CovertToPb(const service_control::CheckRequestInfo& info, + const std::string& service_name, + ::istio::mixer::v1::Attributes* attr) { + SetAttributeDict(attr->mutable_dictionary()); + + auto* str_attrs = attr->mutable_string_attributes(); + (*str_attrs)[ATTR_SERVICE_NAME] = service_name; + (*str_attrs)[ATTR_PEER_ID] = "Proxy"; + (*str_attrs)[ATTR_OPERATION_NAME] = info.operation_name; + (*str_attrs)[ATTR_API_KEY] = info.api_key; +} + +void CovertToPb(const service_control::ReportRequestInfo& info, + const std::string& service_name, + ::istio::mixer::v1::Attributes* attr) { + SetAttributeDict(attr->mutable_dictionary()); + + auto* str_attrs = attr->mutable_string_attributes(); + (*str_attrs)[ATTR_SERVICE_NAME] = service_name; + (*str_attrs)[ATTR_PEER_ID] = "Proxy"; + (*str_attrs)[ATTR_OPERATION_NAME] = info.operation_name; + (*str_attrs)[ATTR_API_KEY] = info.api_key; + + (*str_attrs)[ATTR_URL] = info.url; + (*str_attrs)[ATTR_LOCATION] = info.location; + + (*str_attrs)[ATTR_API_NAME] = info.api_name; + (*str_attrs)[ATTR_API_VERSION] = info.api_version; + (*str_attrs)[ATTR_API_METHOD] = info.api_method; + + (*str_attrs)[ATTR_LOG_MESSAGE] = info.log_message; + + auto* int_attrs = attr->mutable_int64_attributes(); + (*int_attrs)[ATTR_RESPONSE_CODE] = info.response_code; + (*int_attrs)[ATTR_REQUEST_SIZE] = info.request_size; + (*int_attrs)[ATTR_RESPONSE_SIZE] = info.response_size; +} + +} // namespace + +Mixer::Mixer(ApiManagerEnvInterface* env, const std::string& service_name) + : env_(env), request_index_(0), service_name_(service_name) {} + +Mixer::~Mixer() {} + +Status Mixer::Init() { return Status::OK; } + +Status Mixer::Close() { return Status::OK; } + +Status Mixer::Report(const service_control::ReportRequestInfo& info) { + std::unique_ptr grpc_request(new GRPCRequest([this]( + Status status, std::string&& body) { + if (status.ok()) { + // Handle 200 response + ::istio::mixer::v1::ReportResponse response; + if (!response.ParseFromString(body)) { + status = + Status(Code::INVALID_ARGUMENT, std::string("Invalid response")); + env_->LogError(std::string("Failed parse report response: ") + body); + } + env_->LogInfo(std::string("Report response: ") + response.DebugString()); + } else { + env_->LogError(std::string("Failed to call Mixer::report, Error: ") + + status.ToString()); + } + })); + + ::istio::mixer::v1::ReportRequest request; + request.set_request_index(++request_index_); + CovertToPb(info, service_name_, request.mutable_attribute_update()); + env_->LogInfo(std::string("Send Report: ") + request.DebugString()); + + std::string request_body; + request.SerializeToString(&request_body); + + grpc_request->set_server("mixer_server") + .set_method("Report") + .set_body(request_body); + + env_->RunGRPCRequest(std::move(grpc_request)); + return Status::OK; +} + +void Mixer::Check( + const service_control::CheckRequestInfo& info, + cloud_trace::CloudTraceSpan* parent_span, + std::function + on_done) { + std::unique_ptr grpc_request(new GRPCRequest([this, on_done]( + Status status, std::string&& body) { + if (status.ok()) { + // Handle 200 response + ::istio::mixer::v1::CheckResponse response; + if (!response.ParseFromString(body)) { + status = + Status(Code::INVALID_ARGUMENT, std::string("Invalid response")); + env_->LogError(std::string("Failed parse check response: ") + body); + } + env_->LogInfo(std::string("Check response: ") + response.DebugString()); + } else { + env_->LogError(std::string("Failed to call Mixer::check, Error: ") + + status.ToString()); + } + service_control::CheckResponseInfo info; + on_done(status, info); + })); + + ::istio::mixer::v1::CheckRequest request; + request.set_request_index(++request_index_); + CovertToPb(info, service_name_, request.mutable_attribute_update()); + env_->LogInfo(std::string("Send Check: ") + request.DebugString()); + + std::string request_body; + request.SerializeToString(&request_body); + + grpc_request->set_server("mixer_server") + .set_method("Check") + .set_body(request_body); + + env_->RunGRPCRequest(std::move(grpc_request)); +} + +Status Mixer::GetStatistics(service_control::Statistics* esp_stat) const { + return Status::OK; +} + +service_control::Interface* Mixer::Create(ApiManagerEnvInterface* env, + const std::string& service_name) { + return new Mixer(env, service_name); +} + +} // namespace mixer +} // namespace api_manager +} // namespace google diff --git a/contrib/endpoints/src/api_manager/mixer/mixer.h b/contrib/endpoints/src/api_manager/mixer/mixer.h new file mode 100644 index 00000000000..5d4052cd152 --- /dev/null +++ b/contrib/endpoints/src/api_manager/mixer/mixer.h @@ -0,0 +1,63 @@ +/* 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. + */ +#ifndef API_MANAGER_MIXER_MIXER_H_ +#define API_MANAGER_MIXER_MIXER_H_ + +#include "contrib/endpoints/include/api_manager/env_interface.h" +#include "contrib/endpoints/src/api_manager/service_control/interface.h" + +namespace google { +namespace api_manager { +namespace mixer { + +// This implementation uses service-control-client-cxx module. +class Mixer : public service_control::Interface { + public: + static service_control::Interface* Create(ApiManagerEnvInterface* env, + const std::string& service_name); + + virtual ~Mixer(); + + virtual utils::Status Report(const service_control::ReportRequestInfo& info); + + virtual void Check( + const service_control::CheckRequestInfo& info, + cloud_trace::CloudTraceSpan* parent_span, + std::function + on_done); + + virtual utils::Status Init(); + virtual utils::Status Close(); + + virtual utils::Status GetStatistics(service_control::Statistics* stat) const; + + private: + // The constructor. + Mixer(ApiManagerEnvInterface* env, const std::string& service_name); + + // The Api Manager environment interface. + ApiManagerEnvInterface* env_; + int64_t request_index_; + + // The service name. + std::string service_name_; +}; + +} // namespace mixer +} // namespace api_manager +} // namespace google + +#endif // API_MANAGER_MIXER_MIXER_H_