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 }