Files
Abhijit MukherjeeandGitHub a211287670 Fix: validate non empty projects for delete (#154)
fix: validate non empty projects for delete

Signed-off-by: mabhi <abhijit.mukherjee@infracloud.io>
2023-02-20 11:50:00 +05:30

226 lines
5.7 KiB
Go

package reconcile
import (
"context"
"time"
"github.com/paralus/paralus/pkg/common"
"github.com/paralus/paralus/pkg/event"
"github.com/paralus/paralus/pkg/query"
"github.com/paralus/paralus/pkg/sentry/cryptoutil"
"github.com/paralus/paralus/pkg/service"
commonv3 "github.com/paralus/paralus/proto/types/commonpb/v3"
infrav3 "github.com/paralus/paralus/proto/types/infrapb/v3"
"github.com/uptrace/bun"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/workqueue"
)
const (
numClusterWorkers = 3
clusterEventHandleDuration = time.Second * 10
)
// ClusterEventHandler is the interface for handling cluster events
type ClusterEventHandler interface {
// ClusterHook should be registred in cluster service to listen on
// Cluster create/update/delete
ClusterHook() event.Handler
// ClusterWorkloadHook should be registered in cluster service to listen on
// Task/Namespace/Workload ready events
ClusterWorkloadHook() event.Handler
// AntiEntropyHook should be used to handle anti entropy for
// cluster
AntiEntropyHook() event.Handler
// Handle runs the placement event handler
Handle(stop <-chan struct{})
}
type clusterEventHandler struct {
cs service.ClusterService
// cluster work queue
cwq workqueue.RateLimitingInterface
// cluster workload work queue
wwq workqueue.RateLimitingInterface
// required for cluster event reconciler
db *bun.DB
bs service.BootstrapService
pf cryptoutil.PasswordFunc
}
// NewClusterEventHandler returns new cluster event handler
func NewClusterEventHandler(cs service.ClusterService, db *bun.DB, bs service.BootstrapService, pf cryptoutil.PasswordFunc) ClusterEventHandler {
return &clusterEventHandler{
cs: cs,
cwq: workqueue.NewRateLimitingQueue(workqueue.DefaultItemBasedRateLimiter()),
wwq: workqueue.NewRateLimitingQueue(workqueue.DefaultItemBasedRateLimiter()),
db: db,
bs: bs,
pf: pf,
}
}
func (h *clusterEventHandler) ClusterHook() event.Handler {
return event.HandlerFuncs{
OnChangeFunc: func(r event.Resource) {
h.cwq.Add(resourceToKey(r))
},
}
}
func (h *clusterEventHandler) ClusterWorkloadHook() event.Handler {
return event.HandlerFuncs{
OnChangeFunc: func(r event.Resource) {
h.wwq.Add(resourceToKey(r))
},
}
}
func (h *clusterEventHandler) AntiEntropyHook() event.Handler {
return event.HandlerFuncs{
OnChangeFunc: func(r event.Resource) {
h.cwq.Add(resourceToKey(r))
},
}
}
func (h *clusterEventHandler) processNextCluster() bool {
item, shutdown := h.cwq.Get()
if shutdown {
return false
}
defer h.cwq.Done(item)
ev := keyToResource(item.(string))
h.handleClusterEvent(ev)
return true
}
func (h *clusterEventHandler) runClusterWorker() {
for h.processNextCluster() {
}
}
func (h *clusterEventHandler) Handle(stop <-chan struct{}) {
for i := 0; i < numClusterWorkers; i++ {
go wait.Until(h.runClusterWorker, time.Second, stop)
go wait.Until(h.runClusterWorkloadWorker, time.Second, stop)
}
<-stop
}
func (h *clusterEventHandler) processNextClusterWorkload() bool {
item, shutdown := h.wwq.Get()
if shutdown {
return false
}
defer h.wwq.Done(item)
ev := keyToResource(item.(string))
h.handleClusterWorkloadEvent(ev)
return true
}
func (h *clusterEventHandler) runClusterWorkloadWorker() {
for h.processNextClusterWorkload() {
}
}
func (h *clusterEventHandler) handleClusterEvent(ev event.Resource) {
ctx, cancel := context.WithTimeout(context.Background(), clusterEventHandleDuration)
defer cancel()
var cluster *infrav3.Cluster
var err error
if ev.ID != "" {
cluster, err = h.cs.Select(ctx, &infrav3.Cluster{
Metadata: &commonv3.Metadata{Id: ev.ID, Project: ev.ProjectID},
}, true)
} else {
cluster, err = h.cs.Get(ctx,
query.WithName(ev.Name),
query.WithPartnerID(ev.PartnerID),
query.WithOrganizationID(ev.OrganizationID),
query.WithProjectID(ev.ProjectID),
)
}
if err != nil {
_log.Infow("unable to get cluster for event", "event", ev, "error", err)
return
}
//Update back the Ids
cluster.Metadata.Project = ev.ProjectID
cluster.Metadata.Organization = ev.OrganizationID
cluster.Metadata.Partner = ev.PartnerID
cluster.Metadata.Id = ev.ID
ctx = context.WithValue(ctx, common.SessionDataKey, &commonv3.SessionData{
Username: ev.Username,
Account: ev.Account,
})
_log.Debugw("handling cluster reconcile", "cluster", cluster.Metadata, "event", ev, "cluster status", cluster.Spec.ClusterData.ClusterStatus)
reconciler := NewClusterReconciler(h.cs, h.db, h.bs, h.pf)
err = reconciler.Reconcile(ctx, cluster)
if err != nil {
_log.Infow("unable to reconcile cluster", "error", err, "event", "ev")
return
}
_log.Debugw("successfully reconciled cluster for event", "event", ev)
}
func (h *clusterEventHandler) handleClusterWorkloadEvent(ev event.Resource) {
ctx, cancel := context.WithTimeout(context.Background(), clusterEventHandleDuration)
defer cancel()
var cluster *infrav3.Cluster
var err error
if ev.ID != "" {
cluster, err = h.cs.Select(ctx, &infrav3.Cluster{
Metadata: &commonv3.Metadata{Id: ev.ID, Project: ev.ProjectID},
}, true)
} else {
cluster, err = h.cs.Get(ctx,
query.WithName(ev.Name),
query.WithPartnerID(ev.PartnerID),
query.WithOrganizationID(ev.OrganizationID),
query.WithProjectID(ev.ProjectID),
)
}
if err != nil {
_log.Infow("unable to get cluster for event", "event", ev, "error", err)
return
}
_log.Debugw("handling cluster reconcile", "cluster", cluster.Metadata, "event", ev)
reconciler := NewClusterConditionReconciler(h.cs)
err = reconciler.Reconcile(ctx, cluster)
if err != nil {
_log.Infow("unable to reconcile cluster workload event", "error", err, "event", "ev")
return
}
_log.Debugw("successfully reconciled cluster workload event", "event", ev)
}