service

package
v0.1.0-dev.20260823192442 Latest Latest
Warning

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

Go to latest
Published: Aug 23, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package service provides platform-agnostic service management actions.

Index

Constants

View Source
const (
	Disable op.ActionName = "service.disable"
	Enable  op.ActionName = "service.enable"
	Enabled op.ActionName = "service.enabled"
	Exists  op.ActionName = "service.exists"
	Restart op.ActionName = "service.restart"
	Running op.ActionName = "service.running"
	Start   op.ActionName = "service.start"
	Stop    op.ActionName = "service.stop"
)

Action-name constants for the service provider's plan-mode actions.

Each constant is the short dotted action label its method dispatches under. Pass these to plan.Plan, op.ReceiverRegistry().BuildAction, RuntimeEnvironment.ActionByName, or WithActionNamed in place of a string literal so a typo is a compile error and rename / find-references work through the constant.

Variables

This section is empty.

Functions

This section is empty.

Types

type Provider

type Provider struct {
	op.ProviderBase
}

Provider provides platform-agnostic service management.

Platform-specific behavior is delegated to p.RuntimeEnvironment().Platform.ServiceManager.

+devlore:access=planned

func NewProvider

func NewProvider(runtimeEnvironment *op.RuntimeEnvironment) *Provider

NewProvider creates a service provider bound to the given runtime environment.

func (*Provider) CompensateDisable

func (p *Provider) CompensateDisable(activationRecord *op.ActivationRecord, receipt *Receipt) error

CompensateDisable undoes a Disable by re-enabling the service if it was enabled before.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the *Receipt from Provider.Disable; a no-op when serviceless or not enabled.

Returns:

  • `error`: non-nil when no service manager is available or the enable command fails.

func (*Provider) CompensateEnable

func (p *Provider) CompensateEnable(activationRecord *op.ActivationRecord, receipt *Receipt) error

CompensateEnable undoes an Enable by disabling the service if it wasn't enabled before.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the *Receipt from Provider.Enable; a no-op when serviceless or already enabled.

Returns:

  • `error`: non-nil when no service manager is available or the disable command fails.

func (*Provider) CompensateRestart

func (p *Provider) CompensateRestart(activationRecord *op.ActivationRecord, _ *Receipt) error

CompensateRestart is a no-op. A restarted service was already running.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the *Receipt from Provider.Restart; ignored.

Returns:

  • `error`: always nil.

func (*Provider) CompensateStart

func (p *Provider) CompensateStart(activationRecord *op.ActivationRecord, receipt *Receipt) error

CompensateStart undoes a Start by stopping the service if it wasn't running before.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the *Receipt from Provider.Start; a no-op when serviceless or already running.

Returns:

  • `error`: non-nil when no service manager is available or the stop command fails.

func (*Provider) CompensateStop

func (p *Provider) CompensateStop(activationRecord *op.ActivationRecord, receipt *Receipt) error

CompensateStop undoes a Stop by starting the service if it was running before.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensating actions — step 27).
  • `receipt`: the *Receipt from Provider.Stop; a no-op when serviceless or not running.

Returns:

  • `error`: non-nil when no service manager is available or the start command fails.

func (*Provider) Disable

func (p *Provider) Disable(activationRecord *op.ActivationRecord, name *Resource) (*Resource, *Receipt, error)

Disable disables a service from starting at boot.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `name`: service resource identifying the service.

Returns:

  • `*Resource`: the service resource (identity unchanged).
  • `*Receipt`: compensation state recording whether the service was enabled before.
  • `error`: non-nil when no service manager is available or the disable command fails.

func (*Provider) Enable

func (p *Provider) Enable(activationRecord *op.ActivationRecord, name *Resource) (*Resource, *Receipt, error)

Enable enables a service to start at boot.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `name`: service resource identifying the service.

Returns:

  • `*Resource`: the service resource (identity unchanged).
  • `*Receipt`: compensation state recording whether the service was enabled before.
  • `error`: non-nil when no service manager is available or the enable command fails.

func (*Provider) Enabled

func (p *Provider) Enabled(name *Resource) (bool, error)

Enabled returns true if the named service is enabled to start at boot.

Parameters:

  • `name`: service resource to check.

Returns:

  • `bool`: true when the service is enabled.
  • `error`: non-nil when no service manager is available.

func (*Provider) Exists

func (p *Provider) Exists(name *Resource) (bool, error)

Exists returns true if the named service exists on the system.

Parameters:

  • `name`: service resource to check.

