github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/syslog/drainer.go (about) 1 package syslog 2 3 import ( 4 "context" 5 "encoding/json" 6 "time" 7 8 "code.cloudfoundry.org/lager" 9 "code.cloudfoundry.org/lager/lagerctx" 10 "github.com/pf-qiu/concourse/v6/atc/db" 11 "github.com/pf-qiu/concourse/v6/atc/event" 12 ) 13 14 //go:generate counterfeiter . Drainer 15 16 type Drainer interface { 17 Run(context.Context) error 18 } 19 20 type drainer struct { 21 hostname string 22 transport string 23 address string 24 caCerts []string 25 buildFactory db.BuildFactory 26 } 27 28 func NewDrainer(transport string, address string, hostname string, caCerts []string, buildFactory db.BuildFactory) Drainer { 29 return &drainer{ 30 hostname: hostname, 31 transport: transport, 32 address: address, 33 buildFactory: buildFactory, 34 caCerts: caCerts, 35 } 36 } 37 38 func (d *drainer) Run(ctx context.Context) error { 39 logger := lagerctx.FromContext(ctx).Session("syslog") 40 41 builds, err := d.buildFactory.GetDrainableBuilds() 42 if err != nil { 43 logger.Error("failed-to-get-drainable-builds", err) 44 return err 45 } 46 47 if len(builds) > 0 { 48 syslog, err := Dial(d.transport, d.address, d.caCerts) 49 if err != nil { 50 logger.Error("failed-to-connect", err) 51 return err 52 } 53 54 // ignore any errors coming from syslog.Close() 55 defer db.Close(syslog) 56 57 for _, build := range builds { 58 err := d.drainBuild(logger, build, syslog) 59 if err != nil { 60 return err 61 } 62 } 63 } 64 return nil 65 } 66 67 func (d *drainer) drainBuild(logger lager.Logger, build db.Build, syslog *Syslog) error { 68 logger = logger.Session("drain-build", build.LagerData()) 69 70 events, err := build.Events(0) 71 if err != nil { 72 return err 73 } 74 75 // ignore any errors coming from events.Close() 76 defer db.Close(events) 77 78 for { 79 ev, err := events.Next() 80 if err != nil { 81 if err == db.ErrEndOfBuildEventStream { 82 break 83 } 84 logger.Error("failed-to-get-next-event", err) 85 return err 86 } 87 88 if ev.Event == event.EventTypeLog { 89 var log event.Log 90 91 err := json.Unmarshal(*ev.Data, &log) 92 if err != nil { 93 logger.Error("failed-to-unmarshal", err) 94 return err 95 } 96 97 err = syslog.Write( 98 d.hostname, 99 build.SyslogTag(log.Origin.ID), 100 time.Unix(log.Time, 0), 101 log.Payload, 102 ) 103 if err != nil { 104 logger.Error("failed-to-write-to-server", err) 105 return err 106 } 107 } 108 } 109 110 err = build.SetDrained(true) 111 if err != nil { 112 logger.Error("failed-to-update-status", err) 113 return err 114 } 115 116 return nil 117 }