blob: ab31682a37d9fc08d1d0a0aeef2b4469234c558c [file] [log] [blame]
Lorenz Brun35fcf032023-06-29 04:15:58 +02001package mgmt
2
3import (
4 "context"
5 "time"
6
Lorenz Brun1e90c6d2024-02-19 22:21:01 +01007 "github.com/vishvananda/netlink"
Lorenz Brun35fcf032023-06-29 04:15:58 +02008 "golang.org/x/sys/unix"
9 "google.golang.org/grpc/codes"
10 "google.golang.org/grpc/status"
11
12 apb "source.monogon.dev/metropolis/proto/api"
13)
14
15func (s *Service) UpdateNode(ctx context.Context, req *apb.UpdateNodeRequest) (*apb.UpdateNodeResponse, error) {
Lorenz Brund14be0e2023-07-31 16:46:14 +020016 ok := s.updateMutex.TryLock()
17 if ok {
18 defer s.updateMutex.Unlock()
19 } else {
20 return nil, status.Error(codes.Aborted, "another UpdateNode RPC is in progress on this node")
21 }
22 if req.ActivationMode == apb.ActivationMode_ACTIVATION_INVALID {
23 return nil, status.Errorf(codes.InvalidArgument, "activation_mode needs to be explicitly specified")
24 }
25 if err := s.UpdateService.InstallBundle(ctx, req.BundleUrl, req.ActivationMode == apb.ActivationMode_ACTIVATION_KEXEC); err != nil {
Lorenz Brun35fcf032023-06-29 04:15:58 +020026 return nil, status.Errorf(codes.Unavailable, "error installing update: %v", err)
27 }
Lorenz Brund14be0e2023-07-31 16:46:14 +020028 if req.ActivationMode != apb.ActivationMode_ACTIVATION_NONE {
Tim Windelschmidt45d6f182023-08-07 13:19:41 +000029
30 methodString, method := "reboot", unix.LINUX_REBOOT_CMD_RESTART
31 if req.ActivationMode == apb.ActivationMode_ACTIVATION_KEXEC {
32 methodString = "kexec"
33 method = unix.LINUX_REBOOT_CMD_KEXEC
34 }
35
36 s.LogTree.MustLeveledFor("update").Infof("activating update with method: %s", methodString)
37
Lorenz Brun35fcf032023-06-29 04:15:58 +020038 go func() {
Tim Windelschmidt45d6f182023-08-07 13:19:41 +000039 // TODO(#253): Tell Supervisor to shut down gracefully and reboot
Lorenz Brun35fcf032023-06-29 04:15:58 +020040 time.Sleep(10 * time.Second)
Tim Windelschmidt45d6f182023-08-07 13:19:41 +000041 s.LogTree.MustLeveledFor("update").Info("activating now...")
Lorenz Brunb80b8442023-08-03 17:40:17 +020042 unix.Unmount(s.UpdateService.ESPPath, 0)
Lorenz Brun35fcf032023-06-29 04:15:58 +020043 unix.Sync()
Lorenz Brun1e90c6d2024-02-19 22:21:01 +010044 disableNetworkInterfaces()
Tim Windelschmidt45d6f182023-08-07 13:19:41 +000045 unix.Reboot(method)
Lorenz Brun35fcf032023-06-29 04:15:58 +020046 }()
47 }
Lorenz Brund14be0e2023-07-31 16:46:14 +020048
Lorenz Brun35fcf032023-06-29 04:15:58 +020049 return &apb.UpdateNodeResponse{}, nil
50}
Lorenz Brun1e90c6d2024-02-19 22:21:01 +010051
52// For kexec it's recommended to disable all physical network interfaces
53// before doing it. This function doesn't return any errors as it's best-
54// effort anyways as we cannot reliably log the error anymore.
55func disableNetworkInterfaces() {
56 links, err := netlink.LinkList()
57 if err != nil {
58 return
59 }
60 for _, link := range links {
61 d, ok := link.(*netlink.Device)
62 if !ok {
63 continue
64 }
65 if err := netlink.LinkSetDown(d); err != nil {
66 continue
67 }
68 }
69}