util: Add a simple template system for systemd unit files
Just the basics for what we need, nothing more. Not intended as a general-purpose library for use elsewhere.
This commit is contained in:
134
util/systemd_unit.go
Normal file
134
util/systemd_unit.go
Normal file
@@ -0,0 +1,134 @@
|
||||
// Mgmt
|
||||
// Copyright (C) 2013-2024+ James Shubin and the project contributors
|
||||
// Written by James Shubin <james@shubin.ca> and the project contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Additional permission under GNU GPL version 3 section 7
|
||||
//
|
||||
// If you modify this program, or any covered work, by linking or combining it
|
||||
// with embedded mcl code and modules (and that the embedded mcl code and
|
||||
// modules which link with this program, contain a copy of their source code in
|
||||
// the authoritative form) containing parts covered by the terms of any other
|
||||
// license, the licensors of this program grant you additional permission to
|
||||
// convey the resulting work. Furthermore, the licensors of this program grant
|
||||
// the original author, James Shubin, additional permission to update this
|
||||
// additional permission if he deems it necessary to achieve the goals of this
|
||||
// additional permission.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// UnitData is the data struct used to build a systemd unit file. This isn't an
|
||||
// exhaustive representation of what's possible, but is meant to handle most
|
||||
// common cases. Alternatively we could have used the
|
||||
// github.com/coreos/go-systemd/v22/unit library, but it didn't provide much
|
||||
// value. More documentation on these fields can be seen at:
|
||||
// https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
|
||||
type UnitData struct {
|
||||
// Description field for the unit file.
|
||||
Description string
|
||||
|
||||
// Documentation field for the unit file.
|
||||
Documentation string
|
||||
|
||||
// After makes this happen after that target is ready. Usually you want
|
||||
// "network.target" or "systemd-networkd.service" here I think.
|
||||
After []string
|
||||
|
||||
// Type is the type of service to run, such as "oneshot".
|
||||
Type string
|
||||
|
||||
// ExecStart is the main command to run.
|
||||
ExecStart string
|
||||
|
||||
// RestartSec is the number of seconds to wait between restarts.
|
||||
RestartSec string
|
||||
|
||||
// Restart is the restart policy. Usually you want "always".
|
||||
Restart string
|
||||
|
||||
// RemainAfterExit can be set to true to make it look like the service
|
||||
// is still active if it exits successfully.
|
||||
RemainAfterExit bool
|
||||
|
||||
// StandardOutput specifies what happens with stdout.
|
||||
StandardOutput string
|
||||
|
||||
// StandardError specifies what happens with stderr.
|
||||
StandardError string
|
||||
|
||||
// WantedBy makes this a dependency of this target. Usually you want
|
||||
// "multi-user.target" here.
|
||||
WantedBy []string
|
||||
}
|
||||
|
||||
// Template uses the UnitData to build a systemd unit file. This API is subject
|
||||
// to change, don't assume the output is stable either.
|
||||
// TODO: Should this return an error or not?
|
||||
func (obj *UnitData) Template() (string, error) {
|
||||
data := ""
|
||||
data += "[Unit]\n"
|
||||
if obj.Description != "" {
|
||||
data += fmt.Sprintf("Description=%s\n", obj.Description)
|
||||
}
|
||||
if obj.Documentation != "" {
|
||||
data += fmt.Sprintf("Documentation=%s\n", obj.Documentation)
|
||||
}
|
||||
for _, x := range obj.After {
|
||||
if x == "" {
|
||||
continue
|
||||
}
|
||||
data += fmt.Sprintf("After=%s\n", x)
|
||||
}
|
||||
|
||||
data += "\n"
|
||||
data += "[Service]\n"
|
||||
if obj.Type != "" {
|
||||
data += fmt.Sprintf("Type=%s\n", obj.Type)
|
||||
}
|
||||
if obj.ExecStart != "" {
|
||||
data += fmt.Sprintf("ExecStart=%s\n", obj.ExecStart)
|
||||
}
|
||||
if obj.RestartSec != "" {
|
||||
data += fmt.Sprintf("RestartSec=%s\n", obj.RestartSec)
|
||||
}
|
||||
if obj.Restart != "" {
|
||||
data += fmt.Sprintf("Restart=%s\n", obj.Restart)
|
||||
}
|
||||
|
||||
if obj.RemainAfterExit {
|
||||
data += "RemainAfterExit=yes\n"
|
||||
}
|
||||
if obj.StandardOutput != "" {
|
||||
data += fmt.Sprintf("StandardOutput=%s\n", obj.StandardOutput)
|
||||
}
|
||||
if obj.StandardError != "" {
|
||||
data += fmt.Sprintf("StandardError=%s\n", obj.StandardError)
|
||||
}
|
||||
|
||||
data += "\n"
|
||||
data += "[Install]\n"
|
||||
for _, x := range obj.WantedBy {
|
||||
if x == "" {
|
||||
continue
|
||||
}
|
||||
data += fmt.Sprintf("WantedBy=%s\n", x)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
Reference in New Issue
Block a user