unitfile

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jan 2, 2023 License: MIT Imports: 12 Imported by: 0

README

SystemD Unit File Encoding for Go

The unitfile package provides utilities for encoding and decoding (certain) Go structs with semantics as similar to encoding/json as possible.

Using

  1. Install the module using go get funkhouse.rs/unitfile
  2. Read the documentation at https://pkg.go.dev/funkhouse.rs/unitfile
  3. Create a struct and Marshal and Unmarshal some Units for fun or profit
Supported Types

Currently, the following builtin types are supported by this package as struct fields. Additionally, pointers to these types are also supported.

  • bool
  • float32, float64
  • int, int64, int32, int16, int8
  • string
  • []string
Decoding

Decoding / Unmarshalling is performed using a lexer and parser generated by ANTLR from a custom grammar. See UnitLexer.g4 and UnitParser.g4.

Though the goal is to be as similar to encoding/json as possible, the structure of SystemD Unit files does not lend them to good generic encoding. I do not recommend you use this library for that purpose. Instead, this library concerns itself exclusively with at-most singly-nested structs. The usual structure of a destination struct will contain the top-level Unit section options as struct fields, and each subsequent section will be a struct.

For some well-known Unit and section types, see wellknown.go. For a simplified example, consider:

type SimpleUnit struct {
  Description string
  Requires    []string
  Service struct {
    StartCommand string `unit:"ExecStart"`
    StopCommand  string `unit:"ExecStop"`
  }
}

Given this struct and ssh.service (in this case, the one distributed with Ubuntu 22.04.1), after unmarshalling

var dest SimpleUnit
unitfile.Unmarshal(must(os.ReadFile("ssh.service")), &dest)

... dest will contain a value, like:

SimpleUnit{
  Description: "OpenBSD Secure Shell server",
  Requires:    []string(nil),
  Service: struct {
    StartCommand string "unit:\"ExecStart\""
    StopCommand  string "unit:\"ExecStop\""
  }{
    StartCommand: "/usr/sbin/sshd -D $SSHD_OPTS",
    StopCommand:  "",
  },
}

Encoding

The encoded / marshalled Unit file content is generated following the rules:

  1. Exported struct fields will be treated as Unit options
  2. Unexported fields will be ignored
  3. Fields of anonymous member structs will be treated as options of the parent
  4. Non-anonymous struct members will be treated as sections
  5. Non-anonymous structs nested more than a single level deep will result in an error.
  6. The name of the output field will be
    • the value of the unit: struct tag if it exists, or
    • the name of the struct field
  7. All field names and values are sorted before output for determinism
  8. Section names are sorted before output, except for the top-level section, which stays at the top
  9. []string fields are output in the repeated key=value format

Continuing the example from above, after re-marshalling dest

data = must(unitfile.Marshal(&dest))

... data will contain a generated Unit file, like:

[Unit]
Description=OpenBSD Secure Shell server
[Service]
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS

Developing

Feature Requests are more likely to be acknowledged if phrased in the form of a Pull Request.

The details of the parser are hidden in funkhouse.rs/unitfile/internal/parser. See the documentation in that package for details on how ANTLR grammar changes should be handled.

Documentation

Overview

Package unitfile contains utilities for encoding and decoding (certain) Go structs. The semantics are as similar to encoding/json as possible.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidDestination is returned when the destination is invalid.
	ErrInvalidDestination = errors.New("invalid unmarshal target")

	// ErrMalformedUnitFile describes an error decodig the Unit file input.
	ErrMalformedUnitFile = errors.New("malformed unit file")
)
View Source
var (
	// ErrInvalidSource is returned when the destination is invalid.
	ErrInvalidSource = errors.New("invalid marshal source")
)

Functions

func Marshal added in v0.1.0

func Marshal(from any, opts ...MarshalOption) ([]byte, error)

Marshal returns the SystemD Unit file encoding of from, which must be a pointer to a struct.

func Strictly

func Strictly(d *decoder)

Strictly is an UnmarshalOption which causes decoding to error when a field contained in the Unit contents would be ignored because the destination does not contain a matching field.

func Unmarshal

func Unmarshal(data []byte, to any, opts ...UnmarshalOption) error

