code: func (c *containerAdapter) waitNodeAttachments(ctx context.Context) error {
  	// to do this, we're going to get the attachment store and try getting the
  	// IP address for each network. if any network comes back not existing,
  	// we'll wait and try again.
  	attachmentStore := c.backend.GetAttachmentStore()
  	if attachmentStore == nil {
  		return fmt.Errorf("error getting attachment store")
  	}
  
  	// essentially, we're long-polling here. this is really sub-optimal, but a
  	// better solution based off signaling channels would require a more
  	// substantial rearchitecture and probably not be worth our time in terms
  	// of performance gains.
  	poll := time.NewTicker(nodeAttachmentReadyInterval)
  	defer poll.Stop()
  	for {
  		// set a flag ready to true. if we try to get a network IP that doesn't
  		// exist yet, we will set this flag to "false"
  		ready := true
  		for _, attachment := range c.container.networksAttachments {
  			// we only need node attachments (IP address) for overlay networks
  			// TODO(dperny): unsure if this will work with other network
  			// drivers, but i also don't think other network drivers use the
  			// node attachment IP address.
  			if attachment.Network.DriverState.Name == "overlay" {
  				if _, exists := attachmentStore.GetIPForNetwork(attachment.Network.ID); !exists {
  					ready = false
  				}
  			}
  		}
  
  		// if everything is ready here, then we can just return no error
  		if ready {
  			return nil
  		}
  
  		// otherwise, try polling again, or wait for context canceled.
  		select {
  		case <-ctx.Done():
  			return fmt.Errorf("node is missing network attachments, ip addresses may be exhausted")
  		case <-poll.C:
  		}
  	}
  }
docs: // waitNodeAttachments validates that NetworkAttachments exist on this node
  // for every network in use by this task. It blocks until the network
  // attachments are ready, or the context times out. If it returns nil, then the
  // node's network attachments are all there.