@@ -22,35 +22,139 @@ package containerd
2222import (
2323 "fmt"
2424 "log/slog"
25+ "os"
26+ "os/exec"
27+ "regexp"
2528 "syscall"
2629
2730 "github.com/mitchellh/go-ps"
2831)
2932
3033var psProcesses = ps .Processes
3134
32- type restarter struct {}
35+ type defaultRestarter struct {}
3336
34- func NewRestarter () Restarter {
35- return restarter {}
37+ func NewDefaultRestarter () Restarter {
38+ return defaultRestarter {}
3639}
3740
38- func (c restarter ) Restart () error {
39- pid , err := getPid ()
41+ func (c defaultRestarter ) Restart () error {
42+ // If listing systemd units succeeds, prefer systemctl restart; otherwise kill pid
43+ if _ , err := listSystemdUnits (); err == nil {
44+ out , err := nsenterCmd ("systemctl" , "restart" , "containerd" ).CombinedOutput ()
45+ slog .Debug (string (out ))
46+ if err != nil {
47+ return fmt .Errorf ("unable to restart containerd: %w" , err )
48+ }
49+ } else {
50+ pid , err := getPid ("containerd" )
51+ if err != nil {
52+ return err
53+ }
54+ slog .Debug ("found containerd process" , "pid" , pid )
55+
56+ err = syscall .Kill (pid , syscall .SIGHUP )
57+ if err != nil {
58+ return fmt .Errorf ("failed to send SIGHUP to containerd: %w" , err )
59+ }
60+ }
61+
62+ return nil
63+ }
64+
65+ type K0sRestarter struct {}
66+
67+ func (c K0sRestarter ) Restart () error {
68+ // First, collect systemd units to determine which mode k0s is running in, eg
69+ // k0sworker or k0scontroller
70+ units , err := listSystemdUnits ()
71+ if err != nil {
72+ return fmt .Errorf ("unable to list systemd units: %w" , err )
73+ }
74+ service := regexp .MustCompile ("k0sworker|k0scontroller" ).FindString (string (units ))
75+
76+ out , err := nsenterCmd ("systemctl" , "restart" , service ).CombinedOutput ()
77+ slog .Debug (string (out ))
78+ if err != nil {
79+ return fmt .Errorf ("unable to restart %s: %w" , service , err )
80+ }
81+
82+ return nil
83+ }
84+
85+ type K3sRestarter struct {}
86+
87+ func (c K3sRestarter ) Restart () error {
88+ // This restarter will be used both for stock K3s distros, which use systemd as well as K3d, which does not.
89+
90+ // If listing systemd units succeeds, prefer systemctl restart; otherwise kill pid
91+ if _ , err := listSystemdUnits (); err == nil {
92+ out , err := nsenterCmd ("systemctl" , "restart" , "k3s" ).CombinedOutput ()
93+ slog .Debug (string (out ))
94+ if err != nil {
95+ return fmt .Errorf ("unable to restart k3s: %w" , err )
96+ }
97+ } else {
98+ // TODO: this approach still leads to the behavior mentioned in https://github.com/spinframework/runtime-class-manager/issues/140:
99+ // The first pod's provisioner container exits with code 255, leading to pod status Unknown,
100+ // followed by the subsequent pod's provisioner container no-op-ing and finishing with status Completed.
101+ pid , err := getPid ("k3s" )
102+ if err != nil {
103+ return err
104+ }
105+ slog .Debug ("found k3s process" , "pid" , pid )
106+
107+ err = syscall .Kill (pid , syscall .SIGHUP )
108+ if err != nil {
109+ return fmt .Errorf ("failed to send SIGHUP to k3s: %w" , err )
110+ }
111+ }
112+
113+ return nil
114+ }
115+
116+ type MicroK8sRestarter struct {}
117+
118+ func (c MicroK8sRestarter ) Restart () error {
119+ out , err := nsenterCmd ("systemctl" , "restart" , "snap.microk8s.daemon-containerd" ).CombinedOutput ()
120+ slog .Debug (string (out ))
40121 if err != nil {
41- return err
122+ return fmt . Errorf ( "unable to restart snap.microk8s.daemon-containerd: %w" , err )
42123 }
43- slog .Debug ("found containerd process" , "pid" , pid )
44124
45- err = syscall .Kill (pid , syscall .SIGHUP )
125+ return nil
126+ }
127+
128+ type RKE2Restarter struct {}
129+
130+ func (c RKE2Restarter ) Restart () error {
131+ // First, collect systemd units to determine which mode rke2 is running in, eg
132+ // rke2-agent or rke2-server
133+ units , err := listSystemdUnits ()
134+ if err != nil {
135+ return fmt .Errorf ("unable to list systemd units: %w" , err )
136+ }
137+ service := regexp .MustCompile ("rke2-agent|rke2-server" ).FindString (string (units ))
46138
139+ out , err := nsenterCmd ("systemctl" , "restart" , service ).CombinedOutput ()
140+ slog .Debug (string (out ))
47141 if err != nil {
48- return fmt .Errorf ("failed to send SIGHUP to containerd : %w" , err )
142+ return fmt .Errorf ("unable to restart %s : %w" , service , err )
49143 }
144+
50145 return nil
51146}
52147
53- func getPid () (int , error ) {
148+ func listSystemdUnits () ([]byte , error ) {
149+ return nsenterCmd ("systemctl" , "list-units" , "--type" , "service" ).CombinedOutput ()
150+ }
151+
152+ func nsenterCmd (cmd ... string ) * exec.Cmd {
153+ return exec .Command ("nsenter" ,
154+ append ([]string {fmt .Sprintf ("-m/%s/proc/1/ns/mnt" , os .Getenv ("HOST_ROOT" )), "--" }, cmd ... )... ) // #nosec G204
155+ }
156+
157+ func getPid (executable string ) (int , error ) {
54158 processes , err := psProcesses ()
55159 if err != nil {
56160 return 0 , fmt .Errorf ("could not get processes: %w" , err )
@@ -59,13 +163,13 @@ func getPid() (int, error) {
59163 var containerdProcesses = []ps.Process {}
60164
61165 for _ , process := range processes {
62- if process .Executable () == "containerd" {
166+ if process .Executable () == executable {
63167 containerdProcesses = append (containerdProcesses , process )
64168 }
65169 }
66170
67171 if len (containerdProcesses ) != 1 {
68- return 0 , fmt .Errorf ("need exactly one containerd process, found: %d" , len (containerdProcesses ))
172+ return 0 , fmt .Errorf ("need exactly one %s process, found: %d" , executable , len (containerdProcesses ))
69173 }
70174
71175 return containerdProcesses [0 ].Pid (), nil
0 commit comments