Unmarshal parses SystemD Unit file-encoded data and stores the result in to, which must be a pointer to a struct. When an error is returned, the value of to is undefined.

Types

type InstallSection

type InstallSection struct {
	Alias           []string `unit:"Alias"`
	WantedBy        []string `unit:"WantedBy"`
	RequiredBy      []string `unit:"RequiredBy"`
	Also            []string `unit:"Also"`
	DefaultInstance []string `unit:"DefaultInstance"`
}

InstallSection contains the options for the Install section of SystemD Units.

See https://www.freedesktop.org/software/systemd/man/systemd.unit.html#id-1.12

type MarshalOption added in v0.1.0

type MarshalOption func(*encoder)

MarshalOption modifies the behavior of Marshal.

type Service

type Service struct {
	Unit    `unit:"Unit"`
	Service ServiceSection `unit:"Service"`
	Install InstallSection `unit:"Install"`
}

Service is a SystemD Unit which describes a process controlled and supervised by SystemD.

See: https://www.freedesktop.org/software/systemd/man/systemd.service.html

type ServiceSection

type ServiceSection struct {
	Type                     string        `unit:"Type"`
	ExitType                 string        `unit:"ExitType"`
	RemainAfterExit          string        `unit:"RemainAfterExit"`
	GuessMainPID             string        `unit:"GuessMainPID"`
	PIDFile                  string        `unit:"PIDFile"`
	BusName                  string        `unit:"BusName"`
	ExecStart                string        `unit:"ExecStart"`
	ExecStartPre             string        `unit:"ExecStartPre"`
	ExecStartPost            string        `unit:"ExecStartPost"`
	ExecCondition            string        `unit:"ExecCondition"`
	ExecReload               string        `unit:"ExecReload"`
	ExecStop                 string        `unit:"ExecStop"`
	ExecStopPost             string        `unit:"ExecStopPost"`
	RestartSec               string        `unit:"RestartSec"`
	TimeoutStart             time.Duration `unit:"TimeoutStartSec"`
	TimeoutStop              time.Duration `unit:"TimeoutStopSec"`
	TimeoutAbort             time.Duration `unit:"TimeoutAbortSec"`
	Timeout                  time.Duration `unit:"TimeoutSec"`
	TimeoutStartFailureMode  string        `unit:"TimeoutStartFailureMode"`
	TimeoutStopFailureMode   string        `unit:"TimeoutStopFailureMode"`
	RuntimeMax               time.Duration `unit:"RuntimeMaxSec"`
	RuntimeRandomizedExtra   time.Duration `unit:"RuntimeRandomizedExtraSec"`
	WatchdogDuration         time.Duration `unit:"WatchdogSec"`
	Restart                  string        `unit:"Restart"`
	SuccessExitStatus        string        `unit:"SuccessExitStatus"`
	RestartPreventExitStatus int           `unit:"RestartPreventExitStatus"`
	RestartForceExitStatus   string        `unit:"RestartForceExitStatus"`
	RootDirectoryStartOnly   string        `unit:"RootDirectoryStartOnly"`
	NonBlocking              string        `unit:"NonBlocking"`
	NotifyAccess             string        `unit:"NotifyAccess"`
	Sockets                  string        `unit:"Sockets"`
	FileDescriptorStoreMax   string        `unit:"FileDescriptorStoreMax"`
	USBFunctionDescriptors   string        `unit:"USBFunctionDescriptors"`
	USBFunctionStrings       string        `unit:"USBFunctionStrings"`
	OOMPolicy                string        `unit:"OOMPolicy"`
}

ServiceSection contains the options for the Service section of SystemD Units.

See https://www.freedesktop.org/software/systemd/man/systemd.service.html#id-1.8

type Unit

