github.com/netdata/go.d.plugin@v0.58.1/agent/discovery/sd/sd.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package sd
     4  
     5  import (
     6  	"context"
     7  	"sync"
     8  
     9  	"github.com/netdata/go.d.plugin/agent/confgroup"
    10  	"github.com/netdata/go.d.plugin/agent/discovery/sd/pipeline"
    11  	"github.com/netdata/go.d.plugin/logger"
    12  
    13  	"gopkg.in/yaml.v2"
    14  )
    15  
    16  func NewServiceDiscovery() (*ServiceDiscovery, error) {
    17  	return nil, nil
    18  }
    19  
    20  type (
    21  	ServiceDiscovery struct {
    22  		*logger.Logger
    23  
    24  		confProv  ConfigFileProvider
    25  		sdFactory sdPipelineFactory
    26  
    27  		confCache map[string]uint64
    28  		pipelines map[string]func()
    29  	}
    30  	sdPipeline interface {
    31  		Run(ctx context.Context, in chan<- []*confgroup.Group)
    32  	}
    33  	sdPipelineFactory interface {
    34  		create(config pipeline.Config) (sdPipeline, error)
    35  	}
    36  )
    37  
    38  func (d *ServiceDiscovery) Run(ctx context.Context, in chan<- []*confgroup.Group) {
    39  	d.Info("instance is started")
    40  	defer d.Info("instance is stopped")
    41  	defer d.cleanup()
    42  
    43  	var wg sync.WaitGroup
    44  
    45  	wg.Add(1)
    46  	go func() { defer wg.Done(); d.confProv.Run(ctx) }()
    47  
    48  	for {
    49  		select {
    50  		case <-ctx.Done():
    51  			return
    52  		case cf := <-d.confProv.Configs():
    53  			if cf.Source == "" {
    54  				continue
    55  			}
    56  			if len(cf.Data) == 0 {
    57  				delete(d.confCache, cf.Source)
    58  				d.removePipeline(cf)
    59  			} else if hash, ok := d.confCache[cf.Source]; !ok || hash != cf.Hash() {
    60  				d.confCache[cf.Source] = cf.Hash()
    61  				d.addPipeline(ctx, cf, in)
    62  			}
    63  		}
    64  	}
    65  }
    66  
    67  func (d *ServiceDiscovery) addPipeline(ctx context.Context, cf ConfigFile, in chan<- []*confgroup.Group) {
    68  	var cfg pipeline.Config
    69  
    70  	if err := yaml.Unmarshal(cf.Data, &cfg); err != nil {
    71  		d.Error(err)
    72  		return
    73  	}
    74  
    75  	pl, err := d.sdFactory.create(cfg)
    76  	if err != nil {
    77  		d.Error(err)
    78  		return
    79  	}
    80  
    81  	if stop, ok := d.pipelines[cf.Source]; ok {
    82  		stop()
    83  	}
    84  
    85  	var wg sync.WaitGroup
    86  	plCtx, cancel := context.WithCancel(ctx)
    87  
    88  	wg.Add(1)
    89  	go func() { defer wg.Done(); pl.Run(plCtx, in) }()
    90  	stop := func() { cancel(); wg.Wait() }
    91  
    92  	d.pipelines[cf.Source] = stop
    93  }
    94  
    95  func (d *ServiceDiscovery) removePipeline(cf ConfigFile) {
    96  	if stop, ok := d.pipelines[cf.Source]; ok {
    97  		delete(d.pipelines, cf.Source)
    98  		stop()
    99  	}
   100  }
   101  
   102  func (d *ServiceDiscovery) cleanup() {
   103  	for _, stop := range d.pipelines {
   104  		stop()
   105  	}
   106  }