[netemul] Basic layout for netemul runner/sandbox
- Netemul runner offers fuchsia.sys.Runner and calls sandbox to start
tests in tailored environment for network emulation
- Netemul sandbox is the "root process" that will create the emulated
environment, launch the tests and observe exit codes
TESTS: no significant tests here apart from a simple test to make sure
runner and sandbox are creating processes as intended
Change-Id: Id2b8f99528a7ede3c585e15e816f756a621f672e
diff --git a/bin/netemul_runner/BUILD.gn b/bin/netemul_runner/BUILD.gn
new file mode 100644
index 0000000..313485b
--- /dev/null
+++ b/bin/netemul_runner/BUILD.gn
@@ -0,0 +1,59 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/package.gni")
+
+executable("bin") {
+ testonly = true
+ output_name = "netemul_sandbox"
+ sources = [
+ "main.cc",
+ "managed_environment.cc",
+ "managed_environment.h",
+ "managed_launcher.cc",
+ "managed_launcher.h",
+ "sandbox.cc",
+ "sandbox.h",
+ "sandbox_env.h",
+ ]
+
+ deps = [
+ "//garnet/lib/cmx:cmx",
+ "//garnet/lib/process",
+ "//garnet/public/fidl/fuchsia.sys",
+ "//garnet/public/lib/component/cpp",
+ "//garnet/public/lib/component/cpp/testing",
+ "//garnet/public/lib/fsl",
+ "//garnet/public/lib/fxl",
+ "//garnet/public/lib/netemul/fidl:network",
+ "//garnet/public/lib/netemul/network:network_service",
+ "//third_party/rapidjson",
+ "//zircon/public/lib/async-cpp",
+ "//zircon/public/lib/async-default",
+ "//zircon/public/lib/async-loop-cpp",
+ "//zircon/public/lib/fdio",
+ "//zircon/public/lib/zx",
+ ]
+}
+
+package("netemul_sandbox") {
+ testonly = true
+
+ deps = [
+ ":bin",
+ ]
+
+ binaries = [
+ {
+ name = "netemul_sandbox"
+ },
+ ]
+
+ meta = [
+ {
+ path = rebase_path("meta/netemul_sandbox.cmx")
+ dest = "netemul_sandbox.cmx"
+ },
+ ]
+}
diff --git a/bin/netemul_runner/MAINTAINERS b/bin/netemul_runner/MAINTAINERS
new file mode 100644
index 0000000..c891e99
--- /dev/null
+++ b/bin/netemul_runner/MAINTAINERS
@@ -0,0 +1 @@
+brunodalbo@google.com
diff --git a/bin/netemul_runner/main.cc b/bin/netemul_runner/main.cc
new file mode 100644
index 0000000..03da980
--- /dev/null
+++ b/bin/netemul_runner/main.cc
@@ -0,0 +1,61 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/component/cpp/termination_reason.h>
+#include <lib/fxl/command_line.h>
+#include <lib/fxl/log_settings_command_line.h>
+#include <lib/fxl/logging.h>
+#include <iostream>
+#include "sandbox.h"
+
+using namespace netemul;
+
+void PrintUsage() {
+ fprintf(stderr, R"(
+Usage: netemul_sandbox <package_url> [arguments...]
+
+ *package_url* takes the form of component manifest URL which uniquely
+ identifies a component. Example:
+ fuchsia-pkg://fuchsia.com/component_hello_world#meta/hello.cmx
+)");
+}
+
+int main(int argc, const char** argv) {
+ auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
+ if (!fxl::SetLogSettingsFromCommandLine(command_line))
+ return 1;
+
+ async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
+ async_set_default_dispatcher(loop.dispatcher());
+
+ SandboxArgs args;
+
+ auto posargs = command_line.positional_args().begin();
+ if (posargs == command_line.positional_args().end()) {
+ PrintUsage();
+ return 1;
+ }
+ args.package = *posargs++;
+ args.args.insert(args.args.end(), posargs,
+ command_line.positional_args().end());
+
+ FXL_LOG(INFO) << "Starting netemul sandbox for " << args.package;
+
+ Sandbox sandbox(std::move(args));
+ sandbox.SetTerminationCallback([](int64_t exit_code,
+ Sandbox::TerminationReason reason) {
+ FXL_LOG(INFO) << "Sandbox terminated with (" << exit_code << ") reason: "
+ << component::HumanReadableTerminationReason(reason);
+ if (reason != Sandbox::TerminationReason::EXITED) {
+ exit_code = 1;
+ }
+ zx_process_exit(exit_code);
+ });
+
+ sandbox.Start();
+ loop.Run();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/bin/netemul_runner/managed_environment.cc b/bin/netemul_runner/managed_environment.cc
new file mode 100644
index 0000000..7b8f5f6
--- /dev/null
+++ b/bin/netemul_runner/managed_environment.cc
@@ -0,0 +1,42 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "managed_environment.h"
+
+namespace netemul {
+
+using component::testing::EnclosingEnvironment;
+using component::testing::EnvironmentServices;
+
+ManagedEnvironment::Ptr ManagedEnvironment::CreateRoot(
+ const fuchsia::sys::EnvironmentPtr& parent,
+ const SandboxEnv::Ptr& sandbox_env) {
+ auto services = EnvironmentServices::Create(parent);
+
+ fuchsia::sys::EnvironmentOptions options = {.kill_on_oom = true,
+ .allow_parent_runners = false,
+ .inherit_parent_services = true};
+
+ auto enclosing = EnclosingEnvironment::Create("root", parent,
+ std::move(services), options);
+
+ return ManagedEnvironment::Ptr(
+ new ManagedEnvironment(std::move(enclosing), sandbox_env));
+}
+
+ManagedEnvironment::ManagedEnvironment(
+ std::unique_ptr<component::testing::EnclosingEnvironment> env,
+ const SandboxEnv::Ptr& sandbox_env)
+ : sandbox_env_(sandbox_env), env_(std::move(env)), launcher_(this) {
+ env_->SetRunningChangedCallback([this](bool running) {
+ if (running && running_callback_) {
+ running_callback_();
+ }
+ });
+}
+
+component::testing::EnclosingEnvironment& ManagedEnvironment::environment() {
+ return *env_;
+}
+} // namespace netemul
diff --git a/bin/netemul_runner/managed_environment.h b/bin/netemul_runner/managed_environment.h
new file mode 100644
index 0000000..b2a1014
--- /dev/null
+++ b/bin/netemul_runner/managed_environment.h
@@ -0,0 +1,57 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_NETEMUL_RUNNER_MANAGED_ENVIRONMENT_H_
+#define GARNET_BIN_NETEMUL_RUNNER_MANAGED_ENVIRONMENT_H_
+
+#include <lib/component/cpp/testing/enclosing_environment.h>
+#include <lib/svc/cpp/services.h>
+#include <memory>
+#include "managed_launcher.h"
+#include "sandbox_env.h"
+
+namespace netemul {
+
+class ManagedEnvironment {
+ public:
+ using EnvironmentRunningCallback = fit::closure;
+ using Ptr = std::unique_ptr<ManagedEnvironment>;
+ static Ptr CreateRoot(const fuchsia::sys::EnvironmentPtr& parent,
+ const SandboxEnv::Ptr& sandbox_env);
+
+ const SandboxEnv::Ptr& sandbox_env() const { return sandbox_env_; }
+
+ const std::shared_ptr<component::Services>& services() {
+ if (!services_) {
+ services_ = std::make_shared<component::Services>();
+ }
+ return services_;
+ }
+
+ ManagedLauncher& launcher() { return launcher_; }
+
+ void SetRunningCallback(EnvironmentRunningCallback cb) {
+ running_callback_ = std::move(cb);
+ }
+
+ protected:
+ friend ManagedLauncher;
+
+ component::testing::EnclosingEnvironment& environment();
+
+ private:
+ ManagedEnvironment(
+ std::unique_ptr<component::testing::EnclosingEnvironment> env,
+ const SandboxEnv::Ptr& sandbox_env);
+
+ SandboxEnv::Ptr sandbox_env_;
+ std::unique_ptr<component::testing::EnclosingEnvironment> env_;
+ ManagedLauncher launcher_;
+ std::shared_ptr<component::Services> services_;
+ EnvironmentRunningCallback running_callback_;
+};
+
+} // namespace netemul
+
+#endif // GARNET_BIN_NETEMUL_RUNNER_MANAGED_ENVIRONMENT_H_
diff --git a/bin/netemul_runner/managed_launcher.cc b/bin/netemul_runner/managed_launcher.cc
new file mode 100644
index 0000000..c67f6ed
--- /dev/null
+++ b/bin/netemul_runner/managed_launcher.cc
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "managed_launcher.h"
+#include <lib/fdio/io.h>
+#include <lib/fxl/logging.h>
+#include <lib/fxl/strings/concatenate.h>
+#include <zircon/status.h>
+#include "garnet/lib/process/process_builder.h"
+#include "managed_environment.h"
+
+namespace netemul {
+
+using fuchsia::sys::TerminationReason;
+using process::ProcessBuilder;
+
+struct LaunchArgs {
+ std::string binary;
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller;
+};
+
+void ManagedLauncher::CreateComponent(
+ fuchsia::sys::LaunchInfo launch_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
+ // Just pass through to real launcher.
+ real_launcher_->CreateComponent(std::move(launch_info),
+ std::move(controller));
+}
+
+ManagedLauncher::ManagedLauncher(ManagedEnvironment* environment)
+ : env_(environment) {
+ env_->environment().ConnectToService(real_launcher_.NewRequest());
+}
+
+ManagedLauncher::~ManagedLauncher() = default;
+
+} // namespace netemul
diff --git a/bin/netemul_runner/managed_launcher.h b/bin/netemul_runner/managed_launcher.h
new file mode 100644
index 0000000..eecf6d8
--- /dev/null
+++ b/bin/netemul_runner/managed_launcher.h
@@ -0,0 +1,31 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_NETEMUL_RUNNER_MANAGED_LAUNCHER_H_
+#define GARNET_BIN_NETEMUL_RUNNER_MANAGED_LAUNCHER_H_
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <string>
+
+namespace netemul {
+class ManagedEnvironment;
+class ManagedLauncher {
+ public:
+ explicit ManagedLauncher(ManagedEnvironment* environment);
+
+ ~ManagedLauncher();
+
+ void CreateComponent(
+ fuchsia::sys::LaunchInfo launch_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
+
+ private:
+ // Pointer to parent environment. Not owned.
+ ManagedEnvironment* env_;
+ fuchsia::sys::LauncherPtr real_launcher_;
+};
+
+} // namespace netemul
+
+#endif // GARNET_BIN_NETEMUL_RUNNER_MANAGED_LAUNCHER_H_
diff --git a/bin/netemul_runner/meta/netemul_sandbox.cmx b/bin/netemul_runner/meta/netemul_sandbox.cmx
new file mode 100644
index 0000000..21fd9b1
--- /dev/null
+++ b/bin/netemul_runner/meta/netemul_sandbox.cmx
@@ -0,0 +1,12 @@
+{
+ "program": {
+ "binary": "bin/netemul_sandbox"
+ },
+ "sandbox": {
+ "services": [
+ "fuchsia.sys.Environment",
+ "fuchsia.sys.Loader",
+ "fuchsia.sys.Launcher"
+ ]
+ }
+}
diff --git a/bin/netemul_runner/runner/BUILD.gn b/bin/netemul_runner/runner/BUILD.gn
new file mode 100644
index 0000000..e7fb80d
--- /dev/null
+++ b/bin/netemul_runner/runner/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/package.gni")
+
+executable("bin") {
+ testonly = true
+ output_name = "netemul_runner"
+ sources = [
+ "main.cc",
+ "runner.cc",
+ "runner.h",
+ ]
+
+ deps = [
+ "//garnet/lib/cmx:cmx",
+ "//garnet/public/fidl/fuchsia.sys",
+ "//garnet/public/lib/component/cpp",
+ "//garnet/public/lib/fsl",
+ "//garnet/public/lib/fxl",
+ "//garnet/public/lib/pkg_url",
+ "//third_party/rapidjson",
+ "//zircon/public/lib/async-cpp",
+ "//zircon/public/lib/async-default",
+ "//zircon/public/lib/async-loop-cpp",
+ ]
+}
+
+package("netemul_runner") {
+ testonly = true
+
+ deps = [
+ ":bin",
+ "//garnet/bin/netemul_runner:netemul_sandbox",
+ ]
+
+ binary = "netemul_runner"
+
+ meta = [
+ {
+ path = rebase_path("meta/netemul_runner.cmx")
+ dest = "netemul_runner.cmx"
+ },
+ ]
+}
diff --git a/bin/netemul_runner/runner/main.cc b/bin/netemul_runner/runner/main.cc
new file mode 100644
index 0000000..848bc27
--- /dev/null
+++ b/bin/netemul_runner/runner/main.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/fxl/command_line.h>
+#include <lib/fxl/log_settings_command_line.h>
+#include <lib/fxl/logging.h>
+#include <iostream>
+#include "runner.h"
+
+using namespace netemul;
+
+int main(int argc, const char** argv) {
+ auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
+ if (!fxl::SetLogSettingsFromCommandLine(command_line))
+ return 1;
+
+ async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
+ async_set_default_dispatcher(loop.dispatcher());
+
+ FXL_LOG(INFO) << "Starting netemul runner";
+
+ Runner r(loop.dispatcher());
+ loop.Run();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/bin/netemul_runner/runner/meta/netemul_runner.cmx b/bin/netemul_runner/runner/meta/netemul_runner.cmx
new file mode 100644
index 0000000..ef8c26b
--- /dev/null
+++ b/bin/netemul_runner/runner/meta/netemul_runner.cmx
@@ -0,0 +1,11 @@
+{
+ "program": {
+ "binary": "bin/app"
+ },
+ "sandbox": {
+ "services": [
+ "fuchsia.sys.Launcher",
+ "fuchsia.sys.Loader"
+ ]
+ }
+}
diff --git a/bin/netemul_runner/runner/runner.cc b/bin/netemul_runner/runner/runner.cc
new file mode 100644
index 0000000..210ba68
--- /dev/null
+++ b/bin/netemul_runner/runner/runner.cc
@@ -0,0 +1,107 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "runner.h"
+
+#include <lib/async/default.h>
+#include <lib/fsl/io/fd.h>
+#include <lib/fxl/files/unique_fd.h>
+#include <lib/fxl/logging.h>
+#include <lib/pkg_url/fuchsia_pkg_url.h>
+#include "garnet/lib/cmx/cmx.h"
+
+namespace netemul {
+using component::StartupContext;
+static const char* kSandbox =
+ "fuchsia-pkg://fuchsia.com/netemul_sandbox#meta/netemul_sandbox.cmx";
+
+Runner::Runner(async_dispatcher_t* dispatcher) {
+ if (dispatcher == nullptr) {
+ dispatcher = async_get_default_dispatcher();
+ }
+ dispatcher_ = dispatcher;
+
+ startup_context_ = StartupContext::CreateFromStartupInfo();
+ startup_context_->ConnectToEnvironmentService(
+ launcher_.NewRequest(dispatcher_));
+ startup_context_->ConnectToEnvironmentService(
+ loader_.NewRequest(dispatcher_));
+ startup_context_->outgoing().AddPublicService(
+ bindings_.GetHandler(this, dispatcher_));
+}
+
+struct RunnerArgs {
+ fuchsia::sys::StartupInfo startup_info;
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller;
+};
+
+void Runner::StartComponent(
+ fuchsia::sys::Package package, fuchsia::sys::StartupInfo startup_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
+ FXL_LOG(INFO) << "resolved URL: " << package.resolved_url;
+
+ // args needs to be shared ptr 'cause Loader fidl
+ // uses std::function and not fit::function (i.e. legacy callbacks)
+ std::shared_ptr<RunnerArgs> args = std::make_shared<RunnerArgs>();
+ args->startup_info = std::move(startup_info);
+ args->controller = std::move(controller);
+
+ // go through loader to get information, 'cause info is not complete
+ // from caller (missing directory and other stuff)
+ loader_->LoadUrl(
+ package.resolved_url, [this, args](fuchsia::sys::PackagePtr package) {
+ RunComponent(std::move(package), std::move(args->startup_info),
+ std::move(args->controller));
+ });
+}
+
+void Runner::RunComponent(
+ fuchsia::sys::PackagePtr package, fuchsia::sys::StartupInfo startup_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
+ if (!package) {
+ // TODO(brunodalbo) expose errors correctly through interface request
+ FXL_LOG(ERROR) << "Can't load package";
+ return;
+ }
+ // extract and parse cmx:
+ component::FuchsiaPkgUrl fp;
+ if (!fp.Parse(package->resolved_url.get())) {
+ FXL_LOG(ERROR) << "can't parse fuchsia URL " << package->resolved_url;
+ // TODO(brunodalbo) expose errors correctly through interface request
+ return;
+ }
+
+ if (!package->directory.is_valid()) {
+ FXL_LOG(ERROR) << "Package directory not provided";
+ return;
+ }
+
+ component::CmxMetadata cmx;
+ fxl::UniqueFD fd =
+ fsl::OpenChannelAsFileDescriptor(std::move(package->directory));
+
+ json::JSONParser json_parser;
+ if (!cmx.ParseFromFileAt(fd.get(), fp.resource_path(), &json_parser)) {
+ FXL_LOG(ERROR) << "cmx file failed to parse: " << json_parser.error_str();
+ // TODO(brunodalbo) expose errors correctly through interface request
+ return;
+ }
+
+ std::stringstream launchpkg;
+ launchpkg << "fuchsia-pkg://fuchsia.com/" << fp.package_name() << "#"
+ << cmx.program_meta().data();
+
+ auto sandbox_arg = launchpkg.str();
+
+ auto linfo = std::move(startup_info.launch_info);
+ linfo.url = kSandbox;
+ linfo.arguments->push_back(sandbox_arg);
+ linfo.arguments->insert(linfo.arguments->end(),
+ startup_info.launch_info.arguments->begin(),
+ startup_info.launch_info.arguments->end());
+
+ launcher_->CreateComponent(std::move(linfo), std::move(controller));
+}
+
+} // namespace netemul
diff --git a/bin/netemul_runner/runner/runner.h b/bin/netemul_runner/runner/runner.h
new file mode 100644
index 0000000..1c837cf
--- /dev/null
+++ b/bin/netemul_runner/runner/runner.h
@@ -0,0 +1,37 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_NETEMUL_RUNNER_RUNNER_RUNNER_H_
+#define GARNET_BIN_NETEMUL_RUNNER_RUNNER_RUNNER_H_
+
+#include <lib/component/cpp/startup_context.h>
+#include <lib/fidl/cpp/binding_set.h>
+#include "fuchsia/sys/cpp/fidl.h"
+
+namespace netemul {
+class Runner : public fuchsia::sys::Runner {
+ public:
+ using FRunner = fuchsia::sys::Runner;
+ explicit Runner(async_dispatcher_t* dispatcher = nullptr);
+
+ void StartComponent(fuchsia::sys::Package package,
+ fuchsia::sys::StartupInfo startup_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+ controller) override;
+
+ private:
+ void RunComponent(
+ fuchsia::sys::PackagePtr package, fuchsia::sys::StartupInfo startup_info,
+ fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
+
+ async_dispatcher_t* dispatcher_;
+ std::unique_ptr<component::StartupContext> startup_context_;
+ fidl::BindingSet<FRunner> bindings_;
+ fuchsia::sys::LauncherPtr launcher_;
+ fuchsia::sys::LoaderPtr loader_;
+};
+
+} // namespace netemul
+
+#endif // GARNET_BIN_NETEMUL_RUNNER_RUNNER_RUNNER_H_
diff --git a/bin/netemul_runner/sandbox.cc b/bin/netemul_runner/sandbox.cc
new file mode 100644
index 0000000..1b8e89a
--- /dev/null
+++ b/bin/netemul_runner/sandbox.cc
@@ -0,0 +1,95 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox.h"
+#include <fcntl.h>
+#include <lib/async/default.h>
+#include <lib/component/cpp/startup_context.h>
+#include <lib/component/cpp/testing/test_util.h>
+#include <lib/fdio/watcher.h>
+#include <lib/fsl/io/fd.h>
+#include <lib/fxl/logging.h>
+#include <lib/fxl/strings/concatenate.h>
+#include <lib/pkg_url/fuchsia_pkg_url.h>
+#include <zircon/status.h>
+#include "garnet/lib/cmx/cmx.h"
+
+namespace netemul {
+
+Sandbox::Sandbox(SandboxArgs args) : args_(std::move(args)) {
+ auto startup_context = component::StartupContext::CreateFromStartupInfo();
+ startup_context->ConnectToEnvironmentService(parent_env_.NewRequest());
+ startup_context->ConnectToEnvironmentService(loader_.NewRequest());
+}
+
+void Sandbox::Start() {
+ if (!parent_env_ || !loader_) {
+ Terminate(TerminationReason::INTERNAL_ERROR);
+ }
+
+ loader_->LoadUrl(args_.package, [this](fuchsia::sys::PackagePtr package) {
+ if (!package) {
+ Terminate(TerminationReason::PACKAGE_NOT_FOUND);
+ return;
+ } else if (!package->directory) {
+ Terminate(TerminationReason::INTERNAL_ERROR);
+ }
+ LoadPackage(std::move(package));
+ });
+}
+
+void Sandbox::Terminate(int64_t exit_code, Sandbox::TerminationReason reason) {
+ if (termination_callback_) {
+ termination_callback_(exit_code, reason);
+ }
+}
+
+void Sandbox::Terminate(Sandbox::TerminationReason reason) {
+ Terminate(-1, reason);
+}
+void Sandbox::LoadPackage(fuchsia::sys::PackagePtr package) {
+ // package is loaded, proceed to parsing cmx and starting child env
+ component::FuchsiaPkgUrl pkgUrl;
+ if (!pkgUrl.Parse(package->resolved_url)) {
+ FXL_LOG(ERROR) << "Can't parse fuchsia url: " << package->resolved_url;
+ Terminate(TerminationReason::INTERNAL_ERROR);
+ return;
+ }
+
+ fxl::UniqueFD dirfd =
+ fsl::OpenChannelAsFileDescriptor(std::move(package->directory));
+ sandbox_env_ = std::make_shared<SandboxEnv>(args_.package, std::move(dirfd));
+
+ component::CmxMetadata cmx;
+
+ json::JSONParser json_parser;
+ if (!cmx.ParseFromFileAt(sandbox_env_->dir().get(), pkgUrl.resource_path(),
+ &json_parser)) {
+ FXL_LOG(ERROR) << "cmx file failed to parse: " << json_parser.error_str();
+ Terminate(TerminationReason::INTERNAL_ERROR);
+ return;
+ }
+
+ root_ = ManagedEnvironment::CreateRoot(parent_env_, sandbox_env_);
+
+ // TODO(brunodalbo) parameterize environment based on
+ // facets in cmx file
+
+ root_->SetRunningCallback([this] {
+ root_proc_.events().OnTerminated = [this](int64_t code,
+ TerminationReason reason) {
+ Terminate(code, reason); // mimic termination of root process
+ };
+
+ // start root test process:
+ fuchsia::sys::LaunchInfo linfo;
+ linfo.url = sandbox_env_->name();
+ linfo.out = component::testing::CloneFileDescriptor(STDOUT_FILENO);
+ linfo.err = component::testing::CloneFileDescriptor(STDERR_FILENO);
+ root_->launcher().CreateComponent(std::move(linfo),
+ root_proc_.NewRequest());
+ });
+}
+
+} // namespace netemul
\ No newline at end of file
diff --git a/bin/netemul_runner/sandbox.h b/bin/netemul_runner/sandbox.h
new file mode 100644
index 0000000..71bd3a2
--- /dev/null
+++ b/bin/netemul_runner/sandbox.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_NETEMUL_RUNNER_SANDBOX_H_
+#define GARNET_BIN_NETEMUL_RUNNER_SANDBOX_H_
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include "managed_environment.h"
+#include "sandbox_env.h"
+
+namespace netemul {
+
+class SandboxArgs {
+ public:
+ std::string package;
+ std::vector<std::string> args;
+};
+
+class Sandbox {
+ public:
+ using TerminationReason = fuchsia::sys::TerminationReason;
+ using TerminationCallback =
+ fit::function<void(int64_t code, TerminationReason reason)>;
+ explicit Sandbox(SandboxArgs args);
+
+ void SetTerminationCallback(TerminationCallback callback) {
+ termination_callback_ = std::move(callback);
+ }
+
+ void Start();
+
+ private:
+ void LoadPackage(fuchsia::sys::PackagePtr package);
+ void Terminate(TerminationReason reason);
+ void Terminate(int64_t exit_code, TerminationReason reason);
+ void StartRootEnvironment();
+
+ SandboxArgs args_;
+ SandboxEnv::Ptr sandbox_env_;
+ TerminationCallback termination_callback_;
+ fuchsia::sys::EnvironmentPtr parent_env_;
+ fuchsia::sys::LoaderPtr loader_;
+ ManagedEnvironment::Ptr root_;
+ fuchsia::sys::ComponentControllerPtr root_proc_;
+};
+
+} // namespace netemul
+
+#endif // GARNET_BIN_NETEMUL_RUNNER_SANDBOX_H_
diff --git a/bin/netemul_runner/sandbox_env.h b/bin/netemul_runner/sandbox_env.h
new file mode 100644
index 0000000..671fcb8
--- /dev/null
+++ b/bin/netemul_runner/sandbox_env.h
@@ -0,0 +1,32 @@
+#include <utility>
+
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GARNET_BIN_NETEMUL_RUNNER_SANDBOX_ENV_H_
+#define GARNET_BIN_NETEMUL_RUNNER_SANDBOX_ENV_H_
+
+#include <lib/fxl/files/unique_fd.h>
+#include <memory>
+#include <string>
+
+namespace netemul {
+class SandboxEnv {
+ public:
+ using Ptr = std::shared_ptr<SandboxEnv>;
+
+ SandboxEnv(std::string package_name, fxl::UniqueFD dir)
+ : package_name_(std::move(package_name)), package_dir_(std::move(dir)) {}
+
+ const std::string& name() const { return package_name_; }
+
+ const fxl::UniqueFD& dir() const { return package_dir_; }
+
+ private:
+ std::string package_name_;
+ fxl::UniqueFD package_dir_;
+};
+} // namespace netemul
+
+#endif // GARNET_BIN_NETEMUL_RUNNER_SANDBOX_ENV_H_
diff --git a/bin/netemul_runner/test/BUILD.gn b/bin/netemul_runner/test/BUILD.gn
new file mode 100644
index 0000000..e4d1e5f
--- /dev/null
+++ b/bin/netemul_runner/test/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/test/test_package.gni")
+
+test_package("netemul_sandbox_test") {
+ deps = [
+ "//garnet/bin/netemul_runner/test/svc_list",
+ ]
+
+ meta = [
+ {
+ path = rebase_path("meta/svc_list_run.cmx")
+ dest = "svc_list_run.cmx"
+ },
+ ]
+
+ tests = [
+ {
+ name = "svc_list"
+ },
+ ]
+}
diff --git a/bin/netemul_runner/test/meta/svc_list.cmx b/bin/netemul_runner/test/meta/svc_list.cmx
new file mode 100644
index 0000000..bd906ba
--- /dev/null
+++ b/bin/netemul_runner/test/meta/svc_list.cmx
@@ -0,0 +1,6 @@
+{
+ "program": {
+ "data": "meta/svc_list_run.cmx"
+ },
+ "runner": "fuchsia-pkg://fuchsia.com/netemul_runner#meta/netemul_runner.cmx"
+}
diff --git a/bin/netemul_runner/test/meta/svc_list_run.cmx b/bin/netemul_runner/test/meta/svc_list_run.cmx
new file mode 100644
index 0000000..1f58670
--- /dev/null
+++ b/bin/netemul_runner/test/meta/svc_list_run.cmx
@@ -0,0 +1,5 @@
+{
+ "program": {
+ "binary": "test/svc_list"
+ }
+}
diff --git a/bin/netemul_runner/test/svc_list/BUILD.gn b/bin/netemul_runner/test/svc_list/BUILD.gn
new file mode 100644
index 0000000..206acbb
--- /dev/null
+++ b/bin/netemul_runner/test/svc_list/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/package.gni")
+import("//build/rust/rustc_binary.gni")
+
+rustc_binary("svc_list") {
+ name = "svc_list"
+ edition = "2018"
+ deps = [
+ "//garnet/lib/rust/ethernet",
+ "//garnet/public/rust/fuchsia-async",
+ "//garnet/public/rust/fuchsia-zircon",
+ "//third_party/rust-crates/rustc_deps:failure",
+ "//third_party/rust-crates/rustc_deps:futures-preview",
+ ]
+}
diff --git a/bin/netemul_runner/test/svc_list/src/main.rs b/bin/netemul_runner/test/svc_list/src/main.rs
new file mode 100644
index 0000000..b5e921b
--- /dev/null
+++ b/bin/netemul_runner/test/svc_list/src/main.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::fs;
+use std::io;
+use std::path::Path;
+
+fn visit_dirs(dir: &Path) -> io::Result<()> {
+ if dir.is_dir() {
+ for entry in fs::read_dir(dir)? {
+ let entry = entry?;
+ let path = entry.path();
+ let str = path.to_str().expect("paths need strings?");
+ println!("{}", str);
+ visit_dirs(dir.join(path).as_path())?;
+ }
+ }
+ Ok(())
+}
+
+fn main() -> io::Result<()> {
+ println!("Hello World");
+ visit_dirs(Path::new("/"))?;
+
+ // TODO(brunodalbo) the idea of this test is to find the sandbox services and ensure they're there
+
+ Ok(())
+}
diff --git a/packages/testing/all b/packages/testing/all
index 1a2bb15..5e5803d 100644
--- a/packages/testing/all
+++ b/packages/testing/all
@@ -1,5 +1,6 @@
{
"imports": [
- "garnet/packages/testing/run_test_component"
+ "garnet/packages/testing/run_test_component",
+ "garnet/packages/testing/netemul_runner"
]
}
diff --git a/packages/testing/netemul_runner b/packages/testing/netemul_runner
new file mode 100644
index 0000000..7a11092
--- /dev/null
+++ b/packages/testing/netemul_runner
@@ -0,0 +1,6 @@
+{
+ "packages": [
+ "//garnet/bin/netemul_runner/runner:netemul_runner",
+ "//garnet/bin/netemul_runner:netemul_sandbox"
+ ]
+}
diff --git a/packages/tests/netemul b/packages/tests/netemul
index 8a97dcc..d5cb344 100644
--- a/packages/tests/netemul
+++ b/packages/tests/netemul
@@ -1,8 +1,10 @@
{
"imports": [
- "garnet/packages/prod/netstack"
+ "garnet/packages/prod/netstack",
+ "garnet/packages/testing/netemul_runner"
],
"packages": [
- "//garnet/public/lib/netemul/network:netemul_network_test"
+ "//garnet/public/lib/netemul/network:netemul_network_test",
+ "//garnet/bin/netemul_runner/test:netemul_sandbox_test"
]
}
diff --git a/public/lib/netemul/MAINTAINERS b/public/lib/netemul/MAINTAINERS
new file mode 100644
index 0000000..c891e99
--- /dev/null
+++ b/public/lib/netemul/MAINTAINERS
@@ -0,0 +1 @@
+brunodalbo@google.com