Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
669f269dd3 | |||
c15e9feb66 | |||
ae7f311c8e | |||
b66adef4f6 | |||
be728e798a |
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Justin Hawkins
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
38
README.md
38
README.md
@ -1,31 +1,41 @@
|
||||
# unitard - automatically deploy a systemd unit file from your application
|
||||
|
||||
[](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?
|
||||
|
||||
|
@ -5,7 +5,7 @@ Description={{ .description }}
|
||||
|
||||
[Service]
|
||||
WorkingDirectory={{ .workingDirectory }}
|
||||
ExecStart={{ .execStart }}
|
||||
ExecStart={{ .execStart }} {{ .execStartArgs }}
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
32
unitard.go
32
unitard.go
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user