Repository: Azure/ARO-RP
Pull request #1925 (2022-01-31 17:16:11)

Minor ARO operator refactoring
### What this PR does / why we need it:

Minor ARO operator refactoring

* Gets rid of exported constants like `ENABLED` where exported constants are not required
* Gets rid of constant concatenations like `CONFIG_NAMESPACE + ".enabled"` to make search easier
* Removes unnecessary `Copy` method of `OperatorFlags` stuct as well as package level `DefaultOperatorFlags` variable. Introduces `DefaultOperatorFlags()` instead.

### Test plan for issue:

Should be covered by existing tests.

### Is there any documentation that needs to be updated for this PR?

No, just refactoring.


github-actions[bot]: Please rebase pull request.
github-actions[bot]: Please rebase pull request.
github-actions[bot]: Please rebase pull request.

Patch:
diff --git a/cmd/aro/operator.go b/cmd/aro/operator.go
index daa960dc5..386916359 100644
--- a/cmd/aro/operator.go
+++ b/cmd/aro/operator.go
@@ -22,7 +22,6 @@ import (
 	"github.com/Azure/ARO-RP/pkg/env"
 	pkgoperator "github.com/Azure/ARO-RP/pkg/operator"
 	aroclient "github.com/Azure/ARO-RP/pkg/operator/clientset/versioned"
-	"github.com/Azure/ARO-RP/pkg/operator/controllers"
 	"github.com/Azure/ARO-RP/pkg/operator/controllers/alertwebhook"
 	"github.com/Azure/ARO-RP/pkg/operator/controllers/banner"
 	"github.com/Azure/ARO-RP/pkg/operator/controllers/checker"
@@ -115,109 +114,108 @@ func operator(ctx context.Context, log *logrus.Entry) error {
 
 	if role == pkgoperator.RoleMaster {
 		if err = (genevalogging.NewReconciler(
-			log.WithField("controller", controllers.GenevaLoggingControllerName),
+			log.WithField("controller", genevalogging.ControllerName),
 			arocli, kubernetescli, securitycli,
 			restConfig)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Genevalogging: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", genevalogging.ControllerName, err)
 		}
 		if err = (clusteroperatoraro.NewReconciler(
-			log.WithField("controller", controllers.ClusterOperatorAROName),
+			log.WithField("controller", clusteroperatoraro.ControllerName),
 			arocli, configcli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller ClusterOperatorARO: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", clusteroperatoraro.ControllerName, err)
 		}
 		if err = (pullsecret.NewReconciler(
-			log.WithField("controller", controllers.PullSecretControllerName),
+			log.WithField("controller", pullsecret.ControllerName),
 			arocli, kubernetescli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller PullSecret: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", pullsecret.ControllerName, err)
 		}
 		if err = (alertwebhook.NewReconciler(
-			log.WithField("controller", controllers.AlertwebhookControllerName),
+			log.WithField("controller", alertwebhook.ControllerName),
 			arocli, kubernetescli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller AlertWebhook: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", alertwebhook.ControllerName, err)
 		}
 		if err = (workaround.NewReconciler(
-			log.WithField("controller", controllers.WorkaroundControllerName),
+			log.WithField("controller", workaround.ControllerName),
 			arocli, configcli, kubernetescli, mcocli, restConfig)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Workaround: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", workaround.ControllerName, err)
 		}
 		if err = (routefix.NewReconciler(
-			log.WithField("controller", controllers.RouteFixControllerName),
+			log.WithField("controller", routefix.ControllerName),
 			arocli, configcli, kubernetescli, securitycli, restConfig)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller RouteFix: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", routefix.ControllerName, err)
 		}
 		if err = (monitoring.NewReconciler(
-			log.WithField("controller", controllers.MonitoringControllerName),
+			log.WithField("controller", monitoring.ControllerName),
 			arocli, kubernetescli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Monitoring: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", monitoring.ControllerName, err)
 		}
 		if err = (rbac.NewReconciler(
-			log.WithField("controller", controllers.RBACControllerName),
+			log.WithField("controller", rbac.ControllerName),
 			arocli, dh)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller RBAC: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", rbac.ControllerName, err)
 		}
 		if err = (dnsmasq.NewClusterReconciler(
-			log.WithField("controller", controllers.DnsmasqClusterControllerName),
+			log.WithField("controller", dnsmasq.ClusterControllerName),
 			arocli, mcocli, dh)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller DnsmasqCluster: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", dnsmasq.ClusterControllerName, err)
 		}
 		if err = (dnsmasq.NewMachineConfigReconciler(
-			log.WithField("controller", controllers.DnsmasqMachineConfigControllerName),
+			log.WithField("controller", dnsmasq.MachineConfigControllerName),
 			arocli, mcocli, dh)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller DnsmasqMachineConfig: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", dnsmasq.MachineConfigControllerName, err)
 		}
 		if err = (dnsmasq.NewMachineConfigPoolReconciler(
-			log.WithField("controller", controllers.DnsmasqMachineConfigPoolControllerName),
+			log.WithField("controller", dnsmasq.MachineConfigPoolControllerName),
 			arocli, mcocli, dh)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller DnsmasqMachineConfigPool: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", dnsmasq.MachineConfigPoolControllerName, err)
 		}
 		if err = (node.NewReconciler(
-			log.WithField("controller", controllers.NodeControllerName),
+			log.WithField("controller", node.ControllerName),
 			arocli, kubernetescli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Node: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", node.ControllerName, err)
 		}
 		if err = (subnets.NewReconciler(
-			log.WithField("controller", controllers.AzureSubnetsControllerName),
+			log.WithField("controller", subnets.ControllerName),
 			arocli, kubernetescli, maocli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Subnets: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", subnets.ControllerName, err)
 		}
 		if err = (machine.NewReconciler(
-			log.WithField("controller", controllers.MachineControllerName),
+			log.WithField("controller", machine.ControllerName),
 			arocli, maocli, isLocalDevelopmentMode, role)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Machine: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", machine.ControllerName, err)
 		}
 		if err = (banner.NewReconciler(
-			log.WithField("controller", controllers.BannerControllerName),
+			log.WithField("controller", banner.ControllerName),
 			arocli, consolecli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller Banner: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", banner.ControllerName, err)
 		}
 		if err = (machineset.NewReconciler(
-			log.WithField("controller", controllers.MachineSetControllerName),
+			log.WithField("controller", machineset.ControllerName),
 			arocli, maocli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller MachineSet: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", machineset.ControllerName, err)
 		}
-		if err = (imageconfig.NewReconciler(
-			arocli, configcli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller ImageConfig: %v", err)
+		if err = (imageconfig.NewReconciler(arocli, configcli)).SetupWithManager(mgr); err != nil {
+			return fmt.Errorf("unable to create controller %s: %v", imageconfig.ControllerName, err)
 		}
 		if err = (previewfeature.NewReconciler(
-			log.WithField("controller", controllers.PreviewFeatureControllerName),
+			log.WithField("controller", previewfeature.ControllerName),
 			arocli, kubernetescli, maocli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller PreviewFeature: %v", err)
+			return fmt.Errorf("unable to create controller %s: %v", previewfeature.ControllerName, err)
 		}
 		if err = (storageaccounts.NewReconciler(
-			log.WithField("controller", controllers.StorageAccountsControllerName),
+			log.WithField("controller", storageaccounts.ControllerName),
 			arocli, maocli, kubernetescli, imageregistrycli)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller %s: %v", controllers.StorageAccountsControllerName, err)
+			return fmt.Errorf("unable to create controller %s: %v", storageaccounts.ControllerName, err)
 		}
 		if err = (muo.NewReconciler(arocli, kubernetescli, dh)).SetupWithManager(mgr); err != nil {
-			return fmt.Errorf("unable to create controller %s: %v", controllers.ManagedUpgradeOperatorControllerName, err)
+			return fmt.Errorf("unable to create controller %s: %v", muo.ControllerName, err)
 		}
 	}
 
 	if err = (checker.NewReconciler(
-		log.WithField("controller", controllers.CheckerControllerName),
+		log.WithField("controller", checker.ControllerName),
 		arocli, kubernetescli, maocli, role)).SetupWithManager(mgr); err != nil {
-		return fmt.Errorf("unable to create controller Checker: %v", err)
+		return fmt.Errorf("unable to create controller %s: %v", checker.ControllerName, err)
 	}
 
 	// +kubebuilder:scaffold:builder
diff --git a/pkg/api/admin/openshiftcluster.go b/pkg/api/admin/openshiftcluster.go
index ee093605f..bac3029a4 100644
--- a/pkg/api/admin/openshiftcluster.go
+++ b/pkg/api/admin/openshiftcluster.go
@@ -182,6 +182,16 @@ const (
 	VMSizeStandardM128ms VMSize = "Standard_M128ms"
 	VMSizeStandardG5     VMSize = "Standard_G5"
 	VMSizeStandardGS5    VMSize = "Standard_GS5"
+
+	VMSizeStandardL4s    VMSize = "Standard_L4s"
+	VMSizeStandardL8s    VMSize = "Standard_L8s"
+	VMSizeStandardL16s   VMSize = "Standard_L16s"
+	VMSizeStandardL32s   VMSize = "Standard_L32s"
+	VMSizeStandardL8sV2  VMSize = "Standard_L8s_v2"
+	VMSizeStandardL16sV2 VMSize = "Standard_L16s_v2"
+	VMSizeStandardL32sV2 VMSize = "Standard_L32s_v2"
+	VMSizeStandardL48sV2 VMSize = "Standard_L48s_v2"
+	VMSizeStandardL64sV2 VMSize = "Standard_L64s_v2"
 )
 
 // WorkerProfile represents a worker profile.
diff --git a/pkg/api/defaults.go b/pkg/api/defaults.go
index f26b143ee..1e6d88b69 100644
--- a/pkg/api/defaults.go
+++ b/pkg/api/defaults.go
@@ -38,42 +38,43 @@ func SetDefaults(doc *OpenShiftClusterDocument) {
 		}
 		// If there's no operator flags, set the default ones
 		if doc.OpenShiftCluster.Properties.OperatorFlags == nil {
-			doc.OpenShiftCluster.Properties.OperatorFlags = DefaultOperatorFlags.Copy()
+			doc.OpenShiftCluster.Properties.OperatorFlags = DefaultOperatorFlags()
 		}
 	}
 }
 
 // shorthand
-const FLAG_TRUE string = "true"
-const FLAG_FALSE string = "false"
+const flagTrue string = "true"
+const flagFalse string = "false"
 
-// Default flags for new clusters & ones that have not been AdminUpdated
-var DefaultOperatorFlags OperatorFlags = OperatorFlags{
-	"aro.alertwebhook.enabled":                 FLAG_TRUE,
-	"aro.azuresubnets.enabled":                 FLAG_TRUE,
-	"aro.azuresubnets.nsg.managed":             FLAG_TRUE,
-	"aro.azuresubnets.serviceendpoint.managed": FLAG_TRUE,
-	"aro.banner.enabled":                       FLAG_FALSE,
-	"aro.checker.enabled":                      FLAG_TRUE,
-	"aro.dnsmasq.enabled":                      FLAG_TRUE,
-	"aro.genevalogging.enabled":                FLAG_TRUE,
-	"aro.imageconfig.enabled":                  FLAG_TRUE,
-	"aro.machine.enabled":                      FLAG_TRUE,
-	"aro.machineset.enabled":                   FLAG_TRUE,
-	"aro.monitoring.enabled":                   FLAG_TRUE,
-	"aro.nodedrainer.enabled":                  FLAG_TRUE,
-	"aro.pullsecret.enabled":                   FLAG_TRUE,
-	"aro.pullsecret.managed":                   FLAG_TRUE,
-	"aro.rbac.enabled":                         FLAG_TRUE,
-	"aro.routefix.enabled":                     FLAG_TRUE,
-	"aro.storageaccounts.enabled":              FLAG_TRUE,
-	"aro.workaround.enabled":                   FLAG_TRUE,
-}
-
-func (d OperatorFlags) Copy() OperatorFlags {
-	newFlags := make(OperatorFlags)
-	for k, v := range d {
-		newFlags[k] = v
+// DefaultOperatorFlags returns flags for new clusters
+// and ones that have not been AdminUpdated.
+func DefaultOperatorFlags() OperatorFlags {
+	// TODO: Get rid of magic strings.
+	// We already have constants for all of the below strings.
+	// For example `controllerEnabled` in `github.com/Azure/ARO-RP/pkg/operator/controllers/machine`.
+	// But if we import packages with constants here we will have a cyclic import issue because controllers
+	// import this package. We should probably move this somewhere else.
+	// Maybe into a subpackage like `github.com/Azure/ARO-RP/pkg/api/defaults`?
+	return OperatorFlags{
+		"aro.alertwebhook.enabled":                 flagTrue,
+		"aro.azuresubnets.enabled":                 flagTrue,
+		"aro.azuresubnets.nsg.managed":             flagTrue,
+		"aro.azuresubnets.serviceendpoint.managed": flagTrue,
+		"aro.banner.enabled":                       flagFalse,
+		"aro.checker.enabled":                      flagTrue,
+		"aro.dnsmasq.enabled":                      flagTrue,
+		"aro.genevalogging.enabled":                flagTrue,
+		"aro.imageconfig.enabled":                  flagTrue,
+		"aro.machine.enabled":                      flagTrue,
+		"aro.machineset.enabled":                   flagTrue,
+		"aro.monitoring.enabled":                   flagTrue,
+		"aro.nodedrainer.enabled":                  flagTrue,
+		"aro.pullsecret.enabled":                   flagTrue,
+		"aro.pullsecret.managed":                   flagTrue,
+		"aro.rbac.enabled":                         flagTrue,
+		"aro.routefix.enabled":                     flagTrue,
+		"aro.storageaccounts.enabled":              flagTrue,
+		"aro.workaround.enabled":                   flagTrue,
 	}
-	return newFlags
 }
diff --git a/pkg/api/openshiftcluster.go b/pkg/api/openshiftcluster.go
index c843d952b..b6aa897b5 100644
--- a/pkg/api/openshiftcluster.go
+++ b/pkg/api/openshiftcluster.go
@@ -300,6 +300,16 @@ const (
 	VMSizeStandardM128ms VMSize = "Standard_M128ms"
 	VMSizeStandardG5     VMSize = "Standard_G5"
 	VMSizeStandardGS5    VMSize = "Standard_GS5"
+
+	VMSizeStandardL4s    VMSize = "Standard_L4s"
+	VMSizeStandardL8s    VMSize = "Standard_L8s"
+	VMSizeStandardL16s   VMSize = "Standard_L16s"
+	VMSizeStandardL32s   VMSize = "Standard_L32s"
+	VMSizeStandardL8sV2  VMSize = "Standard_L8s_v2"
+	VMSizeStandardL16sV2 VMSize = "Standard_L16s_v2"
+	VMSizeStandardL32sV2 VMSize = "Standard_L32s_v2"
+	VMSizeStandardL48sV2 VMSize = "Standard_L48s_v2"
+	VMSizeStandardL64sV2 VMSize = "Standard_L64s_v2"
 )
 
 // WorkerProfile represents a worker profile
diff --git a/pkg/api/validate/dynamic/dynamic.go b/pkg/api/validate/dynamic/dynamic.go
index af2029a86..8af3d815f 100644
--- a/pkg/api/validate/dynamic/dynamic.go
+++ b/pkg/api/validate/dynamic/dynamic.go
@@ -53,6 +53,7 @@ type Dynamic interface {
 	ValidateQuota(ctx context.Context, oc *api.OpenShiftCluster) error
 	ValidateDiskEncryptionSets(ctx context.Context, oc *api.OpenShiftCluster) error
 	ValidateEncryptionAtHost(ctx context.Context, oc *api.OpenShiftCluster) error
+	ValidateVMSku(ctx context.Context, location string, subscriptionID string, oc *api.OpenShiftCluster) error
 }
 
 type dynamic struct {
@@ -65,14 +66,17 @@ type dynamic struct {
 	providers          features.ProvidersClient
 	virtualNetworks    virtualNetworksGetClient
 	diskEncryptionSets compute.DiskEncryptionSetsClient
+	resourceSkusClient compute.ResourceSkusClient
 	spComputeUsage     compute.UsageClient
 	spNetworkUsage     network.UsageClient
 }
 
 type AuthorizerType string
 
-const AuthorizerFirstParty AuthorizerType = "resource provider"
-const AuthorizerClusterServicePrincipal AuthorizerType = "cluster"
+const (
+	AuthorizerFirstParty              AuthorizerType = "resource provider"
+	AuthorizerClusterServicePrincipal AuthorizerType = "cluster"
+)
 
 func NewValidator(log *logrus.Entry, env env.Interface, azEnv *azureclient.AROEnvironment, subscriptionID string, authorizer refreshable.Authorizer, authorizerType AuthorizerType) (Dynamic, error) {
 	return &dynamic{
@@ -87,6 +91,7 @@ func NewValidator(log *logrus.Entry, env env.Interface, azEnv *azureclient.AROEn
 		permissions:        authorization.NewPermissionsClient(azEnv, subscriptionID, authorizer),
 		virtualNetworks:    newVirtualNetworksCache(network.NewVirtualNetworksClient(azEnv, subscriptionID, authorizer)),
 		diskEncryptionSets: compute.NewDiskEncryptionSetsClient(azEnv, subscriptionID, authorizer),
+		resourceSkusClient: compute.NewResourceSkusClient(azEnv, subscriptionID, authorizer),
 	}, nil
 }
 
diff --git a/pkg/api/validate/dynamic/quota.go b/pkg/api/validate/dynamic/quota.go
index 4c1181b42..c6305ab05 100644
--- a/pkg/api/validate/dynamic/quota.go
+++ b/pkg/api/validate/dynamic/quota.go
@@ -88,6 +88,33 @@ func addRequiredResources(requiredResources map[string]int, vmSize api.VMSize, c
 	case api.VMSizeStandardGS5:
 		requiredResources["standardGSFamily"] += (count * 32)
 		requiredResources["cores"] += (count * 32)
+	case api.VMSizeStandardL4s:
+		requiredResources["standardLsFamily"] += (count * 4)
+		requiredResources["cores"] += (count * 4)
+	case api.VMSizeStandardL8s:
+		requiredResources["standardLsFamily"] += (count * 8)
+		requiredResources["cores"] += (count * 8)
+	case api.VMSizeStandardL16s:
+		requiredResources["standardLsFamily"] += (count * 16)
+		requiredResources["cores"] += (count * 16)
+	case api.VMSizeStandardL32s:
+		requiredResources["standardLsFamily"] += (count * 32)
+		requiredResources["cores"] += (count * 32)
+	case api.VMSizeStandardL8sV2:
+		requiredResources["standardLsv2Family"] += (count * 8)
+		requiredResources["cores"] += (count * 8)
+	case api.VMSizeStandardL16sV2:
+		requiredResources["standardLsv2Family"] += (count * 16)
+		requiredResources["cores"] += (count * 16)
+	case api.VMSizeStandardL32sV2:
+		requiredResources["standardLsv2Family"] += (count * 32)
+		requiredResources["cores"] += (count * 32)
+	case api.VMSizeStandardL48sV2:
+		requiredResources["standardLsv2Family"] += (count * 48)
+		requiredResources["cores"] += (count * 48)
+	case api.VMSizeStandardL64sV2:
+		requiredResources["standardLsv2Family"] += (count * 64)
+		requiredResources["cores"] += (count * 64)
 	default:
 		//will only happen if pkg/api verification allows new VMSizes
 		return fmt.Errorf("unexpected node VMSize %s", vmSize)
diff --git a/pkg/api/validate/dynamic/sku.go b/pkg/api/validate/dynamic/sku.go
new file mode 100644
index 000000000..ae4885c83
--- /dev/null
+++ b/pkg/api/validate/dynamic/sku.go
@@ -0,0 +1,63 @@
+package dynamic
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the Apache License 2.0.
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
+
+	"github.com/Azure/ARO-RP/pkg/api"
+	"github.com/Azure/ARO-RP/pkg/util/computeskus"
+)
+
+// ValidateWorkerSku uses resourceSkusClient to ensure that the VM sizes listed in the cluster document are available for use in the target region.
+func (dv *dynamic) ValidateVMSku(ctx context.Context, location string, subscriptionID string, oc *api.OpenShiftCluster) error {
+	// Get a list of available worker SKUs, filtering by location. We initialize a new resourceSkusClient here instead of using the one in dv.env,
+	// so that we can determine SKU availability within target cluster subscription instead of within RP subscription.
+	filter := fmt.Sprintf("location eq %s", location)
+	skus, err := dv.resourceSkusClient.List(ctx, filter)
+	if err != nil {
+		return err
+	}
+
+	filteredSkus := computeskus.FilterVMSizes(skus, location)
+	masterProfileSku := string(oc.Properties.MasterProfile.VMSize)
+
+	err = checkSKUAvailability(filteredSkus, location, "properties.masterProfile.VMSize", masterProfileSku)
+	if err != nil {
+		return err
+	}
+
+	// In case there are multiple WorkerProfiles listed in the cluster document (such as post-install),
+	// compare VMSize in each WorkerProfile to the resourceSkusClient call above to ensure that the sku is available in region.
+	for i, workerprofile := range oc.Properties.WorkerProfiles {
+		workerProfileSku := string(workerprofile.VMSize)
+
+		err = checkSKUAvailability(filteredSkus, location, fmt.Sprintf("properties.workerProfiles[%d].VMSize", i), workerProfileSku)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func checkSKUAvailability(skus map[string]*mgmtcompute.ResourceSku, location, path, vmsize string) error {
+	// Ensure desired sku exists in target region
+	if skus[vmsize] == nil {
+		return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, path, "The selected SKU '%v' is unavailable in region '%v'", vmsize, location)
+	}
+
+	// Fail if sku is available, but restricted within the subscription. Restrictions are subscription-specific.
+	// https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/error-sku-not-available
+	isRestricted := computeskus.IsRestricted(skus, location, vmsize)
+	if isRestricted {
+		return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, path, "The selected SKU '%v' is restricted in region '%v' for selected subscription", vmsize, location)
+	}
+
+	return nil
+}
diff --git a/pkg/api/validate/openshiftcluster_validatedynamic.go b/pkg/api/validate/openshiftcluster_validatedynamic.go
index 0f7cabc01..4ecab714e 100644
--- a/pkg/api/validate/openshiftcluster_validatedynamic.go
+++ b/pkg/api/validate/openshiftcluster_validatedynamic.go
@@ -121,5 +121,10 @@ func (dv *openShiftClusterDynamicValidator) Dynamic(ctx context.Context) error {
 		return err
 	}
 
+	err = spDynamic.ValidateVMSku(ctx, dv.oc.Location, dv.subscriptionDoc.ID, dv.oc)
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
diff --git a/pkg/api/validate/vm.go b/pkg/api/validate/vm.go
index e8d8c53b5..79f8b19b5 100644
--- a/pkg/api/validate/vm.go
+++ b/pkg/api/validate/vm.go
@@ -54,7 +54,16 @@ func VMSizeIsValid(vmSize api.VMSize, requiredD2sV3Workers, isMaster bool) bool
 				api.VMSizeStandardF72sV2,
 				api.VMSizeStandardG5,
 				api.VMSizeStandardGS5,
-				api.VMSizeStandardM128ms:
+				api.VMSizeStandardM128ms,
+				api.VMSizeStandardL4s,
+				api.VMSizeStandardL8s,
+				api.VMSizeStandardL16s,
+				api.VMSizeStandardL32s,
+				api.VMSizeStandardL8sV2,
+				api.VMSizeStandardL16sV2,
+				api.VMSizeStandardL32sV2,
+				api.VMSizeStandardL48sV2,
+				api.VMSizeStandardL64sV2:
 				return true
 			}
 		}
diff --git a/pkg/env/prod.go b/pkg/env/prod.go
index e2d231cb5..e30d54eb6 100644
--- a/pkg/env/prod.go
+++ b/pkg/env/prod.go
@@ -22,6 +22,7 @@ import (
 	"github.com/Azure/ARO-RP/pkg/proxy"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/compute"
 	"github.com/Azure/ARO-RP/pkg/util/clientauthorizer"
+	"github.com/Azure/ARO-RP/pkg/util/computeskus"
 	"github.com/Azure/ARO-RP/pkg/util/keyvault"
 	"github.com/Azure/ARO-RP/pkg/util/refreshable"
 	"github.com/Azure/ARO-RP/pkg/util/version"
@@ -274,29 +275,7 @@ func (p *prod) populateVMSkus(ctx context.Context, resourceSkusClient compute.Re
 		return err
 	}
 
-	p.vmskus = map[string]*mgmtcompute.ResourceSku{}
-	for _, sku := range skus {
-		// TODO(mjudeikis): At some point some SKU's stopped returning zones and
-		// locations. IcM is open with MSFT but this might take a while.
-		// Revert once we find out right behaviour.
-		// https://github.com/Azure/ARO-RP/issues/1515
-		if len(*sku.Locations) == 0 || !strings.EqualFold((*sku.Locations)[0], p.Location()) ||
-			*sku.ResourceType != "virtualMachines" {
-			continue
-		}
-
-		if len(*sku.LocationInfo) == 0 { // happened in eastus2euap
-			continue
-		}
-
-		// We copy only part of the object so we don't have to keep
-		// a lot of data in memory.
-		p.vmskus[*sku.Name] = &mgmtcompute.ResourceSku{
-			Name:         sku.Name,
-			LocationInfo: sku.LocationInfo,
-			Capabilities: sku.Capabilities,
-		}
-	}
+	p.vmskus = computeskus.FilterVMSizes(skus, p.Location())
 
 	return nil
 }
diff --git a/pkg/operator/controllers/alertwebhook/alertwebhook_controller.go b/pkg/operator/controllers/alertwebhook/alertwebhook_controller.go
index 2eb606970..fd96f188a 100644
--- a/pkg/operator/controllers/alertwebhook/alertwebhook_controller.go
+++ b/pkg/operator/controllers/alertwebhook/alertwebhook_controller.go
@@ -21,12 +21,12 @@ import (
 
 	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"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.alertwebhook"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Alertwebhook"
+
+	controllerEnabled = "aro.alertwebhook.enabled"
 )
 
 var alertManagerName = types.NamespacedName{Name: "alertmanager-main", Namespace: "openshift-monitoring"}
@@ -54,7 +54,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -125,6 +125,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&corev1.Secret{}, builder.WithPredicates(isAlertManagerPredicate)).
-		Named(controllers.AlertwebhookControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/banner/banner_controller.go b/pkg/operator/controllers/banner/banner_controller.go
index 291029b64..3e3477a2b 100644
--- a/pkg/operator/controllers/banner/banner_controller.go
+++ b/pkg/operator/controllers/banner/banner_controller.go
@@ -20,12 +20,12 @@ import (
 
 	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"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.banner"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Banner"
+
+	controllerEnabled = "aro.banner.enabled"
 )
 
 // BannerReconciler is the controller struct
@@ -52,7 +52,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -74,6 +74,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
 		// watching ConsoleNotifications in case a user edits it
 		Watches(&source.Kind{Type: &consolev1.ConsoleNotification{}}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(aroBannerPredicate)).
-		Named(controllers.BannerControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/checker/checker_controller.go b/pkg/operator/controllers/checker/checker_controller.go
index 579cad709..c41ee4771 100644
--- a/pkg/operator/controllers/checker/checker_controller.go
+++ b/pkg/operator/controllers/checker/checker_controller.go
@@ -20,12 +20,12 @@ import (
 	"github.com/Azure/ARO-RP/pkg/operator"
 	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"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.checker"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Checker"
+
+	controllerEnabled = "aro.checker.enabled"
 )
 
 // Reconciler runs a number of checkers
@@ -67,7 +67,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -99,5 +99,5 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	builder := ctrl.NewControllerManagedBy(mgr).
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate))
 
-	return builder.Named(controllers.CheckerControllerName).Complete(r)
+	return builder.Named(ControllerName).Complete(r)
 }
diff --git a/pkg/operator/controllers/clusteroperatoraro/clusteroperatoraro_controller.go b/pkg/operator/controllers/clusteroperatoraro/clusteroperatoraro_controller.go
index ce2e4ffac..3c822dfc2 100644
--- a/pkg/operator/controllers/clusteroperatoraro/clusteroperatoraro_controller.go
+++ b/pkg/operator/controllers/clusteroperatoraro/clusteroperatoraro_controller.go
@@ -23,10 +23,12 @@ import (
 
 	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"
 )
 
 const (
+	ControllerName = "ClusterOperatorARO"
+
+	// Operator object name
 	clusterOperatorName = "aro"
 )
 
@@ -61,7 +63,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
 		Owns(&configv1.ClusterOperator{}).
-		Named(controllers.ClusterOperatorAROName).
+		Named(ControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/const.go b/pkg/operator/controllers/const.go
deleted file mode 100644
index f0fea5f91..000000000
--- a/pkg/operator/controllers/const.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package controllers
-
-// Copyright (c) Microsoft Corporation.
-// Licensed under the Apache License 2.0.
-
-const (
-	AlertwebhookControllerName             = "Alertwebhook"
-	AzureSubnetsControllerName             = "AzureSubnets"
-	BannerControllerName                   = "Banner"
-	PreviewFeatureControllerName           = "PreviewFeature"
-	ClusterOperatorAROName                 = "ClusterOperatorARO"
-	GenevaLoggingControllerName            = "GenevaLogging"
-	PullSecretControllerName               = "PullSecret"
-	WorkaroundControllerName               = "Workaround"
-	CheckerControllerName                  = "Checker"
-	RouteFixControllerName                 = "RouteFix"
-	MonitoringControllerName               = "Monitoring"
-	RBACControllerName                     = "RBAC"
-	DnsmasqClusterControllerName           = "DnsmasqCluster"
-	DnsmasqMachineConfigControllerName     = "DnsmasqMachineConfig"
-	DnsmasqMachineConfigPoolControllerName = "DnsmasqMachineConfigPool"
-	NodeControllerName                     = "Node"
-	MachineControllerName                  = "Machine"
-	MachineSetControllerName               = "MachineSet"
-	ImageConfigControllerName              = "ImageConfig"
-	StorageAccountsControllerName          = "StorageAccounts"
-	ManagedUpgradeOperatorControllerName   = "ManagedUpgradeOperator"
-)
diff --git a/pkg/operator/controllers/dnsmasq/cluster_controller.go b/pkg/operator/controllers/dnsmasq/cluster_controller.go
index ffb3a5747..d5fd4efdc 100644
--- a/pkg/operator/controllers/dnsmasq/cluster_controller.go
+++ b/pkg/operator/controllers/dnsmasq/cluster_controller.go
@@ -19,13 +19,13 @@ import (
 
 	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/dynamichelper"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.dnsmasq"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ClusterControllerName = "DnsmasqCluster"
+
+	controllerEnabled = "aro.dnsmasq.enabled"
 )
 
 type ClusterReconciler struct {
@@ -53,7 +53,7 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, request ctrl.Request)
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -86,7 +86,7 @@ func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
-		Named(controllers.DnsmasqClusterControllerName).
+		Named(ClusterControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/dnsmasq/machineconfig_controller.go b/pkg/operator/controllers/dnsmasq/machineconfig_controller.go
index d1c7926e0..077cf46c1 100644
--- a/pkg/operator/controllers/dnsmasq/machineconfig_controller.go
+++ b/pkg/operator/controllers/dnsmasq/machineconfig_controller.go
@@ -17,10 +17,13 @@ import (
 
 	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/dynamichelper"
 )
 
+const (
+	MachineConfigControllerName = "DnsmasqMachineConfig"
+)
+
 type MachineConfigReconciler struct {
 	log *logrus.Entry
 
@@ -48,7 +51,7 @@ func (r *MachineConfigReconciler) Reconcile(ctx context.Context, request ctrl.Re
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -81,6 +84,6 @@ func (r *MachineConfigReconciler) Reconcile(ctx context.Context, request ctrl.Re
 func (r *MachineConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&mcv1.MachineConfig{}).
-		Named(controllers.DnsmasqMachineConfigControllerName).
+		Named(MachineConfigControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/dnsmasq/machineconfigpool_controller.go b/pkg/operator/controllers/dnsmasq/machineconfigpool_controller.go
index 71e0e6406..7c8ba7cf1 100644
--- a/pkg/operator/controllers/dnsmasq/machineconfigpool_controller.go
+++ b/pkg/operator/controllers/dnsmasq/machineconfigpool_controller.go
@@ -16,10 +16,13 @@ import (
 
 	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/dynamichelper"
 )
 
+const (
+	MachineConfigPoolControllerName = "DnsmasqMachineConfigPool"
+)
+
 type MachineConfigPoolReconciler struct {
 	log *logrus.Entry
 
@@ -45,7 +48,7 @@ func (r *MachineConfigPoolReconciler) Reconcile(ctx context.Context, request ctr
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -72,6 +75,6 @@ func (r *MachineConfigPoolReconciler) Reconcile(ctx context.Context, request ctr
 func (r *MachineConfigPoolReconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&mcv1.MachineConfigPool{}).
-		Named(controllers.DnsmasqMachineConfigPoolControllerName).
+		Named(MachineConfigPoolControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/genevalogging/genevalogging.go b/pkg/operator/controllers/genevalogging/genevalogging.go
index 9932870a0..937e32b57 100644
--- a/pkg/operator/controllers/genevalogging/genevalogging.go
+++ b/pkg/operator/controllers/genevalogging/genevalogging.go
@@ -41,8 +41,8 @@ func (r *Reconciler) daemonset(cluster *arov1alpha1.Cluster) (*appsv1.DaemonSet,
 		return nil, err
 	}
 
-	fluentbitPullspec := cluster.Spec.OperatorFlags.GetWithDefault(FLUENTBIT_PULLSPEC, version.FluentbitImage(cluster.Spec.ACRDomain))
-	mdsdPullspec := cluster.Spec.OperatorFlags.GetWithDefault(MDSD_PULLSPEC, version.MdsdImage(cluster.Spec.ACRDomain))
+	fluentbitPullspec := cluster.Spec.OperatorFlags.GetWithDefault(controllerFluentbitPullSpec, version.FluentbitImage(cluster.Spec.ACRDomain))
+	mdsdPullspec := cluster.Spec.OperatorFlags.GetWithDefault(controllerMDSDPullSpec, version.MdsdImage(cluster.Spec.ACRDomain))
 
 	return &appsv1.DaemonSet{
 		ObjectMeta: metav1.ObjectMeta{
diff --git a/pkg/operator/controllers/genevalogging/genevalogging_controller.go b/pkg/operator/controllers/genevalogging/genevalogging_controller.go
index 6d99ecfb3..16833800c 100644
--- a/pkg/operator/controllers/genevalogging/genevalogging_controller.go
+++ b/pkg/operator/controllers/genevalogging/genevalogging_controller.go
@@ -23,17 +23,17 @@ import (
 	"github.com/Azure/ARO-RP/pkg/operator"
 	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/dynamichelper"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.genevalogging"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "GenevaLogging"
+
+	controllerEnabled = "aro.genevalogging.enabled"
 	// full pullspec of fluentbit image
-	FLUENTBIT_PULLSPEC string = CONFIG_NAMESPACE + ".fluentbit.pullSpec"
+	controllerFluentbitPullSpec = "aro.genevalogging.fluentbit.pullSpec"
 	// full pullspec of mdsd image
-	MDSD_PULLSPEC string = CONFIG_NAMESPACE + ".mdsd.pullSpec"
+	controllerMDSDPullSpec = "aro.genevalogging.mdsd.pullSpec"
 )
 
 // Reconciler reconciles a Cluster object
@@ -64,7 +64,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -124,6 +124,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		Owns(&corev1.Secret{}).
 		Owns(&corev1.ServiceAccount{}).
 		Owns(&securityv1.SecurityContextConstraints{}).
-		Named(controllers.GenevaLoggingControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/imageconfig/image_controller.go b/pkg/operator/controllers/imageconfig/image_controller.go
index efe899583..06c4c2e5f 100644
--- a/pkg/operator/controllers/imageconfig/image_controller.go
+++ b/pkg/operator/controllers/imageconfig/image_controller.go
@@ -21,15 +21,16 @@ import (
 
 	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"
+	ControllerName = "ImageConfig"
+
+	controllerEnabled = "aro.imageconfig.enabled"
+
+	// Kubernetes object name
+	imageConfigResource = "cluster"
 )
 
 type Reconciler struct {
@@ -55,7 +56,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -90,7 +91,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 
 	// 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...)
 	}
@@ -113,7 +113,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&configv1.Image{}, builder.WithPredicates(imagePredicate)).
-		Named(controllers.ImageConfigControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/machine/machine_controller.go b/pkg/operator/controllers/machine/machine_controller.go
index f40abaa1b..95e1e1a88 100644
--- a/pkg/operator/controllers/machine/machine_controller.go
+++ b/pkg/operator/controllers/machine/machine_controller.go
@@ -17,14 +17,14 @@ import (
 
 	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/conditions"
 	_ "github.com/Azure/ARO-RP/pkg/util/scheme"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.machine"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Machine"
+
+	controllerEnabled = "aro.machine.enabled"
 )
 
 type Reconciler struct {
@@ -53,7 +53,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -85,6 +85,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&machinev1beta1.Machine{}).
-		Named(controllers.MachineControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/machineset/machineset_controller.go b/pkg/operator/controllers/machineset/machineset_controller.go
index 5c886b9c6..e724dd6ca 100644
--- a/pkg/operator/controllers/machineset/machineset_controller.go
+++ b/pkg/operator/controllers/machineset/machineset_controller.go
@@ -21,12 +21,12 @@ import (
 
 	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"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.machineset"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "MachineSet"
+
+	ControllerEnabled = "aro.machineset.enabled"
 )
 
 type Reconciler struct {
@@ -51,7 +51,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ControllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -102,6 +102,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&machinev1beta1.MachineSet{}, builder.WithPredicates(machineSetPredicate)).
-		Named(controllers.MachineSetControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/monitoring/monitoring_controller.go b/pkg/operator/controllers/monitoring/monitoring_controller.go
index 816a1f8f6..02717af51 100644
--- a/pkg/operator/controllers/monitoring/monitoring_controller.go
+++ b/pkg/operator/controllers/monitoring/monitoring_controller.go
@@ -26,12 +26,12 @@ import (
 	"github.com/Azure/ARO-RP/pkg/api"
 	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"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.monitoring"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Monitoring"
+
+	controllerEnabled = "aro.monitoring.enabled"
 )
 
 var (
@@ -79,7 +79,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -214,6 +214,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 			&handler.EnqueueRequestForObject{},
 			builder.WithPredicates(monitoringConfigMapPredicate),
 		).
-		Named(controllers.MonitoringControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/muo/deploy.go b/pkg/operator/controllers/muo/deploy.go
index 3a93e47ad..e4fb08ffb 100644
--- a/pkg/operator/controllers/muo/deploy.go
+++ b/pkg/operator/controllers/muo/deploy.go
@@ -64,7 +64,7 @@ func (o *deployer) Resources(pullspec string) ([]kruntime.Object, error) {
 }
 
 func (o *deployer) CreateOrUpdate(ctx context.Context, cluster *arov1alpha1.Cluster) error {
-	imagePullspec, ext := cluster.Spec.OperatorFlags[pullSpec]
+	imagePullspec, ext := cluster.Spec.OperatorFlags[controllerPullSpec]
 	if !ext {
 		return errors.New("missing pullspec")
 	}
diff --git a/pkg/operator/controllers/muo/muo_controller.go b/pkg/operator/controllers/muo/muo_controller.go
index 5ed19c396..0f8ca2531 100644
--- a/pkg/operator/controllers/muo/muo_controller.go
+++ b/pkg/operator/controllers/muo/muo_controller.go
@@ -20,14 +20,15 @@ import (
 
 	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/dynamichelper"
 )
 
 const (
-	enabled  string = "rh.srep.muo.enabled"
-	managed  string = "rh.srep.muo.managed"
-	pullSpec string = "rh.srep.muo.deploy.pullspec"
+	ControllerName = "ManagedUpgradeOperator"
+
+	controllerEnabled  = "rh.srep.muo.enabled"
+	controllerManaged  = "rh.srep.muo.managed"
+	controllerPullSpec = "rh.srep.muo.deploy.pullspec"
 )
 
 type Reconciler struct {
@@ -54,12 +55,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(enabled) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
 
-	managed := instance.Spec.OperatorFlags.GetWithDefault(managed, "")
+	managed := instance.Spec.OperatorFlags.GetWithDefault(controllerManaged, "")
 
 	// If enabled and managed=true, install MUO
 	// If enabled and managed=false, remove the MUO deployment
@@ -113,6 +114,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return builder.
 		WithEventFilter(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}, predicate.LabelChangedPredicate{})).
-		Named(controllers.ManagedUpgradeOperatorControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/node/node_controller.go b/pkg/operator/controllers/node/node_controller.go
index 2b53dfc83..d5ea10db2 100644
--- a/pkg/operator/controllers/node/node_controller.go
+++ b/pkg/operator/controllers/node/node_controller.go
@@ -18,13 +18,13 @@ import (
 
 	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/ready"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.nodedrainer"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Node"
+
+	controllerEnabled = "aro.nodedrainer.enabled"
 )
 
 // Reconciler spots nodes that look like they're stuck upgrading.  When this
@@ -50,7 +50,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -139,7 +139,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&corev1.Node{}).
-		Named(controllers.NodeControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/previewfeature/previewfeature_controller.go b/pkg/operator/controllers/previewfeature/previewfeature_controller.go
index 682699d63..1f47845d7 100644
--- a/pkg/operator/controllers/previewfeature/previewfeature_controller.go
+++ b/pkg/operator/controllers/previewfeature/previewfeature_controller.go
@@ -20,7 +20,6 @@ import (
 	arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1"
 	aropreviewv1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/preview.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/operator/controllers/previewfeature/nsgflowlogs"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
@@ -28,6 +27,10 @@ import (
 	"github.com/Azure/ARO-RP/pkg/util/subnet"
 )
 
+const (
+	ControllerName = "PreviewFeature"
+)
+
 type feature interface {
 	Name() string
 	Reconcile(ctx context.Context, instance *aropreviewv1alpha1.PreviewFeature) error
@@ -109,6 +112,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&aropreviewv1alpha1.PreviewFeature{}, builder.WithPredicates(aroPreviewFeaturePredicate)).
-		Named(controllers.PreviewFeatureControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/pullsecret/pullsecret_controller.go b/pkg/operator/controllers/pullsecret/pullsecret_controller.go
index 022ddd309..7badea681 100644
--- a/pkg/operator/controllers/pullsecret/pullsecret_controller.go
+++ b/pkg/operator/controllers/pullsecret/pullsecret_controller.go
@@ -32,14 +32,14 @@ import (
 	"github.com/Azure/ARO-RP/pkg/operator"
 	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/pullsecret"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.pullsecret"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
-	MANAGED          string = CONFIG_NAMESPACE + ".managed"
+	ControllerName = "PullSecret"
+
+	controllerEnabled = "aro.pullsecret.enabled"
+	controllerManaged = "aro.pullsecret.managed"
 )
 
 var pullSecretName = types.NamespacedName{Name: "pull-secret", Namespace: "openshift-config"}
@@ -76,7 +76,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -90,7 +90,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 
 	// reconcile global pull secret
 	// detects if the global pull secret is broken and fixes it by using backup managed by ARO operator
-	if instance.Spec.OperatorFlags.GetSimpleBoolean(MANAGED) {
+	if instance.Spec.OperatorFlags.GetSimpleBoolean(controllerManaged) {
 		operatorSecret, err := r.kubernetescli.CoreV1().Secrets(operator.Namespace).Get(ctx, operator.SecretName, metav1.GetOptions{})
 		if err != nil {
 			return reconcile.Result{}, err
@@ -135,7 +135,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 			&handler.EnqueueRequestForObject{},
 			builder.WithPredicates(pullSecretPredicate),
 		).
-		Named(controllers.PullSecretControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/rbac/rbac_controller.go b/pkg/operator/controllers/rbac/rbac_controller.go
index 4ccc3aae6..609b49646 100644
--- a/pkg/operator/controllers/rbac/rbac_controller.go
+++ b/pkg/operator/controllers/rbac/rbac_controller.go
@@ -19,13 +19,13 @@ import (
 
 	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/dynamichelper"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.rbac"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "RBAC"
+
+	controllerEnabled = "aro.rbac.enabled"
 )
 
 type Reconciler struct {
@@ -49,7 +49,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -102,6 +102,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
 		Owns(&rbacv1.ClusterRole{}).
 		Owns(&rbacv1.ClusterRoleBinding{}).
-		Named(controllers.RBACControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/routefix/routefix_controller.go b/pkg/operator/controllers/routefix/routefix_controller.go
index a6f906c2d..c167bb6a6 100644
--- a/pkg/operator/controllers/routefix/routefix_controller.go
+++ b/pkg/operator/controllers/routefix/routefix_controller.go
@@ -24,15 +24,14 @@ import (
 
 	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/dynamichelper"
 	"github.com/Azure/ARO-RP/pkg/util/version"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.routefix"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
-	MANAGED          string = CONFIG_NAMESPACE + ".managed"
+	ControllerName = "RouteFix"
+
+	controllerEnabled = "aro.routefix.enabled"
 )
 
 // Reconciler is the controller struct
@@ -75,7 +74,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -156,7 +155,7 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		Owns(&corev1.Namespace{}).
 		Owns(&appsv1.DaemonSet{}).
 		Owns(&securityv1.SecurityContextConstraints{}).
-		Named(controllers.RouteFixControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
 
diff --git a/pkg/operator/controllers/storageaccounts/storageaccount_controller.go b/pkg/operator/controllers/storageaccounts/storageaccount_controller.go
index c12302a19..545e7c46e 100644
--- a/pkg/operator/controllers/storageaccounts/storageaccount_controller.go
+++ b/pkg/operator/controllers/storageaccounts/storageaccount_controller.go
@@ -24,7 +24,6 @@ import (
 
 	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"
 	"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/storage"
 	"github.com/Azure/ARO-RP/pkg/util/clusterauthorizer"
@@ -32,8 +31,9 @@ import (
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.storageaccounts"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "StorageAccounts"
+
+	controllerEnabled = "aro.storageaccounts.enabled"
 )
 
 // Reconciler is the controller struct
@@ -76,7 +76,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -121,6 +121,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
 		Watches(&source.Kind{Type: &machinev1beta1.Machine{}}, &handler.EnqueueRequestForObject{}). // to reconcile on machine replacement
 		Watches(&source.Kind{Type: &corev1.Node{}}, &handler.EnqueueRequestForObject{}).            // to reconcile on node status change
-		Named(controllers.StorageAccountsControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/subnets/subnets_controller.go b/pkg/operator/controllers/subnets/subnets_controller.go
index 376e0c5e0..0f159f14e 100644
--- a/pkg/operator/controllers/subnets/subnets_controller.go
+++ b/pkg/operator/controllers/subnets/subnets_controller.go
@@ -25,17 +25,17 @@ import (
 
 	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"
 	"github.com/Azure/ARO-RP/pkg/util/clusterauthorizer"
 	"github.com/Azure/ARO-RP/pkg/util/subnet"
 )
 
 const (
-	CONFIG_NAMESPACE         string = "aro.azuresubnets"
-	ENABLED                  string = CONFIG_NAMESPACE + ".enabled"
-	NSG_MANAGED              string = CONFIG_NAMESPACE + ".nsg.managed"
-	SERVICE_ENDPOINT_MANAGED string = CONFIG_NAMESPACE + ".serviceendpoint.managed"
+	ControllerName = "AzureSubnets"
+
+	controllerEnabled                = "aro.azuresubnets.enabled"
+	controllerNSGManaged             = "aro.azuresubnets.nsg.managed"
+	controllerServiceEndpointManaged = "aro.azuresubnets.serviceendpoint.managed"
 )
 
 // Reconciler is the controller struct
@@ -75,12 +75,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(NSG_MANAGED) && !instance.Spec.OperatorFlags.GetSimpleBoolean(SERVICE_ENDPOINT_MANAGED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerNSGManaged) && !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerServiceEndpointManaged) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -126,14 +126,14 @@ func (r *reconcileManager) reconcileSubnets(ctx context.Context, instance *arov1
 	// to pay for keeping logic split, separate, and simple
 	for _, s := range subnets {
 
-		if instance.Spec.OperatorFlags.GetSimpleBoolean(NSG_MANAGED) {
+		if instance.Spec.OperatorFlags.GetSimpleBoolean(controllerNSGManaged) {
 			err = r.ensureSubnetNSG(ctx, s)
 			if err != nil {
 				combinedErrors = append(combinedErrors, err.Error())
 			}
 		}
 
-		if instance.Spec.OperatorFlags.GetSimpleBoolean(SERVICE_ENDPOINT_MANAGED) {
+		if instance.Spec.OperatorFlags.GetSimpleBoolean(controllerServiceEndpointManaged) {
 			err = r.ensureSubnetServiceEndpoints(ctx, s)
 			if err != nil {
 				combinedErrors = append(combinedErrors, err.Error())
@@ -158,6 +158,6 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 		For(&arov1alpha1.Cluster{}, builder.WithPredicates(aroClusterPredicate)).
 		Watches(&source.Kind{Type: &machinev1beta1.Machine{}}, &handler.EnqueueRequestForObject{}). // to reconcile on machine replacement
 		Watches(&source.Kind{Type: &corev1.Node{}}, &handler.EnqueueRequestForObject{}).            // to reconcile on node status change
-		Named(controllers.AzureSubnetsControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/operator/controllers/workaround/workaround_controller.go b/pkg/operator/controllers/workaround/workaround_controller.go
index a99c63614..c538a7456 100644
--- a/pkg/operator/controllers/workaround/workaround_controller.go
+++ b/pkg/operator/controllers/workaround/workaround_controller.go
@@ -18,14 +18,14 @@ import (
 
 	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/dynamichelper"
 	"github.com/Azure/ARO-RP/pkg/util/version"
 )
 
 const (
-	CONFIG_NAMESPACE string = "aro.workaround"
-	ENABLED          string = CONFIG_NAMESPACE + ".enabled"
+	ControllerName = "Workaround"
+
+	controllerEnabled = "aro.workaround.enabled"
 )
 
 // Reconciler the point of the workaround controller is to apply
@@ -64,7 +64,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 		return reconcile.Result{}, err
 	}
 
-	if !instance.Spec.OperatorFlags.GetSimpleBoolean(ENABLED) {
+	if !instance.Spec.OperatorFlags.GetSimpleBoolean(controllerEnabled) {
 		// controller is disabled
 		return reconcile.Result{}, nil
 	}
@@ -94,6 +94,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
 func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		For(&arov1alpha1.Cluster{}).
-		Named(controllers.WorkaroundControllerName).
+		Named(ControllerName).
 		Complete(r)
 }
diff --git a/pkg/util/computeskus/computeskus.go b/pkg/util/computeskus/computeskus.go
index 7ea6a69fb..5bd534c79 100644
--- a/pkg/util/computeskus/computeskus.go
+++ b/pkg/util/computeskus/computeskus.go
@@ -4,6 +4,8 @@ package computeskus
 // Licensed under the Apache License 2.0.
 
 import (
+	"strings"
+
 	mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
 )
 
@@ -18,7 +20,7 @@ func Zones(sku *mgmtcompute.ResourceSku) []string {
 	return *(*sku.LocationInfo)[0].Zones
 }
 
-// Capabilities checks whether given resource SKU has specific capability
+// HasCapability checks whether given resource SKU has specific capability
 func HasCapability(sku *mgmtcompute.ResourceSku, capabilityName string) bool {
 	if sku.Capabilities == nil {
 		return false
@@ -32,3 +34,46 @@ func HasCapability(sku *mgmtcompute.ResourceSku, capabilityName string) bool {
 
 	return false
 }
+
+// IsRestricted checks whether given resource SKU is restricted in a given location
+func IsRestricted(skus map[string]*mgmtcompute.ResourceSku, location, VMSize string) bool {
+	for _, restriction := range *skus[VMSize].Restrictions {
+		for _, restrictedLocation := range *restriction.RestrictionInfo.Locations {
+			if restrictedLocation == location {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+// FilterVMSizes filters resource SKU by location and returns only virtual machines, their names, restrictions, location info, and capabilities.
+func FilterVMSizes(skus []mgmtcompute.ResourceSku, location string) map[string]*mgmtcompute.ResourceSku {
+	vmskus := map[string]*mgmtcompute.ResourceSku{}
+	for _, sku := range skus {
+		// TODO(mjudeikis): At some point some SKU's stopped returning zones and
+		// locations. IcM is open with MSFT but this might take a while.
+		// Revert once we find out right behaviour.
+		// https://github.com/Azure/ARO-RP/issues/1515
+		if len(*sku.Locations) == 0 || !strings.EqualFold((*sku.Locations)[0], location) ||
+			*sku.ResourceType != "virtualMachines" {
+			continue
+		}
+
+		if len(*sku.LocationInfo) == 0 { // happened in eastus2euap
+			continue
+		}
+
+		// We copy only part of the object so we don't have to keep
+		// a lot of data in memory.
+		vmskus[*sku.Name] = &mgmtcompute.ResourceSku{
+			Name:         sku.Name,
+			Restrictions: sku.Restrictions,
+			LocationInfo: sku.LocationInfo,
+			Capabilities: sku.Capabilities,
+		}
+	}
+
+	return vmskus
+}


Test patch:
diff --git a/pkg/api/defaults_test.go b/pkg/api/defaults_test.go
index 274adc20a..ecd5e9cc3 100644
--- a/pkg/api/defaults_test.go
+++ b/pkg/api/defaults_test.go
@@ -27,7 +27,7 @@ func validOpenShiftClusterDocument() *OpenShiftClusterDocument {
 				ClusterProfile: ClusterProfile{
 					FipsValidatedModules: FipsValidatedModulesDisabled,
 				},
-				OperatorFlags: DefaultOperatorFlags.Copy(),
+				OperatorFlags: DefaultOperatorFlags(),
 			},
 		},
 	}
diff --git a/pkg/api/validate/dynamic/sku_test.go b/pkg/api/validate/dynamic/sku_test.go
new file mode 100644
index 000000000..1a31b013d
--- /dev/null
+++ b/pkg/api/validate/dynamic/sku_test.go
@@ -0,0 +1,172 @@
+package dynamic
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the Apache License 2.0.
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+
+	mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
+	"github.com/Azure/go-autorest/autorest/to"
+	"github.com/golang/mock/gomock"
+	"github.com/sirupsen/logrus"
+
+	"github.com/Azure/ARO-RP/pkg/api"
+	mock_compute "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/compute"
+)
+
+func TestValidateVMSku(t *testing.T) {
+	for _, tt := range []struct {
+		name                  string
+		restrictions          mgmtcompute.ResourceSkuRestrictionsReasonCode
+		restrictionLocation   *[]string
+		targetLocation        string
+		workerProfile1Sku     string
+		workerProfile2Sku     string
+		masterProfileSku      string
+		availableSku          string
+		restrictedSku         string
+		resourceSkusClientErr error
+		wantErr               string
+	}{
+		{
+			name:              "worker and master sku are valid",
+			workerProfile1Sku: "Standard_D4s_v2",
+			workerProfile2Sku: "Standard_D4s_v2",
+			masterProfileSku:  "Standard_D4s_v2",
+			availableSku:      "Standard_D4s_v2",
+		},
+		{
+			name:                  "unable to retrieve skus information",
+			workerProfile1Sku:     "Standard_D4s_v2",
+			workerProfile2Sku:     "Standard_D4s_v2",
+			resourceSkusClientErr: errors.New("unable to retrieve skus information"),
+			wantErr:               "unable to retrieve skus information",
+		},
+		{
+			name:              "desired worker sku doesn't exist in the target region",
+			workerProfile1Sku: "Standard_L80",
+			workerProfile2Sku: "Standard_L80",
+			masterProfileSku:  "Standard_D4s_v2",
+			availableSku:      "Standard_D4s_v2",
+			wantErr:           "400: InvalidParameter: properties.workerProfiles[0].VMSize: The selected SKU 'Standard_L80' is unavailable in region 'eastus'",
+		},
+		{
+			name:              "desired master sku doesn't exist in the target region",
+			workerProfile1Sku: "Standard_D4s_v2",
+			workerProfile2Sku: "Standard_D4s_v2",
+			masterProfileSku:  "Standard_L80",
+			availableSku:      "Standard_D4s_v2",
+			wantErr:           "400: InvalidParameter: properties.masterProfile.VMSize: The selected SKU 'Standard_L80' is unavailable in region 'eastus'",
+		},
+		{
+			name:              "one valid workerprofile and one invalid workerprofile",
+			workerProfile1Sku: "Standard_L80",
+			workerProfile2Sku: "Standard_D4s_v2",
+			masterProfileSku:  "Standard_D4s_v2",
+			availableSku:      "Standard_D4s_v2",
+			wantErr:           "400: InvalidParameter: properties.workerProfiles[0].VMSize: The selected SKU 'Standard_L80' is unavailable in region 'eastus'",
+		},
+		{
+			name:         "worker sku exists in region but is not available in subscription",
+			restrictions: mgmtcompute.NotAvailableForSubscription,
+			restrictionLocation: &[]string{
+				"eastus",
+			},
+			workerProfile1Sku: "Standard_L80",
+			workerProfile2Sku: "Standard_L80",
+			masterProfileSku:  "Standard_D4s_v2",
+			availableSku:      "Standard_D4s_v2",
+			restrictedSku:     "Standard_L80",
+			wantErr:           "400: InvalidParameter: properties.workerProfiles[0].VMSize: The selected SKU 'Standard_L80' is restricted in region 'eastus' for selected subscription",
+		},
+		{
+			name:         "master sku exists in region but is not available in subscription",
+			restrictions: mgmtcompute.NotAvailableForSubscription,
+			restrictionLocation: &[]string{
+				"eastus",
+			},
+			workerProfile1Sku: "Standard_D4s_v2",
+			workerProfile2Sku: "Standard_D4s_v2",
+			masterProfileSku:  "Standard_L80",
+			availableSku:      "Standard_D4s_v2",
+			restrictedSku:     "Standard_L80",
+			wantErr:           "400: InvalidParameter: properties.masterProfile.VMSize: The selected SKU 'Standard_L80' is restricted in region 'eastus' for selected subscription",
+		},
+	} {
+		t.Run(tt.name, func(t *testing.T) {
+			if tt.targetLocation == "" {
+				tt.targetLocation = "eastus"
+			}
+
+			controller := gomock.NewController(t)
+			defer controller.Finish()
+
+			oc := &api.OpenShiftCluster{
+				Properties: api.OpenShiftClusterProperties{
+					WorkerProfiles: []api.WorkerProfile{
+						{
+							VMSize: api.VMSize(tt.workerProfile1Sku),
+						},
+						{
+							VMSize: api.VMSize(tt.workerProfile2Sku),
+						},
+					},
+					MasterProfile: api.MasterProfile{
+						VMSize: api.VMSize(tt.masterProfileSku),
+					},
+				},
+			}
+
+			skus := []mgmtcompute.ResourceSku{
+				{
+					Name:      &tt.availableSku,
+					Locations: &[]string{"eastus"},
+					LocationInfo: &[]mgmtcompute.ResourceSkuLocationInfo{
+						{Zones: &[]string{"1, 2, 3"}},
+					},
+					Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{},
+					Capabilities: &[]mgmtcompute.ResourceSkuCapabilities{},
+					ResourceType: to.StringPtr("virtualMachines"),
+				},
+				{
+					Name:      &tt.restrictedSku,
+					Locations: &[]string{tt.targetLocation},
+					LocationInfo: &[]mgmtcompute.ResourceSkuLocationInfo{
+						{Zones: &[]string{"1, 2, 3"}},
+					},
+					Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{
+						{
+							ReasonCode: tt.restrictions,
+							RestrictionInfo: &mgmtcompute.ResourceSkuRestrictionInfo{
+								Locations: tt.restrictionLocation,
+							},
+						},
+					},
+					Capabilities: &[]mgmtcompute.ResourceSkuCapabilities{},
+					ResourceType: to.StringPtr("virtualMachines"),
+				},
+			}
+
+			resourceSkusClient := mock_compute.NewMockResourceSkusClient(controller)
+			resourceSkusClient.EXPECT().
+				List(gomock.Any(), fmt.Sprintf("location eq %v", tt.targetLocation)).
+				Return(skus, tt.resourceSkusClientErr)
+
+			dv := dynamic{
+				authorizerType:     AuthorizerClusterServicePrincipal,
+				log:                logrus.NewEntry(logrus.StandardLogger()),
+				resourceSkusClient: resourceSkusClient,
+			}
+
+			err := dv.ValidateVMSku(context.Background(), tt.targetLocation, subscriptionID, oc)
+			if err != nil && err.Error() != tt.wantErr ||
+				err == nil && tt.wantErr != "" {
+				t.Error(err)
+			}
+		})
+	}
+}
diff --git a/pkg/frontend/openshiftcluster_putorpatch_test.go b/pkg/frontend/openshiftcluster_putorpatch_test.go
index adeaefd23..c215f2b95 100644
--- a/pkg/frontend/openshiftcluster_putorpatch_test.go
+++ b/pkg/frontend/openshiftcluster_putorpatch_test.go
@@ -287,7 +287,7 @@ func TestPutOrPatchOpenShiftClusterAdminAPI(t *testing.T) {
 							MasterProfile: api.MasterProfile{
 								EncryptionAtHost: api.EncryptionAtHostDisabled,
 							},
-							OperatorFlags: api.DefaultOperatorFlags.Copy(),
+							OperatorFlags: api.DefaultOperatorFlags(),
 						},
 					},
 				})
@@ -311,7 +311,7 @@ func TestPutOrPatchOpenShiftClusterAdminAPI(t *testing.T) {
 					ClusterProfile: admin.ClusterProfile{
 						FipsValidatedModules: admin.FipsValidatedModulesDisabled,
 					},
-					OperatorFlags: admin.OperatorFlags(api.DefaultOperatorFlags.Copy()),
+					OperatorFlags: admin.OperatorFlags(api.DefaultOperatorFlags()),
 				},
 			},
 		},
@@ -369,7 +369,7 @@ func TestPutOrPatchOpenShiftClusterAdminAPI(t *testing.T) {
 							MasterProfile: api.MasterProfile{
 								EncryptionAtHost: api.EncryptionAtHostDisabled,
 							},
-							OperatorFlags: api.DefaultOperatorFlags.Copy(),
+							OperatorFlags: api.DefaultOperatorFlags(),
 						},
 					},
 				})
@@ -393,7 +393,7 @@ func TestPutOrPatchOpenShiftClusterAdminAPI(t *testing.T) {
 					MasterProfile: admin.MasterProfile{
 						EncryptionAtHost: admin.EncryptionAtHostDisabled,
 					},
-					OperatorFlags: admin.OperatorFlags(api.DefaultOperatorFlags.Copy()),
+					OperatorFlags: admin.OperatorFlags(api.DefaultOperatorFlags()),
 				},
 			},
 		},
@@ -721,7 +721,7 @@ func TestPutOrPatchOpenShiftCluster(t *testing.T) {
 							FeatureProfile: api.FeatureProfile{
 								GatewayEnabled: true,
 							},
-							OperatorFlags: api.DefaultOperatorFlags.Copy(),
+							OperatorFlags: api.DefaultOperatorFlags(),
 						},
 					},
 				})
diff --git a/pkg/operator/controllers/alertwebhook/alertwebhook_controller_test.go b/pkg/operator/controllers/alertwebhook/alertwebhook_controller_test.go
index fdac6b346..d632fe352 100644
--- a/pkg/operator/controllers/alertwebhook/alertwebhook_controller_test.go
+++ b/pkg/operator/controllers/alertwebhook/alertwebhook_controller_test.go
@@ -162,7 +162,7 @@ func TestSetAlertManagerWebhook(t *testing.T) {
 						},
 						Spec: arov1alpha1.ClusterSpec{
 							OperatorFlags: arov1alpha1.OperatorFlags{
-								ENABLED: "true",
+								controllerEnabled: "true",
 							},
 						},
 					},
@@ -189,7 +189,7 @@ func TestSetAlertManagerWebhook(t *testing.T) {
 						},
 						Spec: arov1alpha1.ClusterSpec{
 							OperatorFlags: arov1alpha1.OperatorFlags{
-								ENABLED: "true",
+								controllerEnabled: "true",
 							},
 						},
 					},
@@ -216,7 +216,7 @@ func TestSetAlertManagerWebhook(t *testing.T) {
 						},
 						Spec: arov1alpha1.ClusterSpec{
 							OperatorFlags: arov1alpha1.OperatorFlags{
-								ENABLED: "false",
+								controllerEnabled: "false",
 							},
 						},
 					},
@@ -243,7 +243,7 @@ func TestSetAlertManagerWebhook(t *testing.T) {
 						},
 						Spec: arov1alpha1.ClusterSpec{
 							OperatorFlags: arov1alpha1.OperatorFlags{
-								ENABLED: "false",
+								controllerEnabled: "false",
 							},
 						},
 					},
diff --git a/pkg/operator/controllers/banner/banner_controller_test.go b/pkg/operator/controllers/banner/banner_controller_test.go
index b6e045a16..4fca880b7 100644
--- a/pkg/operator/controllers/banner/banner_controller_test.go
+++ b/pkg/operator/controllers/banner/banner_controller_test.go
@@ -140,7 +140,7 @@ func TestBannerReconcile(t *testing.T) {
 						Content: arov1alpha1.BannerContent(tt.bannerSetting),
 					},
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						ENABLED: strconv.FormatBool(tt.featureFlag),
+						controllerEnabled: strconv.FormatBool(tt.featureFlag),
 					},
 				},
 			}
diff --git a/pkg/operator/controllers/genevalogging/genevalogging_test.go b/pkg/operator/controllers/genevalogging/genevalogging_test.go
index 9282cac56..28de61f45 100644
--- a/pkg/operator/controllers/genevalogging/genevalogging_test.go
+++ b/pkg/operator/controllers/genevalogging/genevalogging_test.go
@@ -42,7 +42,7 @@ func TestGenevaLoggingDaemonset(t *testing.T) {
 		{
 			name: "no flags given",
 			operatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED: "true",
+				controllerEnabled: "true",
 			},
 			validateDaemonset: func(d *appsv1.DaemonSet) (errs []error) {
 				if len(d.Spec.Template.Spec.Containers) != 2 {
@@ -75,8 +75,8 @@ func TestGenevaLoggingDaemonset(t *testing.T) {
 		{
 			name: "fluentbit changed",
 			operatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED:            "true",
-				FLUENTBIT_PULLSPEC: "otherurl/fluentbit",
+				controllerEnabled:           "true",
+				controllerFluentbitPullSpec: "otherurl/fluentbit",
 			},
 			validateDaemonset: func(d *appsv1.DaemonSet) (errs []error) {
 				if len(d.Spec.Template.Spec.Containers) != 2 {
@@ -109,8 +109,8 @@ func TestGenevaLoggingDaemonset(t *testing.T) {
 		{
 			name: "mdsd changed",
 			operatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED:       "true",
-				MDSD_PULLSPEC: "otherurl/mdsd",
+				controllerEnabled:      "true",
+				controllerMDSDPullSpec: "otherurl/mdsd",
 			},
 			validateDaemonset: func(d *appsv1.DaemonSet) (errs []error) {
 				if len(d.Spec.Template.Spec.Containers) != 2 {
diff --git a/pkg/operator/controllers/imageconfig/image_controller_test.go b/pkg/operator/controllers/imageconfig/image_controller_test.go
index f1e51a65d..f0d7c245a 100644
--- a/pkg/operator/controllers/imageconfig/image_controller_test.go
+++ b/pkg/operator/controllers/imageconfig/image_controller_test.go
@@ -41,7 +41,7 @@ func TestImageConfigReconciler(t *testing.T) {
 					ACRDomain:     "arointsvc.azurecr.io",
 					AZEnvironment: azureclient.PublicCloud.Environment.Name,
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						ENABLED: strconv.FormatBool(false),
+						controllerEnabled: strconv.FormatBool(false),
 					},
 					Location: "eastus",
 				},
@@ -117,7 +117,7 @@ func TestImageConfigReconciler(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{Name: arov1alpha1.SingletonClusterName},
 				Spec: arov1alpha1.ClusterSpec{
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						ENABLED: strconv.FormatBool(true),
+						controllerEnabled: strconv.FormatBool(true),
 					},
 				},
 			}),
@@ -178,7 +178,7 @@ func TestImageConfigReconciler(t *testing.T) {
 						ACRDomain:     "arointsvc.azurecr.io",
 						AZEnvironment: azureclient.PublicCloud.Environment.Name,
 						OperatorFlags: arov1alpha1.OperatorFlags{
-							ENABLED: strconv.FormatBool(true),
+							controllerEnabled: strconv.FormatBool(true),
 						},
 						Location: "eastus",
 					},
diff --git a/pkg/operator/controllers/machine/machine_controller_test.go b/pkg/operator/controllers/machine/machine_controller_test.go
index c68ba7093..fbfa41446 100644
--- a/pkg/operator/controllers/machine/machine_controller_test.go
+++ b/pkg/operator/controllers/machine/machine_controller_test.go
@@ -71,7 +71,7 @@ func TestMachineReconciler(t *testing.T) {
 		Status:     arov1alpha1.ClusterStatus{Conditions: []operatorv1.OperatorCondition{}},
 		Spec: arov1alpha1.ClusterSpec{
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED: "true",
+				controllerEnabled: "true",
 			},
 		},
 	}
diff --git a/pkg/operator/controllers/machineset/machineset_controller_test.go b/pkg/operator/controllers/machineset/machineset_controller_test.go
index 4941e2ecd..c46fd939e 100644
--- a/pkg/operator/controllers/machineset/machineset_controller_test.go
+++ b/pkg/operator/controllers/machineset/machineset_controller_test.go
@@ -196,7 +196,7 @@ func TestReconciler(t *testing.T) {
 				Spec: arov1alpha1.ClusterSpec{
 					InfraID: "aro-fake",
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						ENABLED: strconv.FormatBool(tt.featureFlag),
+						ControllerEnabled: strconv.FormatBool(tt.featureFlag),
 					},
 				},
 			}
diff --git a/pkg/operator/controllers/monitoring/monitoring_controller_test.go b/pkg/operator/controllers/monitoring/monitoring_controller_test.go
index 9a0f3193a..153395b5f 100644
--- a/pkg/operator/controllers/monitoring/monitoring_controller_test.go
+++ b/pkg/operator/controllers/monitoring/monitoring_controller_test.go
@@ -31,7 +31,7 @@ var (
 		},
 		Spec: arov1alpha1.ClusterSpec{
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED: "true",
+				controllerEnabled: "true",
 			},
 		},
 	})
diff --git a/pkg/operator/controllers/muo/deploy_test.go b/pkg/operator/controllers/muo/deploy_test.go
index 2b6832775..400cfd7e6 100644
--- a/pkg/operator/controllers/muo/deploy_test.go
+++ b/pkg/operator/controllers/muo/deploy_test.go
@@ -31,7 +31,7 @@ func TestDeployCreateOrUpdateCorrectKinds(t *testing.T) {
 		},
 		Spec: arov1alpha1.ClusterSpec{
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				pullSpec: setPullSpec,
+				controllerPullSpec: setPullSpec,
 			},
 		},
 	}
@@ -100,7 +100,7 @@ func TestDeployCreateOrUpdateSetsOwnerReferences(t *testing.T) {
 		},
 		Spec: arov1alpha1.ClusterSpec{
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				pullSpec: setPullSpec,
+				controllerPullSpec: setPullSpec,
 			},
 		},
 	}
diff --git a/pkg/operator/controllers/muo/muo_controller_test.go b/pkg/operator/controllers/muo/muo_controller_test.go
index 5ef8c27ec..404e5323b 100644
--- a/pkg/operator/controllers/muo/muo_controller_test.go
+++ b/pkg/operator/controllers/muo/muo_controller_test.go
@@ -96,14 +96,14 @@ func TestMUOReconciler(t *testing.T) {
 				},
 				Spec: arov1alpha1.ClusterSpec{
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						enabled:  strconv.FormatBool(tt.enabled),
-						pullSpec: "wonderfulPullspec",
+						controllerEnabled:  strconv.FormatBool(tt.enabled),
+						controllerPullSpec: "wonderfulPullspec",
 					},
 				},
 			}
 			// nil and empty string are valid values, be careful to preserve them
 			if tt.managed != "" {
-				cluster.Spec.OperatorFlags[managed] = tt.managed
+				cluster.Spec.OperatorFlags[controllerManaged] = tt.managed
 			}
 			arocli := arofake.NewSimpleClientset(cluster)
 			deployer := mock_muo.NewMockDeployer(controller)
diff --git a/pkg/operator/controllers/node/node_controller_test.go b/pkg/operator/controllers/node/node_controller_test.go
index b244f4a8f..dc5b83479 100644
--- a/pkg/operator/controllers/node/node_controller_test.go
+++ b/pkg/operator/controllers/node/node_controller_test.go
@@ -363,7 +363,7 @@ func TestReconciler(t *testing.T) {
 				Spec: arov1alpha1.ClusterSpec{
 					InfraID: "aro-fake",
 					OperatorFlags: arov1alpha1.OperatorFlags{
-						ENABLED: strconv.FormatBool(tt.featureFlag),
+						controllerEnabled: strconv.FormatBool(tt.featureFlag),
 					},
 				},
 			}
diff --git a/pkg/operator/controllers/pullsecret/pullsecret_controller_test.go b/pkg/operator/controllers/pullsecret/pullsecret_controller_test.go
index 76514786d..5ec7e8aef 100644
--- a/pkg/operator/controllers/pullsecret/pullsecret_controller_test.go
+++ b/pkg/operator/controllers/pullsecret/pullsecret_controller_test.go
@@ -52,8 +52,8 @@ func TestPullSecretReconciler(t *testing.T) {
 		Status:     arov1alpha1.ClusterStatus{},
 		Spec: arov1alpha1.ClusterSpec{
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED: "true",
-				MANAGED: "true",
+				controllerEnabled: "true",
+				controllerManaged: "true",
 			},
 		},
 	}
@@ -175,8 +175,8 @@ func TestPullSecretReconciler(t *testing.T) {
 					Status:     arov1alpha1.ClusterStatus{},
 					Spec: arov1alpha1.ClusterSpec{
 						OperatorFlags: arov1alpha1.OperatorFlags{
-							ENABLED: "true",
-							MANAGED: "false",
+							controllerEnabled: "true",
+							controllerManaged: "false",
 						},
 					},
 				}),
@@ -198,8 +198,8 @@ func TestPullSecretReconciler(t *testing.T) {
 					Status:     arov1alpha1.ClusterStatus{},
 					Spec: arov1alpha1.ClusterSpec{
 						OperatorFlags: arov1alpha1.OperatorFlags{
-							ENABLED: "true",
-							MANAGED: "false",
+							controllerEnabled: "true",
+							controllerManaged: "false",
 						},
 					},
 				}),
diff --git a/pkg/operator/controllers/storageaccounts/storageaccounts_test.go b/pkg/operator/controllers/storageaccounts/storageaccounts_test.go
index 06eb638ca..68e9fe6b6 100644
--- a/pkg/operator/controllers/storageaccounts/storageaccounts_test.go
+++ b/pkg/operator/controllers/storageaccounts/storageaccounts_test.go
@@ -46,7 +46,7 @@ func getValidClusterInstance(operatorFlag bool) *arov1alpha1.Cluster {
 			ClusterResourceGroupID: clusterResourceGroupId,
 			StorageSuffix:          storageSuffix,
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED: strconv.FormatBool(operatorFlag),
+				controllerEnabled: strconv.FormatBool(operatorFlag),
 			},
 		},
 	}
diff --git a/pkg/operator/controllers/subnets/subnet_controller_test.go b/pkg/operator/controllers/subnets/subnet_controller_test.go
index 45f908a7d..d5ad0dafb 100644
--- a/pkg/operator/controllers/subnets/subnet_controller_test.go
+++ b/pkg/operator/controllers/subnets/subnet_controller_test.go
@@ -43,9 +43,9 @@ func getValidClusterInstance(operatorFlagEnabled bool, operatorFlagNSG bool, ope
 			ClusterResourceGroupID: clusterResourceGroupId,
 			InfraID:                infraId,
 			OperatorFlags: arov1alpha1.OperatorFlags{
-				ENABLED:                  strconv.FormatBool(operatorFlagEnabled),
-				NSG_MANAGED:              strconv.FormatBool(operatorFlagNSG),
-				SERVICE_ENDPOINT_MANAGED: strconv.FormatBool(operatorFlagServiceEndpoint),
+				controllerEnabled:                strconv.FormatBool(operatorFlagEnabled),
+				controllerNSGManaged:             strconv.FormatBool(operatorFlagNSG),
+				controllerServiceEndpointManaged: strconv.FormatBool(operatorFlagServiceEndpoint),
 			},
 		},
 	}
diff --git a/pkg/operator/controllers/workaround/workaround_controller_test.go b/pkg/operator/controllers/workaround/workaround_controller_test.go
index 9bd6e774f..96990accf 100644
--- a/pkg/operator/controllers/workaround/workaround_controller_test.go
+++ b/pkg/operator/controllers/workaround/workaround_controller_test.go
@@ -50,7 +50,7 @@ func TestWorkaroundReconciler(t *testing.T) {
 			},
 			Spec: arov1alpha1.ClusterSpec{
 				OperatorFlags: arov1alpha1.OperatorFlags{
-					ENABLED: "true",
+					controllerEnabled: "true",
 				},
 			},
 		})
diff --git a/pkg/util/computeskus/computeskus_test.go b/pkg/util/computeskus/computeskus_test.go
index 014b11924..cfa7ef7da 100644
--- a/pkg/util/computeskus/computeskus_test.go
+++ b/pkg/util/computeskus/computeskus_test.go
@@ -102,3 +102,157 @@ func TestHasCapability(t *testing.T) {
 		})
 	}
 }
+
+func TestFilterVmSizes(t *testing.T) {
+	for _, tt := range []struct {
+		name             string
+		providedLocation string
+		resourceType     string
+		skuLocation      []string
+		skuRestrictions  mgmtcompute.ResourceSkuRestrictions
+		skuLocationInfo  []mgmtcompute.ResourceSkuLocationInfo
+		skuCapabilities  string
+		wantResult       map[string]*mgmtcompute.ResourceSku
+	}{
+		{
+			name:             "resource type is a virtual machine",
+			providedLocation: "eastus",
+			resourceType:     "virtualMachines",
+			skuRestrictions:  mgmtcompute.ResourceSkuRestrictions{ReasonCode: mgmtcompute.NotAvailableForSubscription},
+			skuLocation:      []string{"eastus"},
+			skuLocationInfo:  []mgmtcompute.ResourceSkuLocationInfo{{Zones: &[]string{"eastus-2"}}},
+			skuCapabilities:  "some-capability",
+
+			wantResult: map[string]*mgmtcompute.ResourceSku{
+				"Fake_Sku": {
+					Name: to.StringPtr("Fake_Sku"),
+					Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{{
+						ReasonCode: mgmtcompute.NotAvailableForSubscription}},
+					LocationInfo: &[]mgmtcompute.ResourceSkuLocationInfo{{
+						Zones: &[]string{"eastus-2"}},
+					},
+					Capabilities: &[]mgmtcompute.ResourceSkuCapabilities{{
+						Name: to.StringPtr("some-capability"),
+					}},
+				},
+			},
+		},
+		{
+			name:             "resource type not a virtual machine",
+			providedLocation: "eastus",
+			resourceType:     "disk",
+			skuLocation:      []string{"eastus"},
+			skuLocationInfo:  []mgmtcompute.ResourceSkuLocationInfo{{Zones: &[]string{"eastus-2"}}},
+			wantResult:       map[string]*mgmtcompute.ResourceSku{},
+		},
+		{
+			name:             "sku Location doesn't match provided location",
+			providedLocation: "mars",
+			resourceType:     "virtualMachines",
+			skuLocation:      []string{"eastus"},
+			skuLocationInfo:  []mgmtcompute.ResourceSkuLocationInfo{{Zones: &[]string{"eastus-2"}}},
+			wantResult:       map[string]*mgmtcompute.ResourceSku{},
+		},
+		{
+			name:             "sku Location has length of 0",
+			providedLocation: "eastus",
+			resourceType:     "virtualMachines",
+			skuLocation:      []string{},
+			skuLocationInfo:  []mgmtcompute.ResourceSkuLocationInfo{{Zones: &[]string{"eastus-2"}}},
+			wantResult:       map[string]*mgmtcompute.ResourceSku{},
+		},
+		{
+			name:             "sku LocationInfo has length of 0",
+			providedLocation: "eastus",
+			resourceType:     "virtualMachines",
+			skuLocation:      []string{"eastus"},
+			skuLocationInfo:  []mgmtcompute.ResourceSkuLocationInfo{},
+			wantResult:       map[string]*mgmtcompute.ResourceSku{},
+		},
+	} {
+		t.Run(tt.name, func(t *testing.T) {
+
+			sku := []mgmtcompute.ResourceSku{
+				{
+					Name: to.StringPtr("Fake_Sku"),
+					Capabilities: &[]mgmtcompute.ResourceSkuCapabilities{
+						{
+							Name: to.StringPtr(tt.skuCapabilities),
+						},
+					},
+					Locations:    &tt.skuLocation,
+					Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{tt.skuRestrictions},
+					LocationInfo: &tt.skuLocationInfo,
+					ResourceType: to.StringPtr(tt.resourceType),
+				},
+			}
+
+			result := FilterVMSizes(sku, tt.providedLocation)
+
+			if !reflect.DeepEqual(result, tt.wantResult) {
+				t.Error(cmp.Diff(result, tt.wantResult))
+			}
+		})
+	}
+}
+
+func TestIsRestricted(t *testing.T) {
+	for _, tt := range []struct {
+		name       string
+		location   string
+		vmsize     string
+		sku        map[string]*mgmtcompute.ResourceSku
+		wantResult bool
+	}{
+		{
+			name:     "sku is restricted in one location",
+			location: "eastus",
+			vmsize:   "Standard_Sku_1",
+			sku: map[string]*mgmtcompute.ResourceSku{
+				"Standard_Sku_1": {Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{
+					{
+						RestrictionInfo: &mgmtcompute.ResourceSkuRestrictionInfo{Locations: &[]string{"eastus"}},
+					},
+				}},
+			},
+			wantResult: true,
+		},
+		{
+			name:     "sku is restricted in multiple locations",
+			location: "eastus",
+			vmsize:   "Standard_Sku_1",
+			sku: map[string]*mgmtcompute.ResourceSku{
+				"Standard_Sku_1": {Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{
+					{
+						RestrictionInfo: &mgmtcompute.ResourceSkuRestrictionInfo{Locations: &[]string{
+							"eastus",
+							"eastus2",
+						}},
+					},
+				}},
+			},
+			wantResult: true,
+		},
+		{
+			name:     "sku is not restricted",
+			location: "eastus",
+			vmsize:   "Standard_Sku_2",
+			sku: map[string]*mgmtcompute.ResourceSku{
+				"Standard_Sku_2": {Restrictions: &[]mgmtcompute.ResourceSkuRestrictions{
+					{
+						RestrictionInfo: &mgmtcompute.ResourceSkuRestrictionInfo{Locations: &[]string{""}},
+					},
+				}},
+			},
+			wantResult: false,
+		},
+	} {
+		t.Run(tt.name, func(t *testing.T) {
+			result := IsRestricted(tt.sku, tt.location, tt.vmsize)
+
+			if result != tt.wantResult {
+				t.Error(result)
+			}
+		})
+	}
+}
diff --git a/test/e2e/operator.go b/test/e2e/operator.go
index 07655ecf4..c7fb97417 100644
--- a/test/e2e/operator.go
+++ b/test/e2e/operator.go
@@ -286,7 +286,7 @@ var _ = Describe("ARO Operator - MachineSet Controller", func() {
 		instance, err := clients.AROClusters.AroV1alpha1().Clusters().Get(ctx, "cluster", metav1.GetOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
-		if !instance.Spec.OperatorFlags.GetSimpleBoolean(machineset.ENABLED) {
+		if !instance.Spec.OperatorFlags.GetSimpleBoolean(machineset.ControllerEnabled) {
 			Skip("MachineSet Controller is not enabled, skipping this test")
 		}
 
diff --git a/test/e2e/scalenodes.go b/test/e2e/scalenodes.go
index 6271e1ba6..25eee8517 100644
--- a/test/e2e/scalenodes.go
+++ b/test/e2e/scalenodes.go
@@ -67,7 +67,7 @@ var _ = Describe("Scale nodes", func() {
 		instance, err := clients.AROClusters.AroV1alpha1().Clusters().Get(ctx, "cluster", metav1.GetOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
-		if instance.Spec.OperatorFlags.GetSimpleBoolean(machineset.ENABLED) {
+		if instance.Spec.OperatorFlags.GetSimpleBoolean(machineset.ControllerEnabled) {
 			Skip("MachineSet Controller is enabled, skipping this test")
 		}