@@ -323,6 +323,9 @@ type Driver interface {
323323 // HostIP retrieves the host IP address for the virtual machine based on the state.
324324 HostIP (multistep.StateBag ) (string , error )
325325
326+ // GetGuestIPAddress retrieves the guest IP address for the virtual machine using VMware Tools.
327+ GetGuestIPAddress (string ) (string , error )
328+
326329 // Export exports a virtual machine using the provided arguments.
327330 Export ([]string ) error
328331
@@ -484,6 +487,10 @@ type VmwareDriver struct {
484487 // This method returns an object with the NetworkNameMapper interface
485488 // that maps network to device and vice versa.
486489 NetworkMapper func () (NetworkNameMapper , error )
490+
491+ // IPFinder returns the IP address for a given device. If nil, getHostIPForBridgedNetwork is used.
492+ // This allows for mocking in tests.
493+ IPFinder func (device string ) (string , error )
487494}
488495
489496// GuestAddress retrieves the MAC address of a guest virtual machine from the .vmx configuration.
@@ -586,7 +593,6 @@ func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
586593
587594 var lastError error
588595 for _ , device := range devices {
589- // parse dhcpd configuration
590596 pathDhcpConfig := d .DhcpConfPath (device )
591597 if _ , err := os .Stat (pathDhcpConfig ); err != nil {
592598 return "" , fmt .Errorf ("unable to find vmnetdhcp conf file: %s" , pathDhcpConfig )
@@ -613,7 +619,7 @@ func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
613619
614620 // we didn't find it, so search through our interfaces for the device name
615621 interfaceList , err := net .Interfaces ()
616- if err = = nil {
622+ if err ! = nil {
617623 return "" , err
618624 }
619625
@@ -667,7 +673,31 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
667673
668674 var lastError error
669675 for _ , device := range devices {
670- // parse dhcpd configuration
676+ // Check if this is a bridged network device.
677+ networkName , err := netmap .DeviceIntoName (device )
678+ isBridged := err == nil && strings .EqualFold (networkName , "bridged" )
679+
680+ if isBridged {
681+ // Bridged networks connect to the physical network.
682+ // Find the host's IP address on the physical network interface.
683+ log .Printf ("[INFO] Detected bridged network for device %s, finding host IP on physical network" , device )
684+
685+ var address string
686+ var err error
687+ if d .IPFinder != nil {
688+ address , err = d .IPFinder (device )
689+ } else {
690+ // Get the first non-loopback interface IP address.
691+ address , err = getHostIPForBridgedNetwork ()
692+ }
693+ if err != nil {
694+ lastError = err
695+ continue
696+ }
697+ return address , nil
698+ }
699+
700+ // For non-bridged networks, use the DHCP leases path.
671701 pathDhcpConfig := d .DhcpConfPath (device )
672702 if _ , err := os .Stat (pathDhcpConfig ); err != nil {
673703 return "" , fmt .Errorf ("unable to find vmnetdhcp conf file: %s" , pathDhcpConfig )
@@ -678,7 +708,6 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
678708 continue
679709 }
680710
681- // find the entry configured in the dhcpd
682711 interfaceConfig , err := config .HostByName (device )
683712 if err != nil {
684713 lastError = err
@@ -696,6 +725,38 @@ func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
696725 return "" , fmt .Errorf ("unable to find host IP from devices %v, last error: %s" , devices , lastError )
697726}
698727
728+ // getHostIPForBridgedNetwork returns the host's IP address on the physical
729+ // network for use with bridged networking.
730+ func getHostIPForBridgedNetwork () (string , error ) {
731+ interfaces , err := net .Interfaces ()
732+ if err != nil {
733+ return "" , fmt .Errorf ("unable to enumerate network interfaces: %s" , err )
734+ }
735+
736+ for _ , iface := range interfaces {
737+ // Skip loopback and down interfaces.
738+ if iface .Flags & net .FlagLoopback != 0 || iface .Flags & net .FlagUp == 0 {
739+ continue
740+ }
741+
742+ addrs , err := iface .Addrs ()
743+ if err != nil {
744+ continue
745+ }
746+
747+ for _ , addr := range addrs {
748+ if ipnet , ok := addr .(* net.IPNet ); ok {
749+ if ipv4 := ipnet .IP .To4 (); ipv4 != nil {
750+ log .Printf ("[INFO] Found host IP for bridged network: %s on interface %s" , ipv4 .String (), iface .Name )
751+ return ipv4 .String (), nil
752+ }
753+ }
754+ }
755+ }
756+
757+ return "" , fmt .Errorf ("unable to find a non-loopback IPv4 address on any interface" )
758+ }
759+
699760// GetDhcpLeasesPaths returns a copy of the DHCP leases paths.
700761func GetDhcpLeasesPaths () []string {
701762 return append ([]string (nil ), dhcpLeasesPaths ... )
0 commit comments