discovery

package
v0.0.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SourceStandalone = "standalone"
	SourceCompose    = "compose"
	// SourceAspire marks apps injected via the DEVDASHBOARD_APP_* env
	// contract (aspire mode, or mode-unset with the contract present).
	SourceAspire = "aspire"
	// SourceTestcontainers marks daprd sidecars run by Testcontainers
	// (org.testcontainers=true label), e.g. dapr-spring-boot-starter-test.
	SourceTestcontainers = "testcontainers"
)
View Source
const (
	StatusRunning = "running"
	StatusStopped = "stopped"
)

Per-target process status. Empty string means unknown.

Variables

View Source
var ErrNotFound = errors.New("app not found")

Functions

func AspireContractPresent added in v0.0.9

func AspireContractPresent(getenv func(string) string) bool

AspireContractPresent reports whether the DEVDASHBOARD_APP_* env contract is set at all (anchor variable: DEVDASHBOARD_APP_COUNT). Used with mode unset to decide whether the aspire source joins the merge.

func InferRuntime

func InferRuntime(appCommand string) string

InferRuntime guesses the app's language from its launch command (best-effort).

func InferRuntimeFromEnv added in v0.0.7

func InferRuntimeFromEnv(env []string) string

InferRuntimeFromEnv guesses the app's language from environment variables inherited from official base images (best-effort, conservative — only well-known variable names count, never values).

func InferRuntimeFromImage

func InferRuntimeFromImage(image string) string

InferRuntimeFromImage guesses the app's language from its container image name (best-effort; conservative — a bespoke image name yields "unknown").

func TranslateMountPath

func TranslateMountPath(mounts map[string]string, containerPath string) (string, bool)

TranslateMountPath maps a container-internal path to its host path via a bind-mount table (exact destination match or destination-prefix match). Container paths are always slash-separated (Linux containers).

Types

type ActorType

type ActorType struct {
	Type  string `json:"type"`
	Count int    `json:"count"`
}

type Component

type Component struct {
	Name    string `json:"name"`
	Type    string `json:"type"`
	Version string `json:"version,omitempty"`
}

type ComposeEnv

type ComposeEnv struct {
	Projects map[string]ComposeProject
	// PathProject maps each host resource/config dir found on a sidecar to its
	// compose project name.
	PathProject map[string]string
}

ComposeEnv is the compose network/mount context from the last scan. The reconciler uses it to translate store addresses to host-reachable ones.

func (ComposeEnv) ProjectForPath

func (e ComposeEnv) ProjectForPath(p string) (string, bool)

ProjectForPath returns the compose project owning p (p equal to, or nested under, one of the scanned host resource dirs).

type ComposeProject

type ComposeProject struct {
	// ServicePorts maps service name -> container port -> published host port.
	ServicePorts map[string]map[int]int
	// Mounts maps container destination -> host source, merged across the
	// project's daprd sidecars (first destination wins). Used for SQLite
	// connection-path translation.
	Mounts map[string]string
}

ComposeProject is the host-reachable view of one compose project.

type ComposeSource

type ComposeSource struct {
	// contains filtered or unexported fields
}

ComposeSource discovers Dapr sidecars running in compose-managed containers. A nil runner (no docker/podman) degrades to an empty, error-free scan.

func NewComposeSource

func NewComposeSource(run containerruntime.Runner) *ComposeSource

func (*ComposeSource) Env

func (s *ComposeSource) Env() ComposeEnv

Env returns the compose endpoint/mount context from the last successful scan.

func (*ComposeSource) Scanner

func (s *ComposeSource) Scanner() Scanner

Scanner returns the compose scan as a discovery.Scanner.

type ExtractedFile added in v0.0.10

type ExtractedFile struct {
	Container string
	Path      string
	Content   []byte
}

ExtractedFile is one YAML file copied out of a daprd container's resources dir. Container is the container name (display identity), Path the container-internal file path.

type Health

type Health string

Health represents the health status of an instance

const (
	HealthHealthy   Health = "healthy"
	HealthStarting  Health = "starting"
	HealthUnhealthy Health = "unhealthy"
	HealthUnknown   Health = "unknown"
)

func CheckHealth

func CheckHealth(ctx context.Context, client *http.Client, baseURL string) Health

CheckHealth probes a sidecar's /v1.0/healthz endpoint at baseURL.

type Instance

