Skip to content

Commit a6acf94

Browse files
committed
[control-operator] hostname resolving in EnvironmentReconciler
Environment CRD controller needs a way how to resolve hostname passed from ECS to the one existing inside k8s cluster. ECS passes non fully qualified hostname, while kubernetes needs fully qualified hostname
1 parent db63560 commit a6acf94

2 files changed

Lines changed: 57 additions & 18 deletions

File tree

control-operator/ecs-manifests/environment/test_env.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ metadata:
66
taskTemplates:
77
tasks:
88
mtichak-ost.cern.ch:
9+
# mtichak-ost:
910
# mtichak-xps-cern:
1011
# - name: readout
1112
# argsCLI:
@@ -187,7 +188,8 @@ taskTemplates:
187188
spec:
188189
state: standby
189190
tasks:
190-
mtichak-ost.cern.ch:
191+
# mtichak-ost.cern.ch:
192+
mtichak-ost:
191193
- name: readout
192194
spec:
193195
pod:

control-operator/internal/controller/environment_controller.go

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type EnvironmentReconciler struct {
5353
}
5454

5555
func (r *EnvironmentReconciler) runTasksFromReferenceOnNode(ctx context.Context, taskReferences []aliecsv1alpha1.TaskReference,
56-
nodename string, req ctrl.Request, environment *aliecsv1alpha1.Environment, log logr.Logger,
56+
nodename string, resolvedNodename string, req ctrl.Request, environment *aliecsv1alpha1.Environment, log logr.Logger,
5757
) (*ctrl.Result, error) {
5858
for _, taskReference := range taskReferences {
5959
log.Info("geting stored template for task", "task", taskReference.Name)
@@ -106,7 +106,8 @@ func (r *EnvironmentReconciler) runTasksFromReferenceOnNode(ctx context.Context,
106106
task.Spec.Pod.Containers[0].Args = append(task.Spec.Pod.Containers[0].Args, taskReference.ArgsCLI...)
107107
maps.Copy(task.Spec.Arguments, taskReference.ArgsTransition)
108108

109-
task.Spec.Pod.NodeName = nodename
109+
task.Spec.Pod.NodeName = resolvedNodename
110+
task.Spec.NodeName = resolvedNodename
110111
task.Spec.State = environment.Spec.State
111112

112113
task.Labels = labels(environment, nodename)
@@ -128,7 +129,7 @@ func (r *EnvironmentReconciler) runTasksFromReferenceOnNode(ctx context.Context,
128129
}
129130

130131
func (r *EnvironmentReconciler) runTaskFromDefinitionOnNode(ctx context.Context, taskDefs []aliecsv1alpha1.TaskDefinition,
131-
nodename string, req ctrl.Request, environment *aliecsv1alpha1.Environment, log logr.Logger,
132+
nodename string, resolvedNodename string, req ctrl.Request, environment *aliecsv1alpha1.Environment, log logr.Logger,
132133
) (*ctrl.Result, error) {
133134
for _, taskDef := range taskDefs {
134135
task := &aliecsv1alpha1.Task{}
@@ -148,7 +149,8 @@ func (r *EnvironmentReconciler) runTaskFromDefinitionOnNode(ctx context.Context,
148149
maps.Copy(task.Spec.Arguments, taskDef.Spec.Arguments)
149150
}
150151

151-
task.Spec.Pod.NodeName = nodename
152+
task.Spec.Pod.NodeName = resolvedNodename
153+
task.Spec.NodeName = resolvedNodename
152154
task.Spec.State = environment.Spec.State
153155

154156
task.Labels = labels(environment, nodename)
@@ -246,24 +248,31 @@ func (r *EnvironmentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
246248
}
247249

248250
if environment.Status.State == "" {
251+
nodeNames, err := r.listAndParseNodes(ctx)
252+
if err != nil {
253+
return ctrl.Result{}, err
254+
}
255+
249256
for nodename, tasksReferences := range environment.TaskTemplates.Tasks {
250257
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
258+
resolvedName, err := resolveNodeName(nodeNames, nodename)
259+
if err != nil {
260+
return ctrl.Result{}, err
253261
}
254262

255-
if res, err := r.runTasksFromReferenceOnNode(ctx, tasksReferences, nodename, req, environment, log); res != nil {
263+
if res, err := r.runTasksFromReferenceOnNode(ctx, tasksReferences, nodename, resolvedName, req, environment, log); res != nil {
256264
return *res, err
257265
}
258266
}
259267

260268
for nodename, taskTemplates := range environment.Spec.Tasks {
261269
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
270+
resolvedName, err := resolveNodeName(nodeNames, nodename)
271+
if err != nil {
272+
return ctrl.Result{}, err
264273
}
265274

266-
if res, err := r.runTaskFromDefinitionOnNode(ctx, taskTemplates, nodename, req, environment, log); res != nil {
275+
if res, err := r.runTaskFromDefinitionOnNode(ctx, taskTemplates, nodename, resolvedName, req, environment, log); res != nil {
267276
return *res, err
268277
}
269278
}
@@ -311,15 +320,43 @@ func (r *EnvironmentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
311320
return ctrl.Result{}, nil
312321
}
313322

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)
323+
var filterList = []string{"cern", "ch"}
324+
325+
// listAndParseNodes asks k8s cluster for all nodes and it creates map out of them containing the node names
326+
// and also partial node names while filtering those from `filterList`, so map will contain following for example:
327+
// { "flp001.cern.ch": "flp001.cern.ch", "flp001": "flp001.cern.ch" }
328+
func (r *EnvironmentReconciler) listAndParseNodes(ctx context.Context) (map[string]string, error) {
329+
nodeList := &v1.NodeList{}
330+
nodeNames := make(map[string]string)
331+
if err := r.List(ctx, nodeList); err != nil {
332+
return nodeNames, fmt.Errorf("listing nodes: %w", err)
333+
}
334+
335+
for _, node := range nodeList.Items {
336+
if val, ok := nodeNames[node.Name]; ok {
337+
return nil, fmt.Errorf("duplicate node names %s and %s ", node.Name, val)
338+
}
339+
nodeNames[node.Name] = node.Name
340+
for _, nodePart := range strings.Split(node.Name, ".") {
341+
if !slices.Contains(filterList, nodePart) {
342+
if val, ok := nodeNames[nodePart]; ok {
343+
return nil, fmt.Errorf("duplicate partial node names %s and %s ", nodePart, val)
344+
}
345+
nodeNames[nodePart] = node.Name
346+
}
319347
}
320-
return ctrl.Result{}, err
321348
}
322-
return ctrl.Result{}, nil
349+
350+
return nodeNames, nil
351+
}
352+
353+
// resolveNodeNames checks created map in listAndParseNodes for any match
354+
func resolveNodeName(nodes map[string]string, nodename string) (string, error) {
355+
if res, ok := nodes[nodename]; !ok {
356+
return "", fmt.Errorf("node not in cluster: %s", nodename)
357+
} else {
358+
return res, nil
359+
}
323360
}
324361

325362
func aggregateState(tasks []aliecsv1alpha1.Task, previousState string) string {

0 commit comments

Comments
 (0)