feet: add finalizer

This commit is contained in:
Seraj 2025-01-11 00:25:57 +03:30
parent 14aba80181
commit ef7b16af68
10 changed files with 101 additions and 29 deletions

View File

@ -2,7 +2,7 @@ package main
import ( import (
"flink-kube-operator/internal/crd" "flink-kube-operator/internal/crd"
"flink-kube-operator/internal/manager" "flink-kube-operator/internal/managed_job"
"flink-kube-operator/internal/rest" "flink-kube-operator/internal/rest"
"flink-kube-operator/pkg" "flink-kube-operator/pkg"
"log" "log"
@ -31,7 +31,7 @@ func main() {
pkg.Logger.Info("[main]", zap.Any("cluster-config", clusterConfig)) pkg.Logger.Info("[main]", zap.Any("cluster-config", clusterConfig))
// init flink job manager // init flink job manager
manager.NewManager(c, crdInstance) managed_job.NewManager(c, crdInstance)
// for _, jobDef := range config.Jobs { // for _, jobDef := range config.Jobs {
// managed_job.NewManagedJob(c, db, jobDef) // managed_job.NewManagedJob(c, db, jobDef)

View File

@ -1,14 +1,60 @@
package crd package crd
import ( import (
"context"
"flink-kube-operator/internal/crd/v1alpha1"
"flink-kube-operator/pkg"
"github.com/reactivex/rxgo/v2" "github.com/reactivex/rxgo/v2"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
) )
var FinalizerChannel chan (types.UID) = make(chan (types.UID))
func (crd Crd) manageFinalizer(jobEventObservable rxgo.Observable) { func (crd Crd) manageFinalizer(jobEventObservable rxgo.Observable) {
finalizerName := "flink-operator.logicamp.tech/finalizer"
for j := range jobEventObservable.Observe() { for j := range jobEventObservable.Observe() {
jobEvent := j.V.(*FlinkJobCrdEvent) jobEvent := j.V.(*FlinkJobCrdEvent)
//pkg.Logger.Debug("[crd] [manage-finalizer] adding finalizer for", zap.String("name", jobEvent.Job.GetName()))
controllerutil.AddFinalizer(jobEvent.Job, "") if jobEvent.Job.GetDeletionTimestamp() != nil {
// Resource is being deleted
if controllerutil.ContainsFinalizer(jobEvent.Job, finalizerName) {
// Perform cleanup
pkg.Logger.Debug("[finalizer] stopping managed job", zap.String("name", jobEvent.Job.GetName()))
if err := crd.cleanupResources(jobEvent.Job); err != nil {
pkg.Logger.Error("[crd] [manage-finalizer] cleanup failed", zap.Error(err))
return
}
// Remove finalizer
controllerutil.RemoveFinalizer(jobEvent.Job, finalizerName)
if err := crd.runtimeClient.Update(context.Background(), jobEvent.Job); err != nil {
pkg.Logger.Error("[crd] [manage-finalizer] failed to remove finalizer", zap.Error(err))
return
}
pkg.Logger.Debug("[crd] [manage-finalizer] job removed", zap.String("name", jobEvent.Job.GetName()))
}
return
}
// Add finalizer if not present
if !controllerutil.ContainsFinalizer(jobEvent.Job, finalizerName) {
controllerutil.AddFinalizer(jobEvent.Job, finalizerName)
pkg.Logger.Debug("[finalizer] adding job")
// Update the resource to add the finalizer
if err := crd.runtimeClient.Update(context.Background(), jobEvent.Job); err != nil {
pkg.Logger.Error("[finalizer] failed to add", zap.Error(err))
return
} }
} }
}
}
func (crd Crd) cleanupResources(job *v1alpha1.FlinkJob) error {
FinalizerChannel <- job.GetUID()
return nil
}

View File

@ -3,36 +3,48 @@ package crd
import ( import (
"flink-kube-operator/internal/crd/v1alpha1" "flink-kube-operator/internal/crd/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
) )
type Crd struct { type Crd struct {
client dynamic.NamespaceableResourceInterface client dynamic.NamespaceableResourceInterface
runtimeClient client.Client
} }
func New() *Crd { func New() *Crd {
// Get Kubernetes config // Get Kubernetes config_
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile) config_, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil { if err != nil {
config, err = rest.InClusterConfig() config_, err = rest.InClusterConfig()
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
// Create dynamic client // Create dynamic client
dynamicClient, err := dynamic.NewForConfig(config) dynamicClient, err := dynamic.NewForConfig(config_)
if err != nil { if err != nil {
panic(err) panic(err)
} }
shema := runtime.NewScheme()
v1alpha1.AddKnownTypes(shema)
// Get FlinkJob resource interface // Get FlinkJob resource interface
flinkJobClient := dynamicClient.Resource(v1alpha1.FlinkJobGVR) flinkJobClient := dynamicClient.Resource(v1alpha1.FlinkJobGVR)
runtimeClient, err := client.New(config.GetConfigOrDie(), client.Options{
Scheme: shema,
})
if err != nil {
panic(err)
}
crd := Crd{ crd := Crd{
client: flinkJobClient, client: flinkJobClient,
runtimeClient: runtimeClient,
} }
// Watch for FlinkJob creation // Watch for FlinkJob creation

View File

@ -14,7 +14,7 @@ import (
func (crd *Crd) Patch(jobUid types.UID, patchData map[string]interface{}) error { func (crd *Crd) Patch(jobUid types.UID, patchData map[string]interface{}) error {
job := GetJob(jobUid) job := GetJob(jobUid)
pkg.Logger.Debug("[patch-job]", zap.Any("jobUid", jobUid)) // pkg.Logger.Debug("[patch-job]", zap.Any("jobUid", jobUid))
patchBytes, err := json.Marshal(patchData) patchBytes, err := json.Marshal(patchData)
if err != nil { if err != nil {

View File

@ -14,6 +14,10 @@ func (crd *Crd) repsert(job *v1alpha1.FlinkJob) {
jobs.Store(job.GetUID(), job) jobs.Store(job.GetUID(), job)
} }
func (crd *Crd) remove(uid types.UID) {
jobs.Delete(uid)
}
func GetJob(uid types.UID) v1alpha1.FlinkJob { func GetJob(uid types.UID) v1alpha1.FlinkJob {
job, _ := jobs.Load(uid) job, _ := jobs.Load(uid)
return *job.DeepCopy() return *job.DeepCopy()

View File

@ -20,11 +20,11 @@ var FlinkJobGVR = schema.GroupVersionResource{
} }
var ( var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) SchemeBuilder = runtime.NewSchemeBuilder(AddKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme AddToScheme = SchemeBuilder.AddToScheme
) )
func addKnownTypes(scheme *runtime.Scheme) error { func AddKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion, scheme.AddKnownTypes(SchemeGroupVersion,
&FlinkJob{}, &FlinkJob{},
&FlinkJobList{}, &FlinkJobList{},

View File

@ -56,6 +56,8 @@ func (crd Crd) watchFlinkJobs() rxgo.Observable {
//pkg.Logger.Info("[crd] [watch] new flink job created") //pkg.Logger.Info("[crd] [watch] new flink job created")
crd.repsert(job) crd.repsert(job)
case watch.Deleted: case watch.Deleted:
crd.remove(job.UID)
} }
} }

View File

@ -10,7 +10,7 @@ import (
) )
func (job *ManagedJob) Cycle() { func (job *ManagedJob) Cycle() {
pkg.Logger.Debug("[managed-job] [new] check cycle", zap.String("jobName", job.def.GetName())) // pkg.Logger.Debug("[managed-job] [new] check cycle", zap.String("jobName", job.def.GetName()))
// Init job // Init job
if job.def.Status.LifeCycleStatus == "" && job.def.Status.JobStatus == "" { if job.def.Status.LifeCycleStatus == "" && job.def.Status.JobStatus == "" {

View File

@ -1,9 +1,8 @@
package manager package managed_job
import ( import (
"flink-kube-operator/internal/crd" "flink-kube-operator/internal/crd"
"flink-kube-operator/internal/crd/v1alpha1" "flink-kube-operator/internal/crd/v1alpha1"
"flink-kube-operator/internal/managed_job"
"time" "time"
"flink-kube-operator/pkg" "flink-kube-operator/pkg"
@ -16,7 +15,7 @@ import (
type Manager struct { type Manager struct {
client *api.Client client *api.Client
managedJobs map[types.UID]managed_job.ManagedJob managedJobs map[types.UID]ManagedJob
processingJobsIds []types.UID processingJobsIds []types.UID
} }
@ -31,7 +30,7 @@ func NewManager(client *api.Client, crdInstance *crd.Crd) Manager {
quit := make(chan struct{}) quit := make(chan struct{})
mgr = Manager{ mgr = Manager{
client: client, client: client,
managedJobs: map[types.UID]managed_job.ManagedJob{}, managedJobs: map[types.UID]ManagedJob{},
processingJobsIds: []types.UID{}, processingJobsIds: []types.UID{},
} }
@ -47,6 +46,15 @@ func NewManager(client *api.Client, crdInstance *crd.Crd) Manager {
} }
} }
}() }()
go func() {
for event := range crd.FinalizerChannel {
manager := mgr.GetJob(event)
manager.Stop()
delete(mgr.managedJobs, event)
}
}()
return mgr return mgr
} }
@ -64,7 +72,7 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
// Loop over job definitions as Kubernetes CRD // Loop over job definitions as Kubernetes CRD
for _, uid := range crd.GetAllJobKeys() { for _, uid := range crd.GetAllJobKeys() {
pkg.Logger.Debug("mgr.processingJobsIds", zap.Any("processingJobIds", mgr.processingJobsIds)) // pkg.Logger.Debug("mgr.processingJobsIds", zap.Any("processingJobIds", mgr.processingJobsIds))
if lo.Contains(mgr.processingJobsIds, uid) { if lo.Contains(mgr.processingJobsIds, uid) {
pkg.Logger.Warn("[manager] already in process", zap.Any("uid", uid)) pkg.Logger.Warn("[manager] already in process", zap.Any("uid", uid))
continue continue
@ -80,7 +88,7 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
managedJob.Update(def) managedJob.Update(def)
} else { } else {
// Add job to manager managed job // Add job to manager managed job
managedJob = *managed_job.NewManagedJob(client, def, crdInstance) managedJob = *NewManagedJob(client, def, crdInstance)
} }
if jobManagerJobStatusError != nil { if jobManagerJobStatusError != nil {
@ -94,7 +102,7 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
return false return false
}) })
if ok { if ok {
pkg.Logger.Debug("[manager] read status from flink", zap.String("name", jobManagerJobOverview.Name), zap.String("state", jobManagerJobOverview.State)) // pkg.Logger.Debug("[manager] read status from flink", zap.String("name", jobManagerJobOverview.Name), zap.String("state", jobManagerJobOverview.State))
patchStatusObj := map[string]interface{}{ patchStatusObj := map[string]interface{}{
"jobStatus": v1alpha1.JobStatus(jobManagerJobOverview.State), "jobStatus": v1alpha1.JobStatus(jobManagerJobOverview.State),
} }
@ -117,10 +125,10 @@ func (mgr *Manager) cycle(client *api.Client, crdInstance *crd.Crd) {
} }
} }
func (mgr *Manager) GetJobs() map[types.UID]managed_job.ManagedJob { func (mgr *Manager) GetJobs() map[types.UID]ManagedJob {
return mgr.managedJobs return mgr.managedJobs
} }
func (mgr *Manager) GetJob(id types.UID) managed_job.ManagedJob { func (mgr *Manager) GetJob(id types.UID) ManagedJob {
return mgr.managedJobs[id] return mgr.managedJobs[id]
} }

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"flink-kube-operator/internal/crd" "flink-kube-operator/internal/crd"
"flink-kube-operator/internal/crd/v1alpha1" "flink-kube-operator/internal/crd/v1alpha1"
"flink-kube-operator/internal/manager" "flink-kube-operator/internal/managed_job"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
) )
@ -39,7 +39,7 @@ type StopJobResp struct {
} }
func StopJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) { func StopJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
mgr := manager.GetManager() mgr := managed_job.GetManager()
job := mgr.GetJob(types.UID(req.JobUId)) job := mgr.GetJob(types.UID(req.JobUId))
err := job.Stop() err := job.Stop()
if err != nil { if err != nil {
@ -51,7 +51,7 @@ func StopJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
} }
func StartJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) { func StartJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
mgr := manager.GetManager() mgr := managed_job.GetManager()
job := mgr.GetJob(types.UID(req.JobUId)) job := mgr.GetJob(types.UID(req.JobUId))
err := job.Run(true) err := job.Run(true)
if err != nil { if err != nil {
@ -63,7 +63,7 @@ func StartJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
} }
func RemoveJobJar(ctx context.Context, req *StopJobReq) (*StopJobResp, error) { func RemoveJobJar(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
mgr := manager.GetManager() mgr := managed_job.GetManager()
job := mgr.GetJob(types.UID(req.JobUId)) job := mgr.GetJob(types.UID(req.JobUId))
job.RemoveJar() job.RemoveJar()
return &StopJobResp{Body: StopJobRespBody{ return &StopJobResp{Body: StopJobRespBody{
@ -72,7 +72,7 @@ func RemoveJobJar(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
} }
func PauseJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) { func PauseJob(ctx context.Context, req *StopJobReq) (*StopJobResp, error) {
mgr := manager.GetManager() mgr := managed_job.GetManager()
job := mgr.GetJob(types.UID(req.JobUId)) job := mgr.GetJob(types.UID(req.JobUId))
job.Pause() job.Pause()
return &StopJobResp{Body: StopJobRespBody{ return &StopJobResp{Body: StopJobRespBody{