mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-10-15 17:16:14 -08:00
fix(wasi): initialize and control embedded runtime logging (#2655)
This commit is contained in:
27 files changed
+869
-107
No files matched your search
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
@@ -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.
@@ -3,6 +3,6 @@
|
||||
package artifact
|
||||
|
||||
const (
|
||||
Commit = "9a2290f312dbdec6f40e8b13d8a6de5f66e4c570"
|
||||
SHA256 = "044f9ed79079f449741744d9dd0559d6844e1fff2f1a1994710811904f119986"
|
||||
Commit = "c51437c673a71f69b4b028c8d566a7b23b33e65c"
|
||||
SHA256 = "17d6dd4561c1f1e818e7d70ed031c3cf8ea5dcfc1fd0461a6753f1f23f5fa6ab"
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,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
|
||||
|
||||
@@ -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,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,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,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
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
package proto
|
||||
|
||||
const (
|
||||
EasyTierCommit = "9a2290f312dbdec6f40e8b13d8a6de5f66e4c570"
|
||||
SchemaSHA256 = "c145983fee99e08f6207c425cea0952c1aaf50f9bfea12c834d1ec985e0b39df"
|
||||
EasyTierCommit = "c51437c673a71f69b4b028c8d566a7b23b33e65c"
|
||||
SchemaSHA256 = "e49a4af09e5b66089eebb73fda78ffca7e8468a5a938cf7a593d689881686f0a"
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user