-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add controllers for processing dependent resource deletion
- Loading branch information
1 parent
d29849c
commit 5f257ea
Showing
7 changed files
with
329 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/* | ||
Copyright 2023 Akamai Technologies, Inc. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package controller | ||
|
||
import ( | ||
"context" | ||
wrappedruntimeclient "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimeclient" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/client-go/util/retry" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
"strings" | ||
"time" | ||
|
||
wrappedruntimereconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" | ||
"github.com/linode/cluster-api-provider-linode/util/reconciler" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
|
||
infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2" | ||
) | ||
|
||
// AddressSetReconciler reconciles a FirewallRule object | ||
type AddressSetReconciler struct { | ||
client.Client | ||
Scheme *runtime.Scheme | ||
WatchFilterValue string | ||
ReconcileTimeout time.Duration | ||
} | ||
|
||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=addresssets,verbs=get;list;watch;create;update;patch;delete | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=addresssets/status,verbs=get;update;patch | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=addresssets/finalizers,verbs=update | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=linodefirewalls,verbs=get;list;watch | ||
|
||
func (r *AddressSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) | ||
defer cancel() | ||
|
||
log := ctrl.LoggerFrom(ctx).WithName("LinodeFirewallReconciler").WithValues("name", req.NamespacedName.String()) | ||
addrSet := &infrav1alpha2.AddressSet{} | ||
if err := r.TracedClient().Get(ctx, req.NamespacedName, addrSet); err != nil { | ||
if err = client.IgnoreNotFound(err); err != nil { | ||
log.Error(err, "failed to fetch AddressSet") | ||
} | ||
|
||
return ctrl.Result{}, client.IgnoreNotFound(err) | ||
} | ||
|
||
if !addrSet.DeletionTimestamp.IsZero() { | ||
log.Info("deleting firewallrule", "namespace", addrSet.Namespace, "name", addrSet.Name) | ||
for _, finalizer := range addrSet.Finalizers { | ||
parts := strings.Split(finalizer, ".") | ||
if len(parts) == 3 && parts[0] == "lfw" { | ||
lfw := &infrav1alpha2.LinodeFirewall{} | ||
if err := r.TracedClient().Get(ctx, client.ObjectKey{Namespace: parts[1], Name: parts[2]}, lfw); err != nil { | ||
if apierrors.IsNotFound(err) { | ||
// remove the finalizer since the LinodeFirewall doesn't exist anymore | ||
controllerutil.RemoveFinalizer(addrSet, finalizer) | ||
return ctrl.Result{}, nil | ||
} | ||
log.Error(err, "failed to fetch referenced LinodeFirewall") | ||
return ctrl.Result{}, nil | ||
} | ||
for _, rule := range lfw.Spec.InboundRules { | ||
for _, addrSetRef := range rule.AddressSetRefs { | ||
if addrSetRef.Namespace == "" { | ||
addrSetRef.Namespace = lfw.Namespace | ||
} | ||
if addrSetRef.Namespace == addrSet.Namespace && addrSetRef.Name == addrSet.Name { | ||
// bail out, can't clean up the AddressSet | ||
log.Info("cannot clean up AddressSet, still in use by LinodeFirewall", "namespace", lfw.Namespace, "name", lfw.Name) | ||
return ctrl.Result{}, nil | ||
} | ||
} | ||
} | ||
for _, rule := range lfw.Spec.OutboundRules { | ||
for _, addrSetRef := range rule.AddressSetRefs { | ||
if addrSetRef.Namespace == "" { | ||
addrSetRef.Namespace = lfw.Namespace | ||
} | ||
if addrSetRef.Namespace == addrSet.Namespace && addrSetRef.Name == addrSet.Name { | ||
// bail out, can't clean up the AddressSet | ||
log.Info("cannot clean up AddressSet, still in use by LinodeFirewall", "namespace", lfw.Namespace, "name", lfw.Name) | ||
return ctrl.Result{}, nil | ||
} | ||
} | ||
} | ||
// TODO: check the FWRuleRefs | ||
controllerutil.RemoveFinalizer(addrSet, finalizer) | ||
if retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { | ||
return r.Update(ctx, addrSet) | ||
}); retryErr != nil { | ||
log.Error(retryErr, "failed to remove finalizer") | ||
return ctrl.Result{}, nil | ||
} | ||
log.Info("removed AddressSet finalizer", "namespace", addrSet.Namespace, "name", addrSet.Name, "finalizer", finalizer) | ||
} | ||
} | ||
} | ||
|
||
return ctrl.Result{}, nil | ||
} | ||
|
||
// SetupWithManager sets up the controller with the Manager. | ||
func (r *AddressSetReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&infrav1alpha2.AddressSet{}). | ||
WithEventFilter(predicate.Funcs{ | ||
// only enqueue delete requests | ||
DeleteFunc: func(e event.DeleteEvent) bool { | ||
return true | ||
}, | ||
CreateFunc: func(e event.CreateEvent) bool { | ||
return false | ||
}, | ||
UpdateFunc: func(e event.UpdateEvent) bool { | ||
return false | ||
}, | ||
}). | ||
Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) | ||
} | ||
|
||
func (r *AddressSetReconciler) TracedClient() client.Client { | ||
return wrappedruntimeclient.NewRuntimeClientWithTracing(r.Client, wrappedruntimereconciler.DefaultDecorator()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
Copyright 2023 Akamai Technologies, Inc. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package controller | ||
|
||
import ( | ||
"context" | ||
wrappedruntimeclient "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimeclient" | ||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/client-go/util/retry" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
"strings" | ||
"time" | ||
|
||
wrappedruntimereconciler "github.com/linode/cluster-api-provider-linode/observability/wrappers/runtimereconciler" | ||
"github.com/linode/cluster-api-provider-linode/util/reconciler" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
|
||
infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2" | ||
) | ||
|
||
// FirewallRuleReconciler reconciles a FirewallRule object | ||
type FirewallRuleReconciler struct { | ||
client.Client | ||
Scheme *runtime.Scheme | ||
WatchFilterValue string | ||
ReconcileTimeout time.Duration | ||
} | ||
|
||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=firewallrules,verbs=get;list;watch;create;update;patch;delete | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=firewallrules/status,verbs=get;update;patch | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=firewallrules/finalizers,verbs=update | ||
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=linodefirewalls,verbs=get;list;watch | ||
|
||
func (r *FirewallRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) | ||
defer cancel() | ||
|
||
log := ctrl.LoggerFrom(ctx).WithName("LinodeFirewallReconciler").WithValues("name", req.NamespacedName.String()) | ||
fwRule := &infrav1alpha2.FirewallRule{} | ||
if err := r.TracedClient().Get(ctx, req.NamespacedName, fwRule); err != nil { | ||
if err = client.IgnoreNotFound(err); err != nil { | ||
log.Error(err, "failed to fetch FirewallRule") | ||
} | ||
|
||
return ctrl.Result{}, client.IgnoreNotFound(err) | ||
} | ||
|
||
if !fwRule.DeletionTimestamp.IsZero() { | ||
log.Info("deleting firewallrule", "namespace", fwRule.Namespace, "name", fwRule.Name) | ||
for _, finalizer := range fwRule.Finalizers { | ||
parts := strings.Split(finalizer, ".") | ||
if len(parts) == 3 && parts[0] == "lfw" { | ||
lfw := &infrav1alpha2.LinodeFirewall{} | ||
if err := r.TracedClient().Get(ctx, client.ObjectKey{Namespace: parts[1], Name: parts[2]}, lfw); err != nil { | ||
if apierrors.IsNotFound(err) { | ||
// remove the finalizer since the LinodeFirewall doesn't exist anymore | ||
controllerutil.RemoveFinalizer(fwRule, finalizer) | ||
return ctrl.Result{}, nil | ||
} | ||
log.Error(err, "failed to fetch referenced LinodeFirewall") | ||
return ctrl.Result{}, nil | ||
} | ||
for _, ruleRef := range lfw.Spec.InboundRuleRefs { | ||
if ruleRef.Namespace == "" { | ||
ruleRef.Namespace = lfw.Namespace | ||
} | ||
if ruleRef.Namespace == fwRule.Namespace && ruleRef.Name == fwRule.Name { | ||
// bail out, can't clean up the FirewallRule | ||
log.Info("cannot clean up FirewallRule, still in use by LinodeFirewall", "namespace", lfw.Namespace, "name", lfw.Name) | ||
return ctrl.Result{}, nil | ||
} | ||
} | ||
for _, ruleRef := range lfw.Spec.OutboundRuleRefs { | ||
if ruleRef.Namespace == "" { | ||
ruleRef.Namespace = lfw.Namespace | ||
} | ||
if ruleRef.Namespace == fwRule.Namespace && ruleRef.Name == fwRule.Name { | ||
// bail out, can't clean up the FirewallRule | ||
log.Info("cannot clean up FirewallRule, still in use by LinodeFirewall", "namespace", lfw.Namespace, "name", lfw.Name) | ||
return ctrl.Result{}, nil | ||
} | ||
} | ||
controllerutil.RemoveFinalizer(fwRule, finalizer) | ||
if retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { | ||
return r.Update(ctx, fwRule) | ||
}); retryErr != nil { | ||
log.Error(retryErr, "failed to remove finalizer") | ||
return ctrl.Result{}, nil | ||
} | ||
log.Info("removed FirewallRule finalizer", "namespace", fwRule.Namespace, "name", fwRule.Name, "finalizer", finalizer) | ||
} | ||
} | ||
} | ||
|
||
return ctrl.Result{}, nil | ||
} | ||
|
||
// SetupWithManager sets up the controller with the Manager. | ||
func (r *FirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&infrav1alpha2.FirewallRule{}). | ||
WithEventFilter(predicate.Funcs{ | ||
// only enqueue delete requests | ||
DeleteFunc: func(e event.DeleteEvent) bool { | ||
return true | ||
}, | ||
CreateFunc: func(e event.CreateEvent) bool { | ||
return false | ||
}, | ||
UpdateFunc: func(e event.UpdateEvent) bool { | ||
return false | ||
}, | ||
}). | ||
Complete(wrappedruntimereconciler.NewRuntimeReconcilerWithTracing(r, wrappedruntimereconciler.DefaultDecorator())) | ||
} | ||
|
||
func (r *FirewallRuleReconciler) TracedClient() client.Client { | ||
return wrappedruntimeclient.NewRuntimeClientWithTracing(r.Client, wrappedruntimereconciler.DefaultDecorator()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.