...
1 package patchmanager
2
3 import (
4 "context"
5 "fmt"
6 "strings"
7 "time"
8
9 corev1 "k8s.io/api/core/v1"
10 "k8s.io/apimachinery/pkg/util/wait"
11 "sigs.k8s.io/controller-runtime/pkg/client"
12
13 "edge-infra.dev/pkg/k8s/runtime/conditions"
14 "edge-infra.dev/pkg/sds/patching/common"
15 )
16
17 const (
18 k8sAPICallRetrySleep = 5 * time.Second
19 k8sAPICallRetryTimeout = 5 * time.Minute
20
21 upgradeRetrySleep = 2 * time.Minute
22
23 )
24
25
26 func (p *PatchManager) WaitForRebootAllowed() error {
27 if p.Ienpatch.Spec.DisablePatchOrdering {
28 p.Log.Info("disablePatchOrdering is True. Rebooting immediately")
29 return nil
30 }
31
32 controlPlane, err := p.getControlPlaneHostname()
33 if err != nil {
34 return fmt.Errorf("Could not find control plane: %w", err)
35 }
36
37 if p.HostName == controlPlane {
38 p.Log.Info("This node is control plane. Scheduling reboot")
39 return nil
40 }
41
42 p.Log.Info("This node is not the control plane. Waiting for it to be patched.")
43 if err = p.waitForControlPlaneUpgraded(controlPlane); err != nil {
44 return fmt.Errorf("Timeout waiting for control plane to upgrade: %w", err)
45 }
46 p.Log.Info("Control-Plane has been upgraded. Scheduling reboot")
47 return nil
48 }
49
50
51 func (p *PatchManager) waitForControlPlaneUpgraded(controlplane string) error {
52 var lastError error
53
54 err := wait.PollUntilContextCancel(p.Ctx, upgradeRetrySleep, true, func(ctx context.Context) (done bool, err error) {
55 lastError = p.K8sClient.Get(ctx, client.ObjectKey{Name: p.Ienpatch.Name, Namespace: p.Ienpatch.Namespace}, p.Ienpatch)
56 if lastError != nil {
57 p.Log.Error(lastError, "Waiting for control-plane upgrade, failed to contact api server. Retrying")
58 return false, nil
59 }
60 msg := conditions.GetMessage(p.Ienpatch, controlplane)
61 if conditions.IsTrue(p.Ienpatch, controlplane) && strings.HasSuffix(msg, p.TargetVer) && strings.HasPrefix(msg, "Success") {
62 return true, nil
63 }
64 p.Log.Info("Waiting for control-plane to upgrade to " + p.TargetVer)
65 return false, nil
66 })
67 if lastError != nil {
68 return lastError
69 }
70 return err
71 }
72
73
74
75 func (p *PatchManager) getControlPlaneHostname() (string, error) {
76 nodes := corev1.NodeList{}
77 var lastError error
78
79 err := wait.PollUntilContextTimeout(p.Ctx, k8sAPICallRetrySleep, k8sAPICallRetryTimeout, true, func(ctx context.Context) (done bool, err error) {
80 lastError = p.K8sClient.List(ctx, &nodes, client.MatchingLabels{common.ControlPlaneLabel: ""})
81 if lastError != nil {
82 p.Log.Error(lastError, "Attempting to find control-plane, failed to contact api server. Retrying")
83 return false, nil
84 }
85 return true, nil
86 })
87 if lastError != nil {
88 return "", lastError
89 }
90 if err != nil {
91 return "", err
92 }
93
94 if len(nodes.Items) == 1 {
95 return nodes.Items[0].Name, nil
96 }
97
98 return "", fmt.Errorf("Could not find control plane")
99 }
100
View as plain text