func (m *EtcdManager) AcquireLease(ctx context.Context, network string, attrs *LeaseAttrs) (*Lease, error) { config, err := m.GetNetworkConfig(ctx, network) if err != nil { return nil, err } for { l, err := m.acquireLeaseOnce(ctx, network, config, attrs) switch { case err == nil: log.Info("Subnet lease acquired: ", l.Subnet) return l, nil case err == context.Canceled, err == context.DeadlineExceeded: return nil, err default: log.Error("Failed to acquire subnet: ", err) } select { case <-time.After(time.Second): case <-ctx.Done(): return nil, ctx.Err() } } }
func (msr *MockSubnetRegistry) watchNetworks(ctx context.Context, since uint64) (Event, uint64, error) { msr.mux.Lock() index := msr.index msr.mux.Unlock() for { if since < index { return Event{}, 0, etcd.Error{ Code: etcd.ErrorCodeEventIndexCleared, Cause: "out of date", Message: "cursor is out of date", Index: index, } } select { case <-ctx.Done(): return Event{}, 0, ctx.Err() case e := <-msr.networkEvents: if e.index > since { return e.evt, e.index, nil } } } }
func (msr *MockSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (Event, uint64, error) { n, ok := msr.networks[network] if !ok { return Event{}, msr.index, fmt.Errorf("Network %s not found", network) } for { if since < msr.index { return Event{}, msr.index, etcd.Error{ Code: etcd.ErrorCodeEventIndexCleared, Cause: "out of date", Message: "cursor is out of date", Index: msr.index, } } select { case <-ctx.Done(): return Event{}, msr.index, ctx.Err() case e := <-n.subnetsEvents: if e.index <= since { continue } return e.evt, msr.index, nil } } }
func (msr *MockSubnetRegistry) watchSubnet(ctx context.Context, network string, since uint64, sn ip.IP4Net) (Event, uint64, error) { msr.mux.Lock() n, ok := msr.networks[network] msr.mux.Unlock() if !ok { return Event{}, 0, fmt.Errorf("Network %s not found", network) } for { msr.mux.Lock() index := msr.index msr.mux.Unlock() if since < index { return Event{}, msr.index, etcd.Error{ Code: etcd.ErrorCodeEventIndexCleared, Cause: "out of date", Message: "cursor is out of date", Index: index, } } select { case <-ctx.Done(): return Event{}, index, ctx.Err() case e := <-n.subnetEventsChan(sn): if e.index > since { return e.evt, index, nil } } } }
func (esr *etcdSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (*etcd.Response, error) { stop := make(chan bool) respCh := make(chan watchResp) go func() { for { key := path.Join(esr.etcdCfg.Prefix, network, "subnets") rresp, err := esr.client().RawWatch(key, since, true, nil, stop) if err != nil { respCh <- watchResp{nil, err} return } if len(rresp.Body) == 0 { // etcd timed out, go back but recreate the client as the underlying // http transport gets hosed (http://code.google.com/p/go/issues/detail?id=8648) esr.resetClient() continue } resp, err := rresp.Unmarshal() respCh <- watchResp{resp, err} } }() select { case <-ctx.Done(): close(stop) <-respCh // Wait for f to return. return nil, ctx.Err() case wr := <-respCh: return wr.resp, wr.err } }
func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Response, []byte, error) { req := act.HTTPRequest(c.endpoint) if err := printcURL(req); err != nil { return nil, nil, err } rtchan := make(chan roundTripResponse, 1) go func() { resp, err := c.transport.RoundTrip(req) rtchan <- roundTripResponse{resp: resp, err: err} close(rtchan) }() var resp *http.Response var err error select { case rtresp := <-rtchan: resp, err = rtresp.resp, rtresp.err case <-ctx.Done(): // cancel and wait for request to actually exit before continuing c.transport.CancelRequest(req) rtresp := <-rtchan resp = rtresp.resp err = ctx.Err() } // always check for resp nil-ness to deal with possible // race conditions between channels above defer func() { if resp != nil { resp.Body.Close() } }() if err != nil { return nil, nil, err } var body []byte done := make(chan struct{}) go func() { body, err = ioutil.ReadAll(resp.Body) done <- struct{}{} }() select { case <-ctx.Done(): err = resp.Body.Close() <-done if err == nil { err = ctx.Err() } case <-done: } return resp, body, err }
func (msr *mockSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (*etcd.Response, error) { for { select { case <-ctx.Done(): return nil, ctx.Err() case r := <-msr.events: if r.Node.ModifiedIndex <= since { continue } return r, nil } } }
func (c *httpClusterClient) AutoSync(ctx context.Context, interval time.Duration) error { ticker := time.NewTicker(interval) defer ticker.Stop() for { err := c.Sync(ctx) if err != nil { return err } select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: } } }
func (m *RemoteManager) httpDo(ctx context.Context, req *http.Request) (*http.Response, error) { // Run the HTTP request in a goroutine (so it can be canceled) and pass // the result via the channel c client := &http.Client{Transport: m.transport} c := make(chan httpRespErr, 1) go func() { resp, err := client.Do(req) c <- httpRespErr{resp, err} }() select { case <-ctx.Done(): m.transport.CancelRequest(req) <-c // Wait for f to return. return nil, ctx.Err() case r := <-c: return r.resp, r.err } }
func (m *EtcdManager) acquireLeaseOnce(ctx context.Context, network string, config *Config, attrs *LeaseAttrs) (*Lease, error) { for i := 0; i < registerRetries; i++ { l, err := m.tryAcquireLease(ctx, network, config, attrs.PublicIP, attrs) switch { case err != nil: return nil, err case l != nil: return l, nil } // before moving on, check for cancel // TODO(eyakubovich): propogate ctx deeper into registry select { case <-ctx.Done(): return nil, ctx.Err() default: } } return nil, errors.New("Max retries reached trying to acquire a subnet") }
func (msr *MockSubnetRegistry) watch(ctx context.Context, network string, since uint64) (*etcd.Response, error) { for { if since < msr.index { return nil, etcd.Error{ Code: etcd.ErrorCodeEventIndexCleared, Cause: "out of date", Message: "cursor is out of date", Index: msr.index, } } select { case <-ctx.Done(): return nil, ctx.Err() case r := <-msr.events: if r.Node.ModifiedIndex <= since { continue } return r, nil } } }
func (msr *MockSubnetRegistry) watchNetworks(ctx context.Context, since uint64) (Event, uint64, error) { for { if since < msr.index { return Event{}, msr.index, etcd.Error{ Code: etcd.ErrorCodeEventIndexCleared, Cause: "out of date", Message: "cursor is out of date", Index: msr.index, } } select { case <-ctx.Done(): return Event{}, msr.index, ctx.Err() case e := <-msr.networkEvents: if e.index <= since { continue } return e.evt, msr.index, nil } } }
func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Response, []byte, error) { req := act.HTTPRequest(c.endpoint) if err := printcURL(req); err != nil { return nil, nil, err } hctx, hcancel := context.WithCancel(ctx) if c.headerTimeout > 0 { hctx, hcancel = context.WithTimeout(ctx, c.headerTimeout) } defer hcancel() reqcancel := requestCanceler(c.transport, req) rtchan := make(chan roundTripResponse, 1) go func() { resp, err := c.transport.RoundTrip(req) rtchan <- roundTripResponse{resp: resp, err: err} close(rtchan) }() var resp *http.Response var err error select { case rtresp := <-rtchan: resp, err = rtresp.resp, rtresp.err case <-hctx.Done(): // cancel and wait for request to actually exit before continuing reqcancel() rtresp := <-rtchan resp = rtresp.resp switch { case ctx.Err() != nil: err = ctx.Err() case hctx.Err() != nil: err = fmt.Errorf("client: endpoint %s exceeded header timeout", c.endpoint.String()) default: panic("failed to get error from context") } } // always check for resp nil-ness to deal with possible // race conditions between channels above defer func() { if resp != nil { resp.Body.Close() } }() if err != nil { return nil, nil, err } var body []byte done := make(chan struct{}) go func() { body, err = ioutil.ReadAll(resp.Body) done <- struct{}{} }() select { case <-ctx.Done(): resp.Body.Close() <-done return nil, nil, ctx.Err() case <-done: } return resp, body, err }