Returns:

  • `bool`: true when the service exists.
  • `error`: non-nil when no service manager is available.

func (*Provider) Restart

func (p *Provider) Restart(activationRecord *op.ActivationRecord, name *Resource) (*Resource, *Receipt, error)

Restart restarts a service by stopping then starting it.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `name`: service resource identifying the service.

Returns:

  • `*Resource`: the service resource (identity unchanged).
  • `*Receipt`: compensation state; Provider.CompensateRestart is a no-op (the service was already running).
  • `error`: non-nil when no service manager is available or the stop/start commands fail.

func (*Provider) Running

func (p *Provider) Running(name *Resource) (bool, error)

Running returns true if the named service is currently running.

Parameters:

  • `name`: service resource to check.

Returns:

  • `bool`: true when the service is running.
  • `error`: non-nil when no service manager is available.

func (*Provider) Start

func (p *Provider) Start(activationRecord *op.ActivationRecord, name *Resource) (*Resource, *Receipt, error)

Start starts a service.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `name`: service resource identifying the service.

Returns:

  • `*Resource`: the service resource (identity unchanged).
  • `*Receipt`: compensation state recording whether the service was running before.
  • `error`: non-nil when no service manager is available or the start command fails.

func (*Provider) Stop

func (p *Provider) Stop(activationRecord *op.ActivationRecord, name *Resource) (*Resource, *Receipt, error)

Stop stops a service.

Parameters:

  • `activationRecord`: the dispatch activation (the required floor for compensable actions — step 27).
  • `name`: service resource identifying the service.

Returns:

  • `*Resource`: the service resource (identity unchanged).
  • `*Receipt`: compensation state recording whether the service was running before.
  • `error`: non-nil when no service manager is available or the stop command fails.

type Receipt

type Receipt struct {
	op.ReceiptBase

	// WasRunning records whether the service was running before the action.
	WasRunning bool

	// WasEnabled records whether the service was enabled before the action.
	WasEnabled bool
}

Receipt holds service-specific compensation state for Provider.Start, Provider.Stop, Provider.Enable, and Provider.Disable calls.

The embedded op.ReceiptBase carries the affected service Resource and the opaque op.ReceiptBase.TransactionID minted at op.ReceiptBase.Commit time. The service name is read through the resource — no per-receipt name field. WasRunning and WasEnabled record the pre-call running and enabled flags so the corresponding Compensate methods can restore the service to its prior state.

func (*Receipt) MarshalJSON

func (r *Receipt) MarshalJSON() ([]byte, error)

MarshalJSON encodes the receipt as JSON: the base envelope (action, resource_uri, transaction_id) extended with was_running and was_enabled.

Delegates to Receipt.MarshalYAML for the serialized-shape value, then runs json.Marshal over it.

Returns:

func (*Receipt) MarshalYAML

func (r *Receipt) MarshalYAML() (any, error)

MarshalYAML returns the receipt's full state as an anonymous struct value the YAML encoder serializes.

Returns:

  • `any`: the populated anonymous struct for the YAML encoder to walk.
  • `error`: nil under normal conditions.

func (*Receipt) RestoreEncoded

func (r *Receipt) RestoreEncoded(
	runtimeEnvironment *op.RuntimeEnvironment, base op.ReceiptData, fields map[string]any,
) error

RestoreEncoded reconstructs the receipt from its codec-decoded envelope, resolving its service Resource against the rehydrated catalog.

It is the op.Receipt.RestoreEncoded override the recovery stack drives at re-arm (via [op.reconstructReceipt]) — the env is threaded in explicitly as a parameter, not read off the receiver, so the stack path (which loads a bare receipt before the catalog is rehydrated) can reconstruct it. The service Resource is resolved from `base.ResourceURI` (its "svc:" scheme stripped) via DiscoverResource; the base is re-seated via op.NewReceiptBase so op.ReceiptBase.Restore's URI-match check has a live resource, then Restore writes the full base and the service-specific `was_running` / `was_enabled` flags are read from `fields`.

Parameters:

  • `runtimeEnvironment`: the resume environment; its catalog must hold (or be able to construct) the resource.
  • `base`: the codec-decoded base execution state; its `ResourceURI` ("svc:<name>") names the resource.
  • `fields`: the receipt's whole decoded object; `was_running` / `was_enabled` are read from it.

