-
Notifications
You must be signed in to change notification settings - Fork 0
/
nginx.go
215 lines (177 loc) · 5.07 KB
/
nginx.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
package nginx
import (
"bytes"
"context"
"log"
"os"
"path/filepath"
"strings"
"syscall"
// Packages
cmd "github.com/mutablelogic/go-server/pkg/handler/nginx/cmd"
folders "github.com/mutablelogic/go-server/pkg/handler/nginx/folders"
provider "github.com/mutablelogic/go-server/pkg/provider"
)
///////////////////////////////////////////////////////////////////////////////
// TYPES
type nginx struct {
// The command to run nginx
run *cmd.Cmd
// The command to test nginx configuration
test *cmd.Cmd
// The persistent configuration path
configPath string
// The ephemeral data path
dataPath string
// The log path
logPath string
// The version string from nginx
version []byte
// The available and enabled configuration folders
folders *folders.Config
// The temporarily created paths which should be removed on exit
deletePaths []string
}
///////////////////////////////////////////////////////////////////////////////
// LIFECYCLE
// Create a new http server from the configuration
func New(c *Config) (*nginx, error) {
task := new(nginx)
// Set permissions on config and data dirs
configDir, err := c.ConfigDir()
if err != nil {
return nil, err
} else if err := os.Chmod(configDir, defaultConfDirMode); err != nil {
return nil, err
} else {
task.configPath = configDir
}
dataDir, err := c.DataDir()
if err != nil {
return nil, err
} else if err := os.Chmod(dataDir, defaultConfDirMode); err != nil {
return nil, err
} else {
task.dataPath = dataDir
}
logDir, err := c.LogDir(configDir)
if err != nil {
return nil, err
} else if err := os.Chmod(logDir, defaultConfDirMode); err != nil {
return nil, err
} else {
task.logPath = logDir
}
// Create an available folder in the persistent data directory
availablePath := filepath.Join(configDir, "available")
if err := os.MkdirAll(availablePath, defaultConfDirMode); err != nil {
return nil, err
}
// Create an enabled folder in the persistent data directory
enabledPath := filepath.Join(configDir, "enabled")
if err := os.MkdirAll(enabledPath, defaultConfDirMode); err != nil {
return nil, err
}
// Read the configuration folders
if folders, err := folders.New(availablePath, enabledPath, defaultConfExt, defaultConfRecursive); err != nil {
return nil, err
} else {
folders.DirMode = defaultConfDirMode
task.folders = folders
}
// Create a new command to run the server. Use prefix to ensure that
// the document root is contained within the temporary directory
if run, err := cmd.New(c.ExecFile(), c.Flags(task.configPath, task.configPath)...); err != nil {
return nil, err
} else if test, err := cmd.New(c.ExecFile(), c.Flags(task.configPath, task.configPath)...); err != nil {
return nil, err
} else {
task.run = run
task.test = test
task.test.SetArgs("-t", "-q")
}
// Add the environment variables
if err := task.run.SetEnv(c.Env); err != nil {
return nil, err
} else if err := task.test.SetEnv(c.Env); err != nil {
return nil, err
}
// Set the working directory to the ephemeral data directory
task.run.SetDir(task.dataPath)
task.test.SetDir(task.dataPath)
// Set the paths which should be deleted on exit
task.deletePaths = c.deletePaths
// Return success
return task, nil
}
/////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
// return the persistent config path
func (nginx *nginx) ConfigPath() string {
return nginx.configPath
}
// return the ephermeral data path
func (nginx *nginx) DataPath() string {
return nginx.dataPath
}
// return the log path
func (nginx *nginx) LogPath() string {
return nginx.logPath
}
// Test configuration
func (nginx *nginx) Test() error {
return nginx.test.Run()
}
// Test the configuration and then reload it (the SIGHUP signal)
func (nginx *nginx) Reload() error {
// Reload the folders
if err := nginx.folders.Reload(); err != nil {
return err
}
// Test the configuration
if err := nginx.test.Run(); err != nil {
return err
}
// Signal the server to reload
return nginx.run.Signal(syscall.SIGHUP)
}
// Reopen log files (the SIGUSR1 signal)
func (nginx *nginx) Reopen() error {
return nginx.run.Signal(syscall.SIGUSR1)
}
// Version returns the nginx version string
func (nginx *nginx) Version() string {
if nginx.version == nil {
if version, err := nginx.getVersion(); err == nil {
nginx.version = version
return string(bytes.TrimSpace(version))
}
}
return string(bytes.TrimSpace(nginx.version))
}
/////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
func (nginx *nginx) log(ctx context.Context, line string) {
line = strings.TrimSpace(line)
if logger := provider.Logger(ctx); logger != nil {
logger.Print(ctx, line)
} else {
log.Println(line)
}
}
func (nginx *nginx) getVersion() ([]byte, error) {
var result []byte
// Run the version command to get the nginx version string
version, err := cmd.New(nginx.run.Path(), "-v")
if err != nil {
return nil, err
}
version.Err = func(data []byte) {
result = append(result, data...)
}
if err := version.Run(); err != nil {
return nil, err
}
// Return success
return result, nil
}