diff --git a/controllers/node_controller.go b/controllers/node_controller.go index 9bfbe99..42ad9ef 100644 --- a/controllers/node_controller.go +++ b/controllers/node_controller.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -56,26 +57,43 @@ const ( providerNodeStatusNotFound ) -var ( - errProviderIDEmpty = errors.New("ProviderID is empty") -) +// nodeReconciler reconciles a Node object +type nodeReconciler struct { + cloud cloudprovider.Interface + client client.Client + recorder record.EventRecorder + cloudInstances cloudprovider.Instances + log logr.Logger + scheme *runtime.Scheme + dryRun bool +} + +// RegisterNodeReconciler creates and registers the node reconciler. +func RegisterNodeReconciler(mgr manager.Manager, cloud cloudprovider.Interface, dryRun bool) error { + instances, success := cloud.Instances() + if !success { + return errors.New("unable to set up cloud instances provider") + } + + r := &nodeReconciler{ + cloud: cloud, + recorder: mgr.GetEventRecorderFor("cloud-lifecycle-controller"), + client: mgr.GetClient(), + cloudInstances: instances, + log: ctrl.Log.WithName("controllers").WithName("Node"), + scheme: mgr.GetScheme(), + dryRun: dryRun, + } -// NodeReconciler reconciles a Node object -type NodeReconciler struct { - client.Client - Recorder record.EventRecorder - CloudInstances cloudprovider.Instances - Log logr.Logger - Scheme *runtime.Scheme - DryRun bool + return r.setupWithManager(mgr) } // Recursively check the list of nodes for any nodes that need to be removed from the cluster -func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := r.Log.WithValues("node", req.NamespacedName).V(1) +func (r *nodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := r.log.WithValues("node", req.NamespacedName).V(1) node := &corev1.Node{} - err := r.Client.Get(ctx, req.NamespacedName, node) + err := r.client.Get(ctx, req.NamespacedName, node) if err != nil { if apierrors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. @@ -109,20 +127,29 @@ func (r *NodeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. return ctrl.Result{}, nil } -// SetupWithManager sets up the controller with the Manager. -func (r *NodeReconciler) SetupWithManager(mgr ctrl.Manager) error { +// setupWithManager sets up the controller with the Manager. +func (r *nodeReconciler) setupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&corev1.Node{}). Complete(r) } -func (r *NodeReconciler) nodeStatus(ctx context.Context, node *corev1.Node) (providerNodeStatus, error) { - providerID := node.Spec.ProviderID - if providerID == "" { - return providerNodeStatusUnknown, errProviderIDEmpty +func (r *nodeReconciler) getProviderID(node *corev1.Node) (string, error) { + id := node.Spec.ProviderID + if id != "" { + return id, nil + } + + return generateProviderID(r.cloud, node) +} + +func (r *nodeReconciler) nodeStatus(ctx context.Context, node *corev1.Node) (providerNodeStatus, error) { + providerID, err := r.getProviderID(node) + if err != nil { + return providerNodeStatusUnknown, err } - nodeExists, err := r.CloudInstances.InstanceExistsByProviderID(ctx, providerID) + nodeExists, err := r.cloudInstances.InstanceExistsByProviderID(ctx, providerID) if err != nil && !isAWSNotFoundErr(err) { // This is a hack to work around aws bug return providerNodeStatusUnknown, err } @@ -130,7 +157,7 @@ func (r *NodeReconciler) nodeStatus(ctx context.Context, node *corev1.Node) (pro return providerNodeStatusNotFound, nil } - nodeShutdown, err := r.CloudInstances.InstanceShutdownByProviderID(ctx, providerID) + nodeShutdown, err := r.cloudInstances.InstanceShutdownByProviderID(ctx, providerID) if err != nil && !isAWSNotFoundErr(err) { // This is a hack to work around aws bug return providerNodeStatusUnknown, err } @@ -140,7 +167,7 @@ func (r *NodeReconciler) nodeStatus(ctx context.Context, node *corev1.Node) (pro return providerNodeStatusUnknown, nil } -func (r *NodeReconciler) reconcileNode(ctx context.Context, node *corev1.Node, logger logr.Logger) (ctrl.Result, error) { +func (r *nodeReconciler) reconcileNode(ctx context.Context, node *corev1.Node, logger logr.Logger) (ctrl.Result, error) { nodeStatus, err := r.nodeStatus(ctx, node) if err != nil { logger.Error(err, "Unable to get node status") @@ -163,11 +190,11 @@ func (r *NodeReconciler) reconcileNode(ctx context.Context, node *corev1.Node, l ref := newNodeRef(node) msg := fmt.Sprintf("Deleting node %s because node status is %s", node.Name, nodeStatus.String()) logger.Info(msg) - r.Recorder.Event(ref, corev1.EventTypeNormal, deleteNodeEvent, msg) + r.recorder.Event(ref, corev1.EventTypeNormal, deleteNodeEvent, msg) // Nuke 'em, captain. - if !r.DryRun { - err := r.Client.Delete(ctx, node) + if !r.dryRun { + err := r.client.Delete(ctx, node) if err != nil { logger.Error(err, "Unable to delete node") } diff --git a/controllers/provider_id_extractor.go b/controllers/provider_id_extractor.go new file mode 100644 index 0000000..7eccccc --- /dev/null +++ b/controllers/provider_id_extractor.go @@ -0,0 +1,133 @@ +/* +Copyright 2021. + +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 controllers + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "k8s.io/legacy-cloud-providers/azure" + + corev1 "k8s.io/api/core/v1" + cloudprovider "k8s.io/cloud-provider" +) + +var providerIDBuilders = map[string]func(cloud cloudprovider.Interface, node *corev1.Node) (string, error){ + "azure": azureProviderIDBuilder, + "aws": awsProviderIDBuilder, +} + +var ( + // ErrProviderNotSupported is returned when an attempt is made + // to generate a provider id for an unsupported provider. + ErrProviderNotSupported = errors.New("provider not supported") + + // ErrInvalidVMName is returned when an invalid VM name is found. + ErrInvalidVMName = errors.New("vm id is invalid") +) + +func generateProviderID(cloud cloudprovider.Interface, node *corev1.Node) (string, error) { + f, ok := providerIDBuilders[cloud.ProviderName()] + if !ok { + return "", ErrProviderNotSupported + } + return f(cloud, node) +} + +// awsProviderIDBuilder takes a node name and returns a provider id. +// For example: +// k8s-controllers-i-042988b09f6a493cc +// becomes: +// aws:///i-042988b09f6a493cc +// error will always be ErrInvalidVMName. +func awsProviderIDBuilder(_ cloudprovider.Interface, node *corev1.Node) (string, error) { + parts := strings.Split(node.Name, "-") + if len(parts) != 4 || parts[2] != "i" { + return "", ErrInvalidVMName + } + return fmt.Sprintf("aws:///%s-%s", parts[2], parts[3]), nil +} + +// azureProviderIDBuilder attempts to build a Azure ProviderID. +func azureProviderIDBuilder(cloud cloudprovider.Interface, node *corev1.Node) (string, error) { + name := node.Name + azCloud, ok := cloud.(*azure.Cloud) + if !ok { + return "", errors.New("cloud provider is not azure") + } + + scaleset, err := extractAzureScaleSet(name) + if err != nil { + return "", err + } + + vmID, err := extractAzureVMID(name) + if err != nil { + return "", err + } + + if azCloud.Config.VMType == "vmss" { + return fmt.Sprintf( + "azure:///subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/virtualMachineScaleSets/%s/virtualMachines/%s", + azCloud.SubscriptionID, + azCloud.ResourceGroup, + scaleset, + vmID, + ), nil + } + return fmt.Sprintf( + "azure:///subscriptions/%s/resourceGroups/%s/virtualMachines/%s", + azCloud.SubscriptionID, + azCloud.ResourceGroup, + vmID, + ), nil +} + +// extractAzureVMID takes a machine name and returns the ID. For example: +// aks-agentpool-34751183-vmss001001 +// becomes: +// 1001 +// error will always be ErrInvalidVMName. +func extractAzureVMID(name string) (string, error) { + // Azure names are padded with leading zeros so there should always be + // at least six alphanumeric characters. + if len(name) < 6 { + return "", ErrInvalidVMName + } + id := name[len(name)-6:] + i, err := strconv.ParseInt(id, 36, 64) + if err != nil { + return "", ErrInvalidVMName + } + return strings.ToUpper(strconv.FormatInt(i, 36)), nil +} + +// extractAzureScaleSet takes a machine name and returns the scale set. +// For example: +// aks-agentpool-34751183-vmss001001 +// becomes: +// aks-agentpool-34751183-vmss +// error will always be ErrInvalidVMName. +func extractAzureScaleSet(name string) (string, error) { + if len(name) <= 6 { + return "", ErrInvalidVMName + } + name = name[:len(name)-6] + return name, nil +} diff --git a/controllers/provider_id_extractor_test.go b/controllers/provider_id_extractor_test.go new file mode 100644 index 0000000..4da1c7a --- /dev/null +++ b/controllers/provider_id_extractor_test.go @@ -0,0 +1,134 @@ +/* +Copyright 2021. + +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 controllers + +import ( + "testing" + + "k8s.io/legacy-cloud-providers/azure" + + corev1 "k8s.io/api/core/v1" +) + +func TestAwsProviderIDBuilder(t *testing.T) { + tests := []struct { + have string + want string + wantErr error + }{ + {have: "k8s-controllers-i-042988b09f6a493cc", want: "aws:///i-042988b09f6a493cc"}, + {have: "042988b09f6a493cc", wantErr: ErrInvalidVMName}, + } + + node := &corev1.Node{} + + for _, test := range tests { + node.Name = test.have + got, err := awsProviderIDBuilder(nil, node) + if err != test.wantErr || got != test.want { + t.Fatalf( + "awsProviderIDBuilder(_, name=%q) got %q, %v; want %q, %v", + test.have, + got, + err, + test.want, + test.wantErr, + ) + } + } +} + +func TestExtractAzureScaleSet(t *testing.T) { + tests := []struct { + have string + want string + wantErr error + }{ + {have: "aks-agentpool-34751183-vmss000001", want: "aks-agentpool-34751183-vmss"}, + {have: "aks-agentpool-34751183-vmss999999", want: "aks-agentpool-34751183-vmss"}, + {have: "1234", want: "", wantErr: ErrInvalidVMName}, + } + + for _, test := range tests { + got, err := extractAzureScaleSet(test.have) + if err != test.wantErr || got != test.want { + t.Fatalf("extractAzureScaleSet(%q) = %q, %v; want %q, %v", test.have, got, err, test.want, test.wantErr) + } + } +} + +func TestExtractAzureVMID(t *testing.T) { + tests := []struct { + have string + want string + wantErr error + }{ + {have: "aks-agentpool-34751183-vmss000001", want: "1"}, + {have: "aks-agentpool-34751183-vmss001001", want: "1001"}, + {have: "aks-agentpool-34751183-vmss999999", want: "999999"}, + {have: "aks-agentpool-34751183-vmss00002D", want: "2D"}, + {have: "2D", want: "", wantErr: ErrInvalidVMName}, + } + + for _, test := range tests { + got, err := extractAzureVMID(test.have) + if err != test.wantErr || got != test.want { + t.Fatalf("extractAzureVMID(%q) = %q, %v; want %q, %v", test.have, got, err, test.want, test.wantErr) + } + } +} + +func TestAzureProviderIDBuilder(t *testing.T) { + tests := []struct { + haveResourceGroup string + haveSubscriptionID string + haveVMType string + haveNodeName string + want string + }{ + { + haveResourceGroup: "mc_aks-my_kube-cluster_eastus2", + haveSubscriptionID: "76786c64-3d1b-4f99-a9b5-40a79689adac", + haveVMType: "vmss", + haveNodeName: "aks-agentpool-34751183-vmss000001", + want: "azure:///subscriptions/76786c64-3d1b-4f99-a9b5-40a79689adac/resourceGroups/mc_aks-my_kube-cluster_eastus2/providers/Microsoft.Compute/virtualMachineScaleSets/aks-agentpool-34751183-vmss/virtualMachines/1", + }, + } + + cloud := &azure.Cloud{} + node := &corev1.Node{} + + for _, test := range tests { + cloud.ResourceGroup = test.haveResourceGroup + cloud.SubscriptionID = test.haveSubscriptionID + cloud.VMType = test.haveVMType + node.Name = test.haveNodeName + + got, err := azureProviderIDBuilder(cloud, node) + if err != nil || got != test.want { + t.Fatalf( + "azureProviderIDBuilder({ResourceGroup=%q, SubscriptionID=%q}, %q) got %q, %v; want %q, nil", + cloud.ResourceGroup, + cloud.SubscriptionID, + node.Name, + got, + err, + test.want, + ) + } + } +} diff --git a/go.sum b/go.sum index ecdbd3c..0b8762b 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,7 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v43.0.0+incompatible h1:/wSNCu0e6EsHFR4Qa3vBEBbicaprEHMyyga9g8RTULI= github.com/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -47,7 +48,9 @@ github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0 h1:nQOZzFCudTh+TvquAtCRjM01VEYx85e9qbwt5ncW4L8= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/validation v0.1.0 h1:ISSNzGUh+ZSzizJWOWzs8bwpXIePbGLW4z/AmUFGH5A= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= @@ -116,6 +119,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -214,6 +218,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -409,9 +414,11 @@ github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021 h1:if3/24+h9Sq6eDx8UUz1SO9cT9tizyIsATfB7b4D3tc= github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -788,6 +795,7 @@ k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlm k8s.io/apimachinery v0.20.0 h1:jjzbTJRXk0unNS71L7h3lxGDH/2HPxMPaQY+MjECKL8= k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= +k8s.io/apiserver v0.20.0 h1:0MwO4xCoqZwhoLbFyyBSJdu55CScp4V4sAgX6z4oPBY= k8s.io/apiserver v0.20.0/go.mod h1:6gRIWiOkvGvQt12WTYmsiYoUyYW0FXSiMdNl4m+sxY8= k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.20.0 h1:Xlax8PKbZsjX4gFvNtt4F5MoJ1V5prDvCuoq9B7iax0= diff --git a/main.go b/main.go index 2392311..32b2138 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -36,6 +37,7 @@ import ( // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/legacy-cloud-providers/aws" + _ "k8s.io/legacy-cloud-providers/azure" ) var ( @@ -88,9 +90,9 @@ func main() { LeaderElectionNamespace: leaderElectionNamespace, DryRunClient: dryRun, } - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrlOpts) + mgr, err := newManager(ctrlOpts) if err != nil { - setupLog.Error(err, "unable to start manager") + setupLog.Error(err, "unable to create manager") os.Exit(1) } @@ -115,31 +117,8 @@ func main() { os.Exit(1) } - instances, success := cloud.Instances() - if !success { - setupLog.Error(err, "Unable to set up cloud instances provider") - os.Exit(1) - } - - nodeReconciler := &controllers.NodeReconciler{ - Recorder: mgr.GetEventRecorderFor("cloud-lifecycle-controller"), - Client: mgr.GetClient(), - CloudInstances: instances, - Log: ctrl.Log.WithName("controllers").WithName("Node"), - Scheme: mgr.GetScheme(), - DryRun: dryRun, - } - if err = nodeReconciler.SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Node") - os.Exit(1) - } - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") + if err := controllers.RegisterNodeReconciler(mgr, cloud, dryRun); err != nil { + setupLog.Error(err, "unable to register reconciler", "controller", "Node") os.Exit(1) } @@ -160,3 +139,17 @@ VPC=FakeVPC SubnetID=FakeSubnet ` } + +func newManager(opts ctrl.Options) (manager.Manager, error) { + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), opts) + if err != nil { + return nil, err + } + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + return nil, err + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + return nil, err + } + return mgr, nil +}