-
Notifications
You must be signed in to change notification settings - Fork 13
/
installer.go
113 lines (91 loc) · 3.2 KB
/
installer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package main
import (
"fmt"
"html/template"
"log"
"os"
"path/filepath"
"github.com/pkg/errors"
)
type installer interface {
Install(projectDirectory, dockerComposeFileName, projectName string) error
}
type systemdInstaller struct {
systemdDirectory string
commandExecutor Executor
dryRun bool
doPull bool
}
func (installer *systemdInstaller) Install(projectDirectory, dockerComposeFileName, projectName string) error {
serviceName := getServiceName(projectName)
serviceViewModel := serviceDefinition{
ProjectName: projectName,
ProjectDirectory: projectDirectory,
DockerComposeFile: dockerComposeFileName,
DoPull: installer.doPull,
}
if err := installer.createSystemdService(serviceViewModel); err != nil {
return errors.Wrap(err, fmt.Sprintf("Failed to create a systemd service for project %q (Directory: %q, Docker Compose File: %q)", projectName, projectDirectory, dockerComposeFileName))
}
reloadError := installer.commandExecutor.Run("systemctl", "daemon-reload")
if reloadError != nil {
return errors.Wrap(reloadError, "Failed to reload the systemd configuration")
}
enableError := installer.commandExecutor.Run("systemctl", "enable", serviceName)
if enableError != nil {
return errors.Wrap(enableError, fmt.Sprintf("Failed to enable %q", serviceName))
}
startError := installer.commandExecutor.Run("systemctl", "start", serviceName)
if startError != nil {
return errors.Wrap(startError, fmt.Sprintf("Failed to start %q", serviceName))
}
return nil
}
func (installer *systemdInstaller) createSystemdService(service serviceDefinition) error {
serviceFilePath := filepath.Join(installer.systemdDirectory, getServiceName(service.ProjectName))
var file *os.File
if installer.dryRun {
log.Println("Installing this service file at:", serviceFilePath)
file = os.Stdout
} else {
var err error
file, err = os.OpenFile(serviceFilePath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0664)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("Failed to open the systemd service file: %q", serviceFilePath))
}
defer file.Close()
}
serviceTemplate, err := template.New("systemdservice").Parse(serviceTemplate)
if err != nil {
return errors.Wrap(err, "Failed to parse systemd service template")
}
serviceTemplate.Execute(file, service)
return nil
}
func getServiceName(projectName string) string {
return fmt.Sprintf("%s.service", projectName)
}
const serviceTemplate = `[Unit]
Description={{ .ProjectName }} Service
After=network.service docker.service
Requires=docker.service
[Service]
Restart=always
RestartSec=10
TimeoutSec=300
WorkingDirectory={{ .ProjectDirectory }}
{{- if .DoPull }}
ExecStartPre=/usr/bin/env docker-compose -p "{{ .ProjectName }}" -f "{{ .DockerComposeFile }}" pull
{{- end }}
ExecStart=/usr/bin/env docker-compose -p "{{ .ProjectName }}" -f "{{ .DockerComposeFile }}" up
ExecStop=/usr/bin/env docker-compose -p "{{ .ProjectName }}" -f "{{ .DockerComposeFile }}" stop
ExecStopPost=/usr/bin/env docker-compose -p "{{ .ProjectName }}" -f "{{ .DockerComposeFile }}" down
[Install]
WantedBy=docker.service
`
type serviceDefinition struct {
ProjectName string
ProjectDirectory string
DockerComposeFile string
DoPull bool
}