Skip to content

Commit 0bc7f08

Browse files
committed
Ensure consistent dnsname --> IMEXDaemonIP mapping on all nodes
Without this the IMEX daemons were getting confused if the same DNS name was used to by different nodes to point to differernt IMEX daemons in the ensemble. Signed-off-by: Kevin Klues <[email protected]>
1 parent a92b36e commit 0bc7f08

File tree

6 files changed

+75
-26
lines changed

6 files changed

+75
-26
lines changed

api/nvidia.com/resource/v1beta1/computedomain.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ type ComputeDomainNode struct {
9191
Name string `json:"name"`
9292
IPAddress string `json:"ipAddress"`
9393
CliqueID string `json:"cliqueID"`
94+
// The Index field is used to ensure a consistent IP-to-DNS name
95+
// mapping across all machines within a given IMEX domain. Each node's
96+
// index directly determines its DNS name. It is marked as optional in
97+
// order to support downgrades and avoid an API bump.
98+
Index int `json:"index,omitempty"`
9499
}

cmd/compute-domain-daemon/computedomain.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,16 @@ func (m *ComputeDomainManager) UpdateComputeDomainNodeInfo(ctx context.Context,
218218

219219
// If there isn't one, create one and append it to the list
220220
if nodeInfo == nil {
221+
// Get the next available index for this new node
222+
nextIndex, err := getNextAvailableIndex(newCD.Status.Nodes, m.config.maxNodesPerIMEXDomain)
223+
if err != nil {
224+
return fmt.Errorf("error getting next available index: %w", err)
225+
}
226+
221227
nodeInfo = &nvapi.ComputeDomainNode{
222228
Name: m.config.nodeName,
223229
CliqueID: m.config.cliqueID,
230+
Index: nextIndex,
224231
}
225232
newCD.Status.Nodes = append(newCD.Status.Nodes, nodeInfo)
226233
}
@@ -243,6 +250,46 @@ func (m *ComputeDomainManager) UpdateComputeDomainNodeInfo(ctx context.Context,
243250
return nil
244251
}
245252

253+
// The Index field in the Nodes section of the ComputeDomain status ensures a
254+
// consistent IP-to-DNS name mapping across all machines within a given IMEX
255+
// domain. Each node's index directly determines its DNS name using the format
256+
// "compute-domain-daemon-{index}".
257+
//
258+
// getNextAvailableIndex finds the next available index for the current node by
259+
// seeing which ones are already taken by other nodes in the ComputeDomain
260+
// status. It fills in gaps where it can, and returns an error if no index is
261+
// available within maxNodesPerIMEXDomain.
262+
//
263+
// By filling gaps in the index sequence (rather than always appending), we
264+
// maintain stable DNS names for existing nodes even when intermediate nodes
265+
// are removed from the compute domain and new ones are added.
266+
func getNextAvailableIndex(nodes []*nvapi.ComputeDomainNode, maxNodesPerIMEXDomain int) (int, error) {
267+
if len(nodes) >= maxNodesPerIMEXDomain {
268+
return -1, fmt.Errorf("cannot add more nodes, already at maximum (%d)", maxNodesPerIMEXDomain)
269+
}
270+
271+
// Create a map to track used indices
272+
usedIndices := make(map[int]bool)
273+
274+
// Collect all currently used indices
275+
for _, node := range nodes {
276+
usedIndices[node.Index] = true
277+
}
278+
279+
// Find the next available index, starting from 0 and filling gaps
280+
nextIndex := 0
281+
for usedIndices[nextIndex] {
282+
nextIndex++
283+
}
284+
285+
// Ensure nextIndex is within the range 0..maxNodesPerIMEXDomain
286+
if nextIndex < 0 || nextIndex >= maxNodesPerIMEXDomain {
287+
return -1, fmt.Errorf("no available indices within maxNodesPerIMEXDomain (%d)", maxNodesPerIMEXDomain)
288+
}
289+
290+
return nextIndex, nil
291+
}
292+
246293
// If we've reached the expected number of nodes and if there was actually a
247294
// change compared to the previously known set of nodes: pass info to IMEX
248295
// daemon controller.

cmd/compute-domain-daemon/controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type ManagerConfig struct {
3535
computeDomainNamespace string
3636
cliqueID string
3737
podIP string
38+
maxNodesPerIMEXDomain int
3839
}
3940

4041
// ControllerConfig holds the configuration for the controller.
@@ -45,6 +46,7 @@ type ControllerConfig struct {
4546
computeDomainNamespace string
4647
cliqueID string
4748
podIP string
49+
maxNodesPerIMEXDomain int
4850
}
4951

5052
// Controller manages the lifecycle of compute domain operations.
@@ -73,6 +75,7 @@ func NewController(config *ControllerConfig) (*Controller, error) {
7375
computeDomainNamespace: config.computeDomainNamespace,
7476
cliqueID: config.cliqueID,
7577
podIP: config.podIP,
78+
maxNodesPerIMEXDomain: config.maxNodesPerIMEXDomain,
7679
}
7780

7881
controller := &Controller{

cmd/compute-domain-daemon/dnsnames.go

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,15 @@ func (m *DNSNameManager) UpdateDNSNameMappings(nodes []*nvapi.ComputeDomainNode)
8484
}
8585
}
8686

