Skip to content

Commit

Permalink
Enable concurrency in BMO controllers
Browse files Browse the repository at this point in the history
  • Loading branch information
kashifest committed Aug 25, 2023
1 parent 757d086 commit 63d5cd7
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 38 deletions.
33 changes: 2 additions & 31 deletions controllers/metal3.io/baremetalhost_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -1732,41 +1729,15 @@ func (r *BareMetalHostReconciler) updateEventHandler(e event.UpdateEvent) bool {
}

// SetupWithManager registers the reconciler to be run by the manager
func (r *BareMetalHostReconciler) SetupWithManager(mgr ctrl.Manager, preprovImgEnable bool) error {

maxConcurrentReconciles := runtime.NumCPU()
if maxConcurrentReconciles > 8 {
maxConcurrentReconciles = 8
}
if maxConcurrentReconciles < 2 {
maxConcurrentReconciles = 2
}
if mcrEnv, ok := os.LookupEnv("BMO_CONCURRENCY"); ok {
mcr, err := strconv.Atoi(mcrEnv)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("BMO_CONCURRENCY value: %s is invalid", mcrEnv))
}
if mcr > 0 {
ctrl.Log.Info(fmt.Sprintf("BMO_CONCURRENCY of %d is set via an environment variable", mcr))
maxConcurrentReconciles = mcr
} else {
ctrl.Log.Info(fmt.Sprintf("Invalid BMO_CONCURRENCY value. Operator Concurrency will be set to a default value of %d", maxConcurrentReconciles))
}
} else {
ctrl.Log.Info(fmt.Sprintf("Operator Concurrency will be set to a default value of %d", maxConcurrentReconciles))
}

opts := controller.Options{
MaxConcurrentReconciles: maxConcurrentReconciles,
}
func (r *BareMetalHostReconciler) SetupWithManager(mgr ctrl.Manager, preprovImgEnable bool, options controller.Options) error {

controller := ctrl.NewControllerManagedBy(mgr).
For(&metal3api.BareMetalHost{}).
WithEventFilter(
predicate.Funcs{
UpdateFunc: r.updateEventHandler,
}).
WithOptions(opts).
WithOptions(options).
Owns(&corev1.Secret{}, builder.MatchEveryOwner)

if preprovImgEnable {
Expand Down
5 changes: 4 additions & 1 deletion controllers/metal3.io/bmceventsubscription_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
Expand Down Expand Up @@ -289,9 +290,11 @@ func (r *BMCEventSubscriptionReconciler) updateEventHandler(e event.UpdateEvent)
}

// SetupWithManager registers the reconciler to be run by the manager
func (r *BMCEventSubscriptionReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *BMCEventSubscriptionReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {

return ctrl.NewControllerManagedBy(mgr).
For(&metal3api.BMCEventSubscription{}).
WithOptions(options).
WithEventFilter(predicate.Funcs{
UpdateFunc: r.updateEventHandler,
}).
Expand Down
4 changes: 3 additions & 1 deletion controllers/metal3.io/hostfirmwaresettings_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
Expand Down Expand Up @@ -364,10 +365,11 @@ func (r *HostFirmwareSettingsReconciler) getOrCreateFirmwareSchema(info *rInfo,
}

// SetupWithManager sets up the controller with the Manager.
func (r *HostFirmwareSettingsReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *HostFirmwareSettingsReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {

return ctrl.NewControllerManagedBy(mgr).
For(&metal3api.HostFirmwareSettings{}).
WithOptions(options).
WithEventFilter(
predicate.Funcs{
UpdateFunc: r.updateEventHandler,
Expand Down
4 changes: 3 additions & 1 deletion controllers/metal3.io/preprovisioningimage_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"

metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
"github.com/metal3-io/baremetal-operator/pkg/imageprovider"
Expand Down Expand Up @@ -351,9 +352,10 @@ func (r *PreprovisioningImageReconciler) CanStart() bool {
return false
}

func (r *PreprovisioningImageReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *PreprovisioningImageReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error {
return ctrl.NewControllerManagedBy(mgr).
For(&metal3.PreprovisioningImage{}).
WithOptions(options).
Owns(&corev1.Secret{}, builder.MatchEveryOwner).
Complete(r)
}
58 changes: 54 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ import (
"fmt"
"os"
"runtime"
"strconv"
"strings"

"github.com/pkg/errors"
"go.uber.org/zap/zapcore"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
cliflag "k8s.io/component-base/cli/flag"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/webhook"
Expand Down Expand Up @@ -123,6 +126,7 @@ func main() {
var webhookPort int
var restConfigQPS float64
var restConfigBurst int
var bmoConcurrency int

// From CAPI point of view, BMO should be able to watch all namespaces
// in case of a deployment that is not multi-tenant. If the deployment
Expand Down Expand Up @@ -164,6 +168,8 @@ func main() {
"If omitted, the default Go cipher suites will be used. \n"+
"Preferred values: "+strings.Join(tlsCipherPreferredValues, ", ")+". \n"+
"Insecure values: "+strings.Join(tlsCipherInsecureValues, ", ")+".")
flag.IntVar(&bmoConcurrency, "bmo-concurrency", 0,
"Number of baremetalhosts to process simultaneously")
flag.Parse()

logOpts := zap.Options{}
Expand Down Expand Up @@ -227,12 +233,18 @@ func main() {
provisionerFactory = ironic.NewProvisionerFactory(provLog, preprovImgEnable)
}

maxConcurrency, err := getMaxConcurrentReconciles(bmoConcurrency)
if err != nil {
setupLog.Error(err, "unable to create controller", "controller", "BareMetalHost")
os.Exit(1)
}

if err = (&metal3iocontroller.BareMetalHostReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("BareMetalHost"),
ProvisionerFactory: provisionerFactory,
APIReader: mgr.GetAPIReader(),
}).SetupWithManager(mgr, preprovImgEnable); err != nil {
}).SetupWithManager(mgr, preprovImgEnable, concurrency(maxConcurrency)); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "BareMetalHost")
os.Exit(1)
}
Expand All @@ -246,7 +258,7 @@ func main() {
ImageProvider: imageprovider.NewDefaultImageProvider(),
}
if imgReconciler.CanStart() {
if err = (&imgReconciler).SetupWithManager(mgr); err != nil {
if err = (&imgReconciler).SetupWithManager(mgr, concurrency(maxConcurrency)); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "PreprovisioningImage")
os.Exit(1)
}
Expand All @@ -258,7 +270,7 @@ func main() {
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("HostFirmwareSettings"),
ProvisionerFactory: provisionerFactory,
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(mgr, concurrency(maxConcurrency)); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "HostFirmwareSettings")
os.Exit(1)
}
Expand All @@ -267,7 +279,7 @@ func main() {
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("BMCEventSubscription"),
ProvisionerFactory: provisionerFactory,
}).SetupWithManager(mgr); err != nil {
}).SetupWithManager(mgr, concurrency(maxConcurrency)); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "BMCEventSubscription")
os.Exit(1)
}
Expand Down Expand Up @@ -356,3 +368,41 @@ func GetTLSVersion(version string) (uint16, error) {
}
return v, nil
}

