Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adaptive Load command line client #616

Merged
merged 79 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
8ea442d
Merge pull request #5 from envoyproxy/master
eric846 Jun 1, 2020
5ac755a
Merge pull request #6 from envoyproxy/master
eric846 Jun 28, 2020
b8c25a5
Merge pull request #7 from envoyproxy/master
eric846 Jul 7, 2020
1c19c68
initial commit
eric846 Jul 9, 2020
7050686
fix comments
eric846 Jul 9, 2020
0776563
fix format
eric846 Jul 9, 2020
16fd8f6
rename adaptive_rps to adaptive_load
eric846 Jul 10, 2020
c383010
add field_selector in example
eric846 Jul 10, 2020
6e1a483
fix example comment
eric846 Jul 10, 2020
4ef1140
fix format
eric846 Jul 10, 2020
4111bf4
add support for fault injection headers
eric846 Jul 10, 2020
871a959
replace linear and binary search with exponential search
eric846 Jul 10, 2020
1fd77c1
add InputVariableSetter mechanism
eric846 Jul 11, 2020
edc36b2
add input variable setter to build file
eric846 Jul 11, 2020
4d0364e
fix syntax errors
eric846 Jul 11, 2020
aed6d94
rename samples/adaptive_rps
eric846 Jul 11, 2020
d9ae87d
improve comments, change step controller initial value from int64 to …
eric846 Jul 12, 2020
a05a6f5
add proto validation rules, fix comments, make rps the default input_…
eric846 Jul 13, 2020
8cd4d21
fix comment wording
eric846 Jul 13, 2020
d814a96
simplify protos, add defaults, specify required or optional
eric846 Jul 14, 2020
5f5a885
add missing newline
eric846 Jul 14, 2020
7e20a78
Kick CI
eric846 Jul 14, 2020
9048267
simplify protos
eric846 Jul 15, 2020
306c0ec
fix format
eric846 Jul 15, 2020
d33f543
fix some optional field comments and rules
eric846 Jul 15, 2020
442cca9
Merge pull request #10 from envoyproxy/master
eric846 Jul 16, 2020
677b783
add Nighthawk status field in BenchmarkResult as nested nighthawk.cli…
eric846 Jul 19, 2020
cefb366
switch to standard Envoy plugin config proto, add prefix to internal …
eric846 Jul 22, 2020
f3684df
Merge remote-tracking branch 'upstream/master' into adaptive-rps-protos2
eric846 Jul 22, 2020
5463051
create headers
eric846 Jul 22, 2020
46e0e25
fix format
eric846 Jul 22, 2020
f634642
use docstring format
eric846 Jul 22, 2020
3c39faa
fix typos in comments
eric846 Jul 23, 2020
b9c8f2b
split build target, get rid of ostream, change InputValueSetter to us…
eric846 Jul 24, 2020
5fc4db4
remove nested namespace, remove redundant _include in target names
eric846 Jul 26, 2020
64e7852
merge from upstream
eric846 Jul 29, 2020
12807f1
Merge remote-tracking branch 'upstream/master' into adaptive-rps-headers
eric846 Jul 29, 2020
e8e960f
merge from upstream
eric846 Aug 27, 2020
6306b4e
Merge remote-tracking branch 'upstream/master' into master2
eric846 Aug 27, 2020
1ece783
Merge remote-tracking branch 'upstream/master' into master2
eric846 Aug 28, 2020
70705e9
Merge remote-tracking branch 'upstream/master' into master2
eric846 Aug 31, 2020
e576bc1
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 1, 2020
1fca528
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 3, 2020
ed32856
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 3, 2020
eecf00d
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 8, 2020
13179fb
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 10, 2020
3eb89e6
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 11, 2020
fae60ad
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 12, 2020
9fec200
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 14, 2020
9d1cf53
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 15, 2020
cfad844
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 19, 2020
bdde910
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 22, 2020
8100376
Merge remote-tracking branch 'upstream/master' into master2
eric846 Sep 28, 2020
694fda6
Merge remote-tracking branch 'upstream/master' into master2
eric846 Dec 29, 2020
1df6137
Merge remote-tracking branch 'upstream/main'
eric846 Jan 21, 2021
2b9e1e8
Merge remote-tracking branch 'upstream/main'
eric846 Jan 26, 2021
a6da150
Merge remote-tracking branch 'upstream/main'
eric846 Feb 3, 2021
f19768f
initial commit - mock adaptive load controller
eric846 Feb 3, 2021
60fb398
initial commit - adaptive load cli
eric846 Feb 3, 2021
d9771ce
restore nighthawk.code-workspace
eric846 Feb 3, 2021
bcc77f4
remove nighthawk.code-workspace whitespace diff
eric846 Feb 3, 2021
264a84d
remove commented-out lines and extraneous deps
eric846 Feb 3, 2021
9b6d002
add trailing newline, remove unneeded NOLINT
eric846 Feb 3, 2021
f4ddcc4
improve coverage on file errors, add comments
eric846 Feb 3, 2021
c2b86a4
remove redundant deps
eric846 Feb 4, 2021
8ab3c97
remove commented-out deps
eric846 Feb 4, 2021
06bcf78
add missing version_linkstamp dep
eric846 Feb 4, 2021
9465d64
fix format
eric846 Feb 4, 2021
4b8ba84
Merge remote-tracking branch 'upstream/main'
eric846 Feb 4, 2021
15817da
Merge branch 'main' into adaptive-rps-cli
eric846 Feb 4, 2021
f69619f
try to work around integration test failure
eric846 Feb 4, 2021
99c04d3
try not testing ECDHE-RSA-CHACHA20-POLY1305
eric846 Feb 4, 2021
77a4ced
fix format
eric846 Feb 4, 2021
975c9de
remove integration test troubleshooting changes
eric846 Feb 5, 2021
1417e02
replace localhost with 127.0.0.1, improve comment in sample adaptive …
eric846 Feb 5, 2021
eaa20de
Merge remote-tracking branch 'upstream/main'
eric846 Feb 11, 2021
11a9161
fix typo
eric846 Feb 11, 2021
3fa6439
Merge branch 'main' into adaptive-rps-cli
eric846 Feb 11, 2021
45dade9
apply typo fix in unit test
eric846 Feb 11, 2021
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: 9 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@ envoy_package()
filegroup(
name = "nighthawk",
srcs = [
":nighthawk_adaptive_load_client",
":nighthawk_client",
":nighthawk_output_transform",
":nighthawk_service",
":nighthawk_test_server",
],
)

