@@ -18,28 +18,37 @@ package controllerv2
1818
1919import (
2020 "context"
21+ "errors"
22+ "fmt"
2123
2224 "github.com/go-logr/logr"
25+ "k8s.io/apimachinery/pkg/runtime/schema"
2326 "k8s.io/client-go/tools/record"
2427 "k8s.io/klog/v2"
28+ "k8s.io/utils/ptr"
2529 ctrl "sigs.k8s.io/controller-runtime"
2630 "sigs.k8s.io/controller-runtime/pkg/client"
31+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2732
2833 kubeflowv2 "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v2alpha1"
29- runtime "github.com/kubeflow/training-operator/pkg/runtime.v2"
34+ jobruntimes "github.com/kubeflow/training-operator/pkg/runtime.v2"
3035)
3136
37+ var errorUnsupportedRuntime = errors .New ("the specified runtime is not supported" )
38+
3239type TrainJobReconciler struct {
3340 log logr.Logger
3441 client client.Client
3542 recorder record.EventRecorder
43+ runtimes map [string ]jobruntimes.Runtime
3644}
3745
38- func NewTrainJobReconciler (client client.Client , recorder record.EventRecorder ) * TrainJobReconciler {
46+ func NewTrainJobReconciler (client client.Client , recorder record.EventRecorder , runtimes map [ string ]jobruntimes. Runtime ) * TrainJobReconciler {
3947 return & TrainJobReconciler {
4048 log : ctrl .Log .WithName ("trainjob-controller" ),
4149 client : client ,
4250 recorder : recorder ,
51+ runtimes : runtimes ,
4352 }
4453}
4554
@@ -52,16 +61,74 @@ func (r *TrainJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
5261 return ctrl.Result {}, client .IgnoreNotFound (err )
5362 }
5463 log := ctrl .LoggerFrom (ctx ).WithValues ("trainJob" , klog .KObj (& trainJob ))
55- ctrl .LoggerInto (ctx , log )
64+ ctx = ctrl .LoggerInto (ctx , log )
5665 log .V (2 ).Info ("Reconciling TrainJob" )
66+ if err := r .createOrUpdateObjs (ctx , & trainJob ); err != nil {
67+ return ctrl.Result {}, err
68+ }
69+ // TODO (tenzen-y): Do update the status.
5770 return ctrl.Result {}, nil
5871}
5972
60- func (r * TrainJobReconciler ) SetupWithManager (mgr ctrl.Manager , runtimes map [string ]runtime.Runtime ) error {
73+ func (r * TrainJobReconciler ) createOrUpdateObjs (ctx context.Context , trainJob * kubeflowv2.TrainJob ) error {
74+ log := ctrl .LoggerFrom (ctx )
75+
76+ runtimeRefGK := runtimeRefToGroupKind (trainJob .Spec .RuntimeRef ).String ()
77+ runtime , ok := r .runtimes [runtimeRefGK ]
78+ if ! ok {
79+ return fmt .Errorf ("%w: %s" , errorUnsupportedRuntime , runtimeRefGK )
80+ }
81+ objs , err := runtime .NewObjects (ctx , trainJob )
82+ if err != nil {
83+ return err
84+ }
85+ for _ , obj := range objs {
86+ var gvk schema.GroupVersionKind
87+ if gvk , err = apiutil .GVKForObject (obj .DeepCopyObject (), r .client .Scheme ()); err != nil {
88+ return err
89+ }
90+ logKeysAndValues := []any {
91+ "groupVersionKind" , gvk .String (),
92+ "namespace" , obj .GetNamespace (),
93+ "name" , obj .GetName (),
94+ }
95+ // TODO (tenzen-y): Ideally, we should use the SSA instead of checking existence.
96+ // Non-empty resourceVersion indicates UPDATE operation.
97+ var creationErr error
98+ var created bool
99+ if obj .GetResourceVersion () == "" {
100+ creationErr = r .client .Create (ctx , obj )
101+ created = creationErr == nil
102+ }
103+ switch {
104+ case created :
105+ log .V (5 ).Info ("Succeeded to create object" , logKeysAndValues )
106+ continue
107+ case client .IgnoreAlreadyExists (creationErr ) != nil :
108+ return creationErr
109+ default :
110+ // This indicates CREATE operation has not been performed or the object has already existed in the cluster.
111+ if err = r .client .Update (ctx , obj ); err != nil {
112+ return err
113+ }
114+ log .V (5 ).Info ("Succeeded to update object" , logKeysAndValues )
115+ }
116+ }
117+ return nil
118+ }
119+
120+ func runtimeRefToGroupKind (runtimeRef kubeflowv2.RuntimeRef ) schema.GroupKind {
121+ return schema.GroupKind {
122+ Group : ptr .Deref (runtimeRef .APIGroup , "" ),
123+ Kind : ptr .Deref (runtimeRef .Kind , "" ),
124+ }
125+ }
126+
127+ func (r * TrainJobReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
61128 b := ctrl .NewControllerManagedBy (mgr ).
62129 For (& kubeflowv2.TrainJob {})
63- for _ , run := range runtimes {
64- for _ , registrar := range run .EventHandlerRegistrars () {
130+ for _ , runtime := range r . runtimes {
131+ for _ , registrar := range runtime .EventHandlerRegistrars () {
65132 if registrar != nil {
66133 b = registrar (b , mgr .GetClient ())
67134 }
0 commit comments