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

Add application config serializer #459

Merged
merged 9 commits into from
Jan 14, 2020
Merged
Show file tree
Hide file tree
Changes from 8 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
17 changes: 16 additions & 1 deletion oak/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.
#

load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")

package(
licenses = ["notice"],
Expand Down Expand Up @@ -43,6 +43,7 @@ cc_library(
hdrs = ["app_config.h"],
visibility = ["//visibility:public"],
deps = [
"//oak/common:utils",
"//oak/proto:manager_cc_proto",
"@com_google_absl//absl/memory",
"@com_google_asylo//asylo/util:logging",
Expand Down Expand Up @@ -93,9 +94,23 @@ cc_library(

cc_library(
name = "utils",
srcs = ["utils.cc"],
hdrs = ["utils.h"],
visibility = ["//visibility:public"],
deps = [
"@com_google_asylo//asylo/util:logging",
],
)

cc_binary(
name = "app_config_serializer",
srcs = ["app_config_serializer.cc"],
visibility = ["//visibility:public"],
deps = [
"//oak/common:app_config",
"//oak/common:utils",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@com_google_asylo//asylo/util:logging",
],
)
15 changes: 15 additions & 0 deletions oak/common/app_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include "oak/common/app_config.h"
#include "oak/common/utils.h"

#include <set>
#include <utility>
Expand Down Expand Up @@ -45,6 +46,20 @@ std::unique_ptr<ApplicationConfiguration> DefaultConfig(const std::string& modul
return config;
}

std::unique_ptr<ApplicationConfiguration> ReadConfigFromFile(const std::string& filename) {
auto config = absl::make_unique<ApplicationConfiguration>();

std::string data = utils::read_file(filename);
config->ParseFromString(data);

return config;
}

void WriteConfigToFile(const ApplicationConfiguration* config, const std::string& filename) {
std::string data = config->SerializeAsString();
utils::write_file(data, filename);
}

void AddLoggingToConfig(ApplicationConfiguration* config) {
NodeConfiguration* node_config = config->add_node_configs();
node_config->set_name(kLogConfigName);
Expand Down
6 changes: 6 additions & 0 deletions oak/common/app_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ namespace oak {
// name and contents, accessible via gRPC.
std::unique_ptr<ApplicationConfiguration> DefaultConfig(const std::string& module_bytes);

// Reads a serialized application configuration from file.
std::unique_ptr<ApplicationConfiguration> ReadConfigFromFile(const std::string& filename);

// Serializes an application configuration from `config` and writes it into a file.
void WriteConfigToFile(const ApplicationConfiguration* config, const std::string& filename);

// Modify application configuration to make logging available.
void AddLoggingToConfig(ApplicationConfiguration* config);

Expand Down
65 changes: 65 additions & 0 deletions oak/common/app_config_serializer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2020 The Project Oak Authors
*
* 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 <memory>
#include <string>

#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "asylo/util/logging.h"
#include "oak/common/app_config.h"
#include "oak/common/utils.h"

ABSL_FLAG(std::string, module, "", "File containing the compiled WebAssembly module");
ipetr0v marked this conversation as resolved.
Show resolved Hide resolved
ABSL_FLAG(bool, logging, false, "Enable application logging");
ABSL_FLAG(std::string, storage_address, "127.0.0.1:7867",
"Address ot the storage provider to connect to");
ABSL_FLAG(int, grpc_port, 8080, "Port for the Application to listen on");
ipetr0v marked this conversation as resolved.
Show resolved Hide resolved
ABSL_FLAG(std::string, output_file, "", "File to write an application configuration to");

int main(int argc, char* argv[]) {
absl::ParseCommandLine(argc, argv);

std::string output_file = absl::GetFlag(FLAGS_output_file);
if (output_file.empty()) {
LOG(QFATAL) << "Output file is not specified";
return 1;
}

// Create an application configuration.
std::string module_bytes = oak::utils::read_file(absl::GetFlag(FLAGS_module));
std::unique_ptr<oak::ApplicationConfiguration> application_config =
oak::DefaultConfig(module_bytes);

// Set application configuration parameters.
if (absl::GetFlag(FLAGS_logging)) {
oak::AddLoggingToConfig(application_config.get());
}
std::string storage_address = absl::GetFlag(FLAGS_storage_address);
if (!storage_address.empty()) {
oak::AddStorageToConfig(application_config.get(), storage_address);
}
oak::AddGrpcPortToConfig(application_config.get(), absl::GetFlag(FLAGS_grpc_port));

if (ValidApplicationConfig(application_config.get())) {
oak::WriteConfigToFile(application_config.get(), output_file);
} else {
LOG(QFATAL) << "Incorrect application configuration";
return 1;
}
ipetr0v marked this conversation as resolved.
Show resolved Hide resolved

return 0;
}
67 changes: 44 additions & 23 deletions oak/common/app_config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,48 @@ namespace oak {

namespace {

std::unique_ptr<ApplicationConfiguration> ConfigFrom(const std::string& filename) {
std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary);
EXPECT_TRUE(ifs.is_open()) << "failed to open " << filename;
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();

auto config = absl::make_unique<ApplicationConfiguration>();
google::protobuf::TextFormat::MergeFromString(ss.str(), config.get());
return config;
}

} // namespace

TEST(ApplicationConfiguration, Default) {
// Fixture class for testing `ApplicationConfiguration` correctness.
class ApplicationConfigurationTest : public ::testing::Test {
protected:
void TearDown() override {
// Clean up temporary files.
std::remove(kTmpFilename.c_str());
}

std::unique_ptr<ApplicationConfiguration> ConfigFrom(const std::string& filename) {
std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary);
EXPECT_TRUE(ifs.is_open()) << "failed to open " << filename;
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();

auto config = absl::make_unique<ApplicationConfiguration>();
google::protobuf::TextFormat::MergeFromString(ss.str(), config.get());
return config;
}

const std::string kTmpFilename = "oak/common/testdata/tmp.bin";
};

TEST_F(ApplicationConfigurationTest, Default) {
std::unique_ptr<ApplicationConfiguration> got = DefaultConfig("<bytes>");
std::unique_ptr<ApplicationConfiguration> want =
ConfigFrom("oak/common/testdata/barenode.textproto");
ASSERT_EQ(want->DebugString(), got->DebugString());
ASSERT_EQ(true, ValidApplicationConfig(*got));
}

TEST(ApplicationConfiguration, DefaultPlusLogging) {
TEST_F(ApplicationConfigurationTest, ReadWriteFile) {
std::ifstream existing_file(kTmpFilename, std::ifstream::in);
ASSERT_FALSE(existing_file.is_open());
std::unique_ptr<ApplicationConfiguration> want = DefaultConfig("<bytes>");
WriteConfigToFile(want.get(), kTmpFilename);
std::unique_ptr<ApplicationConfiguration> got = ReadConfigFromFile(kTmpFilename);
ASSERT_EQ(want->DebugString(), got->DebugString());
ASSERT_EQ(true, ValidApplicationConfig(*got));
}

TEST_F(ApplicationConfigurationTest, DefaultPlusLogging) {
std::unique_ptr<ApplicationConfiguration> got = DefaultConfig("<bytes>");
AddLoggingToConfig(got.get());
std::unique_ptr<ApplicationConfiguration> want =
Expand All @@ -58,7 +77,7 @@ TEST(ApplicationConfiguration, DefaultPlusLogging) {
ASSERT_EQ(true, ValidApplicationConfig(*got));
}

TEST(ApplicationConfiguration, DefaultPlusStorage) {
TEST_F(ApplicationConfigurationTest, DefaultPlusStorage) {
std::unique_ptr<ApplicationConfiguration> got = DefaultConfig("<bytes>");
AddStorageToConfig(got.get(), "localhost:8888");
std::unique_ptr<ApplicationConfiguration> want =
Expand All @@ -67,7 +86,7 @@ TEST(ApplicationConfiguration, DefaultPlusStorage) {
ASSERT_EQ(true, ValidApplicationConfig(*got));
}

TEST(ApplicationConfiguration, DefaultPlusGrpcPort) {
TEST_F(ApplicationConfigurationTest, DefaultPlusGrpcPort) {
std::unique_ptr<ApplicationConfiguration> got = DefaultConfig("<bytes>");
AddGrpcPortToConfig(got.get(), 8080);
std::unique_ptr<ApplicationConfiguration> want =
Expand All @@ -76,30 +95,32 @@ TEST(ApplicationConfiguration, DefaultPlusGrpcPort) {
ASSERT_EQ(true, ValidApplicationConfig(*got));
}

TEST(ApplicationConfiguration, Valid) {
TEST_F(ApplicationConfigurationTest, Valid) {
auto config = ConfigFrom("oak/common/testdata/default.textproto");
ASSERT_EQ(true, ValidApplicationConfig(*config));
}

TEST(ApplicationConfiguration, DuplicateConfigName) {
TEST_F(ApplicationConfigurationTest, DuplicateConfigName) {
auto config = ConfigFrom("oak/common/testdata/dup_config_name.textproto");
ASSERT_EQ(false, ValidApplicationConfig(*config));
}

TEST(ApplicationConfiguration, MultipleLogNodes) {
TEST_F(ApplicationConfigurationTest, MultipleLogNodes) {
// Two log configs are OK.
auto config = ConfigFrom("oak/common/testdata/two_log.textproto");
ASSERT_EQ(true, ValidApplicationConfig(*config));
}

TEST(ApplicationConfiguration, NonWasmCode) {
TEST_F(ApplicationConfigurationTest, NonWasmCode) {
auto config = ConfigFrom("oak/common/testdata/missing_wasm.textproto");
ASSERT_EQ(false, ValidApplicationConfig(*config));
}

TEST(ApplicationConfiguration, DuplicateWasmName) {
TEST_F(ApplicationConfigurationTest, DuplicateWasmName) {
auto config = ConfigFrom("oak/common/testdata/dup_wasm.textproto");
ASSERT_EQ(false, ValidApplicationConfig(*config));
}

} // namespace

} // namespace oak
45 changes: 45 additions & 0 deletions oak/common/utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2020 The Project Oak Authors
*
* 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 <fstream>

#include "asylo/util/logging.h"
#include "oak/common/utils.h"

namespace oak {
namespace utils {

std::string read_file(const std::string& filename) {
std::ifstream t(filename, std::ifstream::in);
if (!t.is_open()) {
LOG(QFATAL) << "Could not open file " << filename;
}
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}

void write_file(const std::string& data, const std::string& filename) {
std::ofstream t(filename, std::ofstream::out);
if (!t.is_open()) {
LOG(QFATAL) << "Could not open file " << filename;
}
t << data;
t.close();
}

} // namespace utils
} // namespace oak
37 changes: 26 additions & 11 deletions oak/common/utils.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
#include <fstream>
/*
* Copyright 2020 The Project Oak Authors
*
* 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 "asylo/util/logging.h"
#ifndef OAK_COMMON_UTILS_H_
#define OAK_COMMON_UTILS_H_

#include <string>

namespace oak {
namespace utils {

// Reads a binary file and returns its contents as a std::string.
std::string read_file(const std::string& module_path) {
std::ifstream t(module_path, std::ifstream::in);
if (!t.is_open()) {
LOG(QFATAL) << "Could not open module " << module_path;
}
std::stringstream buffer;
buffer << t.rdbuf();
return buffer.str();
}
std::string read_file(const std::string& filename);

// Writes `data` string into a binary file.
void write_file(const std::string& data, const std::string& filename);

} // namespace utils
} // namespace oak

#endif // OAK_COMMON_UTILS_H_