Returns:

  • `error`: a missing catalog. The envelope and the rehydrated catalog arrive post-op.LoadTrace — checksum-verified — so a missing or mistyped resource entry, a base-restore failure, or a mistyped flag field is a serialization bug and panics (docs/architecture/5-graph-trace-integrity.md).

type Resource

type Resource struct {
	op.ResourceBase

	// Name is the service name (e.g., "nginx", "sshd"). Identity-bearing — appears in the URI <specific> as
	// `svc:<Name>`. Derivable from URI.
	Name string
}

Resource represents a system service identified by name.

Location-keyed: the canonical URI is `tag:devlore.noblefactor.com,2026-01-01:svc:<Name>#...service.Resource`. Service state (running, enabled, mode, last-changed) is host-side and not part of identity — two service.Resources with the same Name on different hosts share a URI and a catalog entry.

func DiscoverResource

func DiscoverResource(runtimeEnvironment *op.RuntimeEnvironment, value any) (*Resource, error)

DiscoverResource registers a service.Resource via op.ResourceCatalog.Discover without claiming production.

Used by the framework's resource registry adapter for slot coercion (when starlark supplies a string and the slot expects a *service.Resource) and by callers holding a reference handle without claiming production. UnmarshalJSON / UnmarshalText / UnmarshalYAML rehydration is the canonical use case.

Discover does not stamp a producer, so unlike NewResource it takes only `runtimeEnvironment` — no unit reference is needed.

Same value-shape dispatch as NewResource: bare service name or canonical tag URI.

Nil-Catalog tolerance: returns the unlinked candidate when no catalog is present.

Parameters:

  • `runtimeEnvironment`: the session runtime environment.
  • `value`: a bare service name string, or a canonical tag URI; same dispatch as NewResource.

Returns:

  • `*Resource`: canonical catalog entry, or the unlinked candidate when no catalog is present.
  • `error`: non-string input, malformed URI, or op.ResourceBase construction failure.

func NewResource

func NewResource(runtimeEnvironment *op.RuntimeEnvironment, producerID string, value any) (*Resource, error)

NewResource constructs a service.Resource and claims production via op.ResourceCatalog.GetOrCreate.