type Instance struct {
	AppID string `json:"appId"`
	// InstanceKey is the routing identity: container name for compose apps
	// (falling back to app id), app id otherwise. Unique per instance even
	// when several compose sidecars share one -app-id.
	InstanceKey        string `json:"instanceKey"`
	Health             Health `json:"health"`
	Runtime            string `json:"runtime"`            // e.g. "go", "python", "node", "dotnet", "java", "rust", "unknown"
	IsAspire           bool   `json:"isAspire,omitempty"` // true when the app is .NET Aspire-managed
	Source             string `json:"source"`             // "standalone" | "compose" | "aspire"
	ComposeProject     string `json:"composeProject,omitempty"`
	ComposeService     string `json:"composeService,omitempty"`
	DaprdContainerID   string `json:"daprdContainerId,omitempty"`
	DaprdContainerName string `json:"daprdContainerName,omitempty"`
	AppContainerID     string `json:"appContainerId,omitempty"`
	AppContainerName   string `json:"appContainerName,omitempty"`
	SidecarReachable   bool   `json:"sidecarReachable"`
	// DaprHTTPBaseURL is the daprd HTTP endpoint for aspire-source apps
	// ("" otherwise; consumers fall back to 127.0.0.1:httpPort).
	DaprHTTPBaseURL string `json:"daprHttpBaseUrl,omitempty"`
	Namespace       string `json:"namespace,omitempty"`
	Label           string `json:"label,omitempty"`

	// TestcontainersSession groups one Testcontainers run's containers
	// (org.testcontainers.sessionId label; "" for other sources).
	TestcontainersSession string `json:"testcontainersSession,omitempty"`

	HTTPPort       int    `json:"httpPort"`
	GRPCPort       int    `json:"grpcPort"`
	AppPort        int    `json:"appPort"`
	AppProtocol    string `json:"appProtocol,omitempty"`
	DaprdPID       int    `json:"daprdPid"`
	AppPID         int    `json:"appPid"` // 0 = unknown
	CLIPID         int    `json:"cliPid"`
	AppStatus      string `json:"appStatus,omitempty"`      // "running" | "stopped"; "" unknown
	DaprdStatus    string `json:"daprdStatus,omitempty"`    // "running" | "stopped"; "" unknown
	AppStartedAt   string `json:"appStartedAt,omitempty"`   // RFC3339 UTC; "" when stopped/unknown
	DaprdStartedAt string `json:"daprdStartedAt,omitempty"` // RFC3339 UTC; "" when stopped/unknown
	// SidecarOrphaned marks a standalone daprd with no supervising dapr CLI
	// and no live app (e.g. an external stop missed a detached sidecar).
	SidecarOrphaned bool           `json:"sidecarOrphaned,omitempty"`
	Age             string         `json:"age"`     // human, e.g. "14m"
	Created         string         `json:"created"` // local time string
	RunTemplate     string         `json:"runTemplate"`
	ResourcePaths   []string       `json:"resourcePaths"`
	ConfigPath      string         `json:"configPath"`
	AppLogPath      string         `json:"appLogPath"`
	DaprdLogPath    string         `json:"daprdLogPath"`
	AppLogFormat    string         `json:"appLogFormat,omitempty"`   // "" / "plain" / "dcp"
	DaprdLogFormat  string         `json:"daprdLogFormat,omitempty"` // "" / "plain" / "dcp"
	Command         string         `json:"command"`
	RuntimeVersion  string         `json:"runtimeVersion"` // from metadata; "" if unavailable
	MetadataOK      bool           `json:"metadataOk"`     // false if /v1.0/metadata failed
	Actors          []ActorType    `json:"actors,omitempty"`
	Subscriptions   []Subscription `json:"subscriptions,omitempty"`
	Components      []Component    `json:"components,omitempty"`
	EnabledFeatures []string       `json:"enabledFeatures,omitempty"`
	Placement       string         `json:"placement,omitempty"`
}

Instance represents a running application instance with Dapr

func (Instance) BaseURL added in v0.0.15

func (in Instance) BaseURL() string

BaseURL resolves this instance's daprd HTTP endpoint (aspire base URL wins, else the loopback-port form).

type Metadata

type Metadata struct {
	ID              string
	RuntimeVersion  string
	AppPID          int
	CLIPID          int
	AppCommand      string
	AppLogPath      string
	DaprdLogPath    string
	RunTemplate     string
	AppProtocol     string
	Actors          []ActorType
	Subscriptions   []Subscription
	Components      []Component
	EnabledFeatures []string
	Placement       string
}

func FetchMetadata

func FetchMetadata(ctx context.Context, client *http.Client, baseURL string) (Metadata, error)

FetchMetadata queries a sidecar's /v1.0/metadata endpoint at baseURL.

type ScanResult

