Skip to content

Commit 972cd01

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 5da35e9 commit 972cd01

File tree

6 files changed

+67
-26
lines changed

6 files changed

+67
-26
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,5 @@ type ComputeDomainNode struct {
9191
Name string `json:"name"`
9292
IPAddress string `json:"ipAddress"`
9393
CliqueID string `json:"cliqueID"`
94+
Index int `json:"index"`
9495
}

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
@@ -83,14 +83,15 @@ func (m *DNSNameManager) UpdateDNSNameMappings(nodes []*nvapi.ComputeDomainNode)
8383
}
8484
}
8585

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

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

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

158144
// 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,15 @@ spec:
8585
properties:
8686
cliqueID:
8787
type: string
88+
index:
89+
type: integer
8890
ipAddress:
8991
type: string
9092
name:
9193
type: string
9294
required:
9395
- cliqueID
96+
- index
9497
- ipAddress
9598
- name
9699
type: object

0 commit comments

Comments
 (0)