Skip to content

Commit

Permalink
imageconfig controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Karan.Magdani authored and m1kola committed Feb 2, 2022
1 parent 9155a92 commit 3bab885
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ questions or comments.
`openshift-azure-logging` namespace matches the pre-defined specification
found in `pkg/operator/controllers/genevalogging/genevalogging.go`.

* imageconfig: Ensures that required registries are not blocked in `image.config`

* machine: validate machine objects have the correct provider spec,
vm type, vm image, disk size, three master nodes exist, and the number of worker nodes
match the desired worker replicas
Expand Down
6 changes: 6 additions & 0 deletions cmd/aro/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/Azure/ARO-RP/pkg/operator/controllers/clusteroperatoraro"
"github.com/Azure/ARO-RP/pkg/operator/controllers/dnsmasq"
"github.com/Azure/ARO-RP/pkg/operator/controllers/genevalogging"
"github.com/Azure/ARO-RP/pkg/operator/controllers/imageconfig"
"github.com/Azure/ARO-RP/pkg/operator/controllers/machine"
"github.com/Azure/ARO-RP/pkg/operator/controllers/machineset"
"github.com/Azure/ARO-RP/pkg/operator/controllers/monitoring"
Expand Down Expand Up @@ -186,6 +187,11 @@ func operator(ctx context.Context, log *logrus.Entry) error {
arocli, maocli)).SetupWithManager(mgr); err != nil {
return fmt.Errorf("unable to create controller MachineSet: %v", err)
}
if err = (imageconfig.NewReconciler(
log.WithField("controller", controllers.ImageConfigControllerName),
arocli, configcli)).SetupWithManager(mgr); err != nil {
return fmt.Errorf("unable to create controller ImageConfig: %v", err)
}
}

if err = (checker.NewReconciler(
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ var DefaultOperatorFlags OperatorFlags = OperatorFlags{

"aro.genevalogging.enabled": FLAG_TRUE,

"aro.imageconfig.enabled": FLAG_TRUE,

"aro.machine.enabled": FLAG_TRUE,

"aro.machineset.enabled": FLAG_TRUE,
Expand Down
1 change: 1 addition & 0 deletions pkg/operator/controllers/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ const (
NodeControllerName = "Node"
MachineControllerName = "Machine"
MachineSetControllerName = "MachineSet"
ImageConfigControllerName = "ImageConfig"
)
149 changes: 149 additions & 0 deletions pkg/operator/controllers/imageconfig/image_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package imageconfig

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.

import (
"context"
"errors"
"strings"

"github.com/Azure/go-autorest/autorest/azure"
configv1 "github.com/openshift/api/config/v1"
configclient "github.com/openshift/client-go/config/clientset/versioned"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
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/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned"
"github.com/Azure/ARO-RP/pkg/operator/controllers"
"github.com/Azure/ARO-RP/pkg/util/azureclient"
)

const imageConfigResource = "cluster"

const (
CONFIG_NAMESPACE string = "aro.imageconfig"
ENABLED string = CONFIG_NAMESPACE + ".enabled"
)

type Reconciler struct {
log *logrus.Entry
arocli aroclient.Interface
configcli configclient.Interface
}

func NewReconciler(log *logrus.Entry, arocli aroclient.Interface, configcli configclient.Interface) *Reconciler {
return &Reconciler{
log: log,
arocli: arocli,
configcli: configcli,
}
}

// watches the ARO object for changes and reconciles image.config.openshift.io/cluster object.
// - If blockedRegistries is not nil, makes sure required registries are not added
// - If AllowedRegistries is not nil, makes sure required registries are added
// - Fails fast if both are not nil, unsupported
func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
// Get cluster
instance, err := r.arocli.AroV1alpha1().Clusters().Get(ctx, request.Name, metav1.GetOptions{})
if err != nil {
return reconcile.Result{}, err
}

if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
// controller is disabled
return reconcile.Result{}, nil
}

// Check for cloud type
requiredRegistries, err := getCloudAwareRegistries(instance)
if err != nil {
// Not returning error as it will requeue again
return reconcile.Result{}, nil
}

// Get image.config yaml
imageconfig, err := r.configcli.ConfigV1().Images().Get(ctx, request.Name, metav1.GetOptions{})
if err != nil {
return reconcile.Result{}, err
}

// Fail fast if both are not nil
if imageconfig.Spec.RegistrySources.AllowedRegistries != nil && imageconfig.Spec.RegistrySources.BlockedRegistries != nil {
err := errors.New("both AllowedRegistries and BlockedRegistries are present")
return reconcile.Result{}, err
}

removeDuplicateRegistries := func(item string) bool {
for _, v := range requiredRegistries {
if strings.EqualFold(item, v) {
return false
}
}
return true
}

// Append to allowed registries
if imageconfig.Spec.RegistrySources.AllowedRegistries != nil {

imageconfig.Spec.RegistrySources.AllowedRegistries = filterSliceInPlace(imageconfig.Spec.RegistrySources.AllowedRegistries, removeDuplicateRegistries)
imageconfig.Spec.RegistrySources.AllowedRegistries = append(imageconfig.Spec.RegistrySources.AllowedRegistries, requiredRegistries...)
}

// Remove from blocked registries
if imageconfig.Spec.RegistrySources.BlockedRegistries != nil {
imageconfig.Spec.RegistrySources.BlockedRegistries = filterSliceInPlace(imageconfig.Spec.RegistrySources.BlockedRegistries, removeDuplicateRegistries)
}

// Update image config registry
_, err = r.configcli.ConfigV1().Images().Update(ctx, imageconfig, metav1.UpdateOptions{})
return reconcile.Result{}, err
}

// SetupWithManager setup the manager
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
imagePredicate := predicate.NewPredicateFuncs(func(o client.Object) bool {
return o.GetName() == imageConfigResource
})

return ctrl.NewControllerManagedBy(mgr).
For(&configv1.Image{}, builder.WithPredicates(imagePredicate)).
Named(controllers.ImageConfigControllerName).
Complete(r)
}

// Switch case to ensure the correct registries are added depending on the cloud environment (Gov or Public cloud)
func getCloudAwareRegistries(instance *arov1alpha1.Cluster) ([]string, error) {
var requiredRegistries []string
switch instance.Spec.AZEnvironment {
case azureclient.PublicCloud.Environment.Name:
requiredRegistries = []string{instance.Spec.ACRDomain, "arosvc." + instance.Spec.Location + ".data." + azure.PublicCloud.ContainerRegistryDNSSuffix}

case azureclient.USGovernmentCloud.Environment.Name:
requiredRegistries = []string{instance.Spec.ACRDomain, "arosvc." + instance.Spec.Location + ".data." + azure.USGovernmentCloud.ContainerRegistryDNSSuffix}

default:
err := errors.New("cloud environment %s is not supported" + instance.Spec.AZEnvironment)
return nil, err
}
return requiredRegistries, nil
}

// Helper function that filters registries to make sure they are added in consistent order
func filterSliceInPlace(input []string, keep func(string) bool) []string {
n := 0
for _, x := range input {
if keep(x) {
input[n] = x
n++
}
}
return input[:n]
}
Loading

0 comments on commit 3bab885

Please sign in to comment.