1 package detector
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "edge-infra.dev/pkg/lib/fog"
9 v1etcd "edge-infra.dev/pkg/sds/etcd/operator/apis/etcdmember/v1"
10 "edge-infra.dev/pkg/sds/lanoutage/detector/internal/constants"
11 "edge-infra.dev/pkg/sds/lanoutage/detector/internal/firewall"
12 "edge-infra.dev/pkg/sds/lanoutage/detector/internal/leave"
13
14 "github.com/vishvananda/netlink"
15 "golang.org/x/sys/unix"
16 "k8s.io/apimachinery/pkg/runtime"
17 "k8s.io/apimachinery/pkg/types"
18 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
19 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
20 "k8s.io/client-go/tools/clientcmd"
21 "sigs.k8s.io/controller-runtime/pkg/client"
22 )
23
24
25 func (l *LOMReconciler) Leave(ctx context.Context) error {
26 log := fog.FromContext(ctx)
27 log.Info(constants.LeavingMessage)
28
29 log.Info("getting lo interface")
30 lo, err := netlink.LinkByName("lo")
31 if err != nil {
32 return fmt.Errorf("there was an error getting the loopback interface")
33 }
34
35 log.Info("getting vip address")
36 vip, err := getVipAddress(l.cfg.Kubeconfig)
37 if err != nil {
38 return fmt.Errorf("there was an error getting the VIP address")
39 }
40
41 leaveConf := leave.NewLeaveConf(l.cfg, vip, lo)
42
43 listOfSteps := []leave.Step{
44 RemoveVipAlias,
45 RemoveKubeManifests,
46 RemoveKubeConfig,
47 RemoveEtcdManifest,
48 ReverseIsolateNode,
49 RemoveLOMFlag,
50 DeleteMember,
51 }
52
53 for _, step := range listOfSteps {
54 err := step(ctx, *leaveConf)
55 if err != nil {
56 return fmt.Errorf("failed to leave LAN Outage Mode: %w", err)
57 }
58 }
59
60
61 l.isLOM = false
62
63 log.Info(constants.LeaveSuccessMessage)
64 return nil
65 }
66
67
68 func RemoveVipAlias(ctx context.Context, cfg leave.Conf) error {
69 log := fog.FromContext(ctx)
70 log.Info("removing vip alias")
71
72 addr, err := netlink.ParseAddr(cfg.Vip + "/32")
73 if err != nil {
74 return fmt.Errorf("there was an error parsing the VIP address: %w", err)
75 }
76
77 err = netlink.AddrDel(cfg.Lo, addr)
78
79
80 if err != nil && !errors.Is(err, unix.Errno(0x63)) {
81 return fmt.Errorf("there was an error deleting the VIP alias on lo: %w", err)
82 }
83
84 return nil
85 }
86
87
88 func RemoveKubeConfig(ctx context.Context, cfg leave.Conf) error {
89 log := fog.FromContext(ctx)
90 log.Info("removing the kubeconfig")
91
92 err := cfg.ReconcilerConfig.Fs.RemoveAll(constants.Zylevel0ConfFilepath)
93 if err != nil {
94 return fmt.Errorf("there was an error removing the zylevel0 kube config: %w", err)
95 }
96 err = cfg.ReconcilerConfig.Fs.RemoveAll(constants.Zylevel0PEMFilepath)
97 if err != nil {
98 return fmt.Errorf("there was an error removing the zylevel0-auth cert file: %w", err)
99 }
100
101 return nil
102 }
103
104 func RemoveEtcdManifest(ctx context.Context, cfg leave.Conf) error {
105 log := fog.FromContext(ctx)
106 log.Info("deleting etcd manifest")
107
108 err := cfg.ReconcilerConfig.Fs.RemoveAll(constants.EtcdManifestFilepath)
109 if err != nil {
110 return fmt.Errorf("failed to remove the etcd yaml: %w", err)
111 }
112 return nil
113 }
114
115 func ReverseIsolateNode(ctx context.Context, cfg leave.Conf) error {
116 log := fog.FromContext(ctx)
117 log.Info("de-isolating the node")
118
119 lo, err := getLoopbackInterface()
120 if err != nil {
121 return fmt.Errorf("an error occurred fetching the loopback interface: %w", err)
122 }
123
124 err = firewall.RemoveIPFilterRules(cfg.ReconcilerConfig.Fs)
125 if err != nil {
126 return fmt.Errorf("there was an error removing the IP filter rules: %w", err)
127 }
128
129 err = firewall.SetARPFlags(cfg.ReconcilerConfig.Fs, "leave", cfg.ReconcilerConfig.MacAddress)
130 if err != nil {
131 return fmt.Errorf("an error occurred when removing ARP filter: %w", err)
132 }
133
134 err = netlink.LinkSetARPOn(lo)
135 if err != nil {
136 return fmt.Errorf("there was an error removing the ARP block: %w", err)
137 }
138 return nil
139 }
140
141 func RemoveLOMFlag(ctx context.Context, cfg leave.Conf) error {
142 log := fog.FromContext(ctx)
143 log.Info("removing the LAN Outage Mode flag file")
144
145 err := cfg.ReconcilerConfig.Fs.RemoveAll(constants.LOMFlagFilepath)
146 if err != nil {
147 return fmt.Errorf("an error occurred removing the LAN Outage Mode flag file: %w", err)
148 }
149 return nil
150 }
151
152
153
154
155 func DeleteMember(ctx context.Context, cfg leave.Conf) error {
156 log := fog.FromContext(ctx)
157 log.Info("deleting the EtcdMember")
158 emName := types.NamespacedName{Namespace: "", Name: cfg.ReconcilerConfig.NodeName}
159 em := &v1etcd.EtcdMember{}
160
161 err := deleteObject(context.Background(), emName, em)
162 if err != nil {
163 log.Error(err, "failed to delete EtcdMembers")
164 }
165 return nil
166 }
167
168 func deleteObject(ctx context.Context, name types.NamespacedName, obj client.Object) error {
169 log := fog.FromContext(ctx)
170 log.V(1).Info("about to delete object", "Object", obj, "NamespacedName", name)
171 config, err := clientcmd.BuildConfigFromFlags("", constants.AdminConfFilepath)
172 if err != nil {
173 return fmt.Errorf("couldn't create kubeconfig: %w", err)
174 }
175
176 kclient, err := client.New(config, clientOptions())
177 if err != nil {
178 return fmt.Errorf("couldn't create k8s client: %w", err)
179 }
180 if err != client.IgnoreNotFound(kclient.Get(ctx, name, obj)) {
181 return fmt.Errorf("couldn't get EtcdMember: %w", err)
182 }
183 return client.IgnoreNotFound(kclient.Delete(ctx, obj))
184 }
185
186
187 func clientOptions() client.Options {
188 return client.Options{
189 Scheme: newScheme(),
190 }
191 }
192
193 func newScheme() *runtime.Scheme {
194 scheme := runtime.NewScheme()
195 utilruntime.Must(clientgoscheme.AddToScheme(scheme))
196 utilruntime.Must(v1etcd.AddToScheme(scheme))
197 return scheme
198 }
199
View as plain text