Service Type This document describes the design of the service resource type for managing system services.
Overview The service resource manages system services with two independent dimensions:
Running state : Whether the service is currently running or stoppedEnabled state : Whether the service starts automatically at bootThese are managed independently, allowing combinations like “running but disabled” or “stopped but enabled”.
Provider Interface Service providers must implement the ServiceProvider interface:
type ServiceProvider interface {
model .Provider
Enable (ctx context .Context , service string ) error
Disable (ctx context .Context , service string ) error
Start (ctx context .Context , service string ) error
Stop (ctx context .Context , service string ) error
Restart (ctx context .Context , service string ) error
Status (ctx context .Context , service string ) (* model .ServiceState , error )
} Method Responsibilities Method Responsibility StatusQuery current running and enabled state StartStart the service if not running StopStop the service if running RestartStop and start the service (for refresh) EnableConfigure service to start at boot DisableConfigure service to not start at boot
Status Response The Status method returns a ServiceState containing:
type ServiceState struct {
CommonResourceState
Metadata * ServiceMetadata
}
type ServiceMetadata struct {
Name string // Service name
Provider string // Provider name (e.g., "systemd")
Enabled bool // Whether service starts at boot
Running bool // Whether service is currently running
} The Ensure field in CommonResourceState is set to:
running if the service is activestopped if the service is inactiveAvailable Providers Provider Init System Documentation systemdsystemd Systemd
Ensure States Value Description runningService must be running (default) stoppedService must be stopped
If ensure is not specified, it defaults to running.
Enable Property The enable property is a boolean pointer (*bool) with three possible states:
Value Behavior trueEnable service to start at boot falseDisable service from starting at boot nil (not set)Leave boot configuration unchanged
This allows managing running state without affecting boot configuration:
# Start service but don't change boot config
- service :
- myapp :
ensure : running
# Start and enable at boot
- service :
- myapp :
ensure : running
enable : true
# Stop and disable at boot
- service :
- myapp :
ensure : stopped
enable : false Apply Logic The service type applies changes in two phases:
Phase 1: Running State βββββββββββββββββββββββββββββββββββββββββββ
β Check for subscribe refresh β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βββββββββββββββ΄ββββββββββββββ
β Subscribed resource β
β changed? β
βββββββββββββββ¬ββββββββββββββ
Yes β β No
βΌ β
βββββββββββββββββββββββ β
β ensure=running? β β
β already running? β β
βββββββββββββββ¬ββββββββ β
Yes+Yes β β
βΌ β
βββββββββββββ β
β Restart β β
βββββββββββββ β
βΌ
βββββββββββββββββββββββββββ
β Compare ensure vs state β
βββββββββββββββ¬ββββββββββββ
β
βββββββββββββββββββββββββΌββββββββββββββββββββββββ
β ensure=stopped β ensure=running β
β state=running β state=stopped β
βΌ βΌ β
ββββββββββ ββββββββββ β
β Stop β β Start β β
ββββββββββ ββββββββββ β
βΌ
βββββββββββββββββ
β No change β
βββββββββββββββββPhase 2: Enabled State After running state is handled, enabled state is processed:
βββββββββββββββββββββββββββββββββββββββββββ
β enable property set? β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
nil β true/false
βΌ β
βββββββββββββ β
β No change β β
βββββββββββββ β
βΌ
βββββββββββββββββββββββββββββββ
β Compare enable vs enabled β
βββββββββββββββ¬ββββββββββββββββ
β
βββββββββββββββΌββββββββββββββ
β enable=true β enable=falseβ
β !enabled β enabled β
βΌ βΌ β
ββββββββββ βββββββββββ β
β Enable β β Disable β β
ββββββββββ βββββββββββ β
βΌ
βββββββββββββββββ
β No change β
βββββββββββββββββSubscribe Behavior Services can subscribe to other resources and restart when they change:
- service :
- httpd :
ensure : running
subscribe :
- file#/etc/httpd/conf/httpd.conf
- package#httpd Special Cases:
Condition Behavior ensure: stoppedSubscribe ignored (no restart) Service not running + ensure: running Start (not restart) Service running + ensure: running Restart
This prevents restarting stopped services and ensures a clean start when the service should be running but isn’t.
Idempotency The service resource is idempotent through state comparison:
Desired Current Action ensure: runningrunning None ensure: runningstopped Start ensure: stoppedstopped None ensure: stoppedrunning Stop enable: trueenabled None enable: truedisabled Enable enable: falseenabled Disable enable: falsedisabled None enable: nilany None
Desired State Validation After applying changes, the type verifies the service reached the desired state:
func (t * Type ) isDesiredState (properties , state ) bool {
// Check running state
if properties .Ensure != state .Ensure {
return false
}
// Check enabled state (only if explicitly set)
if properties .Enable != nil {
if * properties .Enable != state .Metadata .Enabled {
return false
}
}
return true
} If the desired state is not reached, an ErrDesiredStateFailed error is returned.
Service Name Validation Service names are validated to prevent injection attacks:
Allowed Characters:
Alphanumeric (a-z, A-Z, 0-9) Period (.), underscore (_), plus (+) Colon (:), tilde (~), hyphen (-) Rejected:
Shell metacharacters (;, |, &, etc.) Whitespace Path separators Noop Mode In noop mode, the service type:
Queries current state normally Logs what actions would be taken Sets appropriate NoopMessage (e.g., “Would have started”, “Would have enabled”) Reports Changed: true if changes would occur Does not call provider Start/Stop/Restart/Enable/Disable methods