blob: 9f0ca3763c563ef4ec5d98c999bd4382a7f4988e [file] [log] [blame]
// Copyright 2021 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.
library fuchsia.netemul;
using fuchsia.component;
using fuchsia.io;
using fuchsia.netemul.network;
using fuchsia.url;
using zx;
type Empty = struct {};
/// `Sandbox` is a hermetic container for network emulation testing.
///
/// Every connection to `Sandbox` represents a self-contained context where
/// [`fuchsia.netemul/ManagedRealm`]s can be created. The
/// [`fuchsia.netemul.network/NetworkContext`] instance offered by it is the
/// same that is exposed to any `ManagedRealm`s created by the `Sandbox`.
///
/// The lifetime of the created realms (and the context services) is bound to
/// the connection to the `Sandbox` protocol. If the channel is closed, all the
/// realms and the components created within them will be terminated.
@discoverable
closed protocol Sandbox {
/// Creates a new realm configured by `options`.
///
/// + request `realm` request handle to the newly created managed realm.
/// + request `options` configures the setup and child components of
/// `realm`. If `options` is invalid, `realm` will be closed.
///
/// Errors are presented as an epitaph on the `realm` channel.
/// * error `ZX_ERR_INVALID_ARGS` if `options` was invalid.
/// * error `ZX_ERR_INTERNAL` for internal errors, including failures to
/// build the requested component topology.
strict CreateRealm(resource struct {
realm server_end:ManagedRealm;
options @generated_name("RealmOptions") resource table {
/// Realm name.
///
/// The realm name is used for attribution and debugging purposes.
/// It is used to decorate logs that come from its constituent child
/// components.
///
/// If not set, an automatically-generated name will be used.
1: name string:MAX;
/// Child components to dynamically create in this realm.
///
/// If not set, interpreted as an empty vector.
2: children vector<@generated_name("ChildDef") resource table {
/// The runtime source for creating this child.
///
/// Required.
1: source @generated_name("ChildSource") strict resource union {
/// Spawn a child from a component with the provided URL.
1: component fuchsia.url.Url;
/// Spawn a mock child which serves its exposed directory
/// through the provided handle.
2: mock client_end:fuchsia.io.Directory;
};
/// The name of this child local to its containing realm.
///
/// Required.
2: name fuchsia.component.name;
/// Protocols that this child exposes to the realm.
///
/// If not set, interpreted as an empty vector.
3: exposes vector<fuchsia.component.name>:MAX;
/// Capabilities that this child uses.
///
/// If not set, no capabilities will be routed to the component.
4: uses @generated_name("ChildUses") strict union {
/// The child will be offered each of the specified
/// capabilities.
///
/// `capabilities` must be unique.
1: capabilities vector<@generated_name("Capability") strict union {
/// The `devfs` instance offered by netemul, where
/// virtual devices are mounted.
1: netemul_devfs @generated_name("DevfsDep") table {
/// The name of the capability being offered.
///
/// Required.
1: name fuchsia.component.name;
/// The subdirectory of `/dev` visible to the
/// component.
///
/// If not set, the entire contents of `/dev` will
/// be visible to the component.
2: subdir string:fuchsia.component.MAX_PATH_LENGTH;
};
/// The network context offered by netemul, shared
/// between all the managed realms in a given sandbox.
3: netemul_network_context Empty;
/// The [`fuchsia.logger/LogSink`] offered by netemul.
///
/// Decorates logs produced by components in the managed
/// realm and forwards them to syslog.
4: log_sink Empty;
/// A dependency on a capability exposed by another
/// child component in the same test realm.
5: child_dep table {
/// The name of the child exposing the needed
/// capability.
///
/// Required.
1: name fuchsia.component.name;
/// The exposed capability.
///
/// Required.
2: capability @generated_name("ExposedCapability") strict union {
/// The name of the exposed protocol.
1: protocol fuchsia.component.name;
};
};
/// A dependency on a storage capability offered by
/// netemul.
6: storage_dep table {
/// The variant of the storage capability.
///
/// Required.
1: variant @generated_name("StorageVariant") strict enum : uint8 {
/// The `data` storage capability variant.
DATA = 0;
/// The `cache` storage capability variant.
CACHE = 1;
/// The `tmp` storage capability variant.
TMP = 2;
};
/// The path at which the storage capability will be
/// offered.
///
/// Required.
2: path string:fuchsia.component.MAX_PATH_LENGTH;
};
/// A dependency on the capability to register a tracing
/// provider.
7: tracing_provider Empty;
}>:MAX;
};
/// Arguments to be passed to the child at runtime. If
/// specified, overrides any arguments specified in the
/// manifest.
///
/// If not set, the original arguments from the manifest are
/// used.
5: program_args vector<string:MAX>:MAX;
/// Whether the component should be started eagerly once the
/// realm is created.
///
/// If not set, interpreted as false.
6: eager bool;
}>:MAX;
};
});
/// Gets this sandbox's network context.
///
/// + request `network_context` request handle to the network context.
strict GetNetworkContext(resource struct {
network_context server_end:fuchsia.netemul.network.NetworkContext;
});
};
/// `ManagedRealm` is a netemul-managed realm.
///
/// A `ManagedRealm` is hermetic with respect to capabilities except for
/// * netemul-provided capabilities to allow networking
/// * logging
///
/// `ManagedRealm` also provides a `devfs` instance: a directory standing for a
/// virtual device filesystem that can be controlled through the [`AddDevice`]
/// and [`RemoveDevice`] methods.
///
/// The lifetime of a `ManagedRealm` and all its children are tied to its
/// channel. Upon closure, all children of the realm will be destroyed.
closed protocol ManagedRealm {
/// Returns the moniker of the root of the managed realm.
///
/// - response `moniker` the moniker of the root of the generated
/// topology that contains this realm's child components.
strict GetMoniker() -> (struct {
moniker string:fuchsia.component.MAX_MONIKER_LENGTH;
});
/// Connects to a protocol named `protocol_name` provided by a child in this
/// realm.
///
/// If `child_name` is not provided, connects to the first child offering
/// `protocol_name`.
///
/// + request `protocol_name` the name of the protocol to connect to.
/// + request `child_name` the name of the child component that is exposing
/// the requested protocol.
/// + request `req` a channel to be bound to an implementation of the
/// protocol.
strict ConnectToProtocol(resource struct {
protocol_name fuchsia.component.name;
child_name fuchsia.component.name:optional;
req zx.Handle:CHANNEL;
});
/// Mounts new virtual device `device` on netemul's `devfs` instance within
/// this realm.
///
/// This `devfs` instance is available to components that have the
/// [`Capability.netemul_devfs`] capability.
///
/// + request `path` relative path from `devfs` root to the virtual device
/// to be added to the realm.
/// + request `device` virtual device server.
/// * error `ZX_ERR_ALREADY_EXISTS` if `device.path` is already in use.
/// * error `ZX_ERR_INVALID_ARGS` if an element of `path` exceeds
/// [`fuchsia.io/MAX_FILENAME`] bytes in length.
strict AddDevice(resource struct {
path string:MAX;
device client_end:fuchsia.netemul.network.DeviceProxy;
}) -> () error zx.Status;
/// Removes virtual device mounted at `path`.
///
/// + request `path` the path to virtual device to be removed from the
/// realm, relative to `devfs` root.
/// * error `ZX_ERR_NOT_FOUND` if `path` is not currently bound to a device.
/// * error `ZX_ERR_INVALID_ARGS` if an element of `path` exceeds
/// [`fuchsia.io/MAX_FILENAME`] bytes in length.
strict RemoveDevice(struct {
path string:MAX;
}) -> () error zx.Status;
/// Connects to netemul's `devfs` instance for this realm.
///
/// + request `devfs` request handle to the `devfs` directory.
strict GetDevfs(resource struct {
devfs server_end:fuchsia.io.Directory;
});
/// Starts the specified child component in this realm. Starting an already
/// running child component is a no-op and returns success.
///
/// + request `child_name` the name of the child component to be started.
/// * error `ZX_ERR_NOT_FOUND` if `child_name` is not a child component in
/// this realm.
/// * error `ZX_ERR_INVALID_ARGS` if `child_name` cannot be composed into a
/// well-formed moniker.
/// * error `ZX_ERR_INTERNAL` if the call to the service dependency fails.
strict StartChildComponent(struct {
child_name fuchsia.component.name;
}) -> () error zx.Status;
/// Stops the specified child component in this realm. Stopping an already
/// stopped child component is a no-op and returns success.
///
/// + request `child_name` the name of the child component to be stopped.
/// * error `ZX_ERR_NOT_FOUND` if `child_name` is not a child component in
/// this realm.
/// * error `ZX_ERR_INVALID_ARGS` if `child_name` cannot be composed into a
/// well-formed moniker.
/// * error `ZX_ERR_INTERNAL` if the call to the service dependency fails.
strict StopChildComponent(struct {
child_name fuchsia.component.name;
}) -> () error zx.Status;
/// Request that the managed realm shut down.
///
/// The realm will send an `OnShutdown` event when shutdown is complete and
/// before closing the channel.
strict Shutdown();
/// Opens the diagnostics directory exposed by the component `child_name`.
// TODO(https://fxbug.dev/324494668): remove when Netstack2 is gone.
strict OpenDiagnosticsDirectory(resource struct {
child_name fuchsia.component.name;
directory server_end:fuchsia.io.Directory;
});
/// Signals that shutdown is complete and the channel will be closed.
strict -> OnShutdown();
};