envoy_cc_binary(
name = "nighthawk_adaptive_load_client",
repository = "@envoy",
deps = [
"//source/exe:adaptive_load_client_entry_lib",
],
)

envoy_cc_binary(
name = "nighthawk_client",
repository = "@envoy",
Expand Down
2 changes: 1 addition & 1 deletion api/adaptive_load/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ api_cc_py_proto_library(
],
visibility = ["//visibility:public"],
deps = [
"//api/client:base",
"@envoy_api//envoy/config/core/v3:pkg",
"@nighthawk//api/client:base",
],
)
29 changes: 29 additions & 0 deletions source/adaptive_load/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,35 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "adaptive_load_client_main",
srcs = [
"adaptive_load_client_main.cc",
],
hdrs = [
"adaptive_load_client_main.h",
],
repository = "@envoy",
visibility = ["//visibility:public"],
deps = [
":adaptive_load_controller_impl",
":config_validator_impl",
":input_variable_setter_impl",
":metrics_evaluator_impl",
":metrics_plugin_impl",
":scoring_function_impl",
":session_spec_proto_helper_impl",
":step_controller_impl",
"//api/client:base_cc_proto",
"//api/client:grpc_service_lib",
"//source/common:nighthawk_common_lib",
"@envoy//source/common/common:assert_lib_with_external_headers",
"@envoy//source/common/common:minimal_logger_lib_with_external_headers",
"@envoy//source/common/event:real_time_system_lib_with_external_headers",
"@envoy//source/common/grpc:google_grpc_utils_lib_with_external_headers",
],
)

