<commit_before>package ssh

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

// idleTimer allows a client of the ssh
// library to notice if there has been a
// stall in i/o activity. This enables
// clients to impliment timeout logic
// that works and doesn't timeout under
// long-duration-but-still-successful
// reads/writes.
//
// It is probably simpler to use the
// SetIdleTimeout(dur time.Duration)
// method on the channel.
//
type idleTimer struct {
	mut     sync.Mutex
	idleDur time.Duration
	last    int64

	halt            *Halter
	timeoutCallback []func()

	// GetIdleTimeoutCh returns the current idle timeout duration in use.
	// It will return 0 if timeouts are disabled.
	getIdleTimeoutCh chan time.Duration

	// SetIdleTimeout() will always set the timeOutRaised state to false.
	// Likewise for sending on setIdleTimeoutCh.
	setIdleTimeoutCh chan *setTimeoutTicket
	TimedOut         chan string // sends empty string if no timeout, else details.

	setCallback   chan *callbacks
	addCallback   chan *callbacks
	timeOutRaised string

	// history of Reset() calls.
	getHistoryCh chan *getHistoryTicket

	// each of these, for instance,
	// atomicdur is updated atomically, and should
	// be read atomically. For use by Reset() and
	// internal reporting only.
	atomicdur  int64
	overcount  int64
	undercount int64
	beginnano  int64 // not monotonic time source.
}

type callbacks struct {
	onTimeout func()
}

var seen int

// newIdleTimer creates a new idleTimer which will call
// the `callback` function provided after `dur` inactivity.
// If callback is nil, you must use setTimeoutCallback()
// to establish the callback before activating the timer
// with SetIdleTimeout. The `dur` can be 0 to begin with no
// timeout, in which case the timer will be inactive until
// SetIdleTimeout is called.
func newIdleTimer(callback func(), dur time.Duration) *idleTimer {
	p("newIdleTimer called")
	seen++
	if seen == 3 {
		//panic("where?")
	}
	t := &idleTimer{
		getIdleTimeoutCh: make(chan time.Duration),
		setIdleTimeoutCh: make(chan *setTimeoutTicket),
		setCallback:      make(chan *callbacks),
		addCallback:      make(chan *callbacks),
		getHistoryCh:     make(chan *getHistoryTicket),
		TimedOut:         make(chan string),
		halt:             NewHalter(),
		timeoutCallback:  []func(){callback},
	}
	go t.backgroundStart(dur)
	return t
}

// typically prefer addTimeoutCallback instead; using
// this will blow away any other callbacks that are
// already registered. Unless that is what you want,
// use addTimeoutCallback().
//
func (t *idleTimer) setTimeoutCallback(timeoutFunc func()) {
	select {
	case t.setCallback <- &callbacks{onTimeout: timeoutFunc}:
	case <-t.halt.ReqStop.Chan:
	}
}

// add without removing exiting callbacks
func (t *idleTimer) addTimeoutCallback(timeoutFunc func()) {
	select {
	case t.addCallback <- &callbacks{onTimeout: timeoutFunc}:
	case <-t.halt.ReqStop.Chan:
	}
}

// Reset stores the current monotonic timestamp
// internally, effectively reseting to zero the value
// returned from an immediate next call to NanosecSince().
//
func (t *idleTimer) Reset() {
	mnow := monoNow()
	now := time.Now()
	// diagnose
	atomic.CompareAndSwapInt64(&t.beginnano, 0, now.UnixNano())
	tlast := atomic.LoadInt64(&t.last)
	adur := atomic.LoadInt64(&t.atomicdur)
	if adur > 0 {
		diff := mnow - tlast
		if diff > adur {
			//p("idleTimer.Reset() warning! diff = %v is over adur %v", time.Duration(diff), time.Duration(adur))
			atomic.AddInt64(&t.overcount, 1)
		} else {
			atomic.AddInt64(&t.undercount, 1)
		}
	}
	//q("idleTimer.Reset() called on idleTimer=%p, at %v. storing mnow=%v  into t.last. elap=%v since last update", t, time.Now(), mnow, time.Duration(mnow-tlast))

	// this is the only essential part of this routine. The above is for diagnosis.
	atomic.StoreInt64(&t.last, mnow)
}

func (t *idleTimer) historyOfResets(dur time.Duration) string {
	now := time.Now()
	begin := atomic.LoadInt64(&t.beginnano)
	if begin == 0 {
		return ""
	}
	beginTm := time.Unix(0, begin)

	mnow := monoNow()
	last := atomic.LoadInt64(&t.last)
	lastgap := time.Duration(mnow - last)
	over := atomic.LoadInt64(&t.overcount)
	under := atomic.LoadInt64(&t.undercount)
	return fmt.Sprintf("history of idle Reset: # over dur:%v, # under dur:%v. lastgap: %v.  dur=%v  now: %v. begin: %v", over, under, lastgap, dur, now, beginTm)
}

// NanosecSince returns how many nanoseconds it has
// been since the last call to Reset().
func (t *idleTimer) NanosecSince() int64 {
	mnow := monoNow()
	tlast := atomic.LoadInt64(&t.last)
	res := mnow - tlast
	//p("idleTimer=%p, NanosecSince:  mnow=%v, t.last=%v, so mnow-t.last=%v\n\n", t, mnow, tlast, res)
	return res
}

// SetIdleTimeout stores a new idle timeout duration. This
// activates the idleTimer if dur > 0. Set dur of 0
// to disable the idleTimer. A disabled idleTimer
// always returns false from TimedOut().
//
// This is the main API for idleTimer. Most users will
// only need to use this call.
//
func (t *idleTimer) SetIdleTimeout(dur time.Duration) {
	tk := newSetTimeoutTicket(dur)
	select {
	case t.setIdleTimeoutCh <- tk:
	case <-t.halt.ReqStop.Chan:
	}
	select {
	case <-tk.done:
	case <-t.halt.ReqStop.Chan:
	}

}

func (t *idleTimer) GetResetHistory() string {
	tk := newGetHistoryTicket()
	select {
	case t.getHistoryCh <- tk:
	case <-t.halt.ReqStop.Chan:
	}
	select {
	case <-tk.done:
	case <-t.halt.ReqStop.Chan:
	}
	return tk.hist
}

// GetIdleTimeout returns the current idle timeout duration in use.
// It will return 0 if timeouts are disabled.
func (t *idleTimer) GetIdleTimeout() (dur time.Duration) {
	select {
	case dur = <-t.getIdleTimeoutCh:
	case <-t.halt.ReqStop.Chan:
	}
	return
}

func (t *idleTimer) Stop() {
	p("idleTimer.Stop() called.")
	t.halt.ReqStop.Close()
	select {
	case <-t.halt.Done.Chan:
	case <-time.After(10 * time.Second):
		panic("idleTimer.Stop() problem! t.halt.Done.Chan not received  after 10sec! serious problem")
	}
}

type setTimeoutTicket struct {
	newdur time.Duration
	done   chan struct{}
}

func newSetTimeoutTicket(dur time.Duration) *setTimeoutTicket {
	return &setTimeoutTicket{
		newdur: dur,
		done:   make(chan struct{}),
	}
}

type getHistoryTicket struct {
	hist string
	done chan struct{}
}

func newGetHistoryTicket() *getHistoryTicket {
	return &getHistoryTicket{
		done: make(chan struct{}),
	}
}

const factor = 10

func (t *idleTimer) backgroundStart(dur time.Duration) {
	atomic.StoreInt64(&t.atomicdur, int64(dur))
	go func() {
		var heartbeat *time.Ticker
		var heartch <-chan time.Time
		if dur > 0 {
			// we've got to sample at above niquist
			// in order to have a chance of responding
			// quickly to timeouts of dur length. Theoretically
			// dur/2 suffices, but sooner is better so
			// we go with dur/factor. This also allows for
			// some play/some slop in the sampling, which
			// we empirically observe.
			heartbeat = time.NewTicker(dur / factor)
			heartch = heartbeat.C
		}
		defer func() {
			if heartbeat != nil {
				heartbeat.Stop() // allow GC
			}
			t.halt.Done.Close()
		}()
		for {
			select {
			case <-t.halt.ReqStop.Chan:
				return

			case t.TimedOut <- t.timeOutRaised:
				continue

			case f := <-t.setCallback:
				t.timeoutCallback = []func(){f.onTimeout}

			case f := <-t.addCallback:
				t.timeoutCallback = append(t.timeoutCallback, f.onTimeout)

			case t.getIdleTimeoutCh <- dur:
				continue

			case tk := <-t.setIdleTimeoutCh:
				/* change state, maybe */
				t.timeOutRaised = ""
				t.Reset()
				if dur > 0 {
					// timeouts active currently
					if tk.newdur == dur {
						close(tk.done)
						continue
					}
					if tk.newdur <= 0 {
						// stopping timeouts
						if heartbeat != nil {
							heartbeat.Stop() // allow GC
						}
						dur = tk.newdur
						atomic.StoreInt64(&t.atomicdur, int64(dur))

						heartbeat = nil
						heartch = nil
						close(tk.done)
						continue
					}
					// changing an active timeout dur
					if heartbeat != nil {
						heartbeat.Stop() // allow GC
					}
					dur = tk.newdur
					atomic.StoreInt64(&t.atomicdur, int64(dur))

					heartbeat = time.NewTicker(dur / factor)
					heartch = heartbeat.C
					t.Reset()
					close(tk.done)
					continue
				} else {
					// heartbeats not currently active
					if tk.newdur <= 0 {
						dur = 0
						atomic.StoreInt64(&t.atomicdur, int64(dur))

						// staying inactive
						close(tk.done)
						continue
					}
					// heartbeats activating
					dur = tk.newdur
					atomic.StoreInt64(&t.atomicdur, int64(dur))

					heartbeat = time.NewTicker(dur / factor)
					heartch = heartbeat.C
					t.Reset()
					close(tk.done)
					continue
				}

			case tk := <-t.getHistoryCh:
				tk.hist = t.historyOfResets(dur)
				close(tk.done)

			case <-heartch:
				if dur == 0 {
					panic("should be impossible to get heartbeat.C on dur == 0")
				}
				since := t.NanosecSince()
				udur := int64(dur)
				if since > udur {
					//p("timing out at %v, in %p! since=%v  dur=%v, exceed=%v  \n\n", time.Now(), t, since, udur, since-udur)

					/* change state */
					t.timeOutRaised = fmt.Sprintf("timing out dur='%v' at %v, in %p! "+
						"since=%v  dur=%v, exceed=%v. historyOfResets='%s'",
						dur, time.Now(), t, since, udur, since-udur, t.historyOfResets(dur))

					// After firing, disable until reactivated.
					// Still must be a ticker and not a one-shot because it may take
					// many, many heartbeats before a timeout, if one happens
					// at all.
					if heartbeat != nil {
						heartbeat.Stop() // allow GC
					}
					heartbeat = nil
					heartch = nil
					if len(t.timeoutCallback) == 0 {
						panic("idleTimer.timeoutCallback was never set! call t.setTimeoutCallback() or t.addTimeroutCallback()!!!")
					}
					// our caller may be holding locks...
					// and timeoutCallback will want locks...
					// so unless we start timeoutCallback() on its
					// own goroutine, we are likely to deadlock.
					for _, f := range t.timeoutCallback {
						go f()
					}
				}
			}
		}
	}()
}
<commit_msg>atg. defend against nil callback funcs<commit_after>package ssh

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

