Skip to content
This repository has been archived by the owner on Sep 15, 2022. It is now read-only.

Sustain service broker #76

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions charts/helm-broker/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ rules:
- apiGroups: ["servicecatalog.k8s.io"]
resources: ["servicebrokers", "clusterservicebrokers"]
verbs: ["create","delete","list","get","update", "watch"]
- apiGroups: ["servicecatalog.k8s.io"]
resources: ["serviceinstance", "serviceclass", "clusterserviceclass"]
verbs: ["list","get","update", "watch"]
- apiGroups: ["rafter.kyma-project.io"]
resources: ["clusterassetgroups", "assetgroups"]
verbs: ["get", "create", "update", "delete", "list", "watch"]
Expand Down
7 changes: 5 additions & 2 deletions internal/controller/addons_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ type ReconcileAddonsConfiguration struct {
}

// NewReconcileAddonsConfiguration returns a new reconcile.Reconciler
func NewReconcileAddonsConfiguration(mgr manager.Manager, addonGetterFactory addonGetterFactory, chartStorage chartStorage, addonStorage addonStorage, brokerFacade brokerFacade, docsProvider docsProvider, brokerSyncer brokerSyncer, templateService templateService, tmpDir string, log logrus.FieldLogger) reconcile.Reconciler {
func NewReconcileAddonsConfiguration(mgr manager.Manager, addonGetterFactory addonGetterFactory,
chartStorage chartStorage, addonStorage addonStorage, brokerFacade brokerFacade, docsProvider docsProvider,
brokerSyncer brokerSyncer, templateService templateService, tmpDir string, log logrus.FieldLogger) reconcile.Reconciler {
return &ReconcileAddonsConfiguration{
log: log.WithField("controller", "addons"),
Client: mgr.GetClient(),

common: newControllerCommon(mgr.GetClient(), addonGetterFactory, addonStorage, chartStorage, docsProvider, brokerSyncer, brokerFacade, templateService, path.Join(tmpDir, "addon-loader-dst"), log),
common: newControllerCommon(mgr.GetClient(), addonGetterFactory, addonStorage, chartStorage,
docsProvider, brokerSyncer, brokerFacade, templateService, path.Join(tmpDir, "addon-loader-dst"), log),
}
}

Expand Down
46 changes: 12 additions & 34 deletions internal/controller/addons_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func TestReconcileAddonsConfiguration_AddAddonsProcess(t *testing.T) {
}
}
ts.brokerFacade.On("Exist").Return(false, nil).Once()
ts.brokerFacade.On("Create").Return(nil).Once()
ts.addonGetterFactory.On("NewGetter", fixAddonsCfg.Spec.Repositories[0].URL, path.Join(tmpDir, "addon-loader-dst")).Return(ts.addonGetter, nil).Once()
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand Down Expand Up @@ -105,7 +105,8 @@ func TestReconcileAddonsConfiguration_AddAddonsProcess_ErrorIfBrokerExist(t *tes
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand Down Expand Up @@ -139,12 +140,12 @@ func TestReconcileAddonsConfiguration_UpdateAddonsProcess(t *testing.T) {
}
}
ts.brokerFacade.On("Exist").Return(false, nil).Once()
ts.brokerFacade.On("Create").Return(nil).Once()
ts.addonGetterFactory.On("NewGetter", fixAddonsCfg.Spec.Repositories[0].URL, path.Join(tmpDir, "addon-loader-dst")).Return(ts.addonGetter, nil).Once()
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand Down Expand Up @@ -175,7 +176,8 @@ func TestReconcileAddonsConfiguration_UpdateAddonsProcess_ConflictingAddons(t *t
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand All @@ -195,11 +197,11 @@ func TestReconcileAddonsConfiguration_DeleteAddonsProcess(t *testing.T) {
ts := getTestSuite(t, fixAddonsCfg)
tmpDir := os.TempDir()

ts.brokerFacade.On("Delete").Return(nil).Once()
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand All @@ -219,11 +221,11 @@ func TestReconcileAddonsConfiguration_DeleteAddonsProcess_ReconcileOtherAddons(t
ts := getTestSuite(t, fixAddonsCfg, failedAddCfg)
tmpDir := os.TempDir()

ts.brokerFacade.On("Delete").Return(nil).Once()
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage,
ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
Expand All @@ -241,30 +243,6 @@ func TestReconcileAddonsConfiguration_DeleteAddonsProcess_ReconcileOtherAddons(t
assert.NotContains(t, res.Finalizers, v1alpha1.FinalizerAddonsConfiguration)
}

func TestReconcileAddonsConfiguration_DeleteAddonsProcess_Error(t *testing.T) {
// GIVEN
fixAddonsCfg := fixDeletedAddonsConfiguration()
ts := getTestSuite(t, fixAddonsCfg)
tmpDir := os.TempDir()

ts.brokerFacade.On("Delete").Return(errors.New("")).Once()
defer ts.assertExpectations()

// WHEN
reconciler := NewReconcileAddonsConfiguration(ts.mgr, ts.addonGetterFactory, ts.chartStorage, ts.addonStorage, ts.brokerFacade, ts.docsProvider, ts.brokerSyncer, ts.templateService, tmpDir, spy.NewLogDummy())

// THEN
result, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}})
assert.Error(t, err)
assert.False(t, result.Requeue)
assert.Equal(t, result.RequeueAfter, time.Second*15)

res := v1alpha1.AddonsConfiguration{}
err = ts.mgr.GetClient().Get(context.Background(), types.NamespacedName{Namespace: fixAddonsCfg.Namespace, Name: fixAddonsCfg.Name}, &res)
assert.NoError(t, err)
assert.Contains(t, res.Finalizers, v1alpha1.FinalizerAddonsConfiguration)
}

