Skip to content

Create events on route updates failures and don't keep node routes to main route table #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .ci/pipeline_definitions
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ aws-custom-route-controller:
dockerfile: 'Dockerfile'
steps:
verify:
image: golang:1.19.4
image: golang:1.19.5
jobs:
head-update:
traits:
draft_release: ~
component_descriptor: ~
component_descriptor:
retention_policy: 'clean-snapshots'
pull-request:
traits:
pull-request: ~
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

############# builder
FROM golang:1.19.4 AS builder
FROM golang:1.19.5 AS builder

WORKDIR /build
COPY . .
Expand Down
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
var Version string

const (
// componentName is the component name
componentName = "aws-custom-route-controller"
// leaderElectionId is the name of the lease resource
leaderElectionId = "aws-custom-route-controller-leader-election"
)
Expand All @@ -51,7 +53,7 @@ var (
func main() {
logf.SetLogger(zap.New())

var log = logf.Log.WithName("aws-custom-route-controller")
var log = logf.Log.WithName(componentName)
log.Info("version", "version", Version)

pflag.Parse()
Expand Down Expand Up @@ -81,7 +83,7 @@ func main() {
os.Exit(1)
}

reconciler := controller.NewNodeReconciler(mgr.Elected())
reconciler := controller.NewNodeReconciler(mgr.Elected(), mgr.GetEventRecorderFor(componentName))
err = builder.
ControllerManagedBy(mgr).
For(&corev1.Node{}).
Expand Down
39 changes: 37 additions & 2 deletions pkg/controller/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"go.uber.org/atomic"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
Expand All @@ -33,13 +35,17 @@ type NodeReconciler struct {
nodeRoutes *updater.NamedNodeRoutes
lastTick atomic.Time
tickPeriod time.Duration

recorder record.EventRecorder
lastEventOk bool
}

// NewNodeReconciler creates a NodeReconciler instance
func NewNodeReconciler(elected <-chan struct{}) *NodeReconciler {
func NewNodeReconciler(elected <-chan struct{}, recorder record.EventRecorder) *NodeReconciler {
return &NodeReconciler{
elected: elected,
nodeRoutes: updater.NewNamedNodeRoutes(),
recorder: recorder,
}
}

Expand Down Expand Up @@ -78,7 +84,8 @@ func (r *NodeReconciler) StartUpdater(ctx context.Context, updateFunc updater.No
r.nodeRoutes.SetChanged()
}
if routes := r.nodeRoutes.GetRoutesIfChanged(); routes != nil {
if err := updateFunc(routes); err != nil {
err := updateFunc(routes)
if err != nil {
log.Error(err, "updating routes failed")
lastFailure = time.Now()
if delay == 0 {
Expand All @@ -92,6 +99,7 @@ func (r *NodeReconciler) StartUpdater(ctx context.Context, updateFunc updater.No
} else {
delay = 0
}
r.reportEventIfNeeded(err)
lastUpdate = time.Now()
}
r.lastTick.Store(time.Now())
Expand All @@ -100,6 +108,33 @@ func (r *NodeReconciler) StartUpdater(ctx context.Context, updateFunc updater.No
}()
}

func (r *NodeReconciler) reportEventIfNeeded(err error) {
isOk := err == nil
if isOk && r.lastEventOk {
// only single good event is sent (initial or after recovery)
return
}

// An object is needed this event is about.
// As the aws-custom-route-controller has not many objects in the shoot cluster, just use its ServiceAccount.
ref := &corev1.ObjectReference{
Kind: "ServiceAccount",
APIVersion: "v1",
Namespace: metav1.NamespaceSystem,
Name: "aws-custom-route-controller",
}
if isOk {
r.recorder.Event(ref, corev1.EventTypeNormal, "RoutesUpToDate", "routes for all route tables are up-to-date")
} else {
msg := err.Error()
if len(msg) > 300 {
msg = msg[:300] + "..."
}
r.recorder.Event(ref, corev1.EventTypeWarning, "RoutesUpdateFailed", msg)
}
r.lastEventOk = isOk
}

// Reconcile extracts pod cidrs from nodes
func (r *NodeReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
if r.initialiseStarted.CompareAndSwap(false, true) {
Expand Down
9 changes: 9 additions & 0 deletions pkg/updater/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,12 @@ func hasClusterTag(clusterID string, tags []*ec2.Tag) bool {
}
return false
}

func getNameTagValue(tags []*ec2.Tag) string {
for _, tag := range tags {
if aws.StringValue(tag.Key) == "Name" {
return aws.StringValue(tag.Value)
}
}
return ""
}
7 changes: 7 additions & 0 deletions pkg/updater/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,14 @@ func (r *CustomRoutes) Update(routes []NodeRoute) error {
return updateErrors
}

func (r *CustomRoutes) isMainTable(table *ec2.RouteTable) bool {
return getNameTagValue(table.Tags) == r.clusterName
}

func (r *CustomRoutes) calcRouteChanges(table *ec2.RouteTable, nodeRoutes []NodeRoute) (toBeCreated, toBeDeleted []internalNodeRoute) {
if r.isMainTable(table) {
nodeRoutes = nil
}
found := make([]bool, len(nodeRoutes))
outer:
for _, route := range table.Routes {
Expand Down