github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/rpcd/probeVmPort.go (about) 1 package rpcd 2 3 import ( 4 "fmt" 5 "net" 6 "time" 7 8 "github.com/Cloud-Foundations/Dominator/lib/errors" 9 "github.com/Cloud-Foundations/Dominator/lib/srpc" 10 "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 11 ) 12 13 func (t *srpcType) ProbeVmPort(conn *srpc.Conn, 14 request hypervisor.ProbeVmPortRequest, 15 reply *hypervisor.ProbeVmPortResponse) error { 16 if _, err := t.manager.GetVmInfo(request.IpAddress); err != nil { 17 *reply = hypervisor.ProbeVmPortResponse{ 18 Error: errors.ErrorToString(err)} 19 return nil 20 } 21 ok, err := probeVmPort( 22 fmt.Sprintf("%s:%d", request.IpAddress, request.PortNumber), 23 request.Timeout) 24 *reply = hypervisor.ProbeVmPortResponse{ok, errors.ErrorToString(err)} 25 return nil 26 } 27 28 func probeVmPort(addr string, timeout time.Duration) (bool, error) { 29 // TODO(rgooch): This should be done inside the metadata server namespace 30 // and it should be limited to VM owners. 31 intervalDuration := time.Millisecond * 250 32 intervalTimer := time.NewTimer(intervalDuration) 33 okChannel := make(chan struct{}, 1) 34 timeoutTimer := time.NewTimer(timeout) 35 for { 36 select { 37 case <-intervalTimer.C: 38 go probeOnce(addr, okChannel) 39 intervalTimer.Reset(intervalDuration) 40 case <-okChannel: 41 return true, nil 42 case <-timeoutTimer.C: 43 return false, nil 44 } 45 } 46 } 47 48 func probeOnce(addr string, okChannel chan<- struct{}) { 49 if conn, err := net.DialTimeout("tcp", addr, time.Second); err == nil { 50 conn.Close() 51 select { 52 case okChannel <- struct{}{}: 53 default: 54 } 55 } 56 }