Skip to content

Route Provider

Discovers and loads routes from Docker containers, YAML files, and remote agents.

Overview

The internal/route/provider package implements route discovery and loading for GoDoxy. It supports multiple provider types (Docker, File, Agent) and manages route lifecycle including validation, start/stop, and event handling.

Primary Consumers

  • Main entry point: Creates providers during startup
  • Route layer: Provides route instances to registry
  • Watcher system: Receives container/config change events

Non-goals

  • Does not implement route execution (handled by route package)
  • Does not manage global configuration
  • Does not provide authentication

Stability

Internal package with stable provider interface.

Public API

Exported Types

go
type Provider struct {
    ProviderImpl
    t        provider.Type
    routes   route.Routes
    routesMu sync.RWMutex
    watcher  W.Watcher
}

type ProviderImpl interface {
    fmt.Stringer
    ShortName() string
    IsExplicitOnly() bool
    loadRoutesImpl() (route.Routes, error)
    NewWatcher() W.Watcher
    Logger() *zerolog.Logger
}

Exported Functions

go
// Create a file-based provider
func NewFileProvider(filename string) (p *Provider, err error)

// Create a Docker-based provider
func NewDockerProvider(name string, dockerCfg types.DockerProviderConfig) *Provider

// Create an agent-based provider
func NewAgentProvider(cfg *agent.AgentConfig) *Provider

Provider Methods

go
func (p *Provider) GetType() provider.Type
func (p *Provider) Start(parent task.Parent) error
func (p *Provider) LoadRoutes() error
func (p *Provider) IterRoutes(yield func(string, types.Route) bool)
func (p *Provider) GetRoute(alias string) (types.Route, bool)
func (p *Provider) FindService(project, service string) (types.Route, bool)

Architecture

Core Components

Provider Types

Route Loading Flow

Docker Provider Features

  • Lists all containers and reads their labels
  • Supports Docker Compose project/service discovery
  • Handles host network mode with port detection
  • Supports alias references (#1, #2 for container aliases)
  • Explicit-only mode for providers ending with !

File Provider Features

  • Reads YAML files from the config directory
  • Validates routes on load
  • Supports embedded presets

Agent Provider Features

  • Connects to a remote agent via Unix socket or TCP
  • Delegates to a Docker provider internally
  • Supports the same Docker label-based route discovery

Configuration Surface

Docker Provider Labels

yaml
labels:
  proxy.aliases: app1,app2
  proxy.app1.listen: http://0.0.0.0:8080
  proxy.app1.target: http://app:3000
  proxy.app1.rules: |
    - name: default
      do: pass

File Provider Configuration

yaml
# config/routes/myapp.yml
routes:
  myapp:
    target: http://localhost:8080
    rules:
      - name: default
        do: pass

Agent Provider Configuration

yaml
agents:
  remote:
    socket: /run/godoxy-agent.sock
    name: remote-agent

Dependency and Integration Map

DependencyPurpose
internal/routeRoute types and validation
internal/route/routesRoute registry
internal/dockerDocker API integration
internal/serializationYAML parsing
internal/watcherContainer/config watching
internal/watcher/eventsEvent queue handling
agent/pkg/agentAgent configuration
github.com/yusing/goutils/errsError handling

Observability

Logs

  • INFO: Provider start/stop, route count
  • DEBUG: Route loading details, label parsing
  • ERROR: Container fetch errors, parse failures

Log context includes: provider, alias, route_count

Metrics

  • routes_loaded_total by provider
  • provider_events_total by type

Security Considerations

  • Docker provider requires socket access
  • Agent provider uses Unix socket or TCP with auth
  • Route validation prevents SSRF via URL validation
  • Container labels are validated before use

Failure Modes and Recovery

FailureBehaviorRecovery
Docker socket unavailableProvider fails to startFix socket permissions
Container not foundRoute excluded with errorVerify container exists
YAML parse errorRoute excluded, error loggedFix configuration file
Agent connection lostRoutes removed, reconnectionFix agent connectivity
Watcher errorProvider finishes with errorCheck watcher logs

Usage Examples

Creating a Docker Provider

go
provider := provider.NewDockerProvider("default", types.DockerProviderConfig{
    URL: "unix:///var/run/docker.sock",
})

if err := provider.LoadRoutes(); err != nil {
    return err
}

if err := provider.Start(parentTask); err != nil {
    return err
}

Creating a File Provider

go
provider, err := provider.NewFileProvider("routes/myapp.yml")
if err != nil {
    return err
}

if err := provider.Start(parentTask); err != nil {
    return err
}

Iterating Over Routes

go
for alias, r := range provider.IterRoutes {
    log.Printf("Route: %s -> %s", alias, r.Name())
}

Finding a Service

go
route, ok := provider.FindService("myproject", "myservice")
if ok {
    log.Printf("Found service: %s", route.Name())
}

Testing Notes

  • Docker provider tests use test containers
  • File provider tests use temp directories
  • Agent provider tests use mock agents
  • Integration tests cover event handling

Released under the MIT License.