refactor: use nginx -s reload instead of systemd
- doc: add comment
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
// Package systemd defines the exact systemd boundary used by native executors.
|
||||
// Package systemd 定义原生执行器所依赖的精确 systemd 边界。
|
||||
//
|
||||
// 该包声明 systemd 操作所需的最小抽象,具体实现见 systemctl.go,
|
||||
// 它直接调用 systemctl 可执行文件,绝不经过 shell。
|
||||
package systemd
|
||||
|
||||
import (
|
||||
@@ -6,19 +9,27 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrUnitNotFound 表示未找到指定的 systemd 单元。
|
||||
var ErrUnitNotFound = errors.New("systemd unit not found")
|
||||
|
||||
// Unit is the systemd state required for idempotent start and stop inspection.
|
||||
// Unit 执行幂等启停检查所需的 systemd 状态。
|
||||
type Unit struct {
|
||||
Name string
|
||||
LoadState string
|
||||
// Name 表示单元名称。
|
||||
Name string
|
||||
// LoadState 表示单元的加载状态。
|
||||
LoadState string
|
||||
// ActiveState 表示单元的活动状态。
|
||||
ActiveState string
|
||||
SubState string
|
||||
// SubState 表示单元的子状态。
|
||||
SubState string
|
||||
}
|
||||
|
||||
// Manager performs direct systemd operations without invoking a shell.
|
||||
// Manager 在不调用 shell 的前提下直接执行 systemd 操作。
|
||||
type Manager interface {
|
||||
// Inspect 检查指定单元并返回其状态。
|
||||
Inspect(context.Context, string) (Unit, error)
|
||||
// Start 启动指定单元。
|
||||
Start(context.Context, string) error
|
||||
// Stop 停止指定单元。
|
||||
Stop(context.Context, string) error
|
||||
}
|
||||
|
||||
@@ -12,19 +12,25 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
loadStateProperty = "LoadState"
|
||||
// loadStateProperty systemctl show 输出的加载状态属性名。
|
||||
loadStateProperty = "LoadState"
|
||||
// activeStateProperty systemctl show 输出的活动状态属性名。
|
||||
activeStateProperty = "ActiveState"
|
||||
subStateProperty = "SubState"
|
||||
loadedState = "loaded"
|
||||
notFoundState = "not-found"
|
||||
// subStateProperty systemctl show 输出的子状态属性名。
|
||||
subStateProperty = "SubState"
|
||||
// loadedState 表示单元已加载。
|
||||
loadedState = "loaded"
|
||||
// notFoundState 表示单元未找到。
|
||||
notFoundState = "not-found"
|
||||
)
|
||||
|
||||
// Systemctl invokes one exact systemctl executable directly, never through a shell.
|
||||
// Systemctl 直接调用一个精确的 systemctl 可执行文件,绝不经过 shell。
|
||||
type Systemctl struct {
|
||||
// executable systemctl 的绝对路径。
|
||||
executable string
|
||||
}
|
||||
|
||||
// NewSystemctl requires the absolute executable path supplied by local daemon configuration.
|
||||
// NewSystemctl 要求传入本地守护进程配置提供的可执行文件绝对路径。
|
||||
func NewSystemctl(executable string) (*Systemctl, error) {
|
||||
if !filepath.IsAbs(executable) {
|
||||
return nil, errors.New("systemctl executable path must be absolute")
|
||||
@@ -32,6 +38,8 @@ func NewSystemctl(executable string) (*Systemctl, error) {
|
||||
return &Systemctl{executable: executable}, nil
|
||||
}
|
||||
|
||||
// Inspect 查询指定单元的关键状态属性并返回其状态。
|
||||
// 未找到单元时错误包装 ErrUnitNotFound;加载状态异常时返回错误。
|
||||
func (s *Systemctl) Inspect(ctx context.Context, unitName string) (Unit, error) {
|
||||
if err := validateUnitName(unitName); err != nil {
|
||||
return Unit{}, err
|
||||
@@ -62,14 +70,17 @@ func (s *Systemctl) Inspect(ctx context.Context, unitName string) (Unit, error)
|
||||
return unit, nil
|
||||
}
|
||||
|
||||
// Start 启动指定单元。
|
||||
func (s *Systemctl) Start(ctx context.Context, unitName string) error {
|
||||
return s.changeState(ctx, "start", unitName)
|
||||
}
|
||||
|
||||
// Stop 停止指定单元。
|
||||
func (s *Systemctl) Stop(ctx context.Context, unitName string) error {
|
||||
return s.changeState(ctx, "stop", unitName)
|
||||
}
|
||||
|
||||
// changeState 通过 systemctl 执行给定动作(start 或 stop)。
|
||||
func (s *Systemctl) changeState(ctx context.Context, action, unitName string) error {
|
||||
if err := validateUnitName(unitName); err != nil {
|
||||
return err
|
||||
@@ -81,6 +92,8 @@ func (s *Systemctl) changeState(ctx context.Context, action, unitName string) er
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseUnitProperties 解析 systemctl show 的输出,
|
||||
// 严格要求恰好包含三个预期属性且不重复、不多余。
|
||||
func parseUnitProperties(unitName string, output []byte) (Unit, error) {
|
||||
values := make(map[string]string, 3)
|
||||
scanner := bufio.NewScanner(bytes.NewReader(output))
|
||||
@@ -116,6 +129,7 @@ func parseUnitProperties(unitName string, output []byte) (Unit, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateUnitName 校验单元名称必须非空且不含首尾空白。
|
||||
func validateUnitName(unitName string) error {
|
||||
if unitName == "" || strings.TrimSpace(unitName) != unitName {
|
||||
return errors.New("exact systemd unit name is required")
|
||||
@@ -123,6 +137,7 @@ func validateUnitName(unitName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// commandError 包装命令执行错误,并附带去除首尾空白的命令输出作为诊断细节。
|
||||
func commandError(action string, output []byte, err error) error {
|
||||
detail := strings.TrimSpace(string(output))
|
||||
if detail == "" {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestParseUnitPropertiesRequiresExactProperties 验证属性解析严格接受恰好三个预期属性,并拒绝缺失、多余或重复属性。
|
||||
func TestParseUnitPropertiesRequiresExactProperties(t *testing.T) {
|
||||
t.Parallel()
|
||||
unit, err := parseUnitProperties("yms-green.service", []byte("LoadState=loaded\nActiveState=inactive\nSubState=dead\n"))
|
||||
@@ -26,6 +27,7 @@ func TestParseUnitPropertiesRequiresExactProperties(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewSystemctlRequiresAbsoluteExecutable 验证相对路径会被拒绝,绝对路径会被接受。
|
||||
func TestNewSystemctlRequiresAbsoluteExecutable(t *testing.T) {
|
||||
t.Parallel()
|
||||
if _, err := NewSystemctl("systemctl"); err == nil {
|
||||
@@ -37,6 +39,7 @@ func TestNewSystemctlRequiresAbsoluteExecutable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateUnitNamePreservesOpaqueValue 验证合法单元名被原样保留,空串或带首尾空白被拒绝。
|
||||
func TestValidateUnitNamePreservesOpaqueValue(t *testing.T) {
|
||||
t.Parallel()
|
||||
if err := validateUnitName("backend-green.service"); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user