// idleTimer allows a client of the ssh
// library to notice if there has been a
// stall in i/o activity. This enables
// clients to impliment timeout logic
// that works and doesn't timeout under
// long-duration-but-still-successful
// reads/writes.
//
// It is probably simpler to use the
// SetIdleTimeout(dur time.Duration)
// method on the channel.
//
type idleTimer struct {
	mut     sync.Mutex
	idleDur time.Duration
	last    int64

	halt            *Halter
	timeoutCallback []func()

	// GetIdleTimeoutCh returns the current idle timeout duration in use.
	// It will return 0 if timeouts are disabled.
	getIdleTimeoutCh chan time.Duration

	// SetIdleTimeout() will always set the timeOutRaised state to false.
	// Likewise for sending on setIdleTimeoutCh.
	setIdleTimeoutCh chan *setTimeoutTicket
	TimedOut         chan string // sends empty string if no timeout, else details.

	setCallback   chan *callbacks
	addCallback   chan *callbacks
	timeOutRaised string

	// history of Reset() calls.
	getHistoryCh chan *getHistoryTicket

	// each of these, for instance,
	// atomicdur is updated atomically, and should
	// be read atomically. For use by Reset() and
	// internal reporting only.
	atomicdur  int64
	overcount  int64
	undercount int64
	beginnano  int64 // not monotonic time source.
}

type callbacks struct {
	onTimeout func()
}

var seen int

// newIdleTimer creates a new idleTimer which will call
// the `callback` function provided after `dur` inactivity.
// If callback is nil, you must use setTimeoutCallback()
// to establish the callback before activating the timer
// with SetIdleTimeout. The `dur` can be 0 to begin with no
// timeout, in which case the timer will be inactive until
// SetIdleTimeout is called.
func newIdleTimer(callback func(), dur time.Duration) *idleTimer {
	p("newIdleTimer called")
	seen++
	if seen == 3 {
		//panic("where?")
	}
	t := &idleTimer{
		getIdleTimeoutCh: make(chan time.Duration),
		setIdleTimeoutCh: make(chan *setTimeoutTicket),
		setCallback:      make(chan *callbacks),
		addCallback:      make(chan *callbacks),
		getHistoryCh:     make(chan *getHistoryTicket),
		TimedOut:         make(chan string),
		halt:             NewHalter(),
	}
	if callback != nil {
		t.timeoutCallback = append(t.timeoutCallback, callback)
	}
	go t.backgroundStart(dur)
	return t
}

// typically prefer addTimeoutCallback instead; using
// this will blow away any other callbacks that are
// already registered. Unless that is what you want,
// use addTimeoutCallback().
//
func (t *idleTimer) setTimeoutCallback(timeoutFunc func()) {
	select {
	case t.setCallback <- &callbacks{onTimeout: timeoutFunc}:
	case <-t.halt.ReqStop.Chan:
	}
}

// add without removing exiting callbacks
func (t *idleTimer) addTimeoutCallback(timeoutFunc func()) {
	if timeoutFunc == nil {
		panic("cannot call addTimeoutCallback with nil function!")
	}
	select {
	case t.addCallback <- &callbacks{onTimeout: timeoutFunc}:
	case <-t.halt.ReqStop.Chan:
	}
}

// Reset stores the current monotonic timestamp
// internally, effectively reseting to zero the value
// returned from an immediate next call to NanosecSince().
//
func (t *idleTimer) Reset() {
	mnow := monoNow()
	now := time.Now()
	// diagnose
	atomic.CompareAndSwapInt64(&t.beginnano, 0, now.UnixNano())
	tlast := atomic.LoadInt64(&t.last)
	adur := atomic.LoadInt64(&t.atomicdur)
	if adur > 0 {
		diff := mnow - tlast
		if diff > adur {
			//p("idleTimer.Reset() warning! diff = %v is over adur %v", time.Duration(diff), time.Duration(adur))
			atomic.AddInt64(&t.overcount, 1)
		} else {
			atomic.AddInt64(&t.undercount, 1)
		}
	}
	//q("idleTimer.Reset() called on idleTimer=%p, at %v. storing mnow=%v  into t.last. elap=%v since last update", t, time.Now(), mnow, time.Duration(mnow-tlast))

	// this is the only essential part of this routine. The above is for diagnosis.
	atomic.StoreInt64(&t.last, mnow)
}

func (t *idleTimer) historyOfResets(dur time.Duration) string {
	now := time.Now()
	begin := atomic.LoadInt64(&t.beginnano)
	if begin == 0 {
		return ""
	}
	beginTm := time.Unix(0, begin)

	mnow := monoNow()
	last := atomic.LoadInt64(&t.last)
	lastgap := time.Duration(mnow - last)
	over := atomic.LoadInt64(&t.overcount)
	under := atomic.LoadInt64(&t.undercount)
	return fmt.Sprintf("history of idle Reset: # over dur:%v, # under dur:%v. lastgap: %v.  dur=%v  now: %v. begin: %v", over, under, lastgap, dur, now, beginTm)
}

// NanosecSince returns how many nanoseconds it has
// been since the last call to Reset().
func (t *idleTimer) NanosecSince() int64 {
	mnow := monoNow()
	tlast := atomic.LoadInt64(&t.last)
	res := mnow - tlast
	//p("idleTimer=%p, NanosecSince:  mnow=%v, t.last=%v, so mnow-t.last=%v\n\n", t, mnow, tlast, res)
	return res
}

// SetIdleTimeout stores a new idle timeout duration. This
// activates the idleTimer if dur > 0. Set dur of 0
// to disable the idleTimer. A disabled idleTimer
// always returns false from TimedOut().
//
// This is the main API for idleTimer. Most users will
// only need to use this call.
//
func (t *idleTimer) SetIdleTimeout(dur time.Duration) {
	tk := newSetTimeoutTicket(dur)
	select {
	case t.setIdleTimeoutCh <- tk:
	case <-t.halt.ReqStop.Chan:
	}
	select {
	case <-tk.done:
	case <-t.halt.ReqStop.Chan:
	}

}

func (t *idleTimer) GetResetHistory() string {
	tk := newGetHistoryTicket()
	select {
	case t.getHistoryCh <- tk:
	case <-t.halt.ReqStop.Chan:
	}
	select {
	case <-tk.done:
	case <-t.halt.ReqStop.Chan:
	}
	return tk.hist
}

// GetIdleTimeout returns the current idle timeout duration in use.
// It will return 0 if timeouts are disabled.
func (t *idleTimer) GetIdleTimeout() (dur time.Duration) {
	select {
	case dur = <-t.getIdleTimeoutCh:
	case <-t.halt.ReqStop.Chan:
	}
	return
}

func (t *idleTimer) Stop() {
	p("idleTimer.Stop() called.")
	t.halt.ReqStop.Close()
	select {
	case <-t.halt.Done.Chan:
	case <-time.After(10 * time.Second):
		panic("idleTimer.Stop() problem! t.halt.Done.Chan not received  after 10sec! serious problem")
	}
}

type setTimeoutTicket struct {
	newdur time.Duration
	done   chan struct{}
}

func newSetTimeoutTicket(dur time.Duration) *setTimeoutTicket {
	return &setTimeoutTicket{
		newdur: dur,
		done:   make(chan struct{}),
	}
}

type getHistoryTicket struct {
	hist string
	done chan struct{}
}

func newGetHistoryTicket() *getHistoryTicket {
	return &getHistoryTicket{
		done: make(chan struct{}),
	}
}

const factor = 10

