Compare commits

..

4 Commits
v0.0.3 ... main

Author SHA1 Message Date
669f269dd3 Add option for adding arguments 2022-11-25 18:11:12 +10:30
c15e9feb66
Update README.md 2022-11-24 23:01:50 +10:30
ae7f311c8e Update README, use tighter permissions 2022-11-24 20:08:25 +10:30
b66adef4f6 Update README 2022-11-24 20:00:06 +10:30
3 changed files with 53 additions and 19 deletions

View File

@ -1,31 +1,41 @@
# unitard - automatically deploy a systemd unit file from your application
[![Go Reference](https://pkg.go.dev/badge/github.com/tardisx/unitard.svg)](https://pkg.go.dev/github.com/tardisx/unitard)
## Synopsis
import "github.com/tardisx/unitard"
func main() {
appName := "coolapp"
if deploy {
unit, _ := unitard.NewUnit(appName)
unit.Deploy()
os.Exit(0)
}
// rest of your application here
appName := "coolapp"
if deploy {
// error checking ignored for this example
unit, _ := unitard.NewUnit(appName)
unit.Deploy()
os.Exit(0)
}
// rest of your application here
}
## What it does
`Deploy()` automatically creates a systemd unit file, reloads the systemd daemon
so it can use it, enables the unit (so it starts on boot) and starts the service
This package provides a simple interface to automatically creating and enabling a
systemd "user unit" service, as part of your single-binary deployment.
The `Deploy()` function creates the systemd unit file, reloads the systemd daemon
so it reads it, enables the unit (to start on boot) and starts the service
running.
This means you can have a single binary deployment. Copy your executable to "somewhere"
on your target system, run it with `-deploy` (or however you have enabled the call to `Deploy()`)
and your application starts running in the background, and will restart on boot.
Copy your executable to "somewhere" on your target system, run it with `-deploy`
(or however you have enabled the call to `Deploy()`) and your application starts
running in the background and will restart on boot.
There is also an `Undeploy()` func, which you should of course
provide as an option to your users. It stops the running service, removes the unit file and restarts systemd.
There is also an `Undeploy()` func, which you should of course provide as an option
to your users. It stops the running service, removes the unit file and reloads the
systemd daemon.
While it does shell out to call the `systemctl` tool, this does mean this package
adds no new non-core dependencies to your project.
## What's with the name?

View File

@ -5,7 +5,7 @@ Description={{ .description }}
[Service]
WorkingDirectory={{ .workingDirectory }}
ExecStart={{ .execStart }}
ExecStart={{ .execStart }} {{ .execStartArgs }}
[Install]
WantedBy=default.target

View File

@ -4,6 +4,7 @@ package unitard
import (
"embed"
"errors"
"fmt"
"io"
"os"
@ -21,12 +22,31 @@ type Unit struct {
name string
binary string
binaryPath string
binaryArgs string
systemCtlPath string // path to systemctl command
unitFilePath string
}
type UnitOpts interface{}
type UnitOpts interface {
Apply(u *Unit) error
}
// OptProgramArgs allows you to add an arguments to the invocation of the program
type OptProgramArgs struct {
Args string // Program args
}
func (o OptProgramArgs) Apply(u *Unit) error {
if o.Args == "" {
return errors.New("can't set an empty args option")
}
if u.binaryArgs != "" {
return errors.New("args were already set - use OptProgramArgs only once")
}
u.binaryArgs = o.Args
return nil
}
// NewUnit creates a new systemd unit representation, with a particular name.
// No changes will be made to the system configuration until Deploy or Undeploy
@ -46,8 +66,11 @@ func NewUnit(unitName string, unitOpts ...UnitOpts) (Unit, error) {
binaryPath: path,
}
if len(unitOpts) > 0 {
return Unit{}, fmt.Errorf("sorry, UnitOpts are not yet supported")
for _, opt := range unitOpts {
err := opt.Apply(&u)
if err != nil {
return Unit{}, fmt.Errorf("bad option: %s", err)
}
}
err := u.setupEnvironment()
@ -97,6 +120,7 @@ func (u Unit) writeTemplate(f io.Writer) error {
data := map[string]string{
"description": u.name,
"execStart": u.binary,
"execStartArgs": u.binaryArgs,
"workingDirectory": u.binaryPath,
}
err = t.ExecuteTemplate(f, "basic.service", data)
@ -213,7 +237,7 @@ func (u *Unit) setupEnvironment() error {
"user",
)
err = os.MkdirAll(unitFileDirectory, 0777)
err = os.MkdirAll(unitFileDirectory, 0700)
if err != nil {
return fmt.Errorf("cannot create the user systemd path '%s': %s", unitFileDirectory, err)
}