Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions include/istio/control/http/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include "include/istio/control/http/request_handler.h"
#include "include/istio/mixerclient/client.h"
#include "include/istio/utils/attribute_names.h"
#include "include/istio/utils/local_attributes.h"
#include "mixer/v1/config/client/client_config.pb.h"

namespace istio {
Expand Down Expand Up @@ -69,8 +71,9 @@ class Controller {
// * some functions provided by the environment (Envoy)
// * optional service config cache size.
struct Options {
Options(const ::istio::mixer::v1::config::client::HttpClientConfig& config)
: config(config) {}
Options(const ::istio::mixer::v1::config::client::HttpClientConfig& config,
const ::istio::utils::LocalNode& local_node)
: config(config), local_node(local_node) {}

// Mixer filter config
const ::istio::mixer::v1::config::client::HttpClientConfig& config;
Expand All @@ -81,6 +84,8 @@ class Controller {
// The LRU cache size for service config.
// If not set or is 0 default value, the cache size is 1000.
int service_config_cache_size{};

const ::istio::utils::LocalNode local_node;
Comment thread
mandarjog marked this conversation as resolved.
Outdated
};

// The factory function to create a new instance of the controller.
Expand Down
1 change: 1 addition & 0 deletions include/istio/utils/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cc_library(
name = "headers_lib",
hdrs = [
"attributes_builder.h",
"local_attributes.h",
"md5.h",
"protobuf.h",
"status.h",
Expand Down
4 changes: 4 additions & 0 deletions include/istio/utils/attribute_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct AttributeName {
static const char kSourceUser[];
static const char kSourcePrincipal[];
static const char kSourceNamespace[];
static const char kSourceUID[];
static const char kDestinationPrincipal[];

static const char kRequestHeaders[];
Expand Down Expand Up @@ -63,6 +64,7 @@ struct AttributeName {
static const char kDestinationIp[];
static const char kDestinationPort[];
static const char kDestinationUID[];
static const char kDestinationNamespace[];
static const char kOriginIp[];
static const char kConnectionReceviedBytes[];
static const char kConnectionReceviedTotalBytes[];
Expand All @@ -77,8 +79,10 @@ struct AttributeName {

// Context attributes
static const char kContextProtocol[];
static const char kContextReporterKind[];
static const char kContextTime[];
static const char kContextProxyErrorCode[];
static const char kContextReporterUID[];

// Check error code and message.
static const char kCheckErrorCode[];
Expand Down
54 changes: 54 additions & 0 deletions include/istio/utils/local_attributes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Copyright 2018 Istio Authors. 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 ISTIO_UTILS_LOCAL_ATTRIBUTES_H
#define ISTIO_UTILS_LOCAL_ATTRIBUTES_H

#include "mixer/v1/attributes.pb.h"

using ::istio::mixer::v1::Attributes;
Comment thread
mandarjog marked this conversation as resolved.
Outdated

namespace istio {
namespace utils {

struct LocalAttributes {
LocalAttributes(const Attributes& inbound, const Attributes& outbound,
const Attributes& forward)
: inbound(inbound), outbound(outbound), forward(forward) {}

// local inbound attributes
const Attributes inbound;

// local outbound attributes
const Attributes outbound;

// local forward attributes
const Attributes forward;
};

// LocalNode are used to extract information from envoy Node.
struct LocalNode {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be nothing envoy specific under istio directory. Maybe get rid of this struct and just create LocalAttributes from envoy node in utils there?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LocalNode is a very portable concept. It has the few pieces of information that we need.
It is not evnoy specific.

std::string ns;
std::string ip;
std::string uid;
};

std::unique_ptr<const LocalAttributes> CreateLocalAttributes(
const LocalNode& local);

} // namespace utils
} // namespace istio

#endif // ISTIO_UTILS_LOCAL_ATTRIBUTES_H
12 changes: 10 additions & 2 deletions src/envoy/http/mixer/control.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@

#include "src/envoy/http/mixer/control.h"

using ::istio::mixer::v1::Attributes;
using ::istio::utils::LocalNode;

namespace Envoy {
namespace Http {
namespace Mixer {

Control::Control(const Config& config, Upstream::ClusterManager& cm,
Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Stats::Scope& scope,
Utils::MixerFilterStats& stats)
Utils::MixerFilterStats& stats,
const LocalInfo::LocalInfo& local_info)
: config_(config),
check_client_factory_(Utils::GrpcClientFactoryForCluster(
config_.check_cluster(), cm, scope)),
Expand All @@ -36,7 +40,11 @@ Control::Control(const Config& config, Upstream::ClusterManager& cm,
Utils::SerializeForwardedAttributes(config_.config_pb().transport(),
&serialized_forward_attributes_);

::istio::control::http::Controller::Options options(config_.config_pb());
LocalNode local_node;
Utils::Extract(local_info.node(), &local_node);

::istio::control::http::Controller::Options options(config_.config_pb(),
local_node);

Utils::CreateEnvironment(dispatcher, random, *check_client_factory_,
*report_client_factory_,
Expand Down
5 changes: 4 additions & 1 deletion src/envoy/http/mixer/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
#pragma once

#include "envoy/event/dispatcher.h"
#include "envoy/local_info/local_info.h"
#include "envoy/runtime/runtime.h"
#include "envoy/thread_local/thread_local.h"
#include "envoy/upstream/cluster_manager.h"
#include "include/istio/control/http/controller.h"
#include "include/istio/utils/local_attributes.h"
#include "src/envoy/http/mixer/config.h"
#include "src/envoy/utils/grpc_transport.h"
#include "src/envoy/utils/mixer_control.h"
Expand All @@ -35,7 +37,8 @@ class Control final : public ThreadLocal::ThreadLocalObject {
// The constructor.
Control(const Config& config, Upstream::ClusterManager& cm,
Event::Dispatcher& dispatcher, Runtime::RandomGenerator& random,
Stats::Scope& scope, Utils::MixerFilterStats& stats);
Stats::Scope& scope, Utils::MixerFilterStats& stats,
const LocalInfo::LocalInfo& local_info);

// Get low-level controller object.
::istio::control::http::Controller* controller() { return controller_.get(); }
Expand Down
14 changes: 9 additions & 5 deletions src/envoy/http/mixer/control_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#pragma once

#include "common/common/logger.h"
#include "envoy/local_info/local_info.h"
#include "src/envoy/http/mixer/control.h"
#include "src/envoy/utils/stats.h"

Expand All @@ -42,11 +43,14 @@ class ControlFactory : public Logger::Loggable<Logger::Id::config> {
Upstream::ClusterManager& cm = context.clusterManager();
Runtime::RandomGenerator& random = context.random();
Stats::Scope& scope = context.scope();
tls_->set([this, &cm, &random, &scope](Event::Dispatcher& dispatcher)
-> ThreadLocal::ThreadLocalObjectSharedPtr {
return std::make_shared<Control>(*config_, cm, dispatcher, random, scope,
stats_);
});
const LocalInfo::LocalInfo& local_info = context.localInfo();

tls_->set(
[this, &cm, &random, &scope, &local_info](Event::Dispatcher& dispatcher)
-> ThreadLocal::ThreadLocalObjectSharedPtr {
return std::make_shared<Control>(*config_, cm, dispatcher, random,
scope, stats_, local_info);
});
}

Control& control() { return tls_->getTyped<Control>(); }
Expand Down
13 changes: 12 additions & 1 deletion src/envoy/utils/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "mixer_control_test",
srcs = [
"mixer_control_test.cc",
],
repository = "@envoy",
deps = [
":utils_lib",
"@envoy//test/test_common:utility_lib",
],
)

cc_library(
name = "filter_names_lib",
Expand All @@ -103,4 +114,4 @@ cc_library(
"filter_names.h",
],
visibility = ["//visibility:public"],
)
)
74 changes: 74 additions & 0 deletions src/envoy/utils/mixer_control.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@
#include "src/envoy/utils/grpc_transport.h"

using ::istio::mixerclient::Statistics;
using ::istio::utils::AttributeName;
using ::istio::utils::LocalAttributes;
using ::istio::utils::LocalNode;

namespace Envoy {
namespace Utils {

const char NodeKey::kName[] = "NODE_NAME";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just have UID and namespace? We don't know fully qualified UID yet, not until multi-cluster support lands in Mixer. Until then, we should treat UID as opaque, and not assume it include kubernetes:// and only has two parts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed string processing from code.

const char NodeKey::kNamespace[] = "NODE_NAMESPACE";
const char NodeKey::kIp[] = "NODE_IP";
const char NodeKey::kRegistry[] = "NODE_REGISTRY";

namespace {

// A class to wrap envoy timer for mixer client timer.
Expand Down Expand Up @@ -100,5 +109,70 @@ Grpc::AsyncClientFactoryPtr GrpcClientFactoryForCluster(
return std::make_unique<EnvoyGrpcAsyncClientFactory>(cm, service);
}

// This function is for compatibility with existing node ids.
// "sidecar~10.36.0.15~fortioclient-84469dc8d7-jbbxt.service-graph~service-graph.svc.cluster.local"
// --> {proxy_type}~{ip}~{node_name}.{node_ns}~{node_domain}
bool ExtractInfoCompat(const std::string &nodeid, LocalNode *args) {
auto parts = StringUtil::splitToken(nodeid, "~");
if (parts.size() < 3) {
GOOGLE_LOG(ERROR) << "ExtractInfoCompat error len(nodeid.split(~))<3: "
<< nodeid;
return false;
}

auto ip = std::string(parts[1].begin(), parts[1].end());
auto longname = std::string(parts[2].begin(), parts[2].end());
auto names = StringUtil::splitToken(longname, ".");
if (names.size() < 2) {
GOOGLE_LOG(ERROR)
<< "ExtractInfoCompat error len(split(longname, '.')) < 3: "
<< longname;
return false;
}
auto ns = std::string(names[1].begin(), names[1].end());

args->ip = ip;
args->ns = ns;
args->uid = "kubernetes://" + longname;

return true;
}

// ExtractInfo depends on NODE_NAME, NODE_NAMESPACE, NODE_IP and optional
// NODE_REG If work cannot be done, returns false.
bool ExtractInfo(const envoy::api::v2::core::Node &node, LocalNode *args) {
const auto meta = node.metadata().fields();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check

if node.has_metadata() first

or

if node.metadata().fields().empty()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

std::string name;
if (!ReadMap(meta, NodeKey::kName, &name)) {
GOOGLE_LOG(ERROR) << "ExtractInfo metadata missing " << NodeKey::kName
<< " " << node.metadata().DebugString();
return false;
}
std::string ns;
ReadMap(meta, NodeKey::kNamespace, &ns);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check return value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


std::string ip;
ReadMap(meta, NodeKey::kIp, &ip);

std::string reg("kubernetes");
ReadMap(meta, NodeKey::kRegistry, &reg);

args->ip = ip;
args->ns = ns;
args->uid = reg + "://" + name + "." + ns;

return true;
}

bool Extract(const envoy::api::v2::core::Node &node, LocalNode *args) {
if (ExtractInfo(node, args)) {
return true;
}
if (ExtractInfoCompat(node.id(), args)) {
return true;
}
return false;
}

} // namespace Utils
} // namespace Envoy
41 changes: 41 additions & 0 deletions src/envoy/utils/mixer_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@
#pragma once

#include "envoy/event/dispatcher.h"
#include "envoy/local_info/local_info.h"
#include "envoy/runtime/runtime.h"
#include "envoy/upstream/cluster_manager.h"
#include "include/istio/mixerclient/client.h"
#include "include/istio/utils/attribute_names.h"
#include "include/istio/utils/local_attributes.h"
#include "src/envoy/utils/config.h"

using ::istio::mixer::v1::Attributes;
using ::istio::mixer::v1::Attributes_AttributeValue;
using ::istio::utils::LocalAttributes;
using ::istio::utils::LocalNode;

namespace Envoy {
namespace Utils {
Expand All @@ -42,5 +48,40 @@ Grpc::AsyncClientFactoryPtr GrpcClientFactoryForCluster(
const std::string &cluster_name, Upstream::ClusterManager &cm,
Stats::Scope &scope);

std::unique_ptr<const LocalAttributes> CreateLocalAttributes(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you expect these functions to be used by multiple places? if no, just one place, please just move code to that place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is left there erroneously. Removed.

const LocalNode &local);

bool Extract(const envoy::api::v2::core::Node &node, LocalNode *args);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtractNodeInfo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


inline bool ReadMap(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a correct use of metadata in envoy. It assumes that the key is some filter ID, and the list of values is inside the struct value. Take a look at source/common/config/metadata.cc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node metadata is actually google.protobuf.struct and it does not assume anything about a filter. This is too high level.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you suggesting that this should be nested inside Mixer ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, yes, I assumed node proto is filter-aware. This is fine.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadProtoMap

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

const google::protobuf::Map<std::string, google::protobuf::Value> &meta,
const std::string &key, std::string *val) {
const auto it = meta.find(key);
if (it != meta.end()) {
*val = it->second.string_value();
return true;
}
return false;
}

inline bool ReadMap(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadAttributeMap

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

const google::protobuf::Map<std::string, Attributes_AttributeValue> &meta,
const std::string &key, std::string *val) {
const auto it = meta.find(key);
if (it != meta.end()) {
*val = it->second.string_value();
return true;
}
return false;
}

// NodeKey are node matadata keys that are expected to be set.
struct NodeKey {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a proto that is extracted from metadata for mixer filter (filter ID "mixer").

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that these names are not shared by many places. If so, just defined inside .cc file and inside anonymous namespace

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved it to .cc file.

static const char kName[];
static const char kNamespace[];
static const char kIp[];
static const char kRegistry[];
};

} // namespace Utils
} // namespace Envoy
Loading