type ScanResult struct {
	AppID         string
	HTTPPort      int
	GRPCPort      int
	AppPort       int
	DaprdPID      int
	CLIPID        int
	Created       time.Time
	RunTemplate   string
	ResourcePaths []string
	ConfigPath    string
	Command       string
	AppProtocol   string

	// Source is SourceStandalone (process table) or SourceCompose (containers).
	Source             string
	ComposeProject     string
	ComposeService     string
	DaprdContainerID   string
	DaprdContainerName string
	AppContainerID     string
	AppContainerName   string
	AppImage           string
	// AppRuntime is the compose scanner's language inference for the app
	// container ("" for other sources; possibly "unknown").
	AppRuntime string
	// SidecarReachable is false only for compose sidecars whose HTTP port is
	// not published to the host (metadata/health enrichment impossible).
	SidecarReachable bool

	// DaprHTTPBaseURL, when set (aspire source), replaces
	// http://127.0.0.1:<HTTPPort> as the daprd HTTP endpoint for health,
	// metadata, and workflow calls.
	DaprHTTPBaseURL string
	// Namespace and Label come from the Aspire env contract ("" for other
	// sources). Label is the orchestrator's display name for the app.
	Namespace string
	Label     string

	// TestcontainersSession groups one Testcontainers run's containers
	// (org.testcontainers.sessionId label; "" for other sources).
	TestcontainersSession string

	// Per-target lifecycle status ("" = unknown; compose scanner and standalone enrichment set these).
	AppStatus      string
	DaprdStatus    string
	AppStartedAt   time.Time
	DaprdStartedAt time.Time
}

func (ScanResult) Key added in v0.0.7

func (r ScanResult) Key() string

Key returns the routing identity for this scan result. Compose sidecars can share one -app-id (scaled instances), so they key by container name — the app container when paired, else the daprd container; everything else keys by AppID. Container names are unique per host, so keys are unique whenever a container name is available.

type Scanner

type Scanner func() ([]ScanResult, error)

func Merge

func Merge(scanners ...Scanner) Scanner

Merge combines scanners into one. A failing scanner is logged and skipped so one source (e.g. docker being absent) never hides the others; the merged scan errors only when every scanner fails. When any result has Source == SourceAspire, it wins key collisions: every other result sharing its Key() is dropped (an Aspire-launched daprd host process is otherwise double-counted by both the standalone scan and the env contract). Order is stable otherwise.

func NewAspireScanner added in v0.0.9

func NewAspireScanner(getenv func(string) string) (Scanner, error)

NewAspireScanner parses the DEVDASHBOARD_APP_* env contract eagerly and returns a static Scanner over the parsed apps. Malformed contracts fail here — at startup — with an error naming the exact variable, never at scan time. The returned scanner is static: env is read once; liveness comes from the discovery service's per-poll health/metadata probes.

func StandaloneScanner

func StandaloneScanner() Scanner

StandaloneScanner returns a Scanner that reads running Dapr sidecars from the local process table via the Dapr CLI standalone.List function.

type Service

type Service interface {
	List(ctx context.Context) ([]Instance, error)
	// Get resolves key as an InstanceKey first, then as an AppID (first match).
	Get(ctx context.Context, key string) (Instance, error)
}

func FilterAspire added in v0.0.11

func FilterAspire(inner Service) Service

FilterAspire restricts a Service to Aspire-managed instances. Aspire host mode (dashboard on the host, no env contract) scans the full process table — IsAspire is only known after enrichment (the DCP-proxy heuristic in appproc.go), so the filter must wrap the Service rather than the Scanner. Wrap the outermost Service (after the lifecycle overlay) so every consumer — apps API, workflows, state-store election — sees the filtered view.

func New

func New(scan Scanner, client *http.Client) Service

type SubRule

type SubRule struct {
	Match string `json:"match,omitempty"`
	Path  string `json:"path,omitempty"`
}

type Subscription

type Subscription struct {
	PubsubName      string    `json:"pubsubName"`
	Topic           string    `json:"topic"`
	Rules           []SubRule `json:"rules,omitempty"`
	DeadLetterTopic string    `json:"deadLetterTopic,omitempty"`
	Type            string    `json:"type,omitempty"`
}

type TestcontainersSource added in v0.0.10

type TestcontainersSource struct {
	// contains filtered or unexported fields
}

TestcontainersSource discovers daprd sidecars run by Testcontainers (e.g. dapr-spring-boot-starter-test): containers labeled org.testcontainers=true whose argv invokes daprd. The paired app is a host process reached via host.testcontainers.internal; enrichment resolves it from the app port. A nil runner (no docker/podman) degrades to an empty, error-free scan.

func NewTestcontainersSource added in v0.0.10

func NewTestcontainersSource(run containerruntime.Runner) *TestcontainersSource

func (*TestcontainersSource) Files added in v0.0.10

func (s *TestcontainersSource) Files() []ExtractedFile

Files returns the extracted resource files of all currently-scanned containers, ordered by container name then path.

func (*TestcontainersSource) Scanner added in v0.0.10

func (s *TestcontainersSource) Scanner() Scanner

Scanner returns the testcontainers scan as a discovery.Scanner.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL