@@ -30,6 +30,7 @@ import (
3030 "maps"
3131 "slices"
3232 "strconv"
33+ "strings"
3334
3435 v1 "k8s.io/api/core/v1"
3536 k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -53,7 +54,7 @@ type EnvironmentReconciler struct {
5354}
5455
5556func (r * EnvironmentReconciler ) runTasksFromReferenceOnNode (ctx context.Context , taskReferences []aliecsv1alpha1.TaskReference ,
56- nodename string , req ctrl.Request , environment * aliecsv1alpha1.Environment , log logr.Logger ,
57+ nodename string , resolvedNodename string , req ctrl.Request , environment * aliecsv1alpha1.Environment , log logr.Logger ,
5758) (* ctrl.Result , error ) {
5859 for _ , taskReference := range taskReferences {
5960 log .Info ("geting stored template for task" , "task" , taskReference .Name )
@@ -85,31 +86,44 @@ func (r *EnvironmentReconciler) runTasksFromReferenceOnNode(ctx context.Context,
8586
8687 // TODO: regarding error handling. Is it correct to stop while handling one task? this will fail the whole deployment,
8788 // which might not be desirable outcome especially for non-critical tasks
88- if foundIdx := slices .IndexFunc (taskReference .Env , func (envVar v1.EnvVar ) bool { return envVar .Name == "OCC_CONTROL_PORT" }); foundIdx == - 1 {
89- log .Error (fmt .Errorf ("didn't find OCC_CONTROL_PORT in env" ), "failed to fill in env vars from template" )
90- return & reconcile.Result {}, nil
91- } else {
92- port , err := strconv .Atoi (taskReference .Env [foundIdx ].Value )
93- if err != nil {
94- log .Error (fmt .Errorf ("found OCC_CONTROL_PORT isn't convertible to number " ), "failed to fill in env vars from template" )
95- return & reconcile.Result {}, nil
96- }
97- task .Spec .Control .Port = port
98- }
89+ task .Spec .Control .Port = template .Spec .Control .Port
9990
10091 if task .Spec .Arguments == nil {
10192 task .Spec .Arguments = make (map [string ]string )
10293 }
10394
10495 // TODO: check for containers!
105- task .Spec .Pod .Containers [0 ].Env = append (task .Spec .Pod .Containers [0 ].Env , taskReference .Env ... )
96+ existing := make (map [string ]int , len (task .Spec .Pod .Containers [0 ].Env ))
97+ for i , e := range task .Spec .Pod .Containers [0 ].Env {
98+ existing [e .Name ] = i
99+ }
100+ for _ , e := range taskReference .Env {
101+ if i , ok := existing [e .Name ]; ok {
102+ task .Spec .Pod .Containers [0 ].Env [i ] = e
103+ } else {
104+ task .Spec .Pod .Containers [0 ].Env = append (task .Spec .Pod .Containers [0 ].Env , e )
105+ }
106+ }
106107 task .Spec .Pod .Containers [0 ].Args = append (task .Spec .Pod .Containers [0 ].Args , taskReference .ArgsCLI ... )
108+
109+ for _ , envVar := range task .Spec .Pod .Containers [0 ].Env {
110+ if envVar .Name == "OCC_CONTROL_PORT" {
111+ if port , err := strconv .Atoi (envVar .Value ); err == nil {
112+ task .Spec .Control .Port = port
113+ }
114+ break
115+ }
116+ }
107117 maps .Copy (task .Spec .Arguments , taskReference .ArgsTransition )
108118
109- task .Spec .Pod .NodeName = nodename
119+ task .Spec .Pod .NodeName = resolvedNodename
120+ task .Spec .NodeName = resolvedNodename
110121 task .Spec .State = environment .Spec .State
111122
112123 task .Labels = labels (environment , nodename )
124+ if taskReference .TaskID != "" {
125+ task .Labels ["taskID" ] = taskReference .TaskID
126+ }
113127
114128 if err := controllerutil .SetControllerReference (environment , task , r .Scheme ); err != nil {
115129 log .Error (err , "failed to set controller reference" , "task" , task .Name )
@@ -128,7 +142,7 @@ func (r *EnvironmentReconciler) runTasksFromReferenceOnNode(ctx context.Context,
128142}
129143
130144func (r * EnvironmentReconciler ) runTaskFromDefinitionOnNode (ctx context.Context , taskDefs []aliecsv1alpha1.TaskDefinition ,
131- nodename string , req ctrl.Request , environment * aliecsv1alpha1.Environment , log logr.Logger ,
145+ nodename string , resolvedNodename string , req ctrl.Request , environment * aliecsv1alpha1.Environment , log logr.Logger ,
132146) (* ctrl.Result , error ) {
133147 for _ , taskDef := range taskDefs {
134148 task := & aliecsv1alpha1.Task {}
@@ -148,7 +162,8 @@ func (r *EnvironmentReconciler) runTaskFromDefinitionOnNode(ctx context.Context,
148162 maps .Copy (task .Spec .Arguments , taskDef .Spec .Arguments )
149163 }
150164
151- task .Spec .Pod .NodeName = nodename
165+ task .Spec .Pod .NodeName = resolvedNodename
166+ task .Spec .NodeName = resolvedNodename
152167 task .Spec .State = environment .Spec .State
153168
154169 task .Labels = labels (environment , nodename )
@@ -246,24 +261,31 @@ func (r *EnvironmentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
246261 }
247262
248263 if environment .Status .State == "" {
264+ nodeList := & v1.NodeList {}
265+ if err := r .List (ctx , nodeList ); err != nil {
266+ return ctrl.Result {}, fmt .Errorf ("listing nodes: %w" , err )
267+ }
268+
249269 for nodename , tasksReferences := range environment .TaskTemplates .Tasks {
250270 log .Info ("creating tasks for hostname from references" , "hostname" , nodename , "number of tasks" , len (tasksReferences ))
251- if res , err := r .checkNodeExistence (ctx , nodename ); err != nil {
252- return res , err
271+ resolvedName , err := resolveNodeName (nodeList .Items , nodename )
272+ if err != nil {
273+ return ctrl.Result {}, err
253274 }
254275
255- if res , err := r .runTasksFromReferenceOnNode (ctx , tasksReferences , nodename , req , environment , log ); res != nil {
276+ if res , err := r .runTasksFromReferenceOnNode (ctx , tasksReferences , nodename , resolvedName , req , environment , log ); res != nil {
256277 return * res , err
257278 }
258279 }
259280
260281 for nodename , taskTemplates := range environment .Spec .Tasks {
261282 log .Info ("creating tasks for hostname from definitions" , "hostname" , nodename , "number of tasks" , len (taskTemplates ))
262- if res , err := r .checkNodeExistence (ctx , nodename ); err != nil {
263- return res , err
283+ resolvedName , err := resolveNodeName (nodeList .Items , nodename )
284+ if err != nil {
285+ return ctrl.Result {}, err
264286 }
265287
266- if res , err := r .runTaskFromDefinitionOnNode (ctx , taskTemplates , nodename , req , environment , log ); res != nil {
288+ if res , err := r .runTaskFromDefinitionOnNode (ctx , taskTemplates , nodename , resolvedName , req , environment , log ); res != nil {
267289 return * res , err
268290 }
269291 }
@@ -311,15 +333,28 @@ func (r *EnvironmentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
311333 return ctrl.Result {}, nil
312334}
313335
314- func (r * EnvironmentReconciler ) checkNodeExistence (ctx context.Context , nodename string ) (ctrl.Result , error ) {
315- node := & v1.Node {}
316- if err := r .Get (ctx , types.NamespacedName {Name : nodename }, node ); err != nil {
317- if k8serrors .IsNotFound (err ) {
318- return ctrl.Result {}, fmt .Errorf ("node %s not found in cluster" , nodename )
336+ // resolveNodeName resolves a short node name (e.g. "flp001") to the full name known to
337+ // the cluster (e.g. "flp001.cern.ch") by checking whether any dot-separated component
338+ // of a node's name matches exactly. Returns an error if zero or more than one node matches.
339+ func resolveNodeName (nodes []v1.Node , nodename string ) (string , error ) {
340+ var matches []string
341+ for _ , node := range nodes {
342+ for _ , part := range strings .Split (node .Name , "." ) {
343+ if part == nodename {
344+ matches = append (matches , node .Name )
345+ break
346+ }
319347 }
320- return ctrl.Result {}, err
321348 }
322- return ctrl.Result {}, nil
349+
350+ switch len (matches ) {
351+ case 0 :
352+ return "" , fmt .Errorf ("node %q not found in cluster" , nodename )
353+ case 1 :
354+ return matches [0 ], nil
355+ default :
356+ return "" , fmt .Errorf ("node name %q is ambiguous, matched: %v" , nodename , matches )
357+ }
323358}
324359
325360func aggregateState (tasks []aliecsv1alpha1.Task , previousState string ) string {
0 commit comments