func concurrency(c int) controller.Options {
return controller.Options{MaxConcurrentReconciles: c}
}

func getMaxConcurrentReconciles(bmoConcurrency int) (int, error) {
if bmoConcurrency > 0 {
ctrl.Log.Info(fmt.Sprintf("Controller Concurrency will be set to %d according to command line flag", bmoConcurrency))
return bmoConcurrency, nil
} else if bmoConcurrency < 0 {
return 0, fmt.Errorf("bmo-concurrency value: %d is invalid", bmoConcurrency)
}

// bmo-concurrency value is 0 i.e. no values passed via the flag
// maxConcurrentReconcile value would be set based on env var or number of CPUs.
maxConcurrentReconciles := runtime.NumCPU()
if maxConcurrentReconciles > 8 {
maxConcurrentReconciles = 8
}
if maxConcurrentReconciles < 2 {
maxConcurrentReconciles = 2
}
if mcrEnv, ok := os.LookupEnv("BMO_CONCURRENCY"); ok {
mcr, err := strconv.Atoi(mcrEnv)
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("BMO_CONCURRENCY value: %s is invalid", mcrEnv))
}
if mcr > 0 {
ctrl.Log.Info(fmt.Sprintf("BMO_CONCURRENCY of %d is set via an environment variable", mcr))
maxConcurrentReconciles = mcr
} else {
ctrl.Log.Info(fmt.Sprintf("Invalid BMO_CONCURRENCY value. Operator Concurrency will be set to a default value of %d", maxConcurrentReconciles))
}
} else {
ctrl.Log.Info(fmt.Sprintf("Operator Concurrency will be set to a default value of %d", maxConcurrentReconciles))
}
return maxConcurrentReconciles, nil
}

0 comments on commit 63d5cd7

Please sign in to comment.