Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 57 additions & 10 deletions proxmox/resource_vm_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const (
schemaAgentTimeout = "agent_timeout"
schemaSkipIPv4 = "skip_ipv4"
schemaSkipIPv6 = "skip_ipv6"
schemaPrimaryNetwork = "primary_network"
)

func resourceVmQemu() *schema.Resource {
Expand Down Expand Up @@ -499,6 +500,11 @@ func resourceVmQemu() *schema.Resource {
Default: false,
ConflictsWith: []string{schemaSkipIPv4},
},
schemaPrimaryNetwork: {
Type: schema.TypeInt,
Optional: true,
Description: "The index or ID of the network interface to use for IP address discovery. If set to a positive number N, it selects the Nth network interface. If set to a specific interface ID (e.g., 7 for net7), it uses that interface. If set to -1, it tries all available interfaces. If not set or set to 0, the primary interface is used.",
},
"reboot_required": {
Type: schema.TypeBool,
Computed: true,
Expand Down Expand Up @@ -1398,7 +1404,9 @@ func initConnInfo(ctx context.Context, d *schema.ResourceData, client *pveSDK.Cl
ciAgentEnabled,
d.Get(schemaSkipIPv4).(bool),
d.Get(schemaSkipIPv6).(bool),
hasCiDisk)
hasCiDisk,
d.Get(schemaPrimaryNetwork).(int),
)
if len(agentDiags) > 0 {
diags = append(diags, agentDiags...)
}
Expand Down Expand Up @@ -1436,7 +1444,8 @@ func getPrimaryIP(
networks pveSDK.QemuNetworkInterfaces,
vmr *pveSDK.VmRef,
retryDuration, retryInterval time.Duration,
ciAgentEnabled, skipIPv4, skipIPv6, hasCiDisk bool) (primaryIPs, diag.Diagnostics) {
ciAgentEnabled, skipIPv4, skipIPv6, hasCiDisk bool,
primaryNetwork int) (primaryIPs, diag.Diagnostics) {
logger, _ := CreateSubLogger("getPrimaryIP")
// TODO allow the primary interface to be a different one than the first

Expand All @@ -1452,9 +1461,10 @@ func getPrimaryIP(
if cloudInit.Custom != nil && cloudInit.Custom.Network != nil {
cicustom = true
}

conn = parseCloudInitInterface(cloudInit.NetworkInterfaces[pveSDK.QemuNetworkInterfaceID0], cicustom, conn.SkipIPv4, conn.SkipIPv6)
// early return, we have all information we wanted
if conn.hasRequiredIP() {
if conn.hasRequiredIP() && primaryNetwork == 0 {
if conn.IPs.IPv4 == "" && conn.IPs.IPv6 == "" {
return primaryIPs{}, diag.Diagnostics{diag.Diagnostic{
Severity: diag.Warning,
Expand All @@ -1473,16 +1483,40 @@ func getPrimaryIP(
if !ciAgentEnabled {
return conn.IPs, diag.Diagnostics{}
}

// get all information we can from qemu agent until the timer runs out
var (
primaryMacAddress net.HardwareAddr
err error
)
for i := 0; i < network.AmountNetworkInterfaces; i++ {
if v, ok := networks[pveSDK.QemuNetworkInterfaceID(i)]; ok && v.MAC != nil {

// Determine which network interface to use based on primaryNetwork setting
if primaryNetwork == 0 {
// Use primary interface
for i := 0; i < network.AmountNetworkInterfaces; i++ {
if v, ok := networks[pveSDK.QemuNetworkInterfaceID(i)]; ok && v.MAC != nil {
primaryMacAddress = *v.MAC
break
}
}
} else if primaryNetwork == -1 {
// primaryMacAddress will remain nil, which will trigger the "try all interfaces" logic
} else if primaryNetwork > 0 {
// primaryNetwork is either an index (Nth interface) or a specific interface ID
// First, try to find it as a specific interface ID
if v, ok := networks[pveSDK.QemuNetworkInterfaceID(primaryNetwork)]; ok && v.MAC != nil {
primaryMacAddress = *v.MAC
break
} else {
// If not found as specific ID, treat it as Nth interface (1-based index)
interfaceCount := 0
for i := 0; i < network.AmountNetworkInterfaces; i++ {
if v, ok := networks[pveSDK.QemuNetworkInterfaceID(i)]; ok && v.MAC != nil {
interfaceCount++
if interfaceCount == primaryNetwork {
primaryMacAddress = *v.MAC
break
}
}
}
}
}
endTime := time.Now().Add(retryDuration)
Expand All @@ -1503,9 +1537,22 @@ func getPrimaryIP(
if len(interfaces) > 0 { // agent returned some information
log.Printf("[INFO][getPrimaryIP] QEMU Agent interfaces found: %v", interfaces)
logger.Debug().Int(vmID.Root, int(vmr.VmId())).Msgf("QEMU Agent interfaces found: %v", interfaces)
conn = conn.parsePrimaryIPs(interfaces, primaryMacAddress)
if conn.hasRequiredIP() {
return conn.IPs, diag.Diagnostics{}
if primaryMacAddress != nil {
conn = conn.parsePrimaryIPs(interfaces, primaryMacAddress)
if conn.hasRequiredIP() {
return conn.IPs, diag.Diagnostics{}
}
} else {
// Try to get IP from any available network interface
multiConn := connectionInfo{}
for i := 0; i < network.AmountNetworkInterfaces; i++ {
if v, ok := networks[pveSDK.QemuNetworkInterfaceID(i)]; ok && v.MAC != nil {
conn = multiConn.parsePrimaryIPs(interfaces, *v.MAC)
if conn.hasRequiredIP() {
return conn.IPs, diag.Diagnostics{}
}
}
}
}
}
}
Expand Down