pkg/operator/controllers/subnets/subnets_controller.go (118 lines of code) (raw):
package subnets
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"context"
"fmt"
"strings"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
machinev1beta1 "github.com/openshift/api/machine/v1beta1"
"github.com/Azure/ARO-RP/pkg/operator"
arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
"github.com/Azure/ARO-RP/pkg/operator/predicates"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
"github.com/Azure/ARO-RP/pkg/util/clusterauthorizer"
"github.com/Azure/ARO-RP/pkg/util/subnet"
)
const (
ControllerName = "AzureSubnets"
controllerServiceEndpointManaged = operator.AzureSubnetsServiceEndpointManaged
)
// Reconciler is the controller struct
type Reconciler struct {
log *logrus.Entry
client client.Client
}
// reconcileManager is an instance of the manager instantiated per request
type reconcileManager struct {
log *logrus.Entry
client client.Client
instance *arov1alpha1.Cluster
subscriptionID string
subnets subnet.Manager
kubeSubnets subnet.KubeManager
}
// NewReconciler creates a new Reconciler
func NewReconciler(log *logrus.Entry, client client.Client) *Reconciler {
return &Reconciler{
log: log,
client: client,
}
}
// Reconcile fixes the Network Security Groups
func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
instance := &arov1alpha1.Cluster{}
err := r.client.Get(ctx, types.NamespacedName{Name: arov1alpha1.SingletonClusterName}, instance)
if err != nil {
return reconcile.Result{}, err
}
if !instance.Spec.OperatorFlags.GetSimpleBoolean(operator.AzureSubnetsEnabled) {
r.log.Debug("controller is disabled")
return reconcile.Result{}, nil
}
r.log.Debug("running")
if !instance.Spec.OperatorFlags.GetSimpleBoolean(operator.AzureSubnetsNsgManaged) && !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerServiceEndpointManaged) {
// controller is disabled
return reconcile.Result{}, nil
}
// Get endpoints from the operator
azEnv, err := azureclient.EnvironmentFromName(instance.Spec.AZEnvironment)
if err != nil {
return reconcile.Result{}, err
}
resource, err := azure.ParseResourceID(instance.Spec.ResourceID)
if err != nil {
return reconcile.Result{}, err
}
// create a refreshable authorizer from token
azRefreshAuthorizer, err := clusterauthorizer.NewAzRefreshableAuthorizer(r.log, &azEnv, r.client)
if err != nil {
return reconcile.Result{}, err
}
authorizer, err := azRefreshAuthorizer.NewRefreshableAuthorizerToken(ctx)
if err != nil {
return reconcile.Result{}, err
}
manager := reconcileManager{
log: r.log,
client: r.client,
instance: instance,
subscriptionID: resource.SubscriptionID,
kubeSubnets: subnet.NewKubeManager(r.client, resource.SubscriptionID),
subnets: subnet.NewManager(&azEnv, resource.SubscriptionID, authorizer),
}
return reconcile.Result{}, manager.reconcileSubnets(ctx)
}
func (r *reconcileManager) reconcileSubnets(ctx context.Context) error {
subnets, err := r.kubeSubnets.List(ctx)
if err != nil {
return err
}
var combinedErrors []string
// This potentially calls an update twice for the same loop, but this is the price
// to pay for keeping logic split, separate, and simple
for _, s := range subnets {
if r.instance.Spec.OperatorFlags.GetSimpleBoolean(operator.AzureSubnetsNsgManaged) {
err = r.ensureSubnetNSG(ctx, s)
if err != nil {
combinedErrors = append(combinedErrors, err.Error())
}
}
if r.instance.Spec.OperatorFlags.GetSimpleBoolean(controllerServiceEndpointManaged) {
err = r.ensureSubnetServiceEndpoints(ctx, s)
if err != nil {
combinedErrors = append(combinedErrors, err.Error())
}
}
}
if len(combinedErrors) > 0 {
return fmt.Errorf("%s", strings.Join(combinedErrors, "\n"))
}
return nil
}
// SetupWithManager creates the controller
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&arov1alpha1.Cluster{}, builder.WithPredicates(predicate.And(predicates.AROCluster, predicate.GenerationChangedPredicate{}))).
Watches(&source.Kind{Type: &machinev1beta1.Machine{}}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(predicates.MachineRoleMaster)). // to reconcile on master machine replacement
Watches(&source.Kind{Type: &machinev1beta1.MachineSet{}}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(predicates.MachineRoleWorker)). // to reconcile on worker machines
Named(ControllerName).
Complete(r)
}