fix(wasi): initialize and control embedded runtime logging (#2655)

This commit is contained in:
Fa authored and GitHub committed 2026-10-15 20:37:32 +08:00
1 parent da6d721b97
commit 7588062f7e
27 files changed
+869 -107

No files matched your search

+8
View File
@@ -91,6 +91,14 @@ model for management readback, while the shared host-aware normalization path
omits capabilities that the compact runtime cannot execute. Omitted settings
are silent no-ops and must not be advertised as live network capabilities.
## Embedded logging
Logging belongs to the WASI runtime, which installs its subscriber at module
startup. The independent logger ABI and process-level `LoggerRpc` control
the same module-wide level, including before any Instance exists. Instance
configuration and lifecycle never initialize or reset logging. The Host owns
the output sink through WASI stdout; output errors do not interrupt Core.
## Web compatibility Host
The Web compatibility Host runs the portable EasyTier guest in JavaScript
+7
View File
@@ -67,6 +67,13 @@ pub const GUEST_EXPORTS: &[&str] = &[
// WASI command initialization. This only binds the runtime; core lifecycle
// still starts through the instance exports below.
"_start",
// Module-wide logging; no instance handle is required. Levels 0..=5 are
// off, error, warn, info, debug, trace (matching api.logger.LogLevel).
// set_level(u32) -> i32 returns 0, or -3 without changing the level for
// invalid input. level() -> u32 defaults to info. _start is idempotent
// and does not reset the level. Output uses the WASI stdout sink.
"easytier_logger_set_level",
"easytier_logger_level",
// Guest-memory buffers.
"easytier_buffer_alloc",
"easytier_buffer_free",
+256
View File
@@ -0,0 +1,256 @@
//! Module-wide logging, initialized before any instance or WebClient is created.
use std::{
fmt::Write as _,
io::{self, Write},
sync::{
Arc, Mutex,
atomic::{AtomicU8, Ordering},
},
};
#[cfg(target_os = "wasi")]
use std::sync::OnceLock;
use tracing::{
Event, Metadata, Subscriber,
field::{Field, Visit},
level_filters::LevelFilter,
span::{Attributes, Id, Record},
subscriber::Interest,
};
// These values also match api.logger.LogLevel. Keep the basic WASI logger
// independent of the optional management protobuf API.
const LEVELS: [LevelFilter; 6] = [
LevelFilter::OFF,
LevelFilter::ERROR,
LevelFilter::WARN,
LevelFilter::INFO,
LevelFilter::DEBUG,
LevelFilter::TRACE,
];
struct Logger<W> {
level: AtomicU8,
writer: Mutex<W>,
}
impl<W> Logger<W> {
fn new(writer: W) -> Self {
Self {
level: AtomicU8::new(3),
writer: Mutex::new(writer),
}
}
fn set_level(&self, level: u32) -> bool {
if level >= LEVELS.len() as u32 {
return false;
}
self.level.store(level as u8, Ordering::Relaxed);
true
}
fn level(&self) -> u32 {
u32::from(self.level.load(Ordering::Relaxed))
}
}
impl<W: Write + Send + 'static> Subscriber for Logger<W> {
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
metadata.is_event() && *metadata.level() <= LEVELS[self.level() as usize]
}
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
if metadata.is_event() {
Interest::sometimes()
} else {
Interest::never()
}
}
fn max_level_hint(&self) -> Option<LevelFilter> {
// The host can enable trace after a callsite has already been visited.
Some(LevelFilter::TRACE)
}
fn new_span(&self, _: &Attributes<'_>) -> Id {
Id::from_u64(1)
}
fn record(&self, _: &Id, _: &Record<'_>) {}
fn record_follows_from(&self, _: &Id, _: &Id) {}
fn enter(&self, _: &Id) {}
fn exit(&self, _: &Id) {}
fn event(&self, event: &Event<'_>) {
struct Fields(String);
impl Visit for Fields {
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
let _ = write!(self.0, " {}={value:?}", field.name());
}
}
let mut fields = Fields(String::new());
event.record(&mut fields);
// A host logging sink may fail; that must not trap the guest runtime.
let _ = writeln!(
self.writer.lock().unwrap(),
"[{}] {}{}",
event.metadata().level(),
event.metadata().target(),
fields.0,
);
}
}
#[cfg(target_os = "wasi")]
fn logger() -> &'static Arc<Logger<io::Stdout>> {
static LOGGER: OnceLock<Arc<Logger<io::Stdout>>> = OnceLock::new();
LOGGER.get_or_init(|| {
let logger = Arc::new(Logger::new(io::stdout()));
tracing::subscriber::set_global_default(logger.clone())
.expect("WASI runtime owns the tracing subscriber");
logger
})
}
#[cfg(target_os = "wasi")]
pub(super) fn init() {
logger();
}
/// Sets the module-wide level without requiring an instance handle.
/// Values 0..=5 mean off, error, warn, info, debug, and trace.
/// Invalid values return -3 and leave the current level unchanged.
#[cfg(target_os = "wasi")]
#[unsafe(no_mangle)]
pub extern "C" fn easytier_logger_set_level(level: u32) -> i32 {
if logger().set_level(level) { 0 } else { -3 }
}
/// Returns the module-wide level using the same values as the setter.
#[cfg(target_os = "wasi")]
#[unsafe(no_mangle)]
pub extern "C" fn easytier_logger_level() -> u32 {
logger().level()
}
#[cfg(feature = "management")]
impl<W: Write + Send + 'static> crate::management::LoggerControl for Logger<W> {
fn set_level(&self, name: &str) -> anyhow::Result<()> {
let filter = name.parse::<LevelFilter>()?;
let level = LEVELS
.iter()
.position(|level| *level == filter)
.expect("every tracing level has an ABI value");
self.set_level(level as u32);
Ok(())
}
fn level(&self) -> String {
LEVELS[self.level() as usize]
.to_string()
.to_ascii_lowercase()
}
}
#[cfg(all(target_os = "wasi", feature = "management"))]
pub(super) fn control() -> Arc<dyn crate::management::LoggerControl> {
logger().clone()
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Default)]
struct Output(Arc<Mutex<Vec<u8>>>);
impl Write for Output {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
self.0.lock().unwrap().extend_from_slice(bytes);
Ok(bytes.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
fn emit() {
tracing::error!(target: "logger_test", "error");
tracing::info!(target: "logger_test", "info");
tracing::trace!(target: "logger_test", "trace");
}
#[test]
fn changing_level_rechecks_existing_callsites() {
let output = Output::default();
let logger = Arc::new(Logger::new(output.clone()));
tracing::subscriber::with_default(logger.clone(), || {
for (level, expected) in [
(3, vec!["error", "info"]),
(5, vec!["error", "info", "trace"]),
(0, vec![]),
(3, vec!["error", "info"]),
] {
assert!(logger.set_level(level));
output.0.lock().unwrap().clear();
emit();
let bytes = output.0.lock().unwrap();
let text = std::str::from_utf8(&bytes).unwrap();
let messages = text
.lines()
.map(|line| line.split_once("message=").unwrap().1)
.collect::<Vec<_>>();
assert_eq!(messages, expected);
}
});
}
#[test]
fn invalid_level_preserves_current_filter() {
let logger = Logger::new(io::sink());
assert_eq!(logger.level(), 3);
for level in [6, 256, u32::MAX] {
assert!(!logger.set_level(level));
assert_eq!(logger.level(), 3);
}
}
#[test]
fn output_errors_do_not_panic() {
struct BrokenWriter;
impl Write for BrokenWriter {
fn write(&mut self, _: &[u8]) -> io::Result<usize> {
Err(io::Error::from(io::ErrorKind::BrokenPipe))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
tracing::subscriber::with_default(Logger::new(BrokenWriter), emit);
}
#[cfg(feature = "management")]
#[test]
fn management_control_uses_the_same_filter() {
let logger = Logger::new(io::sink());
let control: &dyn crate::management::LoggerControl = &logger;
control.set_level("trace").unwrap();
assert_eq!(logger.level(), 5);
assert!(logger.set_level(0));
assert_eq!(control.level(), "off");
assert!(control.set_level("invalid").is_err());
assert_eq!(logger.level(), 0);
}
}
+2
View File
@@ -12,6 +12,8 @@ pub mod abi;
pub mod adapter;
#[cfg(target_os = "wasi")]
pub(crate) mod imports;
#[cfg(any(test, target_os = "wasi"))]
mod logger;
#[cfg(target_os = "wasi")]
pub(crate) mod runtime;
#[cfg(any(test, target_os = "wasi"))]
+3 -1
View File
@@ -681,7 +681,9 @@ mod abi {
#[unsafe(no_mangle)]
/// WASI command entrypoint used only to initialize the host runtime.
pub extern "C" fn _start() {}
pub extern "C" fn _start() {
crate::wasi::logger::init();
}
#[unsafe(no_mangle)]
/// Allocates a guest-owned ABI buffer and returns its linear-memory offset.
+6
View File
@@ -260,6 +260,12 @@ impl WebClientBackend for WasiWebClientBackend {
fn register(&self, registry: &ServiceRegistry) {
registry.register(self.handler.clone(), "");
register_forwarded_instance_management_rpc(self.handler.clone(), registry);
registry.register(
crate::proto::api::logger::LoggerRpcServer::new(
crate::management::LoggerManagementRpc::new(crate::wasi::logger::control()),
),
"",
);
}
async fn instance_ids(&self) -> anyhow::Result<Vec<uuid::Uuid>> {
+27
View File
@@ -66,6 +66,33 @@ instance, err := host.CreateInstanceTOML(ctx, "office", "", configTOML)
`Instance.ShowNodeInfo` returns this instance's virtual IPv4 address and
advertised hostname.
### Logging
Logging belongs to the Host and is independent of instance TOML and lifecycle.
Pass an `io.Writer` when creating the Host to receive guest logs; nil discards
them. The default level is `LogLevelInfo`. Change it before creating instances
or at runtime through the Host:
```go
host, err := corehost.New(ctx, corehost.Options{LogWriter: os.Stdout})
if err != nil {
return err
}
defer host.Close(ctx)
if err := host.SetLogLevel(ctx, corehost.LogLevelDebug); err != nil {
return err
}
```
`host.LogLevel(ctx)` reads the current level. `LogLevelOff` disables all logs.
The level applies to every instance and the WebClient in this Host; other
Hosts are independent. The WebClient's existing `LoggerRpc` controls the same
level. Creating or closing an instance never resets it.
Writes are synchronous, so the writer must not call back into this Host.
Writer errors do not interrupt guest execution, and the Host does not close
the writer.
### Web Client management
A host can also connect to an EasyTier Web configuration server. The embedded
Binary file not shown.
+2 -2
View File
@@ -3,6 +3,6 @@
package artifact
const (
Commit = "9a2290f312dbdec6f40e8b13d8a6de5f66e4c570"
SHA256 = "044f9ed79079f449741744d9dd0559d6844e1fff2f1a1994710811904f119986"
Commit = "c51437c673a71f69b4b028c8d566a7b23b33e65c"
SHA256 = "17d6dd4561c1f1e818e7d70ed031c3cf8ea5dcfc1fd0461a6753f1f23f5fa6ab"
)
+57
View File
@@ -0,0 +1,57 @@
package coreabi
import (
"context"
"fmt"
"github.com/metacubex/wazero/api"
)
// LogLevel uses the module-wide logger ABI values, matching api.logger.LogLevel.
type LogLevel uint32
const (
LogLevelOff LogLevel = iota
LogLevelError
LogLevelWarn
LogLevelInfo
LogLevelDebug
LogLevelTrace
)
func SetLogLevel(ctx context.Context, module api.Module, level LogLevel) error {
status, err := callLogger(ctx, module, "easytier_logger_set_level", uint64(level))
if err != nil {
return err
}
if int32(status) != 0 {
return fmt.Errorf("set EasyTier log level %d: status=%d", level, int32(status))
}
return nil
}
func GetLogLevel(ctx context.Context, module api.Module) (LogLevel, error) {
value, err := callLogger(ctx, module, "easytier_logger_level")
if err != nil {
return 0, err
}
if value > uint64(LogLevelTrace) {
return 0, fmt.Errorf("EasyTier guest returned invalid log level %d", value)
}
return LogLevel(value), nil
}
func callLogger(ctx context.Context, module api.Module, name string, args ...uint64) (uint64, error) {
function := module.ExportedFunction(name)
if function == nil {
return 0, fmt.Errorf("EasyTier guest does not export %s", name)
}
results, err := function.Call(ctx, args...)
if err != nil {
return 0, fmt.Errorf("%s: %w", name, err)
}
if len(results) != 1 {
return 0, fmt.Errorf("%s returned %d values, want 1", name, len(results))
}
return results[0], nil
}
+7 -1
View File
@@ -5,6 +5,7 @@ import (
"crypto/rand"
"errors"
"fmt"
"io"
"runtime/debug"
"sync"
"time"
@@ -27,6 +28,7 @@ type Options struct {
Services platform.Services
PacketQueueCapacity int
Management reactor.ManagementHandler
LogWriter io.Writer
}
type Host struct {
@@ -102,7 +104,11 @@ func NewHost(ctx context.Context, options Options) (_ *Host, err error) {
return nil, fmt.Errorf("compile embedded EasyTier core: %w", err)
}
defer compiled.Close(contextutil.WithoutCancel(ctx))
module, err = runtime.InstantiateModule(ctx, compiled, newModuleConfig())
moduleConfig := newModuleConfig()
if options.LogWriter != nil {
moduleConfig = moduleConfig.WithStdout(options.LogWriter)
}
module, err = runtime.InstantiateModule(ctx, compiled, moduleConfig)
if err != nil {
return nil, fmt.Errorf("instantiate embedded EasyTier core: %w", err)
}
+48
View File
@@ -0,0 +1,48 @@
package engine
import (
"context"
"fmt"
"github.com/easytier/easytier/easytier-go/internal/coreabi"
)
func (host *Host) SetLogLevel(ctx context.Context, level coreabi.LogLevel) error {
if host == nil {
return fmt.Errorf("set log level with nil EasyTier engine host")
}
if ctx == nil {
return fmt.Errorf("set EasyTier log level with nil context")
}
host.mu.Lock()
defer host.mu.Unlock()
if host.closed {
return fmt.Errorf("set log level with closed EasyTier engine host")
}
host.guestMu.Lock()
defer host.guestMu.Unlock()
if err := ctx.Err(); err != nil {
return err
}
return coreabi.SetLogLevel(ctx, host.module, level)
}
func (host *Host) LogLevel(ctx context.Context) (coreabi.LogLevel, error) {
if host == nil {
return 0, fmt.Errorf("get log level with nil EasyTier engine host")
}
if ctx == nil {
return 0, fmt.Errorf("get EasyTier log level with nil context")
}
host.mu.Lock()
defer host.mu.Unlock()
if host.closed {
return 0, fmt.Errorf("get log level with closed EasyTier engine host")
}
host.guestMu.Lock()
defer host.guestMu.Unlock()
if err := ctx.Err(); err != nil {
return 0, err
}
return coreabi.GetLogLevel(ctx, host.module)
}
@@ -0,0 +1,32 @@
package engine
import (
"context"
"testing"
"time"
"github.com/easytier/easytier/easytier-go/internal/coreabi"
"github.com/easytier/easytier/easytier-go/platform/netstd"
)
func TestLoggerInitializationDoesNotResetLevel(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
host, err := NewHost(ctx, Options{Services: netstd.Services()})
if err != nil {
t.Fatal(err)
}
defer host.Close(ctx)
if err := host.SetLogLevel(ctx, coreabi.LogLevelTrace); err != nil {
t.Fatal(err)
}
host.guestMu.Lock()
_, err = host.module.ExportedFunction("_start").Call(ctx)
host.guestMu.Unlock()
if err != nil {
t.Fatal(err)
}
if level, err := host.LogLevel(ctx); err != nil || level != coreabi.LogLevelTrace {
t.Fatalf("repeated initialization changed level: %d, %v", level, err)
}
}
+6
View File
@@ -3,6 +3,7 @@ package host
import (
"context"
"fmt"
"io"
"net"
"net/netip"
"strconv"
@@ -33,6 +34,10 @@ const (
type Options struct {
Platform platform.Services
PacketQueueCapacity int
// LogWriter receives module-wide guest logs. Nil discards output.
// Writes run synchronously while the guest is executing; the writer must
// not call back into this Host. The Host does not close the writer.
LogWriter io.Writer
}
type EmbeddedCoreInfo struct {
@@ -77,6 +82,7 @@ func New(ctx context.Context, options Options) (*Host, error) {
Services: mergeServices(options.Platform),
PacketQueueCapacity: options.PacketQueueCapacity,
Management: manager.handle,
LogWriter: options.LogWriter,
},
)
if err != nil {
+36
View File
@@ -0,0 +1,36 @@
package host
import (
"context"
"fmt"
"github.com/easytier/easytier/easytier-go/internal/coreabi"
)
type LogLevel = coreabi.LogLevel
const (
LogLevelOff = coreabi.LogLevelOff
LogLevelError = coreabi.LogLevelError
LogLevelWarn = coreabi.LogLevelWarn
LogLevelInfo = coreabi.LogLevelInfo
LogLevelDebug = coreabi.LogLevelDebug
LogLevelTrace = coreabi.LogLevelTrace
)
// SetLogLevel changes logging for this Host, including all its instances and
// its WebClient. It can be called before any instance is created.
func (host *Host) SetLogLevel(ctx context.Context, level LogLevel) error {
if host == nil {
return fmt.Errorf("set log level with nil EasyTier host")
}
return host.engine.SetLogLevel(ctx, level)
}
// LogLevel returns this Host's current log level, which defaults to Info.
func (host *Host) LogLevel(ctx context.Context) (LogLevel, error) {
if host == nil {
return 0, fmt.Errorf("get log level with nil EasyTier host")
}
return host.engine.LogLevel(ctx)
}
+15
View File
@@ -0,0 +1,15 @@
package host
import internalhost "github.com/easytier/easytier/easytier-go/internal/host"
// LogLevel controls logging for an entire Host, independently of its instances.
type LogLevel = internalhost.LogLevel
const (
LogLevelOff = internalhost.LogLevelOff
LogLevelError = internalhost.LogLevelError
LogLevelWarn = internalhost.LogLevelWarn
LogLevelInfo = internalhost.LogLevelInfo
LogLevelDebug = internalhost.LogLevelDebug
LogLevelTrace = internalhost.LogLevelTrace
)
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: acl.proto
package acl
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: api_config.proto
package config
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: api_instance.proto
package instance
@@ -4399,17 +4399,17 @@ var file_api_instance_proto_goTypes = []any{
nil, // 66: api.instance.ListForeignNetworkResponse.ForeignNetworksEntry
(*ListGlobalForeignNetworkResponse_OneForeignNetwork)(nil), // 67: api.instance.ListGlobalForeignNetworkResponse.OneForeignNetwork
(*ListGlobalForeignNetworkResponse_ForeignNetworks)(nil), // 68: api.instance.ListGlobalForeignNetworkResponse.ForeignNetworks
nil, // 69: api.instance.ListGlobalForeignNetworkResponse.ForeignNetworksEntry
nil, // 70: api.instance.MetricSnapshot.LabelsEntry
(*common.UUID)(nil), // 71: common.UUID
(*common.TunnelInfo)(nil), // 72: common.TunnelInfo
(peer_rpc.SecureAuthLevel)(0), // 73: peer_rpc.SecureAuthLevel
(peer_rpc.PeerIdentityType)(0), // 74: peer_rpc.PeerIdentityType
(*common.Ipv4Inet)(nil), // 75: common.Ipv4Inet
(*common.StunInfo)(nil), // 76: common.StunInfo
(*common.PeerFeatureFlag)(nil), // 77: common.PeerFeatureFlag
(*common.Ipv6Inet)(nil), // 78: common.Ipv6Inet
(*peer_rpc.GetIpListResponse)(nil), // 79: peer_rpc.GetIpListResponse
nil, // 69: api.instance.ListGlobalForeignNetworkResponse.ForeignNetworksEntry
nil, // 70: api.instance.MetricSnapshot.LabelsEntry
(*common.UUID)(nil), // 71: common.UUID
(*common.TunnelInfo)(nil), // 72: common.TunnelInfo
(peer_rpc.SecureAuthLevel)(0), // 73: peer_rpc.SecureAuthLevel
(peer_rpc.PeerIdentityType)(0), // 74: peer_rpc.PeerIdentityType
(*common.Ipv4Inet)(nil), // 75: common.Ipv4Inet
(*common.StunInfo)(nil), // 76: common.StunInfo
(*common.PeerFeatureFlag)(nil), // 77: common.PeerFeatureFlag
(*common.Ipv6Inet)(nil), // 78: common.Ipv6Inet
(*peer_rpc.GetIpListResponse)(nil), // 79: peer_rpc.GetIpListResponse
(*peer_rpc.RouteForeignNetworkSummary)(nil), // 80: peer_rpc.RouteForeignNetworkSummary
(*common.Url)(nil), // 81: common.Url
(*common.SocketAddr)(nil), // 82: common.SocketAddr
+121 -67
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: api_manage.proto
package manage
@@ -200,8 +200,12 @@ type NetworkConfig struct {
VpnPortalConfig *VpnPortalConfig `protobuf:"bytes,69,opt,name=vpn_portal_config,json=vpnPortalConfig,proto3,oneof" json:"vpn_portal_config,omitempty"`
ManagedCredentials []*ManagedCredentialConfig `protobuf:"bytes,71,rep,name=managed_credentials,json=managedCredentials,proto3" json:"managed_credentials,omitempty"`
PreferPeerRelay *bool `protobuf:"varint,72,opt,name=prefer_peer_relay,json=preferPeerRelay,proto3,oneof" json:"prefer_peer_relay,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Bootstrap subnet used when DHCP has not learned a subnet from peers.
DhcpIpv4Cidr *string `protobuf:"bytes,74,opt,name=dhcp_ipv4_cidr,json=dhcpIpv4Cidr,proto3,oneof" json:"dhcp_ipv4_cidr,omitempty"`
Dhcpv6 *bool `protobuf:"varint,75,opt,name=dhcpv6,proto3,oneof" json:"dhcpv6,omitempty"`
DhcpIpv6Cidr *string `protobuf:"bytes,76,opt,name=dhcp_ipv6_cidr,json=dhcpIpv6Cidr,proto3,oneof" json:"dhcp_ipv6_cidr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NetworkConfig) Reset() {
@@ -722,6 +726,27 @@ func (x *NetworkConfig) GetPreferPeerRelay() bool {
return false
}
func (x *NetworkConfig) GetDhcpIpv4Cidr() string {
if x != nil && x.DhcpIpv4Cidr != nil {
return *x.DhcpIpv4Cidr
}
return ""
}
func (x *NetworkConfig) GetDhcpv6() bool {
if x != nil && x.Dhcpv6 != nil {
return *x.Dhcpv6
}
return false
}
func (x *NetworkConfig) GetDhcpIpv6Cidr() string {
if x != nil && x.DhcpIpv6Cidr != nil {
return *x.DhcpIpv6Cidr
}
return ""
}
type ManagedCredentialConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
CredentialId string `protobuf:"bytes,1,opt,name=credential_id,json=credentialId,proto3" json:"credential_id,omitempty"`
@@ -923,8 +948,10 @@ type VpnPortalConfig struct {
WireguardListen string `protobuf:"bytes,1,opt,name=wireguard_listen,json=wireguardListen,proto3" json:"wireguard_listen,omitempty"`
WireguardPrivateKey *string `protobuf:"bytes,2,opt,name=wireguard_private_key,json=wireguardPrivateKey,proto3,oneof" json:"wireguard_private_key,omitempty"`
Clients []*VpnPortalClientConfig `protobuf:"bytes,3,rep,name=clients,proto3" json:"clients,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Omitted in existing configurations, where the portal is enabled.
Enabled *bool `protobuf:"varint,4,opt,name=enabled,proto3,oneof" json:"enabled,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VpnPortalConfig) Reset() {
@@ -978,6 +1005,13 @@ func (x *VpnPortalConfig) GetClients() []*VpnPortalClientConfig {
return nil
}
func (x *VpnPortalConfig) GetEnabled() bool {
if x != nil && x.Enabled != nil {
return *x.Enabled
}
return false
}
type NetworkPeerConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
@@ -1115,8 +1149,9 @@ type MyNodeInfo struct {
StunInfo *common.StunInfo `protobuf:"bytes,5,opt,name=stun_info,json=stunInfo,proto3" json:"stun_info,omitempty"`
Listeners []*common.Url `protobuf:"bytes,6,rep,name=listeners,proto3" json:"listeners,omitempty"`
// Deprecated: Marked as deprecated in api_manage.proto.
VpnPortalCfg *string `protobuf:"bytes,7,opt,name=vpn_portal_cfg,json=vpnPortalCfg,proto3,oneof" json:"vpn_portal_cfg,omitempty"`
PeerId uint32 `protobuf:"varint,8,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
VpnPortalCfg *string `protobuf:"bytes,7,opt,name=vpn_portal_cfg,json=vpnPortalCfg,proto3,oneof" json:"vpn_portal_cfg,omitempty"`
PeerId uint32 `protobuf:"varint,8,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
VirtualIpv6 *common.Ipv6Inet `protobuf:"bytes,9,opt,name=virtual_ipv6,json=virtualIpv6,proto3" json:"virtual_ipv6,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -1208,6 +1243,13 @@ func (x *MyNodeInfo) GetPeerId() uint32 {
return 0
}
func (x *MyNodeInfo) GetVirtualIpv6() *common.Ipv6Inet {
if x != nil {
return x.VirtualIpv6
}
return nil
}
type NetworkInstanceRunningInfo struct {
state protoimpl.MessageState `protogen:"open.v1"`
DevName string `protobuf:"bytes,1,opt,name=dev_name,json=devName,proto3" json:"dev_name,omitempty"`
@@ -2169,7 +2211,7 @@ var File_api_manage_proto protoreflect.FileDescriptor
const file_api_manage_proto_rawDesc = "" +
"\n" +
"\x10api_manage.proto\x12\n" +
"api.manage\x1a\fcommon.proto\x1a\x0epeer_rpc.proto\x1a\x12api_instance.proto\x1a\tacl.proto\"\x80$\n" +
"api.manage\x1a\fcommon.proto\x1a\x0epeer_rpc.proto\x1a\x12api_instance.proto\x1a\tacl.proto\"\xa4%\n" +
"\rNetworkConfig\x12$\n" +
"\vinstance_id\x18\x01 \x01(\tH\x00R\n" +
"instanceId\x88\x01\x01\x12\x17\n" +
@@ -2250,7 +2292,10 @@ const file_api_manage_proto_rawDesc = "" +
"\x05peers\x18D \x03(\v2\x1d.api.manage.NetworkPeerConfigR\x05peers\x12L\n" +
"\x11vpn_portal_config\x18E \x01(\v2\x1b.api.manage.VpnPortalConfigH8R\x0fvpnPortalConfig\x88\x01\x01\x12T\n" +
"\x13managed_credentials\x18G \x03(\v2#.api.manage.ManagedCredentialConfigR\x12managedCredentials\x12/\n" +
"\x11prefer_peer_relay\x18H \x01(\bH9R\x0fpreferPeerRelay\x88\x01\x01B\x0e\n" +
"\x11prefer_peer_relay\x18H \x01(\bH9R\x0fpreferPeerRelay\x88\x01\x01\x12)\n" +
"\x0edhcp_ipv4_cidr\x18J \x01(\tH:R\fdhcpIpv4Cidr\x88\x01\x01\x12\x1b\n" +
"\x06dhcpv6\x18K \x01(\bH;R\x06dhcpv6\x88\x01\x01\x12)\n" +
"\x0edhcp_ipv6_cidr\x18L \x01(\tH<R\fdhcpIpv6Cidr\x88\x01\x01B\x0e\n" +
"\f_instance_idB\a\n" +
"\x05_dhcpB\x0f\n" +
"\r_virtual_ipv4B\x11\n" +
@@ -2308,7 +2353,10 @@ const file_api_manage_proto_rawDesc = "" +
"\x1b_enable_udp_broadcast_relayB\x0e\n" +
"\f_socket_markB\x14\n" +
"\x12_vpn_portal_configB\x14\n" +
"\x12_prefer_peer_relay\"\xa3\x02\n" +
"\x12_prefer_peer_relayB\x11\n" +
"\x0f_dhcp_ipv4_cidrB\t\n" +
"\a_dhcpv6B\x11\n" +
"\x0f_dhcp_ipv6_cidr\"\xa3\x02\n" +
"\x17ManagedCredentialConfig\x12#\n" +
"\rcredential_id\x18\x01 \x01(\tR\fcredentialId\x12+\n" +
"\x11credential_secret\x18\x02 \x01(\tR\x10credentialSecret\x12\x16\n" +
@@ -2326,12 +2374,15 @@ const file_api_manage_proto_rawDesc = "" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" +
"\n" +
"virtual_ip\x18\x02 \x01(\tR\tvirtualIp\x12\x16\n" +
"\x06groups\x18\x03 \x03(\tR\x06groups\"\xcc\x01\n" +
"\x06groups\x18\x03 \x03(\tR\x06groups\"\xf7\x01\n" +
"\x0fVpnPortalConfig\x12)\n" +
"\x10wireguard_listen\x18\x01 \x01(\tR\x0fwireguardListen\x127\n" +
"\x15wireguard_private_key\x18\x02 \x01(\tH\x00R\x13wireguardPrivateKey\x88\x01\x01\x12;\n" +
"\aclients\x18\x03 \x03(\v2!.api.manage.VpnPortalClientConfigR\aclientsB\x18\n" +
"\x16_wireguard_private_key\"f\n" +
"\aclients\x18\x03 \x03(\v2!.api.manage.VpnPortalClientConfigR\aclients\x12\x1d\n" +
"\aenabled\x18\x04 \x01(\bH\x01R\aenabled\x88\x01\x01B\x18\n" +
"\x16_wireguard_private_keyB\n" +
"\n" +
"\b_enabled\"f\n" +
"\x11NetworkPeerConfig\x12\x10\n" +
"\x03uri\x18\x01 \x01(\tR\x03uri\x12+\n" +
"\x0fpeer_public_key\x18\x02 \x01(\tH\x00R\rpeerPublicKey\x88\x01\x01B\x12\n" +
@@ -2341,7 +2392,7 @@ const file_api_manage_proto_rawDesc = "" +
"\tbind_port\x18\x02 \x01(\rR\bbindPort\x12\x15\n" +
"\x06dst_ip\x18\x03 \x01(\tR\x05dstIp\x12\x19\n" +
"\bdst_port\x18\x04 \x01(\rR\adstPort\x12\x14\n" +
"\x05proto\x18\x05 \x01(\tR\x05proto\"\xdb\x02\n" +
"\x05proto\x18\x05 \x01(\tR\x05proto\"\x90\x03\n" +
"\n" +
"MyNodeInfo\x123\n" +
"\fvirtual_ipv4\x18\x01 \x01(\v2\x10.common.Ipv4InetR\vvirtualIpv4\x12\x1a\n" +
@@ -2351,7 +2402,8 @@ const file_api_manage_proto_rawDesc = "" +
"\tstun_info\x18\x05 \x01(\v2\x10.common.StunInfoR\bstunInfo\x12)\n" +
"\tlisteners\x18\x06 \x03(\v2\v.common.UrlR\tlisteners\x12-\n" +
"\x0evpn_portal_cfg\x18\a \x01(\tB\x02\x18\x01H\x00R\fvpnPortalCfg\x88\x01\x01\x12\x17\n" +
"\apeer_id\x18\b \x01(\rR\x06peerIdB\x11\n" +
"\apeer_id\x18\b \x01(\rR\x06peerId\x123\n" +
"\fvirtual_ipv6\x18\t \x01(\v2\x10.common.Ipv6InetR\vvirtualIpv6B\x11\n" +
"\x0f_vpn_portal_cfg\"\xd3\x03\n" +
"\x1aNetworkInstanceRunningInfo\x12\x19\n" +
"\bdev_name\x18\x01 \x01(\tR\adevName\x128\n" +
@@ -2485,11 +2537,12 @@ var file_api_manage_proto_goTypes = []any{
(*peer_rpc.GetIpListResponse)(nil), // 34: peer_rpc.GetIpListResponse
(*common.StunInfo)(nil), // 35: common.StunInfo
(*common.Url)(nil), // 36: common.Url
(*instance.Route)(nil), // 37: api.instance.Route
(*instance.PeerInfo)(nil), // 38: api.instance.PeerInfo
(*instance.PeerRoutePair)(nil), // 39: api.instance.PeerRoutePair
(*peer_rpc.RouteForeignNetworkSummary)(nil), // 40: peer_rpc.RouteForeignNetworkSummary
(*common.UUID)(nil), // 41: common.UUID
(*common.Ipv6Inet)(nil), // 37: common.Ipv6Inet
(*instance.Route)(nil), // 38: api.instance.Route
(*instance.PeerInfo)(nil), // 39: api.instance.PeerInfo
(*instance.PeerRoutePair)(nil), // 40: api.instance.PeerRoutePair
(*peer_rpc.RouteForeignNetworkSummary)(nil), // 41: peer_rpc.RouteForeignNetworkSummary
(*common.UUID)(nil), // 42: common.UUID
}
var file_api_manage_proto_depIdxs = []int32{
0, // 0: api.manage.NetworkConfig.networking_method:type_name -> api.manage.NetworkingMethod
@@ -2506,53 +2559,54 @@ var file_api_manage_proto_depIdxs = []int32{
34, // 11: api.manage.MyNodeInfo.ips:type_name -> peer_rpc.GetIpListResponse
35, // 12: api.manage.MyNodeInfo.stun_info:type_name -> common.StunInfo
36, // 13: api.manage.MyNodeInfo.listeners:type_name -> common.Url
9, // 14: api.manage.NetworkInstanceRunningInfo.my_node_info:type_name -> api.manage.MyNodeInfo
37, // 15: api.manage.NetworkInstanceRunningInfo.routes:type_name -> api.instance.Route
38, // 16: api.manage.NetworkInstanceRunningInfo.peers:type_name -> api.instance.PeerInfo
39, // 17: api.manage.NetworkInstanceRunningInfo.peer_route_pairs:type_name -> api.instance.PeerRoutePair
40, // 18: api.manage.NetworkInstanceRunningInfo.foreign_network_summary:type_name -> peer_rpc.RouteForeignNetworkSummary
29, // 19: api.manage.NetworkInstanceRunningInfoMap.map:type_name -> api.manage.NetworkInstanceRunningInfoMap.MapEntry
41, // 20: api.manage.NetworkMeta.inst_id:type_name -> common.UUID
1, // 21: api.manage.NetworkMeta.source:type_name -> api.manage.ConfigSource
2, // 22: api.manage.ValidateConfigRequest.config:type_name -> api.manage.NetworkConfig
41, // 23: api.manage.RunNetworkInstanceRequest.inst_id:type_name -> common.UUID
2, // 24: api.manage.RunNetworkInstanceRequest.config:type_name -> api.manage.NetworkConfig
1, // 25: api.manage.RunNetworkInstanceRequest.source:type_name -> api.manage.ConfigSource
41, // 26: api.manage.RunNetworkInstanceResponse.inst_id:type_name -> common.UUID
41, // 27: api.manage.RetainNetworkInstanceRequest.inst_ids:type_name -> common.UUID
41, // 28: api.manage.RetainNetworkInstanceResponse.remain_inst_ids:type_name -> common.UUID
41, // 29: api.manage.CollectNetworkInfoRequest.inst_ids:type_name -> common.UUID
11, // 30: api.manage.CollectNetworkInfoResponse.info:type_name -> api.manage.NetworkInstanceRunningInfoMap
41, // 31: api.manage.ListNetworkInstanceResponse.inst_ids:type_name -> common.UUID
41, // 32: api.manage.DeleteNetworkInstanceRequest.inst_ids:type_name -> common.UUID
41, // 33: api.manage.DeleteNetworkInstanceResponse.remain_inst_ids:type_name -> common.UUID
41, // 34: api.manage.GetNetworkInstanceConfigRequest.inst_id:type_name -> common.UUID
2, // 35: api.manage.GetNetworkInstanceConfigResponse.config:type_name -> api.manage.NetworkConfig
1, // 36: api.manage.GetNetworkInstanceConfigResponse.source:type_name -> api.manage.ConfigSource
41, // 37: api.manage.ListNetworkInstanceMetaRequest.inst_ids:type_name -> common.UUID
12, // 38: api.manage.ListNetworkInstanceMetaResponse.metas:type_name -> api.manage.NetworkMeta
10, // 39: api.manage.NetworkInstanceRunningInfoMap.MapEntry.value:type_name -> api.manage.NetworkInstanceRunningInfo
13, // 40: api.manage.WebClientService.ValidateConfig:input_type -> api.manage.ValidateConfigRequest
15, // 41: api.manage.WebClientService.RunNetworkInstance:input_type -> api.manage.RunNetworkInstanceRequest
17, // 42: api.manage.WebClientService.RetainNetworkInstance:input_type -> api.manage.RetainNetworkInstanceRequest
19, // 43: api.manage.WebClientService.CollectNetworkInfo:input_type -> api.manage.CollectNetworkInfoRequest
21, // 44: api.manage.WebClientService.ListNetworkInstance:input_type -> api.manage.ListNetworkInstanceRequest
23, // 45: api.manage.WebClientService.DeleteNetworkInstance:input_type -> api.manage.DeleteNetworkInstanceRequest
25, // 46: api.manage.WebClientService.GetNetworkInstanceConfig:input_type -> api.manage.GetNetworkInstanceConfigRequest
27, // 47: api.manage.WebClientService.ListNetworkInstanceMeta:input_type -> api.manage.ListNetworkInstanceMetaRequest
14, // 48: api.manage.WebClientService.ValidateConfig:output_type -> api.manage.ValidateConfigResponse
16, // 49: api.manage.WebClientService.RunNetworkInstance:output_type -> api.manage.RunNetworkInstanceResponse
18, // 50: api.manage.WebClientService.RetainNetworkInstance:output_type -> api.manage.RetainNetworkInstanceResponse
20, // 51: api.manage.WebClientService.CollectNetworkInfo:output_type -> api.manage.CollectNetworkInfoResponse
22, // 52: api.manage.WebClientService.ListNetworkInstance:output_type -> api.manage.ListNetworkInstanceResponse
24, // 53: api.manage.WebClientService.DeleteNetworkInstance:output_type -> api.manage.DeleteNetworkInstanceResponse
26, // 54: api.manage.WebClientService.GetNetworkInstanceConfig:output_type -> api.manage.GetNetworkInstanceConfigResponse
28, // 55: api.manage.WebClientService.ListNetworkInstanceMeta:output_type -> api.manage.ListNetworkInstanceMetaResponse
48, // [48:56] is the sub-list for method output_type
40, // [40:48] is the sub-list for method input_type
40, // [40:40] is the sub-list for extension type_name
40, // [40:40] is the sub-list for extension extendee
0, // [0:40] is the sub-list for field type_name
37, // 14: api.manage.MyNodeInfo.virtual_ipv6:type_name -> common.Ipv6Inet
9, // 15: api.manage.NetworkInstanceRunningInfo.my_node_info:type_name -> api.manage.MyNodeInfo
38, // 16: api.manage.NetworkInstanceRunningInfo.routes:type_name -> api.instance.Route
39, // 17: api.manage.NetworkInstanceRunningInfo.peers:type_name -> api.instance.PeerInfo
40, // 18: api.manage.NetworkInstanceRunningInfo.peer_route_pairs:type_name -> api.instance.PeerRoutePair
41, // 19: api.manage.NetworkInstanceRunningInfo.foreign_network_summary:type_name -> peer_rpc.RouteForeignNetworkSummary
29, // 20: api.manage.NetworkInstanceRunningInfoMap.map:type_name -> api.manage.NetworkInstanceRunningInfoMap.MapEntry
42, // 21: api.manage.NetworkMeta.inst_id:type_name -> common.UUID
1, // 22: api.manage.NetworkMeta.source:type_name -> api.manage.ConfigSource
2, // 23: api.manage.ValidateConfigRequest.config:type_name -> api.manage.NetworkConfig
42, // 24: api.manage.RunNetworkInstanceRequest.inst_id:type_name -> common.UUID
2, // 25: api.manage.RunNetworkInstanceRequest.config:type_name -> api.manage.NetworkConfig
1, // 26: api.manage.RunNetworkInstanceRequest.source:type_name -> api.manage.ConfigSource
42, // 27: api.manage.RunNetworkInstanceResponse.inst_id:type_name -> common.UUID
42, // 28: api.manage.RetainNetworkInstanceRequest.inst_ids:type_name -> common.UUID
42, // 29: api.manage.RetainNetworkInstanceResponse.remain_inst_ids:type_name -> common.UUID
42, // 30: api.manage.CollectNetworkInfoRequest.inst_ids:type_name -> common.UUID
11, // 31: api.manage.CollectNetworkInfoResponse.info:type_name -> api.manage.NetworkInstanceRunningInfoMap
42, // 32: api.manage.ListNetworkInstanceResponse.inst_ids:type_name -> common.UUID
42, // 33: api.manage.DeleteNetworkInstanceRequest.inst_ids:type_name -> common.UUID
42, // 34: api.manage.DeleteNetworkInstanceResponse.remain_inst_ids:type_name -> common.UUID
42, // 35: api.manage.GetNetworkInstanceConfigRequest.inst_id:type_name -> common.UUID
2, // 36: api.manage.GetNetworkInstanceConfigResponse.config:type_name -> api.manage.NetworkConfig
1, // 37: api.manage.GetNetworkInstanceConfigResponse.source:type_name -> api.manage.ConfigSource
42, // 38: api.manage.ListNetworkInstanceMetaRequest.inst_ids:type_name -> common.UUID
12, // 39: api.manage.ListNetworkInstanceMetaResponse.metas:type_name -> api.manage.NetworkMeta
10, // 40: api.manage.NetworkInstanceRunningInfoMap.MapEntry.value:type_name -> api.manage.NetworkInstanceRunningInfo
13, // 41: api.manage.WebClientService.ValidateConfig:input_type -> api.manage.ValidateConfigRequest
15, // 42: api.manage.WebClientService.RunNetworkInstance:input_type -> api.manage.RunNetworkInstanceRequest
17, // 43: api.manage.WebClientService.RetainNetworkInstance:input_type -> api.manage.RetainNetworkInstanceRequest
19, // 44: api.manage.WebClientService.CollectNetworkInfo:input_type -> api.manage.CollectNetworkInfoRequest
21, // 45: api.manage.WebClientService.ListNetworkInstance:input_type -> api.manage.ListNetworkInstanceRequest
23, // 46: api.manage.WebClientService.DeleteNetworkInstance:input_type -> api.manage.DeleteNetworkInstanceRequest
25, // 47: api.manage.WebClientService.GetNetworkInstanceConfig:input_type -> api.manage.GetNetworkInstanceConfigRequest
27, // 48: api.manage.WebClientService.ListNetworkInstanceMeta:input_type -> api.manage.ListNetworkInstanceMetaRequest
14, // 49: api.manage.WebClientService.ValidateConfig:output_type -> api.manage.ValidateConfigResponse
16, // 50: api.manage.WebClientService.RunNetworkInstance:output_type -> api.manage.RunNetworkInstanceResponse
18, // 51: api.manage.WebClientService.RetainNetworkInstance:output_type -> api.manage.RetainNetworkInstanceResponse
20, // 52: api.manage.WebClientService.CollectNetworkInfo:output_type -> api.manage.CollectNetworkInfoResponse
22, // 53: api.manage.WebClientService.ListNetworkInstance:output_type -> api.manage.ListNetworkInstanceResponse
24, // 54: api.manage.WebClientService.DeleteNetworkInstance:output_type -> api.manage.DeleteNetworkInstanceResponse
26, // 55: api.manage.WebClientService.GetNetworkInstanceConfig:output_type -> api.manage.GetNetworkInstanceConfigResponse
28, // 56: api.manage.WebClientService.ListNetworkInstanceMeta:output_type -> api.manage.ListNetworkInstanceMetaResponse
49, // [49:57] is the sub-list for method output_type
41, // [41:49] is the sub-list for method input_type
41, // [41:41] is the sub-list for extension type_name
41, // [41:41] is the sub-list for extension extendee
0, // [0:41] is the sub-list for field type_name
}
func init() { file_api_manage_proto_init() }
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: common.proto
package common
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: annotations.proto
package easytier
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: error.proto
package error
+59 -16
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: peer_rpc.proto
package peer_rpc
@@ -1146,12 +1146,15 @@ func (*SyncRouteInfoRequest_ConnBitmap) isSyncRouteInfoRequest_ConnInfo() {}
func (*SyncRouteInfoRequest_ConnPeerList) isSyncRouteInfoRequest_ConnInfo() {}
type SyncRouteInfoResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
IsInitiator bool `protobuf:"varint,1,opt,name=is_initiator,json=isInitiator,proto3" json:"is_initiator,omitempty"`
SessionId uint64 `protobuf:"varint,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
Error *SyncRouteInfoError `protobuf:"varint,3,opt,name=error,proto3,enum=peer_rpc.SyncRouteInfoError,oneof" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
IsInitiator bool `protobuf:"varint,1,opt,name=is_initiator,json=isInitiator,proto3" json:"is_initiator,omitempty"`
SessionId uint64 `protobuf:"varint,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"`
Error *SyncRouteInfoError `protobuf:"varint,3,opt,name=error,proto3,enum=peer_rpc.SyncRouteInfoError,oneof" json:"error,omitempty"`
// Missing data for peers referenced by accepted topology. Empty in steady state.
MissingPeerIds []uint32 `protobuf:"varint,4,rep,packed,name=missing_peer_ids,json=missingPeerIds,proto3" json:"missing_peer_ids,omitempty"`
MissingConnPeerIds []uint32 `protobuf:"varint,5,rep,packed,name=missing_conn_peer_ids,json=missingConnPeerIds,proto3" json:"missing_conn_peer_ids,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SyncRouteInfoResponse) Reset() {
@@ -1205,6 +1208,20 @@ func (x *SyncRouteInfoResponse) GetError() SyncRouteInfoError {
return SyncRouteInfoError_DuplicatePeerId
}
func (x *SyncRouteInfoResponse) GetMissingPeerIds() []uint32 {
if x != nil {
return x.MissingPeerIds
}
return nil
}
func (x *SyncRouteInfoResponse) GetMissingConnPeerIds() []uint32 {
if x != nil {
return x.MissingConnPeerIds
}
return nil
}
type AcquireIpv6PublicAddrLeaseRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
PeerId uint32 `protobuf:"varint,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
@@ -1697,8 +1714,10 @@ type SelectPunchListenerRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
ForceNew bool `protobuf:"varint,1,opt,name=force_new,json=forceNew,proto3" json:"force_new,omitempty"`
PreferPortMapping bool `protobuf:"varint,2,opt,name=prefer_port_mapping,json=preferPortMapping,proto3" json:"prefer_port_mapping,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Register source observation before returning the listener address.
TransactionId *uint32 `protobuf:"varint,3,opt,name=transaction_id,json=transactionId,proto3,oneof" json:"transaction_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SelectPunchListenerRequest) Reset() {
@@ -1745,11 +1764,20 @@ func (x *SelectPunchListenerRequest) GetPreferPortMapping() bool {
return false
}
func (x *SelectPunchListenerRequest) GetTransactionId() uint32 {
if x != nil && x.TransactionId != nil {
return *x.TransactionId
}
return 0
}
type SelectPunchListenerResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
ListenerMappedAddr *common.SocketAddr `protobuf:"bytes,1,opt,name=listener_mapped_addr,json=listenerMappedAddr,proto3" json:"listener_mapped_addr,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Echoed only after source observation is registered; absent on older peers.
TransactionId *uint32 `protobuf:"varint,2,opt,name=transaction_id,json=transactionId,proto3,oneof" json:"transaction_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SelectPunchListenerResponse) Reset() {
@@ -1789,6 +1817,13 @@ func (x *SelectPunchListenerResponse) GetListenerMappedAddr() *common.SocketAddr
return nil
}
func (x *SelectPunchListenerResponse) GetTransactionId() uint32 {
if x != nil && x.TransactionId != nil {
return *x.TransactionId
}
return 0
}
type SendPunchPacketConeRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
ListenerMappedAddr *common.SocketAddr `protobuf:"bytes,1,opt,name=listener_mapped_addr,json=listenerMappedAddr,proto3" json:"listener_mapped_addr,omitempty"`
@@ -3459,12 +3494,14 @@ const file_peer_rpc_proto_rawDesc = "" +
"connBitmap\x12C\n" +
"\x0econn_peer_list\x18\a \x01(\v2\x1b.peer_rpc.RouteConnPeerListH\x00R\fconnPeerList\x12V\n" +
"\x15foreign_network_infos\x18\x06 \x01(\v2\".peer_rpc.RouteForeignNetworkInfosR\x13foreignNetworkInfosB\v\n" +
"\tconn_info\"\x9c\x01\n" +
"\tconn_info\"\xf9\x01\n" +
"\x15SyncRouteInfoResponse\x12!\n" +
"\fis_initiator\x18\x01 \x01(\bR\visInitiator\x12\x1d\n" +
"\n" +
"session_id\x18\x02 \x01(\x04R\tsessionId\x127\n" +
"\x05error\x18\x03 \x01(\x0e2\x1c.peer_rpc.SyncRouteInfoErrorH\x00R\x05error\x88\x01\x01B\b\n" +
"\x05error\x18\x03 \x01(\x0e2\x1c.peer_rpc.SyncRouteInfoErrorH\x00R\x05error\x88\x01\x01\x12(\n" +
"\x10missing_peer_ids\x18\x04 \x03(\rR\x0emissingPeerIds\x121\n" +
"\x15missing_conn_peer_ids\x18\x05 \x03(\rR\x12missingConnPeerIdsB\b\n" +
"\x06_error\"c\n" +
"!AcquireIpv6PublicAddrLeaseRequest\x12\x17\n" +
"\apeer_id\x18\x01 \x01(\rR\x06peerId\x12%\n" +
@@ -3505,12 +3542,16 @@ const file_peer_rpc_proto_rawDesc = "" +
"\x0econnector_addr\x18\x01 \x01(\v2\x12.common.SocketAddrR\rconnectorAddr\x12#\n" +
"\rlistener_port\x18\x02 \x01(\rR\flistenerPort\x12>\n" +
"\x12preferred_src_ipv6\x18\x03 \x01(\v2\x10.common.Ipv6AddrR\x10preferredSrcIpv6\x12;\n" +
"\x0fconnector_addrs\x18\x04 \x03(\v2\x12.common.SocketAddrR\x0econnectorAddrs\"i\n" +
"\x0fconnector_addrs\x18\x04 \x03(\v2\x12.common.SocketAddrR\x0econnectorAddrs\"\xa8\x01\n" +
"\x1aSelectPunchListenerRequest\x12\x1b\n" +
"\tforce_new\x18\x01 \x01(\bR\bforceNew\x12.\n" +
"\x13prefer_port_mapping\x18\x02 \x01(\bR\x11preferPortMapping\"c\n" +
"\x13prefer_port_mapping\x18\x02 \x01(\bR\x11preferPortMapping\x12*\n" +
"\x0etransaction_id\x18\x03 \x01(\rH\x00R\rtransactionId\x88\x01\x01B\x11\n" +
"\x0f_transaction_id\"\xa2\x01\n" +
"\x1bSelectPunchListenerResponse\x12D\n" +
"\x14listener_mapped_addr\x18\x01 \x01(\v2\x12.common.SocketAddrR\x12listenerMappedAddr\"\xcb\x02\n" +
"\x14listener_mapped_addr\x18\x01 \x01(\v2\x12.common.SocketAddrR\x12listenerMappedAddr\x12*\n" +
"\x0etransaction_id\x18\x02 \x01(\rH\x00R\rtransactionId\x88\x01\x01B\x11\n" +
"\x0f_transaction_id\"\xcb\x02\n" +
"\x1aSendPunchPacketConeRequest\x12D\n" +
"\x14listener_mapped_addr\x18\x01 \x01(\v2\x12.common.SocketAddrR\x12listenerMappedAddr\x12/\n" +
"\tdest_addr\x18\x02 \x01(\v2\x12.common.SocketAddrR\bdestAddr\x12%\n" +
@@ -3886,6 +3927,8 @@ func file_peer_rpc_proto_init() {
}
file_peer_rpc_proto_msgTypes[13].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[18].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[22].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[23].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[38].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[41].OneofWrappers = []any{}
file_peer_rpc_proto_msgTypes[42].OneofWrappers = []any{}
+2 -2
View File
@@ -3,6 +3,6 @@
package proto
const (
EasyTierCommit = "9a2290f312dbdec6f40e8b13d8a6de5f66e4c570"
SchemaSHA256 = "c145983fee99e08f6207c425cea0952c1aaf50f9bfea12c834d1ec985e0b39df"
EasyTierCommit = "c51437c673a71f69b4b028c8d566a7b23b33e65c"
SchemaSHA256 = "e49a4af09e5b66089eebb73fda78ffca7e8468a5a938cf7a593d689881686f0a"
)
+1 -1
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v7.36.1
// protoc v7.35.1
// source: web.proto
package web
+157
View File
@@ -0,0 +1,157 @@
package host_test
import (
"bytes"
"context"
"io"
"strings"
"sync"
"testing"
"time"
corehost "github.com/easytier/easytier/easytier-go"
)
type logOutput struct {
mu sync.Mutex
buffer bytes.Buffer
fail bool
writes int
}
func (output *logOutput) Write(data []byte) (int, error) {
output.mu.Lock()
defer output.mu.Unlock()
output.writes++
if output.fail {
return 0, io.ErrClosedPipe
}
return output.buffer.Write(data)
}
func (output *logOutput) take() string {
output.mu.Lock()
defer output.mu.Unlock()
text := output.buffer.String()
output.buffer.Reset()
return text
}
func TestHostLoggingIsIndependentOfInstances(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
output := &logOutput{}
host, err := corehost.New(ctx, corehost.Options{LogWriter: output})
if err != nil {
t.Fatal(err)
}
defer host.Close(ctx)
assertLevel := func(want corehost.LogLevel) {
t.Helper()
got, err := host.LogLevel(ctx)
if err != nil || got != want {
t.Fatalf("log level = %d, %v; want %d", got, err, want)
}
}
assertLevel(corehost.LogLevelInfo)
if err := host.SetLogLevel(ctx, corehost.LogLevelOff); err != nil {
t.Fatal(err)
}
create := func(id int) *corehost.Instance {
t.Helper()
instance, err := host.CreateInstance(ctx, instanceConfig(t, id, "10.144.0.1", 0, false, false))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = instance.Close(context.Background()) })
if err := instance.Start(ctx); err != nil {
t.Fatal(err)
}
return instance
}
first := create(1)
assertLevel(corehost.LogLevelOff)
if text := output.take(); text != "" {
t.Fatalf("logging is off but received %q", text)
}
if err := host.SetLogLevel(ctx, corehost.LogLevelTrace); err != nil {
t.Fatal(err)
}
second := create(2)
assertLevel(corehost.LogLevelTrace)
if text := output.take(); !strings.Contains(text, "[INFO]") {
t.Fatalf("guest did not write info logs: %q", text)
}
if err := first.Close(ctx); err != nil {
t.Fatal(err)
}
assertLevel(corehost.LogLevelTrace)
if err := host.SetLogLevel(ctx, corehost.LogLevelOff); err != nil {
t.Fatal(err)
}
output.take()
if err := second.Close(ctx); err != nil {
t.Fatal(err)
}
third := create(3)
if err := third.Close(ctx); err != nil {
t.Fatal(err)
}
assertLevel(corehost.LogLevelOff)
if text := output.take(); text != "" {
t.Fatalf("logging resumed during instance lifecycle: %q", text)
}
if err := host.SetLogLevel(ctx, corehost.LogLevel(6)); err == nil {
t.Fatal("invalid log level was accepted")
}
assertLevel(corehost.LogLevelOff)
other, err := corehost.New(ctx, corehost.Options{})
if err != nil {
t.Fatal(err)
}
defer other.Close(ctx)
if level, err := other.LogLevel(ctx); err != nil || level != corehost.LogLevelInfo {
t.Fatalf("another Host inherited log level: %d, %v", level, err)
}
if err := other.SetLogLevel(ctx, corehost.LogLevelDebug); err != nil {
t.Fatal(err)
}
assertLevel(corehost.LogLevelOff)
if err := host.Close(ctx); err != nil {
t.Fatal(err)
}
if err := host.SetLogLevel(ctx, corehost.LogLevelInfo); err == nil {
t.Fatal("changed log level after Host shutdown")
}
}
func TestHostLoggingWriterFailureDoesNotStopInstance(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
output := &logOutput{fail: true}
host, err := corehost.New(ctx, corehost.Options{LogWriter: output})
if err != nil {
t.Fatal(err)
}
defer host.Close(ctx)
instance, err := host.CreateInstance(ctx, instanceConfig(t, 1, "10.144.0.1", 0, false, false))
if err != nil {
t.Fatal(err)
}
defer instance.Close(ctx)
if err := instance.Start(ctx); err != nil {
t.Fatal(err)
}
if state := instance.State(); state != corehost.StateRunning {
t.Fatalf("instance state = %d, want running", state)
}
if err := instance.Close(ctx); err != nil {
t.Fatal(err)
}
output.mu.Lock()
defer output.mu.Unlock()
if output.writes == 0 {
t.Fatal("test did not exercise the failing writer")
}
}