func fixRepositories() []v1alpha1.StatusRepository {
return []v1alpha1.StatusRepository{
{
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/broker/broker_facade.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const (
BrokerLabelValue = "true"
)

// Facade is responsible for creation k8s objects for namespaced broker
// Facade is responsible for creation k8s objects for namespaced broker. The Facade is not thread-safe.
type Facade struct {
client client.Client
systemNamespace string
Expand Down
111 changes: 111 additions & 0 deletions internal/controller/broker_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package controller

import (
"context"

"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1"
"github.com/kyma-project/helm-broker/internal/controller/broker"
"github.com/kyma-project/helm-broker/pkg/apis/addons/v1alpha1"
"k8s.io/apimachinery/pkg/types"
"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/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

// BrokerController is a controller which reacts on changes for ServiceInstance, ServiceBroker and AddonsConfiguration.
// Only this controller should create/delete ServiceBroker.
type BrokerController struct {
instanceChecker instanceChecker
cli client.Client

namespacedBrokerFacade brokerFacade
}

var createDeletePredicate = predicate.Funcs{
CreateFunc: func(_ event.CreateEvent) bool { return true },
DeleteFunc: func(_ event.DeleteEvent) bool { return true },
UpdateFunc: func(_ event.UpdateEvent) bool { return false },
}

var eventHandler = &handler.EnqueueRequestsFromMapFunc{
ToRequests: handler.ToRequestsFunc(
func(mp handler.MapObject) []reconcile.Request {
return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: mp.Meta.GetNamespace()}}}
},
)}

// NewBrokerController creates BrokerController instance.
func NewBrokerController(checker instanceChecker, cli client.Client, bFacade brokerFacade) *BrokerController {
return &BrokerController{
instanceChecker: checker,
cli: cli,
namespacedBrokerFacade: bFacade,
}
}

// Start starts the controller
func (sbc *BrokerController) Start(mgr manager.Manager) error {
// Create a new controller
c, err := controller.New("broker-controller", mgr, controller.Options{Reconciler: sbc})
if err != nil {
return err
}

// Watch for changes to ServiceInstance
err = c.Watch(&source.Kind{Type: &v1beta1.ServiceInstance{}}, eventHandler, createDeletePredicate)
if err != nil {
return err
}

err = c.Watch(&source.Kind{Type: &v1alpha1.AddonsConfiguration{}}, eventHandler, createDeletePredicate)
if err != nil {
return err
}

err = c.Watch(&source.Kind{Type: &v1beta1.ServiceBroker{}}, eventHandler, predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool { return e.Meta.GetName() == broker.NamespacedBrokerName },
Copy link

@jasiu001 jasiu001 Jan 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why here is permanent name helm-broker and cluster is set by configuration?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name of the namesaces ServiceBroker is set as a constant in the code. The ClusterServiceBroker is configurable

DeleteFunc: func(e event.DeleteEvent) bool { return e.Meta.GetName() == broker.NamespacedBrokerName },
UpdateFunc: func(_ event.UpdateEvent) bool { return false },
})
if err != nil {
return err
}

return nil
}

// Reconcile checks if the (cluster) service broker must be removed
func (sbc *BrokerController) Reconcile(request reconcile.Request) (reconcile.Result, error) {
currentNamespace := request.Namespace

sbc.namespacedBrokerFacade.SetNamespace(request.Namespace)
sbExists, err := sbc.namespacedBrokerFacade.Exist()
if err != nil {
return reconcile.Result{}, err
}
// list addons configurations
acList := v1alpha1.AddonsConfigurationList{}
err = sbc.cli.List(context.TODO(), &client.ListOptions{Namespace: currentNamespace}, &acList)
if err != nil {
return reconcile.Result{}, err
}
anyNamespacedConfigExists := len(acList.Items) > 0

instanceByNamespacedExists, err := sbc.instanceChecker.AnyServiceInstanceExistsForNamespacedServiceBroker(currentNamespace)
if err != nil {
return reconcile.Result{}, err
}
if sbExists && !anyNamespacedConfigExists && !instanceByNamespacedExists {
sbc.namespacedBrokerFacade.Delete()
}
if !sbExists && (anyNamespacedConfigExists || instanceByNamespacedExists) {
sbc.namespacedBrokerFacade.Create()
}

return reconcile.Result{}, nil
}
Loading