github.com/resin-io/docker@v1.13.1/pkg/discovery/file/file.go (about)

     1  package file
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/docker/docker/pkg/discovery"
    10  )
    11  
    12  // Discovery is exported
    13  type Discovery struct {
    14  	heartbeat time.Duration
    15  	path      string
    16  }
    17  
    18  func init() {
    19  	Init()
    20  }
    21  
    22  // Init is exported
    23  func Init() {
    24  	discovery.Register("file", &Discovery{})
    25  }
    26  
    27  // Initialize is exported
    28  func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration, _ map[string]string) error {
    29  	s.path = path
    30  	s.heartbeat = heartbeat
    31  	return nil
    32  }
    33  
    34  func parseFileContent(content []byte) []string {
    35  	var result []string
    36  	for _, line := range strings.Split(strings.TrimSpace(string(content)), "\n") {
    37  		line = strings.TrimSpace(line)
    38  		// Ignoring line starts with #
    39  		if strings.HasPrefix(line, "#") {
    40  			continue
    41  		}
    42  		// Inlined # comment also ignored.
    43  		if strings.Contains(line, "#") {
    44  			line = line[0:strings.Index(line, "#")]
    45  			// Trim additional spaces caused by above stripping.
    46  			line = strings.TrimSpace(line)
    47  		}
    48  		result = append(result, discovery.Generate(line)...)
    49  	}
    50  	return result
    51  }
    52  
    53  func (s *Discovery) fetch() (discovery.Entries, error) {
    54  	fileContent, err := ioutil.ReadFile(s.path)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("failed to read '%s': %v", s.path, err)
    57  	}
    58  	return discovery.CreateEntries(parseFileContent(fileContent))
    59  }
    60  
    61  // Watch is exported
    62  func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
    63  	ch := make(chan discovery.Entries)
    64  	errCh := make(chan error)
    65  	ticker := time.NewTicker(s.heartbeat)
    66  
    67  	go func() {
    68  		defer close(errCh)
    69  		defer close(ch)
    70  
    71  		// Send the initial entries if available.
    72  		currentEntries, err := s.fetch()
    73  		if err != nil {
    74  			errCh <- err
    75  		} else {
    76  			ch <- currentEntries
    77  		}
    78  
    79  		// Periodically send updates.
    80  		for {
    81  			select {
    82  			case <-ticker.C:
    83  				newEntries, err := s.fetch()
    84  				if err != nil {
    85  					errCh <- err
    86  					continue
    87  				}
    88  
    89  				// Check if the file has really changed.
    90  				if !newEntries.Equals(currentEntries) {
    91  					ch <- newEntries
    92  				}
    93  				currentEntries = newEntries
    94  			case <-stopCh:
    95  				ticker.Stop()
    96  				return
    97  			}
    98  		}
    99  	}()
   100  
   101  	return ch, errCh
   102  }
   103  
   104  // Register is exported
   105  func (s *Discovery) Register(addr string) error {
   106  	return discovery.ErrNotImplemented
   107  }