type Unit struct {
	Description                     string
	Documentation                   []string      `unit:"Documentation"`
	Wants                           []string      `unit:"Wants"`
	Requires                        []string      `unit:"Requires"`
	Requisite                       []string      `unit:"Requisite"`
	BindsTo                         []string      `unit:"BindsTo"`
	PartOf                          []string      `unit:"PartOf"`
	Upholds                         []string      `unit:"Upholds"`
	Conflicts                       []string      `unit:"Conflicts"`
	Before                          []string      `unit:"Before"`
	After                           []string      `unit:"After"`
	OnFailure                       []string      `unit:"OnFailure"`
	OnSuccess                       []string      `unit:"OnSuccess"`
	PropagatesReloadTo              []string      `unit:"PropagatesReloadTo"`
	ReloadPropagatedFrom            []string      `unit:"ReloadPropagatedFrom"`
	PropagatesStopTo                []string      `unit:"PropagatesStopTo"`
	StopPropagatedFrom              []string      `unit:"StopPropagatedFrom"`
	JoinsNamespaceOf                []string      `unit:"JoinsNamespaceOf"`
	RequiresMountsFor               []string      `unit:"RequiresMountsFor"`
	OnFailureJobMode                []string      `unit:"OnFailureJobMode"`
	IgnoreOnIsolate                 []string      `unit:"IgnoreOnIsolate"`
	StopWhenUnneeded                []string      `unit:"StopWhenUnneeded"`
	RefuseManualStart               []string      `unit:"RefuseManualStart"`
	RefuseManualStop                []string      `unit:"RefuseManualStop"`
	AllowIsolate                    []string      `unit:"AllowIsolate"`
	DefaultDependencies             []string      `unit:"DefaultDependencies"`
	CollectMode                     []string      `unit:"CollectMode"`
	FailureAction                   []string      `unit:"FailureAction"`
	SuccessAction                   []string      `unit:"SuccessAction"`
	FailureActionExitStatus         []string      `unit:"FailureActionExitStatus"`
	SuccessActionExitStatus         []string      `unit:"SuccessActionExitStatus"`
	JobTimeoutSec                   []string      `unit:"JobTimeoutSec"`
	JobRunningTimeoutSec            []string      `unit:"JobRunningTimeoutSec"`
	JobTimeoutAction                []string      `unit:"JobTimeoutAction"`
	JobTimeoutRebootArgument        []string      `unit:"JobTimeoutRebootArgument"`
	StartLimitInterval              time.Duration `unit:"StartLimitIntervalSec"`
	StartLimitBurst                 int           `unit:"StartLimitBurst"`
	StartLimitAction                []string      `unit:"StartLimitAction"`
	RebootArgument                  []string      `unit:"RebootArgument"`
	SourcePath                      []string      `unit:"SourcePath"`
	ConditionArchitecture           []string      `unit:"ConditionArchitecture"`
	ConditionFirmware               []string      `unit:"ConditionFirmware"`
	ConditionVirtualization         []string      `unit:"ConditionVirtualization"`
	ConditionHost                   []string      `unit:"ConditionHost"`
	ConditionKernelCommandLine      []string      `unit:"ConditionKernelCommandLine"`
	ConditionKernelVersion          []string      `unit:"ConditionKernelVersion"`
	ConditionCredential             []string      `unit:"ConditionCredential"`
	ConditionEnvironment            []string      `unit:"ConditionEnvironment"`
	ConditionSecurity               []string      `unit:"ConditionSecurity"`
	ConditionCapability             []string      `unit:"ConditionCapability"`
	ConditionACPower                []string      `unit:"ConditionACPower"`
	ConditionNeedsUpdate            []string      `unit:"ConditionNeedsUpdate"`
	ConditionFirstBoot              []string      `unit:"ConditionFirstBoot"`
	ConditionPathExists             []string      `unit:"ConditionPathExists"`
	ConditionPathExistsGlob         []string      `unit:"ConditionPathExistsGlob"`
	ConditionPathIsDirectory        []string      `unit:"ConditionPathIsDirectory"`
	ConditionPathIsSymbolicLink     []string      `unit:"ConditionPathIsSymbolicLink"`
	ConditionPathIsMountPoint       []string      `unit:"ConditionPathIsMountPoint"`
	ConditionPathIsReadWrite        []string      `unit:"ConditionPathIsReadWrite"`
	ConditionPathIsEncrypted        []string      `unit:"ConditionPathIsEncrypted"`
	ConditionDirectoryNotEmpty      []string      `unit:"ConditionDirectoryNotEmpty"`
	ConditionFileNotEmpty           []string      `unit:"ConditionFileNotEmpty"`
	ConditionFileIsExecutable       []string      `unit:"ConditionFileIsExecutable"`
	ConditionUser                   []string      `unit:"ConditionUser"`
	ConditionGroup                  []string      `unit:"ConditionGroup"`
	ConditionControlGroupController []string      `unit:"ConditionControlGroupController"`
	ConditionMemory                 []string      `unit:"ConditionMemory"`
	ConditionCPUs                   []string      `unit:"ConditionCPUs"`
	ConditionCPUFeature             []string      `unit:"ConditionCPUFeature"`
	ConditionOSRelease              []string      `unit:"ConditionOSRelease"`
	ConditionMemoryPressure         []string      `unit:"ConditionMemoryPressure"`
	ConditionCPUPressure            []string      `unit:"ConditionCPUPressure"`
	ConditionIOPressure             []string      `unit:"ConditionIOPressure"`
	AssertArchitecture              []string      `unit:"AssertArchitecture"`
	AssertVirtualization            []string      `unit:"AssertVirtualization"`
	AssertHost                      []string      `unit:"AssertHost"`
	AssertKernelCommandLine         []string      `unit:"AssertKernelCommandLine"`
	AssertKernelVersion             []string      `unit:"AssertKernelVersion"`
	AssertCredential                []string      `unit:"AssertCredential"`
	AssertEnvironment               []string      `unit:"AssertEnvironment"`
	AssertSecurity                  []string      `unit:"AssertSecurity"`
	AssertCapability                []string      `unit:"AssertCapability"`
	AssertACPower                   []string      `unit:"AssertACPower"`
	AssertNeedsUpdate               []string      `unit:"AssertNeedsUpdate"`
	AssertFirstBoot                 []string      `unit:"AssertFirstBoot"`
	AssertPathExists                []string      `unit:"AssertPathExists"`
	AssertPathExistsGlob            []string      `unit:"AssertPathExistsGlob"`
	AssertPathIsDirectory           []string      `unit:"AssertPathIsDirectory"`
	AssertPathIsSymbolicLink        []string      `unit:"AssertPathIsSymbolicLink"`
	AssertPathIsMountPoint          []string      `unit:"AssertPathIsMountPoint"`
	AssertPathIsReadWrite           []string      `unit:"AssertPathIsReadWrite"`
	AssertPathIsEncrypted           []string      `unit:"AssertPathIsEncrypted"`
	AssertDirectoryNotEmpty         []string      `unit:"AssertDirectoryNotEmpty"`
	AssertFileNotEmpty              []string      `unit:"AssertFileNotEmpty"`
	AssertFileIsExecutable          []string      `unit:"AssertFileIsExecutable"`
	AssertUser                      []string      `unit:"AssertUser"`
	AssertGroup                     []string      `unit:"AssertGroup"`
	AssertControlGroupController    []string      `unit:"AssertControlGroupController"`
	AssertMemory                    []string      `unit:"AssertMemory"`
	AssertCPUs                      []string      `unit:"AssertCPUs"`
	AssertCPUFeature                []string      `unit:"AssertCPUFeature"`
	AssertOSRelease                 []string      `unit:"AssertOSRelease"`
	AssertMemoryPressure            []string      `unit:"AssertMemoryPressure"`
	AssertCPUPressure               []string      `unit:"AssertCPUPressure"`
	AssertIOPressure                []string      `unit:"AssertIOPressure"`
}

Unit describes generic details about a SystemD Unit which are not dependent on the type of the Unit.

See https://www.freedesktop.org/software/systemd/man/systemd.unit.html#id-1.10

type UnmarshalOption added in v0.1.0

type UnmarshalOption func(*decoder)

UnmarshalOption modifies the behavior of Unmarshal.

Directories

Path Synopsis
internal
parser
Package parser contains an ANTLR-generated lexer and parser for SystemD Unit files, with some tests added to ensure grammar changes don't violate the current contract.
Package parser contains an ANTLR-generated lexer and parser for SystemD Unit files, with some tests added to ensure grammar changes don't violate the current contract.

Jump to

Keyboard shortcuts

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