@@ -22,35 +22,146 @@ 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 systemctl exists, use that, otherwise go pid 
43+ 	if  UsesSystemd () {
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  :=  nsenterCmd ("systemctl" , "list-units" ).CombinedOutput ()
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 
89+ 	// using systemd as well as K3d, which does not. 
90+ 	if  UsesSystemd () {
91+ 		out , err  :=  nsenterCmd ("systemctl" , "restart" , "k3s" ).CombinedOutput ()
92+ 		slog .Debug (string (out ))
93+ 		if  err  !=  nil  {
94+ 			return  fmt .Errorf ("unable to restart k3s: %w" , err )
95+ 		}
96+ 	} else  {
97+ 		// TODO: this approach still leads to the behavior mentioned in https://github.com/spinframework/runtime-class-manager/issues/140: 
98+ 		// The first pod's provisioner container exits with code 255, leading to pod status Unknown, 
99+ 		// followed by the subsequent pod's provisioner container no-op-ing and finishing with status Completed. 
100+ 		pid , err  :=  getPid ("k3s" )
101+ 		if  err  !=  nil  {
102+ 			return  err 
103+ 		}
104+ 		slog .Debug ("found k3s process" , "pid" , pid )
105+ 
106+ 		err  =  syscall .Kill (pid , syscall .SIGHUP )
107+ 		if  err  !=  nil  {
108+ 			return  fmt .Errorf ("failed to send SIGHUP to k3s: %w" , err )
109+ 		}
110+ 	}
111+ 
112+ 	return  nil 
113+ }
114+ 
115+ type  MicroK8sRestarter  struct {}
116+ 
117+ func  (c  MicroK8sRestarter ) Restart () error  {
118+ 	out , err  :=  nsenterCmd ("systemctl" , "restart" , "snap.microk8s.daemon-containerd" ).CombinedOutput ()
119+ 	slog .Debug (string (out ))
40120	if  err  !=  nil  {
41- 		return  err 
121+ 		return  fmt . Errorf ( "unable to restart snap.microk8s.daemon-containerd: %w" ,  err ) 
42122	}
43- 	slog .Debug ("found containerd process" , "pid" , pid )
44123
45- 	err  =  syscall .Kill (pid , syscall .SIGHUP )
124+ 	return  nil 
125+ }
46126
127+ type  RKE2Restarter  struct {}
128+ 
129+ func  (c  RKE2Restarter ) Restart () error  {
130+ 	// First, collect systemd units to determine which mode rke2 is running in, eg 
131+ 	// rke2-agent or rke2-server 
132+ 	units , err  :=  nsenterCmd ("systemctl" , "list-units" ).CombinedOutput ()
47133	if  err  !=  nil  {
48- 		return  fmt .Errorf ("failed  to send SIGHUP to containerd : %w" , err )
134+ 		return  fmt .Errorf ("unable  to list systemd units : %w" , err )
49135	}
136+ 	service  :=  regexp .MustCompile ("rke2-agent|rke2-server" ).FindString (string (units ))
137+ 
138+ 	out , err  :=  nsenterCmd ("systemctl" , "restart" , service ).CombinedOutput ()
139+ 	slog .Debug (string (out ))
140+ 	if  err  !=  nil  {
141+ 		return  fmt .Errorf ("unable to restart %s: %w" , service , err )
142+ 	}
143+ 
50144	return  nil 
51145}
52146
53- func  getPid () (int , error ) {
147+ // TODO: lifted and amended from https://github.com/spinframework/runtime-class-manager/pull/387 
148+ // 
149+ // UsesSystemd checks if the system is using systemd 
150+ func  UsesSystemd () bool  {
151+ 	cmd  :=  nsenterCmd ("systemctl" , "list-units" , "|" , "grep" , "-q" , "containerd.service" )
152+ 	if  err  :=  cmd .Run (); err  !=  nil  {
153+ 		slog .Debug ("Error with systemctl: \n " , "error" , err )
154+ 		return  false 
155+ 	}
156+ 	return  true 
157+ }
158+ 
159+ func  nsenterCmd (cmd  ... string ) * exec.Cmd  {
160+ 	return  exec .Command ("nsenter" ,
161+ 		append ([]string {fmt .Sprintf ("-m/%s/proc/1/ns/mnt" , os .Getenv ("HOST_ROOT" )), "--" }, cmd ... )... ) // #nosec G204 
162+ }
163+ 
164+ func  getPid (executable  string ) (int , error ) {
54165	processes , err  :=  psProcesses ()
55166	if  err  !=  nil  {
56167		return  0 , fmt .Errorf ("could not get processes: %w" , err )
@@ -59,13 +170,13 @@ func getPid() (int, error) {
59170	var  containerdProcesses  =  []ps.Process {}
60171
61172	for  _ , process  :=  range  processes  {
62- 		if  process .Executable () ==  "containerd"  {
173+ 		if  process .Executable () ==  executable  {
63174			containerdProcesses  =  append (containerdProcesses , process )
64175		}
65176	}
66177
67178	if  len (containerdProcesses ) !=  1  {
68- 		return  0 , fmt .Errorf ("need exactly one containerd  process, found: %d" , len (containerdProcesses ))
179+ 		return  0 , fmt .Errorf ("need exactly one %s  process, found: %d" ,  executable , len (containerdProcesses ))
69180	}
70181
71182	return  containerdProcesses [0 ].Pid (), nil 
0 commit comments