func (t *idleTimer) backgroundStart(dur time.Duration) {
	atomic.StoreInt64(&t.atomicdur, int64(dur))
	go func() {
		var heartbeat *time.Ticker
		var heartch <-chan time.Time
		if dur > 0 {
			// we've got to sample at above niquist
			// in order to have a chance of responding
			// quickly to timeouts of dur length. Theoretically
			// dur/2 suffices, but sooner is better so
			// we go with dur/factor. This also allows for
			// some play/some slop in the sampling, which
			// we empirically observe.
			heartbeat = time.NewTicker(dur / factor)
			heartch = heartbeat.C
		}
		defer func() {
			if heartbeat != nil {
				heartbeat.Stop() // allow GC
			}
			t.halt.Done.Close()
		}()
		for {
			select {
			case <-t.halt.ReqStop.Chan:
				return

			case t.TimedOut <- t.timeOutRaised:
				continue

			case f := <-t.setCallback:
				t.timeoutCallback = []func(){f.onTimeout}

			case f := <-t.addCallback:
				t.timeoutCallback = append(t.timeoutCallback, f.onTimeout)

			case t.getIdleTimeoutCh <- dur:
				continue

			case tk := <-t.setIdleTimeoutCh:
				/* change state, maybe */
				t.timeOutRaised = ""
				t.Reset()
				if dur > 0 {
					// timeouts active currently
					if tk.newdur == dur {
						close(tk.done)
						continue
					}
					if tk.newdur <= 0 {
						// stopping timeouts
						if heartbeat != nil {
							heartbeat.Stop() // allow GC
						}
						dur = tk.newdur
						atomic.StoreInt64(&t.atomicdur, int64(dur))

						heartbeat = nil
						heartch = nil
						close(tk.done)
						continue
					}
					// changing an active timeout dur
					if heartbeat != nil {
						heartbeat.Stop() // allow GC
					}
					dur = tk.newdur
					atomic.StoreInt64(&t.atomicdur, int64(dur))

					heartbeat = time.NewTicker(dur / factor)
					heartch = heartbeat.C
					t.Reset()
					close(tk.done)
					continue
				} else {
					// heartbeats not currently active
					if tk.newdur <= 0 {
						dur = 0
						atomic.StoreInt64(&t.atomicdur, int64(dur))

						// staying inactive
						close(tk.done)
						continue
					}
					// heartbeats activating
					dur = tk.newdur
					atomic.StoreInt64(&t.atomicdur, int64(dur))

					heartbeat = time.NewTicker(dur / factor)
					heartch = heartbeat.C
					t.Reset()
					close(tk.done)
					continue
				}

			case tk := <-t.getHistoryCh:
				tk.hist = t.historyOfResets(dur)
				close(tk.done)

			case <-heartch:
				if dur == 0 {
					panic("should be impossible to get heartbeat.C on dur == 0")
				}
				since := t.NanosecSince()
				udur := int64(dur)
				if since > udur {
					//p("timing out at %v, in %p! since=%v  dur=%v, exceed=%v  \n\n", time.Now(), t, since, udur, since-udur)

					/* change state */
					t.timeOutRaised = fmt.Sprintf("timing out dur='%v' at %v, in %p! "+
						"since=%v  dur=%v, exceed=%v. historyOfResets='%s'",
						dur, time.Now(), t, since, udur, since-udur, t.historyOfResets(dur))

					// After firing, disable until reactivated.
					// Still must be a ticker and not a one-shot because it may take
					// many, many heartbeats before a timeout, if one happens
					// at all.
					if heartbeat != nil {
						heartbeat.Stop() // allow GC
					}
					heartbeat = nil
					heartch = nil
					if len(t.timeoutCallback) == 0 {
						panic("idleTimer.timeoutCallback was never set! call t.setTimeoutCallback() or t.addTimeroutCallback()!!!")
					}
					// our caller may be holding locks...
					// and timeoutCallback will want locks...
					// so unless we start timeoutCallback() on its
					// own goroutine, we are likely to deadlock.
					for _, f := range t.timeoutCallback {
						go f()
					}
				}
			}
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package dialer

import (
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"golang.org/x/net/proxy"

	"github.com/syncthing/syncthing/lib/logger"
)

var (
	l           = logger.DefaultLogger.NewFacility("dialer", "Dialing connections")
	proxyDialer = getDialer(proxy.Direct)
	usingProxy  = proxyDialer != proxy.Direct
	noFallback  = os.Getenv("ALL_PROXY_NO_FALLBACK") != ""
)

type dialFunc func(network, addr string) (net.Conn, error)

func init() {
	l.SetDebug("dialer", strings.Contains(os.Getenv("STTRACE"), "dialer") || os.Getenv("STTRACE") == "all")
	if usingProxy {
		http.DefaultTransport = &http.Transport{
			Dial:                Dial,
			Proxy:               http.ProxyFromEnvironment,
			TLSHandshakeTimeout: 10 * time.Second,
		}

		// Defer this, so that logging gets setup.
		go func() {
			time.Sleep(500 * time.Millisecond)
			l.Infoln("Proxy settings detected")
			if noFallback {
				l.Infoln("Proxy fallback disabled")
			}
		}()
	} else {
		go func() {
			time.Sleep(500 * time.Millisecond)
			l.Debugln("Dialer logging disabled, as no proxy was detected")
		}()
	}
}

func dialWithFallback(proxyDialFunc dialFunc, fallbackDialFunc dialFunc, network, addr string) (net.Conn, error) {
	conn, err := proxyDialFunc(network, addr)
	if err == nil {
		l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
		SetTCPOptions(conn)
		return dialerConn{
			conn, newDialerAddr(network, addr),
		}, nil
	}
	l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err)

	if noFallback {
		return conn, err
	}

	conn, err = fallbackDialFunc(network, addr)
	if err == nil {
		l.Debugf("Dialing %s address %s via fallback - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
		SetTCPOptions(conn)
	} else {
		l.Debugf("Dialing %s address %s via fallback - error %s", network, addr, err)
	}
	return conn, err
}

// This is a rip off of proxy.FromEnvironment with a custom forward dialer
func getDialer(forward proxy.Dialer) proxy.Dialer {
	allProxy := os.Getenv("all_proxy")
	if len(allProxy) == 0 {
		return forward
	}

	proxyURL, err := url.Parse(allProxy)
	if err != nil {
		return forward
	}
	prxy, err := proxy.FromURL(proxyURL, forward)
	if err != nil {
		return forward
	}

	noProxy := os.Getenv("no_proxy")
	if len(noProxy) == 0 {
		return prxy
	}

	perHost := proxy.NewPerHost(prxy, forward)
	perHost.AddFromString(noProxy)
	return perHost
}

type timeoutDirectDialer struct {
	timeout time.Duration
}

func (d *timeoutDirectDialer) Dial(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, d.timeout)
}

type dialerConn struct {
	net.Conn
	addr net.Addr
}

func (c dialerConn) RemoteAddr() net.Addr {
	return c.addr
}

func newDialerAddr(network, addr string) net.Addr {
	netaddr, err := net.ResolveIPAddr(network, addr)
	if err == nil {
		return netaddr
	}
	return fallbackAddr{network, addr}
}

type fallbackAddr struct {
	network string
	addr    string
}

func (a fallbackAddr) Network() string {
	return a.network
}

func (a fallbackAddr) String() string {
	return a.addr
}
<commit_msg>lib/dialer: Register dialer for socks URL scheme (fixes #4515)<commit_after>// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

package dialer

import (
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"golang.org/x/net/proxy"

	"github.com/syncthing/syncthing/lib/logger"
)

var (
	l           = logger.DefaultLogger.NewFacility("dialer", "Dialing connections")
	proxyDialer proxy.Dialer
	usingProxy  bool
	noFallback  = os.Getenv("ALL_PROXY_NO_FALLBACK") != ""
)

type dialFunc func(network, addr string) (net.Conn, error)

func init() {
	l.SetDebug("dialer", strings.Contains(os.Getenv("STTRACE"), "dialer") || os.Getenv("STTRACE") == "all")

	proxy.RegisterDialerType("socks", socksDialerFunction)
	proxyDialer = getDialer(proxy.Direct)
	usingProxy = proxyDialer != proxy.Direct

	if usingProxy {
		http.DefaultTransport = &http.Transport{
			Dial:                Dial,
			Proxy:               http.ProxyFromEnvironment,
			TLSHandshakeTimeout: 10 * time.Second,
		}

		// Defer this, so that logging gets setup.
		go func() {
			time.Sleep(500 * time.Millisecond)
			l.Infoln("Proxy settings detected")
			if noFallback {
				l.Infoln("Proxy fallback disabled")
			}
		}()
	} else {
		go func() {
			time.Sleep(500 * time.Millisecond)
			l.Debugln("Dialer logging disabled, as no proxy was detected")
		}()
	}
}

func dialWithFallback(proxyDialFunc dialFunc, fallbackDialFunc dialFunc, network, addr string) (net.Conn, error) {
	conn, err := proxyDialFunc(network, addr)
	if err == nil {
		l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
		SetTCPOptions(conn)
		return dialerConn{
			conn, newDialerAddr(network, addr),
		}, nil
	}
	l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err)

	if noFallback {
		return conn, err
	}

	conn, err = fallbackDialFunc(network, addr)
	if err == nil {
		l.Debugf("Dialing %s address %s via fallback - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
		SetTCPOptions(conn)
	} else {
		l.Debugf("Dialing %s address %s via fallback - error %s", network, addr, err)
	}
	return conn, err
}

// This is a rip off of proxy.FromURL for "socks" URL scheme
func socksDialerFunction(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
	var auth *proxy.Auth
	if u.User != nil {
		auth = new(proxy.Auth)
		auth.User = u.User.Username()
		if p, ok := u.User.Password(); ok {
			auth.Password = p
		}
	}

	return proxy.SOCKS5("tcp", u.Host, auth, forward)
}

// This is a rip off of proxy.FromEnvironment with a custom forward dialer
func getDialer(forward proxy.Dialer) proxy.Dialer {
	allProxy := os.Getenv("all_proxy")
	if len(allProxy) == 0 {
		return forward
	}

	proxyURL, err := url.Parse(allProxy)
	if err != nil {
		return forward
	}
	prxy, err := proxy.FromURL(proxyURL, forward)
	if err != nil {
		return forward
	}

	noProxy := os.Getenv("no_proxy")
	if len(noProxy) == 0 {
		return prxy
	}

	perHost := proxy.NewPerHost(prxy, forward)
	perHost.AddFromString(noProxy)
	return perHost
}

type timeoutDirectDialer struct {
	timeout time.Duration
}

func (d *timeoutDirectDialer) Dial(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, d.timeout)
}

type dialerConn struct {
	net.Conn
	addr net.Addr
}

func (c dialerConn) RemoteAddr() net.Addr {
	return c.addr
}

func newDialerAddr(network, addr string) net.Addr {
	netaddr, err := net.ResolveIPAddr(network, addr)
	if err == nil {
		return netaddr
	}
	return fallbackAddr{network, addr}
}

type fallbackAddr struct {
	network string
	addr    string
}

func (a fallbackAddr) Network() string {
	return a.network
}

func (a fallbackAddr) String() string {
	return a.addr
}
<|endoftext|>


<commit_before>package e2e

import (
	"bytes"
	"context"
	"log"
	"os/exec"

	"github.com/firepear/qsplit"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/xridge/kubestone/api/v1alpha1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"

	perfv1alpha1 "github.com/xridge/kubestone/api/v1alpha1"
)

const (
	iperf3SampleCR = "../../config/samples/perf_v1alpha1_iperf3.yaml"
	e2eNamespace   = "kubestone-e2e"
)

var restClientConfig = ctrl.GetConfigOrDie()
var client ctrlclient.Client
var ctx = context.Background()
var scheme = runtime.NewScheme()

func init() {
	err := perfv1alpha1.AddToScheme(scheme)
	if err != nil {
		panic(err)
	}

	client, err = ctrlclient.New(restClientConfig, ctrlclient.Options{Scheme: scheme})
	if err != nil {
		panic(err)
	}
}

func run(command string) (stdout, stderr string, err error) {
	commandArray := qsplit.ToStrings([]byte(command))
	cmd := exec.Command(commandArray[0], commandArray[1:]...)
	var stdOut bytes.Buffer
	var stdErr bytes.Buffer
	cmd.Stdout, cmd.Stderr = &stdOut, &stdErr
	err = cmd.Run()
	if err != nil {
		log.Printf("Error during execution of `%v`\nerr: %v\nstdout: %v\nstderr: %v\n",
			command, err, stdOut.String(), stdErr.String())
		return "", "", err
	}

	return stdOut.String(), stdErr.String(), nil
}

var _ = Describe("end to end test", func() {
	Describe("for iperf3", func() {
		//var dummy int

		BeforeEach(func() {
			//dummy = 1
		})

		Context("preparing namespace", func() {
			_, _, err := run("kubectl create namespace " + e2eNamespace)
			It("should succeed", func() {
				Expect(err).To(BeNil())
			})
		})

		Context("creation from samples", func() {
			_, _, err := run("kubectl create -n " + e2eNamespace + " -f " + iperf3SampleCR)
			It("should create iperf3-sample cr", func() {
				Expect(err).To(BeNil())
			})
		})

		Context("created job", func() {
			It("Should finish in a pre-defined time", func() {
				timeout := 60
				cr := &v1alpha1.Iperf3{}
				namespacedName := types.NamespacedName{
					Namespace: e2eNamespace,
					Name:      "iperf3-sample",
				}
				Expect(client.Get(ctx, namespacedName, cr)).To(Succeed())
				Eventually(func() bool {
					return (cr.Status.Running == false) && (cr.Status.Completed)
				}, timeout).Should(BeTrue())
			})
		})
	})
})
<commit_msg>FIX: Poll CR in Eventually loop<commit_after>package e2e

import (
	"bytes"
	"context"
	"log"
	"os/exec"

	"github.com/firepear/qsplit"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/xridge/kubestone/api/v1alpha1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"

	perfv1alpha1 "github.com/xridge/kubestone/api/v1alpha1"
)

const (
	iperf3SampleCR = "../../config/samples/perf_v1alpha1_iperf3.yaml"
	e2eNamespace   = "kubestone-e2e"
)

var restClientConfig = ctrl.GetConfigOrDie()
var client ctrlclient.Client
var ctx = context.Background()
var scheme = runtime.NewScheme()

func init() {
	err := perfv1alpha1.AddToScheme(scheme)
	if err != nil {
		panic(err)
	}

	client, err = ctrlclient.New(restClientConfig, ctrlclient.Options{Scheme: scheme})
	if err != nil {
		panic(err)
	}
}

func run(command string) (stdout, stderr string, err error) {
	commandArray := qsplit.ToStrings([]byte(command))
	cmd := exec.Command(commandArray[0], commandArray[1:]...)
	var stdOut bytes.Buffer
	var stdErr bytes.Buffer
	cmd.Stdout, cmd.Stderr = &stdOut, &stdErr
	err = cmd.Run()
	if err != nil {
		log.Printf("Error during execution of `%v`\nerr: %v\nstdout: %v\nstderr: %v\n",
			command, err, stdOut.String(), stdErr.String())
		return "", "", err
	}

	return stdOut.String(), stdErr.String(), nil
}

var _ = Describe("end to end test", func() {
	Describe("for iperf3", func() {
		//var dummy int

		BeforeEach(func() {
			//dummy = 1
		})

		Context("preparing namespace", func() {
			_, _, err := run("kubectl create namespace " + e2eNamespace)
			It("should succeed", func() {
				Expect(err).To(BeNil())
			})
		})

		Context("creation from samples", func() {
			_, _, err := run("kubectl create -n " + e2eNamespace + " -f " + iperf3SampleCR)
			It("should create iperf3-sample cr", func() {
				Expect(err).To(BeNil())
			})
		})

		Context("created job", func() {
			It("Should finish in a pre-defined time", func() {
				timeout := 60
				cr := &v1alpha1.Iperf3{}
				namespacedName := types.NamespacedName{
					Namespace: e2eNamespace,
					Name:      "iperf3-sample",
				}
				Expect(client.Get(ctx, namespacedName, cr)).To(Succeed())
				Eventually(func() bool {
					if err := client.Get(ctx, namespacedName, cr); err != nil {
						panic(err)
					}
					return (cr.Status.Running == false) && (cr.Status.Completed)
				}, timeout).Should(BeTrue())
			})
		})
	})
})
<|endoftext|>


<commit_before>package indexer

import (
	"fmt"
	"time"

	"github.com/rikvdh/ci/models"
	"srcd.works/go-git.v4"
	"srcd.works/go-git.v4/config"
	"srcd.works/go-git.v4/plumbing"
	"srcd.works/go-git.v4/storage/memory"
)

type Branch struct {
	Hash string
	Name string
}

func RemoteBranches(repo string) ([]Branch, error) {
	// Create a new repository
	r, err := git.Init(memory.NewStorage(), nil)
	if err != nil {
		return nil, fmt.Errorf("git init error: %v", err)
	}

	_, err = r.CreateRemote(&config.RemoteConfig{
		Name: "r",
		URL:  repo,
	})
	if err != nil {
		return nil, fmt.Errorf("create remote error: %v", err)
	}

	rem, err := r.Remote("r")
	if err != nil {
		return nil, fmt.Errorf("remote err: %v", err)
	}

	err = rem.Fetch(&git.FetchOptions{})
	if err != nil {
		return nil, err
	}

	refs, err := r.References()
	if err != nil {
		return nil, err
	}

	var branches []Branch

	refs.ForEach(func(ref *plumbing.Reference) error {
		if ref.Type() == plumbing.HashReference && !ref.IsTag() {
			branches = append(branches, Branch{
				Hash: ref.Hash().String(),
				Name: ref.Name().Short(),
			})
		}
		return nil
	})

	return branches, nil
}

func ScheduleJob(buildID, branchID uint, ref string) {
	fmt.Println("Scheduling job for build", buildID, "on branch", branchID)
	job := models.Job{
		BuildID:   buildID,
		BranchID:  branchID,
		Status:    models.StatusNew,
		Reference: ref,
	}
	models.Handle().Create(&job)
}

func checkBranch(buildID uint, branch Branch) {
	dbBranch := models.Branch{}
	models.Handle().Where("name = ? AND build_id = ?", branch.Name, buildID).First(&dbBranch)

	if dbBranch.ID > 0 && dbBranch.LastReference != branch.Hash {
		dbBranch.LastReference = branch.Hash
		models.Handle().Save(&dbBranch)
		ScheduleJob(buildID, dbBranch.ID, branch.Hash)
	} else if dbBranch.ID == 0 {
		dbBranch.Name = branch.Name
		dbBranch.BuildID = buildID
		dbBranch.LastReference = branch.Hash
		models.Handle().Create(&dbBranch)
		ScheduleJob(buildID, dbBranch.ID, branch.Hash)
	}
}

func Run() {
	for {
		var builds []models.Build
		models.Handle().Find(&builds)
		for _, build := range builds {
			branches, err := RemoteBranches(build.Uri)
			if err != nil {
				fmt.Printf("error reading branches from %s: %v\n", build.Uri, err)
			}
			for _, branch := range branches {
				checkBranch(build.ID, branch)
			}
		}
		time.Sleep(time.Second * 5)
	}
}
<commit_msg>Change location of src-d/go-git<commit_after>package indexer

import (
	"fmt"
	"time"

	"github.com/rikvdh/ci/models"
	"gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/config"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/storage/memory"
)

type Branch struct {
	Hash string
	Name string
}

func RemoteBranches(repo string) ([]Branch, error) {
	// Create a new repository
	r, err := git.Init(memory.NewStorage(), nil)
	if err != nil {
		return nil, fmt.Errorf("git init error: %v", err)
	}

	_, err = r.CreateRemote(&config.RemoteConfig{
		Name: "r",
		URL:  repo,
	})
	if err != nil {
		return nil, fmt.Errorf("create remote error: %v", err)
	}

	rem, err := r.Remote("r")
	if err != nil {
		return nil, fmt.Errorf("remote err: %v", err)
	}

	err = rem.Fetch(&git.FetchOptions{})
	if err != nil {
		return nil, err
	}

	refs, err := r.References()
	if err != nil {
		return nil, err
	}

	var branches []Branch

	refs.ForEach(func(ref *plumbing.Reference) error {
		if ref.Type() == plumbing.HashReference && !ref.IsTag() {
			branches = append(branches, Branch{
				Hash: ref.Hash().String(),
				Name: ref.Name().Short(),
			})
		}
		return nil
	})

	return branches, nil
}

func ScheduleJob(buildID, branchID uint, ref string) {
	fmt.Println("Scheduling job for build", buildID, "on branch", branchID)
	job := models.Job{
		BuildID:   buildID,
		BranchID:  branchID,
		Status:    models.StatusNew,
		Reference: ref,
	}
	models.Handle().Create(&job)
}

func checkBranch(buildID uint, branch Branch) {
	dbBranch := models.Branch{}
	models.Handle().Where("name = ? AND build_id = ?", branch.Name, buildID).First(&dbBranch)

	if dbBranch.ID > 0 && dbBranch.LastReference != branch.Hash {
		dbBranch.LastReference = branch.Hash
		models.Handle().Save(&dbBranch)
		ScheduleJob(buildID, dbBranch.ID, branch.Hash)
	} else if dbBranch.ID == 0 {
		dbBranch.Name = branch.Name
		dbBranch.BuildID = buildID
		dbBranch.LastReference = branch.Hash
		models.Handle().Create(&dbBranch)
		ScheduleJob(buildID, dbBranch.ID, branch.Hash)
	}
}

func Run() {
	for {
		var builds []models.Build
		models.Handle().Find(&builds)
		for _, build := range builds {
			branches, err := RemoteBranches(build.Uri)
			if err != nil {
				fmt.Printf("error reading branches from %s: %v\n", build.Uri, err)
			}
			for _, branch := range branches {
				checkBranch(build.ID, branch)
			}
		}
		time.Sleep(time.Second * 5)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

// +build windows

package libdokan

import (
	"sync"

	"github.com/keybase/kbfs/dokan"
	"github.com/keybase/kbfs/libkbfs"
	"golang.org/x/net/context"
)

type fileOpener interface {
	open(ctx context.Context, oc *openContext, path []string) (f dokan.File, isDir bool, err error)
	dokan.File
}

// FolderList is a node that can list all of the logged-in user's
// favorite top-level folders, on either a public or private basis.
type FolderList struct {
	emptyFile
	fs *FS
	// only accept public folders
	public bool

	mu      sync.Mutex
	folders map[string]fileOpener
}

// GetFileInformation for dokan.
func (*FolderList) GetFileInformation(*dokan.FileInfo) (*dokan.Stat, error) {
	return defaultDirectoryInformation()
}

// open tries to open the correct thing. Following aliases and deferring to
// Dir.open as necessary.
func (fl *FolderList) open(ctx context.Context, oc *openContext, path []string) (f dokan.File, isDir bool, err error) {
	fl.fs.log.CDebugf(ctx, "FL Lookup %#v", path)
	defer func() { fl.fs.reportErr(ctx, err) }()

	if len(path) == 0 {
		return oc.returnDirNoCleanup(fl)
	}

	for oc.reduceRedirectionsLeft() {
		name := path[0]

		if name == "desktop.ini" {
			fl.fs.log.CDebugf(ctx, "FL Lookup ignoring desktop.ini")
			return nil, false, dokan.ErrObjectNameNotFound
		}

		fl.mu.Lock()
		child, ok := fl.folders[name]
		fl.mu.Unlock()

		if ok {
			fl.fs.log.CDebugf(ctx, "FL Lookup recursing to child %q", name)
			return child.open(ctx, oc, path[1:])
		}

		fl.fs.log.CDebugf(ctx, "FL Lookup continuing")
		rootNode, _, err :=
			fl.fs.config.KBFSOps().GetOrCreateRootNode(
				ctx, name, fl.public, libkbfs.MasterBranch)
		switch err := err.(type) {
		case nil:
			// No error.
			break

		case libkbfs.TlfNameNotCanonical:
			// Non-canonical name.
			if len(path) == 1 {
				fl.fs.log.CDebugf(ctx, "FL Lookup Alias")
				target := err.NameToTry
				d, bf, err := fl.open(ctx, oc, []string{target})
				switch {
				case err == nil && oc.isOpenReparsePoint():
					d.Cleanup(nil)
					return &Alias{canon: target}, false, nil
				case err == nil:
					return d, bf, err
				case oc.isCreateDirectory():
					fl.fs.log.CDebugf(ctx, "FL Lookup returning EmptyFolder instead of Alias")
					e := &EmptyFolder{}
					fl.lockedAddChild(name, e)
					return e, true, nil
				}
				return nil, false, err
			}
			path[0] = err.NameToTry
			continue

		case libkbfs.NoSuchNameError, libkbfs.NoSuchUserError:
			// Invalid public TLF.
			if len(path) == 1 && oc.isCreateDirectory() {
				fl.fs.log.CDebugf(ctx, "FL Lookup returning EmptyFolder instead of Alias")
				e := &EmptyFolder{}
				fl.lockedAddChild(name, e)
				return e, true, nil
			}
			return nil, false, dokan.ErrObjectNameNotFound

		case libkbfs.WriteAccessError:
			if len(path) == 1 {
				return oc.returnDirNoCleanup(&EmptyFolder{})
			}
			return nil, false, dokan.ErrObjectNameNotFound
		default:
			// Some other error.
			return nil, false, err
		}

		folderBranch := rootNode.GetFolderBranch()
		folder := &Folder{
			fs:           fl.fs,
			list:         fl,
			name:         name,
			folderBranch: folderBranch,
			nodes:        map[libkbfs.NodeID]dokan.File{},
		}

		// TODO unregister all at unmount
		if err := fl.fs.config.Notifier().RegisterForChanges([]libkbfs.FolderBranch{folderBranch}, folder); err != nil {
			return nil, false, err
		}

		child = newDir(folder, rootNode, path[0], nil)
		folder.nodes[rootNode.GetID()] = child
		fl.lockedAddChild(name, child)
		return child.open(ctx, oc, path[1:])
	}
	return nil, false, dokan.ErrObjectNameNotFound
}

func (fl *FolderList) forgetFolder(f *Folder) {
	fl.mu.Lock()
	defer fl.mu.Unlock()

	if err := fl.fs.config.Notifier().UnregisterFromChanges([]libkbfs.FolderBranch{f.folderBranch}, f); err != nil {
		fl.fs.log.Info("cannot unregister change notifier for folder %q: %v",
			f.name, err)
	}
	delete(fl.folders, f.name)
}

// FindFiles for dokan.
func (fl *FolderList) FindFiles(fi *dokan.FileInfo, callback func(*dokan.NamedStat) error) (err error) {
	ctx := NewContextWithOpID(fl.fs)
	fl.fs.log.CDebugf(ctx, "FL ReadDirAll")
	defer func() { fl.fs.reportErr(ctx, err) }()
	favs, err := fl.fs.config.KBFSOps().GetFavorites(ctx)
	fl.fs.log.CDebugf(ctx, "FL ReadDirAll -> %v,%v", favs, err)
	if err != nil {
		return err
	}
	var ns dokan.NamedStat
	ns.FileAttributes = fileAttributeDirectory
	ns.NumberOfLinks = 1
	empty := true
	for _, fav := range favs {
		if fav.Public != fl.public {
			continue
		}
		empty = false
		ns.Name = fav.Name
		err = callback(&ns)
		if err != nil {
			return err
		}
	}
	if empty {
		return dokan.ErrObjectNameNotFound
	}
	return nil
}

func (fl *FolderList) lockedAddChild(name string, val fileOpener) {
	fl.mu.Lock()
	fl.folders[name] = val
	fl.mu.Unlock()
}
<commit_msg>Added Dokan support for logged out public folder viewing<commit_after>// Copyright 2015 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

// +build windows

package libdokan

import (
	"sync"

	"github.com/keybase/client/go/libkb"
	"github.com/keybase/kbfs/dokan"
	"github.com/keybase/kbfs/libkbfs"
	"golang.org/x/net/context"
)

type fileOpener interface {
	open(ctx context.Context, oc *openContext, path []string) (f dokan.File, isDir bool, err error)
	dokan.File
}

// FolderList is a node that can list all of the logged-in user's
// favorite top-level folders, on either a public or private basis.
type FolderList struct {
	emptyFile
	fs *FS
	// only accept public folders
	public bool

	mu      sync.Mutex
	folders map[string]fileOpener
}

// GetFileInformation for dokan.
func (*FolderList) GetFileInformation(*dokan.FileInfo) (*dokan.Stat, error) {
	return defaultDirectoryInformation()
}

// open tries to open the correct thing. Following aliases and deferring to
// Dir.open as necessary.
func (fl *FolderList) open(ctx context.Context, oc *openContext, path []string) (f dokan.File, isDir bool, err error) {
	fl.fs.log.CDebugf(ctx, "FL Lookup %#v", path)
	defer func() { fl.fs.reportErr(ctx, err) }()

	if len(path) == 0 {
		return oc.returnDirNoCleanup(fl)
	}

	for oc.reduceRedirectionsLeft() {
		name := path[0]

		if name == "desktop.ini" {
			fl.fs.log.CDebugf(ctx, "FL Lookup ignoring desktop.ini")
			return nil, false, dokan.ErrObjectNameNotFound
		}

		fl.mu.Lock()
		child, ok := fl.folders[name]
		fl.mu.Unlock()

		if ok {
			fl.fs.log.CDebugf(ctx, "FL Lookup recursing to child %q", name)
			return child.open(ctx, oc, path[1:])
		}

		fl.fs.log.CDebugf(ctx, "FL Lookup continuing")
		rootNode, _, err :=
			fl.fs.config.KBFSOps().GetOrCreateRootNode(
				ctx, name, fl.public, libkbfs.MasterBranch)
		switch err := err.(type) {
		case nil:
			// No error.
			break

		case libkbfs.TlfNameNotCanonical:
			// Non-canonical name.
			if len(path) == 1 {
				fl.fs.log.CDebugf(ctx, "FL Lookup Alias")
				target := err.NameToTry
				d, bf, err := fl.open(ctx, oc, []string{target})
				switch {
				case err == nil && oc.isOpenReparsePoint():
					d.Cleanup(nil)
					return &Alias{canon: target}, false, nil
				case err == nil:
					return d, bf, err
				case oc.isCreateDirectory():
					fl.fs.log.CDebugf(ctx, "FL Lookup returning EmptyFolder instead of Alias")
					e := &EmptyFolder{}
					fl.lockedAddChild(name, e)
					return e, true, nil
				}
				return nil, false, err
			}
			path[0] = err.NameToTry
			continue

		case libkbfs.NoSuchNameError, libkbfs.NoSuchUserError:
			// Invalid public TLF.
			if len(path) == 1 && oc.isCreateDirectory() {
				fl.fs.log.CDebugf(ctx, "FL Lookup returning EmptyFolder instead of Alias")
				e := &EmptyFolder{}
				fl.lockedAddChild(name, e)
				return e, true, nil
			}
			return nil, false, dokan.ErrObjectNameNotFound

		case libkbfs.WriteAccessError:
			if len(path) == 1 {
				return oc.returnDirNoCleanup(&EmptyFolder{})
			}
			return nil, false, dokan.ErrObjectNameNotFound
		default:
			// Some other error.
			return nil, false, err
		}

		folderBranch := rootNode.GetFolderBranch()
		folder := &Folder{
			fs:           fl.fs,
			list:         fl,
			name:         name,
			folderBranch: folderBranch,
			nodes:        map[libkbfs.NodeID]dokan.File{},
		}

		// TODO unregister all at unmount
		if err := fl.fs.config.Notifier().RegisterForChanges([]libkbfs.FolderBranch{folderBranch}, folder); err != nil {
			return nil, false, err
		}

		child = newDir(folder, rootNode, path[0], nil)
		folder.nodes[rootNode.GetID()] = child
		fl.lockedAddChild(name, child)
		return child.open(ctx, oc, path[1:])
	}
	return nil, false, dokan.ErrObjectNameNotFound
}

func (fl *FolderList) forgetFolder(f *Folder) {
	fl.mu.Lock()
	defer fl.mu.Unlock()

	if err := fl.fs.config.Notifier().UnregisterFromChanges([]libkbfs.FolderBranch{f.folderBranch}, f); err != nil {
		fl.fs.log.Info("cannot unregister change notifier for folder %q: %v",
			f.name, err)
	}
	delete(fl.folders, f.name)
}

// FindFiles for dokan.
func (fl *FolderList) FindFiles(fi *dokan.FileInfo, callback func(*dokan.NamedStat) error) (err error) {
	ctx := NewContextWithOpID(fl.fs)
	fl.fs.log.CDebugf(ctx, "FL ReadDirAll")
	defer func() { fl.fs.reportErr(ctx, err) }()
	favs, err := fl.fs.config.KBFSOps().GetFavorites(ctx)
	fl.fs.log.CDebugf(ctx, "FL ReadDirAll -> %v,%v", favs, err)
	if _, isDeviceRequired := err.(libkb.DeviceRequiredError); isDeviceRequired && !fl.public {
		return err
	}
	var ns dokan.NamedStat
	ns.FileAttributes = fileAttributeDirectory
	ns.NumberOfLinks = 1
	empty := true
	for _, fav := range favs {
		if fav.Public != fl.public {
			continue
		}
		empty = false
		ns.Name = fav.Name
		err = callback(&ns)
		if err != nil {
			return err
		}
	}
	if empty {
		return dokan.ErrObjectNameNotFound
	}
	return nil
}

func (fl *FolderList) lockedAddChild(name string, val fileOpener) {
	fl.mu.Lock()
	fl.folders[name] = val
	fl.mu.Unlock()
}
<|endoftext|>


<commit_before>package cmds

import (
	"encoding/json"
	"errors"
	"github.com/SKAhack/go-shortid"
	"github.com/synw/microb/libmicrob/events"
	"github.com/synw/microb/libmicrob/msgs"
	"github.com/synw/microb/libmicrob/types"
	"github.com/synw/terr"
)

var g = shortid.Generator()

func Run(payload interface{}, state *types.State) {
	cmd := ConvertPayload(payload)
	cmd, isValid := getCmd(cmd, state)
	if isValid == false {
		msgs.Error("Invalid command " + cmd.Name)
		return
	}
	exec := state.Cmds[cmd.Name].Exec.(func(*types.Cmd, chan *types.Cmd, ...interface{}))
	events.Cmd(cmd)
	// execute the command
	c := make(chan *types.Cmd)
	go exec(cmd, c, state)
	select {
	case com := <-c:
		events.CmdExec(cmd)
		// set to interface to be able to marshall json
		com.Exec = nil
		tr := sendCommand(com, state)
		if tr != nil {
			msg := "Error executing the " + cmd.Name + " command"
			//events.Err(cmd.Service, cmd.From, msg, tr.ToErr())
			tr.Print()
			msgs.Error(msg)
		}
		close(c)
	}
}

func ConvertPayload(payload interface{}) *types.Cmd {
	pl := payload.(map[string]interface{})
	status := pl["Status"].(string)
	name := pl["Name"].(string)
	serv := pl["Service"].(string)
	from := pl["From"].(string)
	errMsg := pl["ErrMsg"].(string)
	var tr *terr.Trace
	if errMsg != "" {
		err := errors.New("Can not convert payload")
		tr = terr.New("cmds.ConvertPayload", err)
	}
	var args []interface{}
	if pl["Args"] != nil {
		args = pl["Args"].([]interface{})
	}
	cmd := &types.Cmd{
		Id:      g.Generate(),
		Name:    name,
		From:    from,
		Args:    args,
		Status:  status,
		Service: serv,
		ErrMsg:  errMsg,
		Trace:   tr,
	}
	if args != nil {
		cmd.Args = args
	}
	if pl["ErrMsg"].(string) != "" {
		msg := pl["ErrMsg"].(string)
		err := errors.New(msg)
		cmd.Trace = terr.New("cmd.ConvertPayload", err)
	}
	if pl["ReturnValues"] != nil {
		cmd.ReturnValues = pl["ReturnValues"].([]interface{})
	}
	cmd.Status = status
	return cmd
}

func checkServiceCmd(cmd *types.Cmd, state *types.State) (*types.Cmd, bool) {
	isValid := false
	for _, srv := range state.Services {
		if srv.Name == cmd.Name {
			cmd.Service = cmd.Name
			cmd.Name = cmd.Args[0].(string)
			if len(cmd.Args) > 1 {
				cmd.Args = cmd.Args[1:]
			}
			isValid = true
			break
		}
	}
	return cmd, isValid
}

func getCmd(cmd *types.Cmd, state *types.State) (*types.Cmd, bool) {
	for sname, srv := range state.Services {
		if sname == cmd.Service {
			for cname, scmd := range srv.Cmds {
				if cname == cmd.Name {
					cmd.Exec = scmd.Exec
					return cmd, true
				}
			}
		}
	}
	return cmd, false
}

func sendCommand(cmd *types.Cmd, state *types.State) *terr.Trace {
	if cmd.Trace != nil {
		cmd.ErrMsg = cmd.Trace.Formatc()
		cmd.Status = "error"
	} else {
		cmd.Status = "success"
	}
	payload, err := json.Marshal(cmd)
	if err != nil {
		msg := "Unable to marshall json: " + err.Error()
		err := errors.New(msg)
		trace := terr.New("commands.SendCommand", err)
		return trace
	}
	_, err = state.Cli.Http.Publish(state.WsServer.CmdChanOut, payload)
	if err != nil {
		trace := terr.New("commands.SendCommand", err)
		return trace
	}
	return nil
}
<commit_msg>Minor correction in cmds<commit_after>package cmds

import (
	"encoding/json"
	"errors"
	"github.com/SKAhack/go-shortid"
	"github.com/synw/microb/libmicrob/events"
	"github.com/synw/microb/libmicrob/msgs"
	"github.com/synw/microb/libmicrob/types"
	"github.com/synw/terr"
)

var g = shortid.Generator()

func Run(payload interface{}, state *types.State) {
	cmd := ConvertPayload(payload)
	cmd, isValid := getCmd(cmd, state)
	if isValid == false {
		msgs.Error("Invalid command " + cmd.Name)
		return
	}
	events.Cmd(cmd)
	// execute the command
	c := make(chan *types.Cmd)
	if cmd.Service == "infos" {
		exec := state.Cmds[cmd.Name].Exec.(func(*types.Cmd, chan *types.Cmd, ...interface{}))
		go exec(cmd, c, state)
	} else {
		exec := state.Cmds[cmd.Name].Exec.(func(*types.Cmd, chan *types.Cmd))
		go exec(cmd, c)
	}
	select {
	case com := <-c:
		events.CmdExec(cmd)
		// set to interface to be able to marshall json
		com.Exec = nil
		tr := sendCommand(com, state)
		if tr != nil {
			msg := "Error executing the " + cmd.Name + " command"
			//events.Err(cmd.Service, cmd.From, msg, tr.ToErr())
			tr.Print()
			msgs.Error(msg)
		}
		close(c)
	}
}

func ConvertPayload(payload interface{}) *types.Cmd {
	pl := payload.(map[string]interface{})
	status := pl["Status"].(string)
	name := pl["Name"].(string)
	serv := pl["Service"].(string)
	from := pl["From"].(string)
	errMsg := pl["ErrMsg"].(string)
	var tr *terr.Trace
	if errMsg != "" {
		err := errors.New("Can not convert payload")
		tr = terr.New("cmds.ConvertPayload", err)
	}
	var args []interface{}
	if pl["Args"] != nil {
		args = pl["Args"].([]interface{})
	}
	cmd := &types.Cmd{
		Id:      g.Generate(),
		Name:    name,
		From:    from,
		Args:    args,
		Status:  status,
		Service: serv,
		ErrMsg:  errMsg,
		Trace:   tr,
	}
	if args != nil {
		cmd.Args = args
	}
	if pl["ErrMsg"].(string) != "" {
		msg := pl["ErrMsg"].(string)
		err := errors.New(msg)
		cmd.Trace = terr.New("cmd.ConvertPayload", err)
	}
	if pl["ReturnValues"] != nil {
		cmd.ReturnValues = pl["ReturnValues"].([]interface{})
	}
	cmd.Status = status
	return cmd
}

func checkServiceCmd(cmd *types.Cmd, state *types.State) (*types.Cmd, bool) {
	isValid := false
	for _, srv := range state.Services {
		if srv.Name == cmd.Name {
			cmd.Service = cmd.Name
			cmd.Name = cmd.Args[0].(string)
			if len(cmd.Args) > 1 {
				cmd.Args = cmd.Args[1:]
			}
			isValid = true
			break
		}
	}
	return cmd, isValid
}

func getCmd(cmd *types.Cmd, state *types.State) (*types.Cmd, bool) {
	for sname, srv := range state.Services {
		if sname == cmd.Service {
			for cname, scmd := range srv.Cmds {
				if cname == cmd.Name {
					cmd.Exec = scmd.Exec
					return cmd, true
				}
			}
		}
	}
	return cmd, false
}

func sendCommand(cmd *types.Cmd, state *types.State) *terr.Trace {
	if cmd.Trace != nil {
		cmd.ErrMsg = cmd.Trace.Formatc()
		cmd.Status = "error"
	} else {
		cmd.Status = "success"
	}
	payload, err := json.Marshal(cmd)
	if err != nil {
		msg := "Unable to marshall json: " + err.Error()
		err := errors.New(msg)
		trace := terr.New("commands.SendCommand", err)
		return trace
	}
	_, err = state.Cli.Http.Publish(state.WsServer.CmdChanOut, payload)
	if err != nil {
		trace := terr.New("commands.SendCommand", err)
		return trace
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
// The permission bits perm are used for all
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm uint32) Error {
	// If path exists, stop with success or error.
	dir, err := Lstat(path)
	if err == nil {
		if dir.IsDirectory() {
			return nil
		}
		return &PathError{"mkdir", path, ENOTDIR}
	}

	// Doesn't already exist; make sure parent does.
	i := len(path)
	for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
		i--
	}

	j := i
	for j > 0 && path[j-1] != '/' { // Scan backward over element.
		j--
	}

	if j > 0 {
		// Create parent
		err = MkdirAll(path[0:j-1], perm)
		if err != nil {
			return err
		}
	}

	// Now parent exists, try to create.
	err = Mkdir(path, perm)
	if err != nil {
		// Handle arguments like "foo/." by
		// double-checking that directory doesn't exist.
		dir, err1 := Lstat(path)
		if err1 == nil && dir.IsDirectory() {
			return nil
		}
		return err
	}
	return nil
}

// RemoveAll removes path and any children it contains.
// It removes everything it can but returns the first error
// it encounters.  If the path does not exist, RemoveAll
// returns nil (no error).
func RemoveAll(path string) Error {
	// Simple case: if Remove works, we're done.
	err := Remove(path)
	if err == nil {
		return nil
	}

	// Otherwise, is this a directory we need to recurse into?
	dir, serr := Lstat(path)
	if serr != nil {
		if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
			return nil
		}
		return serr
	}
	if !dir.IsDirectory() {
		// Not a directory; return the error from Remove.
		return err
	}

	// Directory.
	fd, err := Open(path, O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer fd.Close()

	// Remove contents & return first error.
	err = nil
	for {
		names, err1 := fd.Readdirnames(100)
		for _, name := range names {
			err1 := RemoveAll(path + "/" + name)
			if err == nil {
				err = err1
			}
		}
		// If Readdirnames returned an error, use it.
		if err == nil {
			err = err1
		}
		if len(names) == 0 {
			break
		}
	}

	// Remove directory.
	err1 := Remove(path)
	if err == nil {
		err = err1
	}
	return err
}
<commit_msg>os: make RemoveAll() work on windows<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os

// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
// The permission bits perm are used for all
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm uint32) Error {
	// If path exists, stop with success or error.
	dir, err := Lstat(path)
	if err == nil {
		if dir.IsDirectory() {
			return nil
		}
		return &PathError{"mkdir", path, ENOTDIR}
	}

	// Doesn't already exist; make sure parent does.
	i := len(path)
	for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
		i--
	}

	j := i
	for j > 0 && path[j-1] != '/' { // Scan backward over element.
		j--
	}

	if j > 0 {
		// Create parent
		err = MkdirAll(path[0:j-1], perm)
		if err != nil {
			return err
		}
	}

	// Now parent exists, try to create.
	err = Mkdir(path, perm)
	if err != nil {
		// Handle arguments like "foo/." by
		// double-checking that directory doesn't exist.
		dir, err1 := Lstat(path)
		if err1 == nil && dir.IsDirectory() {
			return nil
		}
		return err
	}
	return nil
}

// RemoveAll removes path and any children it contains.
// It removes everything it can but returns the first error
// it encounters.  If the path does not exist, RemoveAll
// returns nil (no error).
func RemoveAll(path string) Error {
	// Simple case: if Remove works, we're done.
	err := Remove(path)
	if err == nil {
		return nil
	}

	// Otherwise, is this a directory we need to recurse into?
	dir, serr := Lstat(path)
	if serr != nil {
		if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
			return nil
		}
		return serr
	}
	if !dir.IsDirectory() {
		// Not a directory; return the error from Remove.
		return err
	}

	// Directory.
	fd, err := Open(path, O_RDONLY, 0)
	if err != nil {
		return err
	}

	// Remove contents & return first error.
	err = nil
	for {
		names, err1 := fd.Readdirnames(100)
		for _, name := range names {
			err1 := RemoveAll(path + "/" + name)
			if err == nil {
				err = err1
			}
		}
		// If Readdirnames returned an error, use it.
		if err == nil {
			err = err1
		}
		if len(names) == 0 {
			break
		}
	}

	// Close directory, because windows won't remove opened directory.
	fd.Close()

	// Remove directory.
	err1 := Remove(path)
	if err == nil {
		err = err1
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":7078")
	if err != nil {
		panic(err)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
		}

		log.Printf("open %+v", conn)
		go handleConn2(conn)
	}
}