87-
// Add new IPs to map (filling in holes where others were removed)
87+
// Add new IPs to map
8888
for _, node := range cliqueNodes {
8989
// If IP already has a DNS name, skip it
9090
if _, exists := ipToDNSName[node.IPAddress]; exists {
9191
continue
9292
}
9393

94-
dnsName, err := m.allocateDNSName(node.IPAddress)
94+
// Construct the DNS name from the node index
95+
dnsName, err := m.constructDNSName(node)
9596
if err != nil {
9697
return fmt.Errorf("failed to allocate DNS name for IP %s: %w", node.IPAddress, err)
9798
}
@@ -128,32 +129,17 @@ func (m *DNSNameManager) LogDNSNameMappings() {
128129
}
129130
}
130131

131-
// allocateDNSName allocates a DNS name for an IP address, reusing existing DNS names if possible.
132-
func (m *DNSNameManager) allocateDNSName(ip string) (string, error) {
133-
// If IP already has a DNS name, return it
134-
if dnsName, exists := m.ipToDNSName[ip]; exists {
135-
return dnsName, nil
132+
// contructDNSName constructs a DNS name for a node based on its index field.
133+
// Returns an error if the index is invalid or exceeds maxNodesPerIMEXDomain.
134+
func (m *DNSNameManager) constructDNSName(node *nvapi.ComputeDomainNode) (string, error) {
135+
if node.Index < 0 {
136+
return "", fmt.Errorf("node %s has invalid index %d", node.Name, node.Index)
136137
}
137-
138-
// Find the next available DNS name
139-
for i := 0; i < m.maxNodesPerIMEXDomain; i++ {
140-
dnsName := fmt.Sprintf(dnsNameFormat, i)
141-
// Check if this DNS name is already in use
142-
inUse := false
143-
for _, existingDNSName := range m.ipToDNSName {
144-
if existingDNSName == dnsName {
145-
inUse = true
146-
break
147-
}
148-
}
149-
if !inUse {
150-
m.ipToDNSName[ip] = dnsName
151-
return dnsName, nil
152-
}
138+
if node.Index >= m.maxNodesPerIMEXDomain {
139+
return "", fmt.Errorf("node %s has invalid index %d, must be less than %d", node.Name, node.Index, m.maxNodesPerIMEXDomain)
153140
}
154-
155-
// If all DNS names are used, return an error
156-
return "", fmt.Errorf("no DNS names available (max: %d)", m.maxNodesPerIMEXDomain)
141+
dnsName := fmt.Sprintf(dnsNameFormat, node.Index)
142+
return dnsName, nil
157143
}
158144

159145
// updateHostsFile updates the /etc/hosts file with current IP to DNS name mappings.

cmd/compute-domain-daemon/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ func run(ctx context.Context, cancel context.CancelFunc, flags *Flags) error {
182182
computeDomainNamespace: flags.computeDomainNamespace,
183183
nodeName: flags.nodeName,
184184
podIP: flags.podIP,
185+
maxNodesPerIMEXDomain: flags.maxNodesPerIMEXDomain,
185186
}
186187
klog.Infof("config: %v", config)
187188

deployments/helm/nvidia-dra-driver-gpu/crds/resource.nvidia.com_computedomains.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ spec:
8585
properties:
8686
cliqueID:
8787
type: string
88+
index:
89+
description: |-
90+
The Index field is used to ensure a consistent IP-to-DNS name
91+
mapping across all machines within a given IMEX domain. Each node's
92+
index directly determines its DNS name. It is marked as optional in
93+
order to support downgrades and avoid an API bump.
94+
type: integer
8895
ipAddress:
8996
type: string
9097
name:

0 commit comments

Comments
 (0)