Use NewResource from a producer dispatch context — typically a provider method that has received an op.ActivationRecord from the framework. The returned Resource is the canonical catalog entry, stamped with `producerID = activationRecord.CallerID.ID()` (or empty when `Unit` is nil for non-graph dispatch). Use DiscoverResource instead when the caller is not claiming production (rehydration, reference handles, the framework's slot-coercion adapter).

Today no service provider method actually claims production — Start, Stop, Enable, Disable, Restart all take an existing *Resource and mutate the on-host service state without changing the URI. NewResource exists for symmetry with the two-constructor pattern and as a stable surface for any future service producer.

Nil-Catalog tolerance: returns the unlinked candidate when no catalog is present.

Parameters:

  • `runtimeEnvironment`: the session runtime environment.
  • `producerID`: the producing caller's id (`activationRecord.CallerID`), or "" for caller-less dispatch. for non-graph dispatch.
  • `value`: a bare service name string, or a canonical tag URI (`tag:..:svc:<name>#...`).

Returns:

  • `*Resource`: canonical catalog entry, or the unlinked candidate when no catalog is present.
  • `error`: non-string input, malformed URI, or op.ResourceBase construction failure.

func (*Resource) Addressing

func (r *Resource) Addressing() op.AddressingMode

Addressing reports that service.Resource is location-keyed by service name.

Overrides op.ResourceBase.Addressing's op.AddressingUnknown default. The boot-discipline check in pkg/op/addressing_test.go relies on every announced Resource type returning a non-Unknown mode here.

Returns:

func (*Resource) CanConvertFrom

func (*Resource) CanConvertFrom(source reflect.Type) bool

CanConvertFrom reports whether `source` can be projected into a *Resource via Resource.ConvertFrom.

Opts the service Resource into the framework's op.TargetConverter contract — accepted source shape is `string` (interpreted as a bare service name like "nginx", or a canonical tag URI like `tag:..:svc:<name>#...`). The framework consults this probe both at plan-time via [op.typesAreInterconvertible] (the bubble-up parameter-consistency check) and at dispatch-time via op.Convert step 7 (env-less fallback). The canonical dispatch-time path remains the registered constructor at op.Convert step 6, which receives the full op.RuntimeEnvironment and dispatches the bare-name vs URI input shape via [buildCandidate].

Cheap-probe contract: this method is called against a nil-or-zero `*Resource` receiver by [op.typesAreInterconvertible] during plan-time bubble-up checks. MUST NOT dereference receiver fields.

Parameters:

  • `source`: the candidate source type to test.

Returns:

  • `bool`: true when `source` is `string`.

func (*Resource) ConvertFrom

func (*Resource) ConvertFrom(value any) (any, error)

ConvertFrom projects `value` into an env-less unlinked *Resource.

Used by op.Convert step 7 when the env-aware registered constructor (step 6) is unavailable — env-less library callers, tests, or op.RuntimeEnvironment.Registry-missing contexts. The returned Resource carries only the Name set from `value`; the canonical URI on the embedded op.ResourceBase is NOT populated here. Provider methods consuming the projected Resource are responsible for re-canonicalization via their own NewResource/DiscoverResource path when full identity is required.

Parameters:

  • `value`: the source value; must be `string`.

Returns:

  • `any`: the constructed unlinked *Resource.
  • `error`: non-nil when `value` is not a `string`.

func (*Resource) Digest

func (r *Resource) Digest() (op.Digest, error)

Digest returns the SHA-256 of the canonical URI.

Service state (running/enabled/mode) is host-side and not part of identity, so the digest derives from the identity itself (the URI) rather than runtime state. Hashing the URI keeps the digest algorithm consistent with the rest of the system (op.ParseDigest only accepts sha256) and gives service.Resource a stable token for the catalog's etag-mismatch path. Overrides op.ResourceBase.Digest's op.ErrUnimplemented default.

Returns:

  • `op.Digest`: sha256 of the URI; Algorithm = "sha256", Bytes = 32 raw digest bytes.
  • `error`: nil under normal conditions.

func (*Resource) Equal

func (r *Resource) Equal(other any) bool

Equal reports whether r and other identify the same service.Resource.

Strict equality: other must be a *service.Resource (not merely an op.Resource with the same URI). Once the type check passes, URI comparison is delegated to op.ResourceBase.Equal.

Parameters:

  • `other`: candidate value to compare against; nil or any non-*service.Resource value returns false.

Returns:

  • `bool`: true when `other` is a *service.Resource with the same URI as r.

func (*Resource) Etag

func (r *Resource) Etag() (string, error)

Etag returns the canonical URI as the change-detection token.

For a location-keyed Resource whose state is host-side and outside its identity, the URI doubles as the etag: two service.Resources with the same Name share a URI and are the same Resource. Any host-side state change (the service stops, restarts, changes mode) is detected by callers via explicit probes, not through Etag.

Returns:

  • `string`: the canonical URI (identical to op.ResourceBase.URI).
  • `error`: nil under normal conditions.

func (*Resource) String

func (r *Resource) String() string

String returns the compact JSON encoding of the Resource for debug output.

Delegates to op.ResourceBase.Format per the project Go style guideline that String() of every concrete Resource type calls r.Format(r).

Returns:

  • `string`: the compact JSON encoding of r.

func (*Resource) UnmarshalJSON

func (r *Resource) UnmarshalJSON(data []byte) error

UnmarshalJSON populates the receiver from its JSON document (a bare URI string).

The caller pre-seeds the receiver's embedded op.ResourceBase with a valid op.RuntimeEnvironment before invoking this method. The URI alone is sufficient — identity is the service name encoded in the URI's <specific> as `svc:<Name>`.

Parameters:

  • `data`: JSON bytes encoding a single bare URI string.

Returns:

  • `error`: missing RuntimeEnvironment on receiver, malformed JSON, or rehydration failure.

func (*Resource) UnmarshalText

func (r *Resource) UnmarshalText(text []byte) error

UnmarshalText populates the receiver from raw UTF-8 bytes containing the URI.

Same prerequisites and semantics as Resource.UnmarshalJSON; the receiver's op.RuntimeEnvironment must be set before invocation.

Parameters:

  • `text`: UTF-8 bytes containing the canonical tag URI.

Returns:

  • `error`: missing RuntimeEnvironment on receiver, or rehydration failure.

func (*Resource) UnmarshalYAML

func (r *Resource) UnmarshalYAML(unmarshal func(any) error) error

UnmarshalYAML populates the receiver from its YAML document (a bare URI scalar).

Same prerequisites and semantics as Resource.UnmarshalJSON; the receiver's op.RuntimeEnvironment must be set before invocation.

Parameters:

  • `unmarshal`: yaml decode hook supplied by the YAML library; called with a *string target.

Returns:

  • `error`: missing RuntimeEnvironment on receiver, decode failure, or rehydration failure.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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