-
Notifications
You must be signed in to change notification settings - Fork 833
/
controller.go
94 lines (82 loc) · 2.75 KB
/
controller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
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 node
import (
"context"
"fmt"
"reflect"
"github.com/awslabs/karpenter/pkg/apis/provisioning/v1alpha3"
"github.com/awslabs/karpenter/pkg/utils/result"
"go.uber.org/multierr"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"knative.dev/pkg/logging"
controllerruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)
// NewController constructs a controller instance
func NewController(kubeClient client.Client) *Controller {
return &Controller{
kubeClient: kubeClient,
}
}
// Controller manages a set of properites on karpenter provisioned nodes, such as
// taints, labels, finalizers.
type Controller struct {
kubeClient client.Client
readiness *Readiness
finalizer *Finalizer
}
// Reconcile executes a reallocation control loop for the resource
func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
ctx = logging.WithLogger(ctx, logging.FromContext(ctx).Named("Node"))
// 1. Retrieve node from reconcile request
stored := &v1.Node{}
if err := c.kubeClient.Get(ctx, req.NamespacedName, stored); err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
}
return reconcile.Result{}, err
}
if _, ok := stored.Labels[v1alpha3.ProvisionerNameLabelKey]; !ok {
return reconcile.Result{}, nil
}
// 2. Execute node reconcilers
node := stored.DeepCopy()
var errs error
for _, reconciler := range []interface {
Reconcile(*v1.Node) error
}{
c.readiness,
c.finalizer,
} {
errs = multierr.Append(errs, reconciler.Reconcile(node))
}
// 3. Patch any changes, regardless of errors
if !reflect.DeepEqual(node, stored) {
if err := c.kubeClient.Patch(ctx, node, client.MergeFrom(stored)); err != nil {
return reconcile.Result{}, fmt.Errorf("patching node %s, %w", node.Name, err)
}
}
return result.RetryIfError(ctx, errs)
}
func (c *Controller) Register(_ context.Context, m manager.Manager) error {
return controllerruntime.
NewControllerManagedBy(m).
Named("Node").
For(&v1.Node{}).
WithOptions(controller.Options{MaxConcurrentReconciles: 10}).
Complete(c)
}