envoy_cc_library(
name = "config_validator_impl",
srcs = [
Expand Down
137 changes: 137 additions & 0 deletions source/adaptive_load/adaptive_load_client_main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include "adaptive_load/adaptive_load_client_main.h"

#include <cstring>
#include <memory>
#include <string>
#include <utility>

#include "envoy/common/exception.h"

#include "nighthawk/adaptive_load/adaptive_load_controller.h"
#include "nighthawk/common/exception.h"

#include "external/envoy/source/common/grpc/google_grpc_utils.h"
#include "external/envoy/source/common/protobuf/protobuf.h"

#include "api/adaptive_load/adaptive_load.pb.h"
#include "api/client/service.grpc.pb.h"
#include "api/client/service.pb.h"

#include "common/utility.h"
#include "common/version_info.h"

#include "fmt/ranges.h"
#include "google/rpc/status.pb.h"
#include "tclap/CmdLine.h"

namespace Nighthawk {

namespace {

/**
* Writes a string to a file.
*
* @param filesystem Envoy abstraction around filesystem functions, to facilitate unit testing.
* @param path Relative or absolute path to the file to write.
* @param contents String to write to the file.
*
* @throw Nighthawk::NighthawkException For any filesystem error.
*/
void WriteFileOrThrow(Envoy::Filesystem::Instance& filesystem, absl::string_view path,
absl::string_view contents) {
Envoy::Filesystem::FilePtr file = filesystem.createFile(std::string(path));
const Envoy::Api::IoCallBoolResult open_result =
file->open(((1 << Envoy::Filesystem::File::Operation::Write)) |
(1 << (Envoy::Filesystem::File::Operation::Create)));
if (!open_result.ok()) {
throw Nighthawk::NighthawkException(absl::StrCat("Unable to open output file \"", path,
"\": ", open_result.err_->getErrorDetails()));
}
const Envoy::Api::IoCallSizeResult write_result = file->write(contents);
if (!write_result.ok()) {
throw Nighthawk::NighthawkException(absl::StrCat("Unable to write to output file \"", path,
"\": ", write_result.err_->getErrorDetails()));
}
const Envoy::Api::IoCallBoolResult close_result = file->close();
if (!close_result.ok()) {
throw Nighthawk::NighthawkException(absl::StrCat("Unable to close output file \"", path,
"\": ", close_result.err_->getErrorDetails()));
}
}

} // namespace

AdaptiveLoadClientMain::AdaptiveLoadClientMain(int argc, const char* const* argv,
AdaptiveLoadController& controller,
Envoy::Filesystem::Instance& filesystem)
: controller_{controller}, filesystem_{filesystem} {
TCLAP::CmdLine cmd("Adaptive Load tool that finds the optimal load on the target "
"through a series of Nighthawk Service benchmarks.",
/*delimiter=*/' ', VersionInfo::version());

TCLAP::ValueArg<std::string> nighthawk_service_address(
/*flag_name=*/"", "nighthawk-service-address",
"host:port for Nighthawk Service. To enable TLS, set --use-tls.",
/*required=*/false, "localhost:8443", "string", cmd);
TCLAP::SwitchArg use_tls(
/*flag_name=*/"", "use-tls",
"Use TLS for the gRPC connection from this program to the Nighthawk Service. Set environment "
"variable GRPC_DEFAULT_SSL_ROOTS_FILE_PATH to override the default root certificates.",
cmd);
TCLAP::ValueArg<std::string> spec_filename(
/*flag_name=*/"", "spec-file",
"Path to a textproto file describing the adaptive load session "
"(nighthawk::adaptive_load::AdaptiveLoadSessionSpec).",
/*required=*/true, /*default_value=*/"", "string", cmd);
TCLAP::ValueArg<std::string> output_filename(
/*flag_name=*/"", "output-file",
"Path to write adaptive load session output textproto "
"(nighthawk::adaptive_load::AdaptiveLoadSessionOutput).",
/*required=*/true, /*default_value=*/"", "string", cmd);

Nighthawk::Utility::parseCommand(cmd, argc, argv);

nighthawk_service_address_ = nighthawk_service_address.getValue();
use_tls_ = use_tls.getValue();
spec_filename_ = spec_filename.getValue();
output_filename_ = output_filename.getValue();
}

uint32_t AdaptiveLoadClientMain::Run() {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we file a future bug to enable some dependency injection of the channel here? in the future, people might want to enable other ways of connecting to the nighthawk service besides the two provided here. but we don't need to prematurely allow for that case until we have a specific usecase.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed #626.

ENVOY_LOG(info, "Attempting adaptive load session: {}", DescribeInputs());
std::string spec_textproto;
try {
spec_textproto = filesystem_.fileReadToEnd(spec_filename_);
} catch (const Envoy::EnvoyException& e) {
throw Nighthawk::NighthawkException("Failed to read spec textproto file \"" + spec_filename_ +
"\": " + e.what());
}
nighthawk::adaptive_load::AdaptiveLoadSessionSpec spec;
if (!Envoy::Protobuf::TextFormat::ParseFromString(spec_textproto, &spec)) {
throw Nighthawk::NighthawkException("Unable to parse file \"" + spec_filename_ +
"\" as a text protobuf (type " + spec.GetTypeName() + ")");
}
std::shared_ptr<::grpc::Channel> channel = grpc::CreateChannel(
nighthawk_service_address_, use_tls_ ? grpc::SslCredentials(grpc::SslCredentialsOptions())
: grpc::InsecureChannelCredentials());
std::unique_ptr<nighthawk::client::NighthawkService::StubInterface> stub(
nighthawk::client::NighthawkService::NewStub(channel));

absl::StatusOr<nighthawk::adaptive_load::AdaptiveLoadSessionOutput> output_or =
controller_.PerformAdaptiveLoadSession(stub.get(), spec);
if (!output_or.ok()) {
ENVOY_LOG(error, "Error in adaptive load session: {}", output_or.status().message());
return 1;
}
nighthawk::adaptive_load::AdaptiveLoadSessionOutput output = output_or.value();
WriteFileOrThrow(filesystem_, output_filename_, output.DebugString());
return 0;
}

std::string AdaptiveLoadClientMain::DescribeInputs() {
return "Nighthawk Service " + nighthawk_service_address_ + " using " +
(use_tls_ ? "TLS" : "insecure") + " connection, input file: " + spec_filename_ +
", output file: " + output_filename_;
}

} // namespace Nighthawk
55 changes: 55 additions & 0 deletions source/adaptive_load/adaptive_load_client_main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include "envoy/common/time.h"
#include "envoy/filesystem/filesystem.h"

#include "nighthawk/adaptive_load/adaptive_load_controller.h"

#include "external/envoy/source/common/common/logger.h"

namespace Nighthawk {

/**
* Main implementation of the CLI wrapper around the adaptive load controller library.
* Parses command line options, reads adaptive load session spec proto from a file,
* runs an adaptive load session, and writes the output proto to a file.
*/
class AdaptiveLoadClientMain : public Envoy::Logger::Loggable<Envoy::Logger::Id::main> {
public:
/**
* Parses the command line arguments to class members.
*
* @param argc Standard argc passed through from the exe entry point.
* @param argv Standard argv passed through from the exe entry point.
* @param controller Adaptive load controller, passed in to allow unit testing of this class.
* @param filesystem Abstraction of the filesystem, passed in to allow unit testing of this
* class.
*
* @throw Nighthawk::Client::MalformedArgvException If command line constraints are violated.
*/
AdaptiveLoadClientMain(int argc, const char* const* argv, AdaptiveLoadController& controller,
Envoy::Filesystem::Instance& filesystem);
/**
* Loads the adaptive load session spec proto from a file, runs an adaptive load session, and
* writes the output proto to a file. File paths are taken from class members initialized in the
* constructor.
*
* @return Exit code for this process.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we state that 0 is good or is that implicit?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a standard in linux, so we can rely on that understanding. https://linuxize.com/post/bash-exit/#exit-status

* @throw Nighthawk::NighthawkException If a file read or write error occurs.
*/
uint32_t Run();
/**
* Describes the program inputs as parsed from the command line.
*/
std::string DescribeInputs();

private:
std::string nighthawk_service_address_;
bool use_tls_;
std::string spec_filename_;
std::string output_filename_;
AdaptiveLoadController& controller_;
Envoy::Filesystem::Instance& filesystem_;
};

} // namespace Nighthawk
17 changes: 17 additions & 0 deletions source/exe/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ licenses(["notice"]) # Apache 2

envoy_package()

envoy_cc_library(
name = "adaptive_load_client_entry_lib",
srcs = ["adaptive_load_client_main_entry.cc"],
external_deps = [
"abseil_symbolize",
],
repository = "@envoy",
visibility = ["//visibility:public"],
deps = [
"//source/adaptive_load:adaptive_load_client_main",
"//source/common:nighthawk_service_client_impl",
"//source/common:version_linkstamp",
"@envoy//source/exe:platform_header_lib_with_external_headers",
"@envoy//source/exe:platform_impl_lib",
],
)

envoy_cc_library(
name = "nighthawk_client_entry_lib",
srcs = ["client_main_entry.cc"],
Expand Down
45 changes: 45 additions & 0 deletions source/exe/adaptive_load_client_main_entry.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Command line adaptive load controller driving a Nighthawk Service.
#include <iostream>

#include "nighthawk/common/exception.h"

#include "external/envoy/source/common/event/real_time_system.h"
#include "external/envoy/source/exe/platform_impl.h"

#include "common/nighthawk_service_client_impl.h"

#include "absl/debugging/symbolize.h"
#include "adaptive_load/adaptive_load_client_main.h"
#include "adaptive_load/adaptive_load_controller_impl.h"
#include "adaptive_load/metrics_evaluator_impl.h"
#include "adaptive_load/session_spec_proto_helper_impl.h"

// NOLINT(namespace-nighthawk)

int main(int argc, char* argv[]) {
#ifndef __APPLE__
// absl::Symbolize mostly works without this, but this improves corner case
// handling, such as running in a chroot jail.
absl::InitializeSymbolizer(argv[0]);
#endif
Nighthawk::NighthawkServiceClientImpl nighthawk_service_client;
Nighthawk::MetricsEvaluatorImpl metrics_evaluator;
Nighthawk::AdaptiveLoadSessionSpecProtoHelperImpl spec_proto_helper;
Envoy::Event::RealTimeSystem time_system; // NO_CHECK_FORMAT(real_time)
Nighthawk::AdaptiveLoadControllerImpl controller(nighthawk_service_client, metrics_evaluator,
spec_proto_helper, time_system);
Envoy::PlatformImpl platform_impl;
try {
Nighthawk::AdaptiveLoadClientMain program(argc, argv, controller, platform_impl.fileSystem());
return program.Run();
} catch (const Nighthawk::Client::NoServingException& e) {
return EXIT_SUCCESS;
} catch (const Nighthawk::Client::MalformedArgvException& e) {
std::cerr << "Invalid args: " << e.what() << std::endl;
return EXIT_FAILURE;
} catch (const Nighthawk::NighthawkException& e) {
std::cerr << "Failure: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return 0;
}
22 changes: 22 additions & 0 deletions test/adaptive_load/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,28 @@ envoy_cc_test_library(
],
)

envoy_cc_test(
name = "adaptive_load_client_main_test",
srcs = ["adaptive_load_client_main_test.cc"],
data = [
"test_data/golden_output.textproto",
"test_data/invalid_session_spec.textproto",
"test_data/valid_session_spec.textproto",
],
repository = "@envoy",
deps = [
":minimal_output",
"//include/nighthawk/adaptive_load:adaptive_load_controller",
"//source/adaptive_load:adaptive_load_client_main",
"//test/mocks/adaptive_load:mock_adaptive_load_controller",
"//test/test_common:environment_lib",
"@com_github_grpc_grpc//:grpc++_test",
"@envoy//source/common/protobuf:utility_lib_with_external_headers",
"@envoy//test/mocks/filesystem:filesystem_mocks",
"@envoy//test/test_common:utility_lib",
],
)

envoy_cc_test(
name = "adaptive_load_controller_test",
srcs = ["adaptive_load_controller_test.cc"],
Expand Down
Loading