func handleConn2(conn net.Conn) {
	payload := make([]byte, 512)

	for {
		n, err := conn.Read(payload)
		if err != nil {
			log.Printf("%+v errored %s", conn, err)
			conn.Close()
			break
		}

		payload = payload[:n]
		log.Printf("echo '%v' of len %v", payload, len(payload))

		n, err = conn.Write(payload)
		if err != nil {
			log.Println(err)
		}

		log.Printf("sent %v bytes of %v", n, payload)
	}
}
<commit_msg>experimenting with travis loosing socket connections<commit_after>package main

import (
	"log"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":7078")
	if err != nil {
		panic(err)
	}

	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Println(err)
		}

		log.Printf("open %+v", conn)
		go handleConn2(conn)
	}
}

func handleConn2(conn net.Conn) {
	payload := make([]byte, 512)

	for {
		n, err := conn.Read(payload)
		if err != nil {
			log.Printf("%+v errored %s", conn, err)
			conn.Close()
		}

		payload = payload[:n]
		log.Printf("echo '%v' of len %v", payload, len(payload))

		n, err = conn.Write(payload)
		if err != nil {
			log.Println(err)
		}

		log.Printf("sent %v bytes of %v", n, payload)
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"time"

	"github.com/google/goexpect"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Storage", func() {

	nodeName := ""
	nodeIp := ""
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	BeforeEach(func() {
		tests.BeforeTestCleanup()

		nodes, err := virtClient.CoreV1().Nodes().List(metav1.ListOptions{})
		Expect(err).ToNot(HaveOccurred())
		Expect(nodes.Items).ToNot(BeEmpty())
		nodeName = nodes.Items[0].Name
		for _, addr := range nodes.Items[0].Status.Addresses {
			if addr.Type == k8sv1.NodeInternalIP {
				nodeIp = addr.Address
				break
			}
		}
		Expect(nodeIp).ToNot(Equal(""))
	})

	getTargetLogs := func(tailLines int64) string {
		pods, err := virtClient.CoreV1().Pods(metav1.NamespaceSystem).List(metav1.ListOptions{LabelSelector: v1.AppLabel + " in (iscsi-demo-target)"})
		Expect(err).ToNot(HaveOccurred())

		//FIXME Sometimes pods hang in terminating state, select the pod which does not have a deletion timestamp
		podName := ""
		for _, pod := range pods.Items {
			if pod.ObjectMeta.DeletionTimestamp == nil {
				if pod.Status.HostIP == nodeIp {
					podName = pod.ObjectMeta.Name
					break
				}
			}
		}
		Expect(podName).ToNot(BeEmpty())

		logsRaw, err := virtClient.CoreV1().
			Pods(metav1.NamespaceSystem).
			GetLogs(podName,
				&k8sv1.PodLogOptions{TailLines: &tailLines}).
			DoRaw()
		Expect(err).To(BeNil())

		return string(logsRaw)
	}

	checkReadiness := func() {
		logs := getTargetLogs(75)
		Expect(logs).To(ContainSubstring("Target 1: iqn.2017-01.io.kubevirt:sn.42"))
		Expect(logs).To(ContainSubstring("Driver: iscsi"))
		Expect(logs).To(ContainSubstring("State: ready"))
	}

	RunVMAndExpectLaunch := func(vm *v1.VirtualMachine, withAuth bool, timeout int) runtime.Object {
		obj, err := virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Get()
		Expect(err).To(BeNil())
		tests.WaitForSuccessfulVMStartWithTimeout(obj, timeout)
		return obj
	}

	Context("Given a fresh iSCSI target", func() {
		It("should be available and ready", func() {
			checkReadiness()
		})
	})

	Context("Given a VM and an Alpine PVC", func() {
		It("should be successfully started", func(done Done) {
			checkReadiness()

			// Start the VM with the PVC attached
			vm := tests.NewRandomVMWithPVC(tests.DiskAlpineISCSI)
			vm.Spec.NodeSelector = map[string]string{"kubernetes.io/hostname": nodeName}
			RunVMAndExpectLaunch(vm, false, 45)

			expecter, _, err := tests.NewConsoleExpecter(virtClient, vm, "serial0", 10*time.Second)
			defer expecter.Close()
			Expect(err).To(BeNil())
			_, err = expecter.ExpectBatch([]expect.Batcher{
				&expect.BExp{R: "Welcome to Alpine"},
			}, 90*time.Second)
			Expect(err).To(BeNil())

			close(done)
		}, 110)

		It("should be successfully started and stopped multiple times", func(done Done) {
			checkReadiness()

			vm := tests.NewRandomVMWithPVC(tests.DiskAlpineISCSI)
			vm.Spec.NodeSelector = map[string]string{"kubernetes.io/hostname": nodeName}

			num := 3
			for i := 1; i <= num; i++ {
				obj := RunVMAndExpectLaunch(vm, false, 60)

				// Verify console on last iteration to verify the VM is still booting properly
				// after being restarted multiple times
				if i == num {
					expecter, _, err := tests.NewConsoleExpecter(virtClient, vm, "serial0", 10*time.Second)
					defer expecter.Close()
					Expect(err).To(BeNil())
					_, err = expecter.ExpectBatch([]expect.Batcher{
						&expect.BExp{R: "Welcome to Alpine"},
					}, 90*time.Second)
					Expect(err).To(BeNil())
				}

				err = virtClient.VM(vm.Namespace).Delete(vm.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				tests.NewObjectEventWatcher(obj).SinceWatchedObjectResourceVersion().WaitFor(tests.NormalEvent, v1.Deleted)
			}
			close(done)
		}, 200)
	})
})
<commit_msg>increase storage timeouts<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"time"

	"github.com/google/goexpect"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Storage", func() {

	nodeName := ""
	nodeIp := ""
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	BeforeEach(func() {
		tests.BeforeTestCleanup()

		nodes, err := virtClient.CoreV1().Nodes().List(metav1.ListOptions{})
		Expect(err).ToNot(HaveOccurred())
		Expect(nodes.Items).ToNot(BeEmpty())
		nodeName = nodes.Items[0].Name
		for _, addr := range nodes.Items[0].Status.Addresses {
			if addr.Type == k8sv1.NodeInternalIP {
				nodeIp = addr.Address
				break
			}
		}
		Expect(nodeIp).ToNot(Equal(""))
	})

	getTargetLogs := func(tailLines int64) string {
		pods, err := virtClient.CoreV1().Pods(metav1.NamespaceSystem).List(metav1.ListOptions{LabelSelector: v1.AppLabel + " in (iscsi-demo-target)"})
		Expect(err).ToNot(HaveOccurred())

		//FIXME Sometimes pods hang in terminating state, select the pod which does not have a deletion timestamp
		podName := ""
		for _, pod := range pods.Items {
			if pod.ObjectMeta.DeletionTimestamp == nil {
				if pod.Status.HostIP == nodeIp {
					podName = pod.ObjectMeta.Name
					break
				}
			}
		}
		Expect(podName).ToNot(BeEmpty())

		logsRaw, err := virtClient.CoreV1().
			Pods(metav1.NamespaceSystem).
			GetLogs(podName,
				&k8sv1.PodLogOptions{TailLines: &tailLines}).
			DoRaw()
		Expect(err).To(BeNil())

		return string(logsRaw)
	}

	checkReadiness := func() {
		logs := getTargetLogs(75)
		Expect(logs).To(ContainSubstring("Target 1: iqn.2017-01.io.kubevirt:sn.42"))
		Expect(logs).To(ContainSubstring("Driver: iscsi"))
		Expect(logs).To(ContainSubstring("State: ready"))
	}

	RunVMAndExpectLaunch := func(vm *v1.VirtualMachine, withAuth bool, timeout int) runtime.Object {
		obj, err := virtClient.RestClient().Post().Resource("virtualmachines").Namespace(tests.NamespaceTestDefault).Body(vm).Do().Get()
		Expect(err).To(BeNil())
		tests.WaitForSuccessfulVMStartWithTimeout(obj, timeout)
		return obj
	}

	Context("Given a fresh iSCSI target", func() {
		It("should be available and ready", func() {
			checkReadiness()
		})
	})

	Context("Given a VM and an Alpine PVC", func() {
		It("should be successfully started", func(done Done) {
			checkReadiness()

			// Start the VM with the PVC attached
			vm := tests.NewRandomVMWithPVC(tests.DiskAlpineISCSI)
			vm.Spec.NodeSelector = map[string]string{"kubernetes.io/hostname": nodeName}
			RunVMAndExpectLaunch(vm, false, 45)

			expecter, _, err := tests.NewConsoleExpecter(virtClient, vm, "serial0", 10*time.Second)
			defer expecter.Close()
			Expect(err).To(BeNil())
			_, err = expecter.ExpectBatch([]expect.Batcher{
				&expect.BExp{R: "Welcome to Alpine"},
			}, 200*time.Second)
			Expect(err).To(BeNil())

			close(done)
		}, 240)

		It("should be successfully started and stopped multiple times", func(done Done) {
			checkReadiness()

			vm := tests.NewRandomVMWithPVC(tests.DiskAlpineISCSI)
			vm.Spec.NodeSelector = map[string]string{"kubernetes.io/hostname": nodeName}

			num := 3
			for i := 1; i <= num; i++ {
				obj := RunVMAndExpectLaunch(vm, false, 60)

				// Verify console on last iteration to verify the VM is still booting properly
				// after being restarted multiple times
				if i == num {
					expecter, _, err := tests.NewConsoleExpecter(virtClient, vm, "serial0", 10*time.Second)
					defer expecter.Close()
					Expect(err).To(BeNil())
					_, err = expecter.ExpectBatch([]expect.Batcher{
						&expect.BExp{R: "Welcome to Alpine"},
					}, 200*time.Second)
					Expect(err).To(BeNil())
				}

				err = virtClient.VM(vm.Namespace).Delete(vm.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				tests.NewObjectEventWatcher(obj).SinceWatchedObjectResourceVersion().WaitFor(tests.NormalEvent, v1.Deleted)
			}
			close(done)
		}, 240)
	})
})
<|endoftext|>