-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmain.go
213 lines (179 loc) · 4.38 KB
/
main.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
package main
import (
"context"
"flag"
"fmt"
"github.com/acicn/minit/pkg/mlog"
"os"
"os/signal"
"regexp"
"sync"
"syscall"
"time"
)
var (
optUnitDir string
optLogDir string
optQuickExit bool
)
var (
UnitNamePattern = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9]$`)
)
var (
log *mlog.Logger
)
func exit(err *error) {
if *err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%s [%s] 错误退出: %s\n", time.Now().Format(mlog.LoggerDateLayout), "minit", (*err).Error())
os.Exit(1)
} else {
_, _ = fmt.Fprintf(os.Stdout, "%s [%s] 正常退出\n", time.Now().Format(mlog.LoggerDateLayout), "minit")
}
}
func main() {
var err error
defer exit(&err)
// 命令行参数
flag.StringVar(&optUnitDir, "unit-dir", "/etc/minit.d", "配置单元目录")
flag.StringVar(&optLogDir, "log-dir", "/var/log/minit", "日志目录")
flag.BoolVar(&optQuickExit, "quick-exit", false, "如果没有 L3 任务(守护进程,定时任务 等),则自动退出")
flag.Parse()
// 环境变量
if os.Getenv("MINIT_QUICK_EXIT") == "true" {
optQuickExit = true
}
// 确保配置单元目录
if err = os.MkdirAll(optUnitDir, 0755); err != nil {
return
}
// 确保日志目录
if err = os.MkdirAll(optLogDir, 0755); err != nil {
return
}
if log, err = mlog.NewLogger(mlog.LoggerOptions{
Dir: optLogDir,
Name: "minit",
Filename: "minit",
}); err != nil {
return
}
// 自述文件
setupBanner()
// 内核参数
if err = setupSysctl(); err != nil {
return
}
// 资源限制
if err = setupRLimits(); err != nil {
return
}
// 透明大页
if err = setupTHP(); err != nil {
return
}
// WebDAV
if err = setupWebDAV(); err != nil {
return
}
// 载入单元
var units []Unit
if units, err = LoadDir(optUnitDir); err != nil {
return
}
// 载入环境变量
var (
extraUnit Unit
extraOK bool
)
if extraUnit, extraOK, err = LoadEnvMain(); err != nil {
return
}
if extraOK {
units = append(units, extraUnit)
}
// 载入命令参数
if extraUnit, extraOK, err = LoadArgsMain(); err != nil {
return
}
if extraOK {
units = append(units, extraUnit)
}
// 检查单元命名
unitNames := map[string]bool{"minit": true}
for _, unit := range units {
if unit.Name == "" {
err = fmt.Errorf("缺少单元名称,检查 name 字段")
return
}
if !UnitNamePattern.MatchString(unit.Name) {
err = fmt.Errorf("单元名称 %s 不符合规则,检查 name 字段", unit.Name)
return
}
if unitNames[unit.Name] {
err = fmt.Errorf("单元名称 %s 重复出现,检查 name 字段", unit.Name)
return
}
unitNames[unit.Name] = true
log.Printf("载入单元 %s/%s", unit.Kind, unit.Name)
}
// 控制器组, L1 是 render (渲染配置文件), L2 是 once (一次性命令), L3 是 daemon 和 cron
runners := map[RunnerLevel][]Runner{}
// 创建控制器
for _, unit := range units {
fac := RunnerFactories[unit.Kind]
if fac == nil {
err = fmt.Errorf("单元 %s 类型 %s 未知,检查 kind 字段", unit.Name, unit.Kind)
return
}
var logger *mlog.Logger
if logger, err = mlog.NewLogger(mlog.LoggerOptions{
Dir: optLogDir,
Name: unit.CanonicalName(),
Filename: unit.Name,
}); err != nil {
err = fmt.Errorf("无法为 %s 创建日志: %s", unit.Name, err.Error())
return
}
var runner Runner
if runner, err = fac.Create(unit, logger); err != nil {
err = fmt.Errorf("无法为 %s 创建控制器: %s", unit.Name, err.Error())
return
}
runners[fac.Level] = append(runners[fac.Level], runner)
}
// 运行 L1 控制器
for _, runner := range runners[RunnerL1] {
runner.Run(context.Background())
}
// 运行 L2 控制器
for _, runner := range runners[RunnerL2] {
runner.Run(context.Background())
}
if len(runners[RunnerL3]) == 0 && optQuickExit {
log.Printf("没有 L3 任务")
return
}
// 运行 L3 控制器
ctx, cancel := context.WithCancel(context.Background())
wg := &sync.WaitGroup{}
for _, runner := range runners[RunnerL3] {
wg.Add(1)
go func(runner Runner) {
runner.Run(ctx)
wg.Done()
}(runner)
}
log.Printf("启动完毕")
// 等待信号并退出
chSig := make(chan os.Signal, 1)
signal.Notify(chSig, syscall.SIGINT, syscall.SIGTERM)
sig := <-chSig
log.Printf("接收到信号: %s", sig.String())
// 关闭主环境
cancel()
// 延迟 3 秒播发信号
time.Sleep(time.Second * 3)
notifyPIDs(sig)
// 等待控制器退出
wg.Wait()
}