Skip to content

Commit 91feb1f

Browse files
authored
Update gardener infrastructure egress cidrs for ACL extension. (#61)
1 parent b444052 commit 91feb1f

File tree

4 files changed

+722
-16
lines changed

4 files changed

+722
-16
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package deployment
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/netip"
7+
"slices"
8+
"strings"
9+
10+
v2 "github.com/metal-stack/firewall-controller-manager/api/v2"
11+
"github.com/metal-stack/firewall-controller-manager/controllers"
12+
"github.com/metal-stack/metal-lib/pkg/pointer"
13+
apierrors "k8s.io/apimachinery/pkg/api/errors"
14+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15+
"k8s.io/apimachinery/pkg/runtime/schema"
16+
"k8s.io/apimachinery/pkg/types"
17+
"sigs.k8s.io/controller-runtime/pkg/client"
18+
)
19+
20+
func (c *controller) updateInfrastructureStatus(r *controllers.Ctx[*v2.FirewallDeployment], infrastructureName string, ownedFirewalls []*v2.Firewall) error {
21+
infraObj := &unstructured.Unstructured{}
22+
23+
infraObj.SetGroupVersionKind(schema.GroupVersionKind{
24+
Group: "extensions.gardener.cloud",
25+
Kind: "Infrastructure",
26+
Version: "v1alpha1",
27+
})
28+
29+
err := c.c.GetSeedClient().Get(r.Ctx, client.ObjectKey{
30+
Namespace: c.c.GetSeedNamespace(),
31+
Name: infrastructureName,
32+
}, infraObj)
33+
if err != nil {
34+
if apierrors.IsNotFound(err) {
35+
return nil
36+
}
37+
return err
38+
}
39+
40+
type infrastructure struct {
41+
Spec struct {
42+
ProviderConfig struct {
43+
Firewall struct {
44+
EgressRules []struct {
45+
IPs []string `json:"ips"`
46+
} `json:"egressRules"`
47+
} `json:"firewall"`
48+
} `json:"providerConfig"`
49+
} `json:"spec"`
50+
Status struct {
51+
EgressCIDRs []string `json:"egressCIDRs"`
52+
} `json:"status"`
53+
}
54+
55+
infraRaw, err := json.Marshal(infraObj)
56+
if err != nil {
57+
return fmt.Errorf("unable to convert gardener infrastructure object: %w", err)
58+
}
59+
60+
var typedInfra infrastructure
61+
err = json.Unmarshal(infraRaw, &typedInfra)
62+
if err != nil {
63+
return fmt.Errorf("unable to convert gardener infrastructure object: %w", err)
64+
}
65+
66+
var egressCIDRs []string
67+
68+
for _, fw := range ownedFirewalls {
69+
for _, network := range fw.Status.FirewallNetworks {
70+
if pointer.SafeDeref(network.NetworkType) != "external" {
71+
continue
72+
}
73+
74+
for _, ip := range network.IPs {
75+
parsed, err := netip.ParseAddr(ip)
76+
if err != nil {
77+
continue
78+
}
79+
80+
egressCIDRs = append(egressCIDRs, fmt.Sprintf("%s/%d", ip, parsed.BitLen()))
81+
}
82+
}
83+
}
84+
85+
for _, rule := range typedInfra.Spec.ProviderConfig.Firewall.EgressRules {
86+
for _, ip := range rule.IPs {
87+
parsed, err := netip.ParseAddr(ip)
88+
if err != nil {
89+
continue
90+
}
91+
92+
egressCIDRs = append(egressCIDRs, fmt.Sprintf("%s/%d", ip, parsed.BitLen()))
93+
}
94+
}
95+
96+
slices.Sort(egressCIDRs)
97+
slices.Sort(typedInfra.Status.EgressCIDRs)
98+
99+
// check if an update is required or not
100+
if slices.Equal(egressCIDRs, typedInfra.Status.EgressCIDRs) {
101+
c.log.Info("found gardener infrastructure resource, egress cidrs already up-to-date", "infrastructure-name", infraObj.GetName(), "egress-cidrs", egressCIDRs)
102+
return nil
103+
}
104+
105+
infraStatusPatch := map[string]any{
106+
"status": map[string]any{
107+
"egressCIDRs": egressCIDRs,
108+
},
109+
}
110+
111+
jsonPatch, err := json.Marshal(infraStatusPatch)
112+
if err != nil {
113+
return fmt.Errorf("unable to marshal infrastructure status patch: %w", err)
114+
}
115+
116+
err = c.c.GetSeedClient().Status().Patch(r.Ctx, infraObj, client.RawPatch(types.MergePatchType, jsonPatch))
117+
if err != nil {
118+
return fmt.Errorf("error patching infrastructure status egress cidrs field: %w", err)
119+
}
120+
121+
c.log.Info("found gardener infrastructure resource and patched egress cidrs for acl extension", "infrastructure-name", infraObj.GetName(), "egress-cidrs", egressCIDRs)
122+
123+
aclObj := &unstructured.Unstructured{}
124+
125+
aclObj.SetGroupVersionKind(schema.GroupVersionKind{
126+
Group: "extensions.gardener.cloud",
127+
Kind: "Extension",
128+
Version: "v1alpha1",
129+
})
130+
131+
err = c.c.GetSeedClient().Get(r.Ctx, client.ObjectKey{
132+
Namespace: c.c.GetSeedNamespace(),
133+
Name: "acl",
134+
}, aclObj)
135+
if err != nil {
136+
if apierrors.IsNotFound(err) {
137+
return nil
138+
}
139+
return err
140+
}
141+
142+
err = v2.AddAnnotation(r.Ctx, c.c.GetSeedClient(), aclObj, "gardener.cloud/operation", "reconcile")
143+
if err != nil {
144+
return fmt.Errorf("error annotating acl extension with reconcile operation: %w", err)
145+
}
146+
147+
c.log.Info("added reconcile annotation to gardener acl extension object")
148+
149+
return nil
150+
}
151+
152+
func extractInfrastructureNameFromSeedNamespace(namespace string) (string, bool) {
153+
if !strings.HasPrefix(namespace, "shoot--") {
154+
return "", false
155+
}
156+
157+
parts := strings.Split(namespace, "--")
158+
if len(parts) < 3 {
159+
return "", false
160+
}
161+
162+
return strings.Join(parts[2:], "--"), true
163+
}

0 commit comments

Comments
 (0)