1515package main
1616
1717import (
18+ "context"
19+ "errors"
1820 "os"
21+ "os/signal"
1922 "runtime/debug"
2023 "syscall"
2124 "time"
@@ -25,6 +28,7 @@ import (
2528
2629 "github.com/vmware/govmomi/toolbox"
2730 "github.com/vmware/vic/lib/tether"
31+ "github.com/vmware/vic/lib/tether/shared"
2832 viclog "github.com/vmware/vic/pkg/log"
2933 "github.com/vmware/vic/pkg/log/syslog"
3034 "github.com/vmware/vic/pkg/logmgr"
@@ -79,6 +83,8 @@ func main() {
7983 extraconfig .Decode (src , & config )
8084 debugLevel = config .Diagnostics .DebugLevel
8185
86+ startSignalHandler ()
87+
8288 logcfg := viclog .NewLoggingConfig ()
8389 if debugLevel > 0 {
8490 logcfg .Level = log .DebugLevel
@@ -136,33 +142,80 @@ func main() {
136142 log .Info ("Clean exit from init" )
137143}
138144
145+ // exitTether signals the current process, which triggers tether.Stop and the killing of its children.
146+ // NOTE: I don't like having this here and it really needs to be moved into an interface that
147+ // can be provided to toolbox for system callbacks. While this could be part of the Operations
148+ // interface I think I'd rather have a separate one specifically for the possible toolbox interactions.
149+ func exitTether () error {
150+ defer trace .End (trace .Begin ("" ))
151+
152+ p , err := os .FindProcess (os .Getpid ())
153+ if err != nil {
154+ return err
155+ }
156+
157+ if err = p .Signal (syscall .SIGUSR2 ); err != nil {
158+ return err
159+ }
160+
161+ return err
162+ }
163+
139164// exit cleanly shuts down the system
140- func halt () {
165+ func halt () error {
141166 log .Infof ("Powering off the system" )
142- if debugLevel > 0 {
167+
168+ err := exitTether ()
169+ if err != nil {
170+ log .Warn (err )
171+ }
172+
173+ if debugLevel > 2 {
143174 log .Info ("Squashing power off for debug init" )
144- return
175+ return errors . New ( "debug config suppresses shutdown" )
145176 }
146177
178+ timeout , cancel := context .WithTimeout (context .Background (), shared .GuestShutdownTimeout )
179+ err = tthr .Wait (timeout )
180+ cancel ()
181+
147182 syscall .Sync ()
148183 syscall .Reboot (syscall .LINUX_REBOOT_CMD_POWER_OFF )
184+
185+ return err
149186}
150187
151- func reboot () {
188+ func reboot () error {
152189 log .Infof ("Rebooting the system" )
153- if debugLevel > 0 {
190+
191+ err := exitTether ()
192+ if err != nil {
193+ log .Warn (err )
194+ }
195+
196+ if debugLevel > 2 {
154197 log .Info ("Squashing reboot for debug init" )
155- return
198+ return errors . New ( "debug config suppresses reboot" )
156199 }
157200
201+ timeout , cancel := context .WithTimeout (context .Background (), shared .GuestRebootTimeout )
202+ err = tthr .Wait (timeout )
203+ cancel ()
204+
158205 syscall .Sync ()
159206 syscall .Reboot (syscall .LINUX_REBOOT_CMD_RESTART )
207+
208+ return err
160209}
161210
162211func configureToolbox (t * tether.Toolbox ) * tether.Toolbox {
163212 cmd := t .Service .Command
164213 cmd .ProcessStartCommand = startCommand
165214
215+ t .Power .Halt .Handler = halt
216+ t .Power .Reboot .Handler = reboot
217+ t .Power .Suspend .Handler = exitTether
218+
166219 return t
167220}
168221
@@ -201,3 +254,31 @@ func defaultIP() string {
201254
202255 return toolbox .DefaultIP ()
203256}
257+
258+ // This code is mirrored in cmd/tether/main_linux.go and should be de-duped
259+ func startSignalHandler () {
260+ sigs := make (chan os.Signal , 1 )
261+ signal .Notify (sigs , syscall .SIGHUP , syscall .SIGUSR1 , syscall .SIGUSR2 , syscall .SIGPWR , syscall .SIGTERM , syscall .SIGINT )
262+
263+ go func () {
264+ for s := range sigs {
265+ switch s {
266+ case syscall .SIGHUP :
267+ log .Infof ("Reloading tether configuration" )
268+ tthr .Reload ()
269+ case syscall .SIGUSR1 , syscall .SIGUSR2 , syscall .SIGPWR :
270+ log .Infof ("Stopping tether via signal %s" , s .String ())
271+ tthr .Stop ()
272+ return
273+ case syscall .SIGTERM , syscall .SIGINT :
274+ log .Infof ("Stopping system in lieu of restart handling via signal %s" , s .String ())
275+ // TODO: update this to adjust power off handling for reboot
276+ // this should be in guest reboot rather than power cycle
277+ tthr .Stop ()
278+ return
279+ default :
280+ log .Infof ("%s signal not defined" , s .String ())
281+ }
282+ }
283+ }()
284+ }
0 commit comments