• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brotherlogic / gobuildslave / 21327689624

25 Jan 2026 05:39AM UTC coverage: 29.823%. First build
21327689624

Pull #9563

github

brotherlogic
Switch to google
Pull Request #9563: Switch to google

0 of 1 new or added line in 1 file covered. (0.0%)

371 of 1244 relevant lines covered (29.82%)

0.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.78
/command.go
1
package main
2

3
import (
4
        "bufio"
5
        "context"
6
        "crypto/md5"
7
        "flag"
8
        "fmt"
9
        "io"
10
        "io/ioutil"
11
        "log"
12
        "net"
13
        "net/http"
14
        "os"
15
        "os/exec"
16
        "strconv"
17
        "strings"
18
        "sync"
19
        "time"
20

21
        "github.com/brotherlogic/goserver"
22
        "github.com/brotherlogic/goserver/utils"
23
        "github.com/prometheus/client_golang/prometheus"
24
        "github.com/prometheus/client_golang/prometheus/promauto"
25
        "google.golang.org/grpc"
26
        "google.golang.org/grpc/codes"
27
        "google.golang.org/grpc/status"
28
        "google.golang.org/protobuf/proto"
29

30
        pbb "github.com/brotherlogic/buildserver/proto"
31
        pbd "github.com/brotherlogic/discovery/proto"
32
        pbfc "github.com/brotherlogic/filecopier/proto"
33
        pbgh "github.com/brotherlogic/githubcard/proto"
34
        pb "github.com/brotherlogic/gobuildslave/proto"
35
        pbs "github.com/brotherlogic/goserver/proto"
36
        pbv "github.com/brotherlogic/versionserver/proto"
37
)
38

39
var (
40
        fails = promauto.NewCounter(prometheus.CounterOpts{
41
                Name: "gobuildslave_pingfails",
42
                Help: "The size of the print queue",
43
        })
44

45
        voltage = promauto.NewGauge(prometheus.GaugeOpts{
46
                Name: "gobuildslave_voltage",
47
                Help: "The size of the print queue",
48
        })
49
)
50

51
type version interface {
52
        confirm(ctx context.Context, job string) bool
53
}
54

55
type prodVersion struct {
56
        dial   func(ctx context.Context, server string) (*grpc.ClientConn, error)
57
        server string
58
        log    func(ctx context.Context, line string)
59
}
60

61
func (p *prodVersion) confirm(ctx context.Context, job string) bool {
×
62
        conn, err := p.dial(ctx, "versionserver")
×
63
        if err != nil {
×
64
                return false
×
65
        }
×
66
        defer conn.Close()
×
67

×
68
        client := pbv.NewVersionServerClient(conn)
×
69

×
70
        setTime := time.Now().Add(time.Minute).Unix()
×
71
        resp, err := client.SetIfLessThan(ctx,
×
72
                &pbv.SetIfLessThanRequest{
×
73
                        TriggerValue: time.Now().Unix(),
×
74
                        Set: &pbv.Version{
×
75
                                Key:    "guard." + job,
×
76
                                Value:  setTime,
×
77
                                Setter: "gobuildslave" + p.server,
×
78
                        },
×
79
                })
×
80
        p.log(ctx, fmt.Sprintf("Result = %v, %v", err, resp))
×
81
        if err != nil {
×
82
                return false
×
83
        }
×
84

85
        return resp.Success
×
86
}
87

88
type prodBuilder struct {
89
        dial   func(ctx context.Context, server string) (*grpc.ClientConn, error)
90
        server func() string
91
        Log    func(context.Context, string)
92
}
93

94
func (p *prodBuilder) build(ctx context.Context, job *pb.Job) (*pbb.Version, error) {
×
95
        file := fmt.Sprintf("/home/simon/gobuild/bin/%v.version", job.Name)
×
96
        data, err := ioutil.ReadFile(file)
×
97
        if err != nil {
×
98
                if os.IsNotExist(err) {
×
99
                        file := fmt.Sprintf("/home/simon/gobuild/bin/%v.nversion", job.Name)
×
100
                        data, err = ioutil.ReadFile(file)
×
101
                        if err != nil {
×
102
                                return nil, err
×
103
                        }
×
104
                } else {
×
105
                        return nil, err
×
106
                }
×
107
        }
108

109
        version := &pbb.Version{}
×
110
        proto.Unmarshal(data, version)
×
111

×
112
        return version, nil
×
113
}
114

115
func (p *prodBuilder) copy(ctx context.Context, v *pbb.Version) (*pbfc.CopyResponse, error) {
×
116
        conn, err := p.dial(ctx, "filecopier")
×
117
        if err != nil {
×
118
                return nil, err
×
119
        }
×
120
        defer conn.Close()
×
121
        copier := pbfc.NewFileCopierServiceClient(conn)
×
122
        req := &pbfc.CopyRequest{
×
123
                InputFile:    v.Path,
×
124
                InputServer:  v.Server,
×
125
                OutputFile:   "/home/simon/gobuild/bin/" + v.Job.Name,
×
126
                OutputServer: p.server(),
×
127
        }
×
128
        return copier.QueueCopy(ctx, req)
×
129
}
130

131
type prodDisker struct{}
132

133
func (p *prodDisker) getDisks() []string {
×
134
        disks := make([]string, 0)
×
135
        read, err := os.ReadDir("/media")
×
136
        if err == nil {
×
137
                for _, f := range read {
×
138
                        if f.IsDir() || f.Name() == "datastore" {
×
139
                                disks = append(disks, f.Name())
×
140
                        }
×
141
                }
142
        }
143

144
        return disks
×
145
}
146

147
// Server the main server type
148
type Server struct {
149
        *goserver.GoServer
150
        runner          *Runner
151
        disk            diskChecker
152
        jobs            map[string]*pb.JobDetails
153
        nMut            *sync.Mutex
154
        njobs           map[string]*pb.JobAssignment
155
        translator      translator
156
        scheduler       *Scheduler
157
        disker          disker
158
        crashFails      int64
159
        crashError      string
160
        crashAttempts   int64
161
        builder         Builder
162
        doesBuild       bool
163
        stateMap        map[string]string
164
        pendingMap      map[time.Weekday]map[string]int
165
        stateMutex      *sync.Mutex
166
        rejecting       bool
167
        lastCopyTime    time.Duration
168
        lastCopyStatus  string
169
        versionsMutex   *sync.Mutex
170
        versions        map[string]*pbb.Version
171
        skippedCopies   int64
172
        copies          int64
173
        version         version
174
        lastBadHearts   int
175
        accessPoint     string
176
        discoverStartup time.Time
177
        discoverSync    time.Time
178
        lastAccess      time.Time
179
        ackChan         chan *pb.JobAssignment
180
        maxJobs         int
181
        shuttingDown    bool
182
}
183

184
// InitServer builds out a server
185
func InitServer(build bool) *Server {
1✔
186
        s := &Server{
1✔
187
                &goserver.GoServer{},
1✔
188
                Init(&prodBuilder{}),
1✔
189
                prodDiskChecker{},
1✔
190
                make(map[string]*pb.JobDetails),
1✔
191
                &sync.Mutex{},
1✔
192
                make(map[string]*pb.JobAssignment),
1✔
193
                &pTranslator{},
1✔
194
                &Scheduler{
1✔
195
                        blockingQueue:    make(chan *rCommand),
1✔
196
                        nonblockingQueue: make(chan *rCommand),
1✔
197
                        complete:         make([]*rCommand, 0),
1✔
198
                },
1✔
199
                &prodDisker{},
1✔
200
                int64(0),
1✔
201
                "",
1✔
202
                int64(0),
1✔
203
                &prodBuilder{},
1✔
204
                build,
1✔
205
                make(map[string]string),
1✔
206
                make(map[time.Weekday]map[string]int),
1✔
207
                &sync.Mutex{},
1✔
208
                build,
1✔
209
                0,
1✔
210
                "",
1✔
211
                &sync.Mutex{},
1✔
212
                make(map[string]*pbb.Version),
1✔
213
                int64(0),
1✔
214
                int64(0),
1✔
215
                &prodVersion{},
1✔
216
                0,
1✔
217
                "",
1✔
218
                time.Now(),
1✔
219
                time.Now(),
1✔
220
                time.Now(),
1✔
221
                make(chan *pb.JobAssignment, 1000),
1✔
222
                7,
1✔
223
                false,
1✔
224
        }
1✔
225

1✔
226
        // Run the processing queues
1✔
227
        go s.scheduler.processBlockingCommands()
1✔
228
        go s.scheduler.processNonblockingCommands()
1✔
229

1✔
230
        return s
1✔
231
}
1✔
232

233
func (s *Server) deliverCrashReport(ctx context.Context, j *pb.JobAssignment, output string) {
1✔
234
        s.crashAttempts++
1✔
235

1✔
236
        s.CtxLog(ctx, fmt.Sprintf("Attempting to send crash report: %v -> %v", j.Job, output))
1✔
237

1✔
238
        if j.Job.Name == "buildserver" && len(output) > 0 {
1✔
239
                s.RaiseIssue("Buildserver failing", fmt.Sprintf("on %v -> %v", s.Registry, output))
×
240
        }
×
241

242
        if len(strings.TrimSpace(output)) > 0 && !s.SkipLog {
1✔
243
                conn, err := s.FDialServer(ctx, "buildserver")
×
244
                if err == nil && s.Registry != nil {
×
245
                        defer conn.Close()
×
246
                        client := pbb.NewBuildServiceClient(conn)
×
247
                        _, err := client.ReportCrash(ctx, &pbb.CrashRequest{Origin: s.Registry.Identifier, Version: j.RunningVersion, Job: j.Job, Crash: &pbb.Crash{ErrorMessage: output}})
×
248

×
249
                        if err != nil {
×
250
                                s.crashFails++
×
251
                                s.crashError = fmt.Sprintf("%v-%v", j.Job, err)
×
252
                                s.CtxLog(ctx, fmt.Sprintf("Failed to send crash report: %v -> %v because %v", j.Job, output, err))
×
253

×
254
                        }
×
255
                }
256
        } else {
1✔
257
                s.CtxLog(ctx, fmt.Sprintf("Skipping empty crash report"))
1✔
258
        }
1✔
259

260
}
261

262
func (s *Server) addMessage(details *pb.JobDetails, message string) {
×
263
        for _, t := range s.runner.backgroundTasks {
×
264
                if t.details.GetSpec().Name == details.Spec.Name {
×
265
                        t.output += message
×
266
                }
×
267
        }
268
}
269

270
func (s *Server) nmonitor(job *pb.JobAssignment) {
1✔
271
        for job.State != pb.State_DEAD {
2✔
272
                ctx, cancel := utils.ManualContext(fmt.Sprintf("nmonitor-%v", job.Job.Name), time.Minute)
1✔
273
                s.runTransition(ctx, job)
1✔
274
                cancel()
1✔
275
                time.Sleep(time.Second * 10)
1✔
276
        }
1✔
277
}
278

279
func getHash(file string) (string, error) {
×
280
        env := os.Environ()
×
281
        home := ""
×
282
        for _, s := range env {
×
283
                if strings.HasPrefix(s, "HOME=") {
×
284
                        home = s[5:]
×
285
                }
×
286
        }
287

288
        gpath := home + "/gobuild"
×
289

×
290
        f, err := os.Open(strings.Replace(file, "$GOPATH", gpath, 1))
×
291
        if err != nil {
×
292
                return "", err
×
293
        }
×
294
        defer f.Close()
×
295

×
296
        h := md5.New()
×
297
        if _, err := io.Copy(h, f); err != nil {
×
298
                return "", err
×
299
        }
×
300

301
        return string(h.Sum(nil)), nil
×
302
}
303

304
// DoRegister Registers this server
305
func (s *Server) DoRegister(server *grpc.Server) {
×
306
        pb.RegisterGoBuildSlaveServer(server, s)
×
307
        pb.RegisterBuildSlaveServer(server, s)
×
308
}
×
309

310
// ReportHealth determines if the server is healthy
311
func (s *Server) ReportHealth() bool {
×
312
        return true
×
313
}
×
314

315
func (s *Server) Shutdown(ctx context.Context) error {
×
316
        return nil
×
317
}
×
318

319
// Mote promotes/demotes this server
320
func (s *Server) Mote(ctx context.Context, master bool) error {
×
321
        return nil
×
322
}
×
323

324
// GetState gets the state of the server
325
func (s *Server) GetState() []*pbs.State {
×
326
        return []*pbs.State{}
×
327
}
×
328

329
// Init builds the default runner framework
330
func Init(b Builder) *Runner {
1✔
331
        r := &Runner{gopath: "goautobuild", m: &sync.Mutex{}, bm: &sync.Mutex{}, builder: b}
1✔
332
        r.runner = runCommand
1✔
333
        return r
1✔
334
}
1✔
335

336
func runCommand(c *runnerCommand) {
1✔
337
        if c == nil || c.command == nil {
1✔
338
                return
×
339
        }
×
340

341
        env := os.Environ()
1✔
342
        home := ""
1✔
343
        for _, s := range env {
2✔
344
                if strings.HasPrefix(s, "HOME=") {
2✔
345
                        home = s[5:]
1✔
346
                }
1✔
347
        }
348

349
        gpath := home + "/gobuild"
1✔
350
        c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
1✔
351
        for i := range c.command.Args {
2✔
352
                c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
1✔
353
        }
1✔
354

355
        path := fmt.Sprintf("GOPATH=%v/gobuild/", home)
1✔
356
        pathbin := fmt.Sprintf("GOBIN=%v/gobuild/bin/", home)
1✔
357
        found := false
1✔
358
        envl := os.Environ()
1✔
359
        for i, blah := range envl {
2✔
360
                if strings.HasPrefix(blah, "GOPATH") {
1✔
361
                        envl[i] = path
×
362
                        found = true
×
363
                }
×
364
                if strings.HasPrefix(blah, "GOBIN") {
1✔
365
                        envl[i] = pathbin
×
366
                        found = true
×
367
                }
×
368
        }
369
        if !found {
2✔
370
                envl = append(envl, path)
1✔
371
        }
1✔
372
        c.command.Env = envl
1✔
373

1✔
374
        out, err := c.command.StderrPipe()
1✔
375
        if err != nil {
1✔
376
                log.Fatalf("Problem getting stderr: %v", err)
×
377
        }
×
378

379
        if out != nil {
2✔
380
                scanner := bufio.NewScanner(out)
1✔
381
                go func() {
2✔
382
                        for scanner != nil && scanner.Scan() {
2✔
383
                                c.output += scanner.Text()
1✔
384
                        }
1✔
385
                        out.Close()
1✔
386
                }()
387
        }
388

389
        c.command.Start()
1✔
390

1✔
391
        if !c.background {
1✔
392
                c.command.Wait()
×
393
                c.complete = true
×
394
        } else {
1✔
395
                c.details.StartTime = time.Now().Unix()
1✔
396
        }
1✔
397
}
398

399
func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
1✔
400
        return diskUsage(path)
1✔
401
}
1✔
402

403
type pTranslator struct{}
404

405
func (p *pTranslator) build(job *pb.Job) *exec.Cmd {
×
406
        return exec.Command("go", "install", fmt.Sprintf("%v@latest", job.GoPath))
×
407
}
×
408

409
func (p *pTranslator) run(job *pb.Job) *exec.Cmd {
×
410
        elems := strings.Split(job.GoPath, "/")
×
411
        command := elems[len(elems)-1]
×
412
        if job.Sudo {
×
413
                return exec.Command("sudo", "$GOPATH/bin/"+command)
×
414
        }
×
415
        return exec.Command("$GOPATH/bin/" + command)
×
416
}
417

418
// updateState of the runner command
419
func (s *Server) isJobAlive(ctx context.Context, job *pb.JobAssignment) bool {
×
420
        if job.GetPort() == 0 {
×
421
                dServer, dPort, err := s.getIP(ctx, job.Job.Name, job.Server)
×
422

×
423
                s.CtxLog(ctx, fmt.Sprintf("GOT THE PORT %v with %v", dPort, err))
×
424

×
425
                e, ok := status.FromError(err)
×
426
                if ok && e.Code() == codes.DeadlineExceeded {
×
427
                        //Ignore deadline exceeds on discover
×
428
                        return true
×
429
                }
×
430

431
                if err != nil {
×
432
                        return false
×
433
                }
×
434

435
                job.Host = dServer
×
436
                job.Port = dPort
×
437
        }
438

439
        dConn, err := grpc.Dial(job.Host+":"+strconv.Itoa(int(job.Port)), grpc.WithInsecure())
×
440
        if err != nil {
×
441
                return false
×
442
        }
×
443
        defer dConn.Close()
×
444

×
445
        c := pbs.NewGoserverServiceClient(dConn)
×
446
        resp, err := c.IsAlive(ctx, &pbs.Alive{}, grpc.FailFast(false))
×
447

×
448
        if err != nil || resp.Name != job.Job.Name {
×
449
                e, ok := status.FromError(err)
×
450
                if ok && e.Code() != codes.Unavailable {
×
451
                        return false
×
452
                }
×
453
        }
454

455
        return true
×
456
}
457

458
func (s *Server) getIP(ctx context.Context, name string, server string) (string, int32, error) {
×
459
        conn, err := s.FDial(utils.LocalDiscover)
×
460
        if err != nil {
×
461
                return "", -1, err
×
462
        }
×
463
        defer conn.Close()
×
464

×
465
        registry := pbd.NewDiscoveryServiceV2Client(conn)
×
466
        r, err := registry.Get(ctx, &pbd.GetRequest{Job: name, Server: server})
×
467

×
468
        if err != nil {
×
469
                return "", -1, err
×
470
        }
×
471
        if len(r.GetServices()) == 0 {
×
472
                return "", -1, fmt.Errorf("No services found for %v and %v", name, server)
×
473
        }
×
474

475
        s.CtxLog(ctx, fmt.Sprintf("%v -> %v", server, r.GetServices()))
×
476

×
477
        return r.GetServices()[0].Ip, r.GetServices()[0].Port, nil
×
478

479
}
480

481
func (s *Server) checkOnSsh(ctx context.Context) error {
×
482
        f := "/home/simon/.ssh"
×
483

×
484
        for true {
×
485
                _, err := os.Stat(f)
×
486
                if err != nil {
×
487
                        conn, err := s.FDialServer(ctx, "githubcard")
×
488
                        if err == nil {
×
489
                                defer conn.Close()
×
490
                                client := pbgh.NewGithubClient(conn)
×
491
                                client.AddIssue(ctx, &pbgh.Issue{Service: "gobuildslave", Title: "SSH Needed", Body: s.Registry.Identifier}, grpc.FailFast(false))
×
492
                        }
×
493
                }
494
                time.Sleep(time.Hour)
×
495
        }
496

497
        return nil
×
498
}
499

500
func (s *Server) checkOnUpdate(ctx context.Context) error {
×
501
        f := "/var/cache/apt/pkgcache.bin"
×
502

×
503
        for true {
×
504
                info, err := os.Stat(f)
×
505
                if err == nil {
×
506
                        if info.ModTime().Before(time.Now().AddDate(0, -1, 0)) {
×
507
                                conn, err := s.FDialServer(ctx, "githubcard")
×
508
                                if err == nil {
×
509
                                        defer conn.Close()
×
510
                                        client := pbgh.NewGithubClient(conn)
×
511
                                        client.AddIssue(ctx, &pbgh.Issue{Service: "gobuildslave", Title: "UDPATE NEEDED", Body: fmt.Sprintf("%v -> %v", s.Registry.Identifier, s.Registry.Ip)}, grpc.FailFast(false))
×
512

×
513
                                }
×
514

515
                        }
516
                }
517
                time.Sleep(time.Hour)
×
518
        }
519

520
        return nil
×
521
}
522

523
func (s *Server) getServerName() string {
×
524
        return s.Registry.Identifier
×
525
}
×
526

527
func (s *Server) loadCurrentVersions() {
×
528
        files, err := ioutil.ReadDir("/home/simon/gobuild/bin")
×
529
        if err == nil {
×
530
                for _, f := range files {
×
531
                        if strings.HasSuffix(f.Name(), ".version") {
×
532
                                data, _ := ioutil.ReadFile("/home/simon/gobuild/bin/" + f.Name())
×
533
                                val := &pbb.Version{}
×
534
                                proto.Unmarshal(data, val)
×
535
                                s.versionsMutex.Lock()
×
536
                                s.versions[val.GetJob().GetName()] = val
×
537
                                s.versionsMutex.Unlock()
×
538
                        }
×
539
                }
540

541
        }
542
}
543

544
func (s *Server) getLatestVersion(ctx context.Context, jobName, path string) (*pbb.Version, error) {
×
545
        conn, err := s.FDialServer(ctx, "buildserver")
×
546
        if err != nil {
×
547
                return nil, err
×
548
        }
×
549
        defer conn.Close()
×
550
        client := pbb.NewBuildServiceClient(conn)
×
551
        resp, err := client.GetVersions(ctx, &pbb.VersionRequest{BitSize: int32(s.Bits), JustLatest: true, Job: &pb.Job{Name: jobName, GoPath: path}})
×
552
        if err != nil {
×
553
                return nil, err
×
554
        }
×
555
        return resp.GetVersions()[0], nil
×
556
}
557

558
func (s *Server) badHeartChecker(ctx context.Context) error {
×
559
        badHearts := s.BadHearts
×
560
        if badHearts-s.lastBadHearts > 100 {
×
561
                ioutil.WriteFile("/home/simon/gobuildcrash", []byte(fmt.Sprintf("%v bad hearts", badHearts)), 0644)
×
562
                //cmd := exec.Command("sudo", "reboot")
×
563
                //cmd.Run()
×
564
        }
×
565
        s.lastBadHearts = badHearts
×
566

×
567
        return nil
×
568
}
569

570
func (s *Server) stateChecker(ctx context.Context) error {
×
571
        s.nMut.Lock()
×
572
        defer s.nMut.Unlock()
×
573
        for _, job := range s.njobs {
×
574
                if job.State == pb.State_ACKNOWLEDGED && time.Now().Sub(time.Unix(job.LastTransitionTime, 0)) > time.Minute*30 {
×
575
                        s.CtxLog(ctx, fmt.Sprintf("%v is having a long ACK (%v) on %v", job.Job.Name, time.Now().Sub(time.Unix(job.LastTransitionTime, 0)), s.Registry.Identifier))
×
576
                }
×
577
        }
578
        return nil
×
579
}
580

581
func (s *Server) backgroundRegister() {
×
582
        err := fmt.Errorf("Initial error")
×
583
        for err != nil {
×
584
                err = s.RegisterServerV2(false)
×
585
                if err == nil {
×
586
                        ctx, cancel := utils.ManualContext("gbs-rereg", time.Minute)
×
587
                        defer cancel()
×
588

×
589
                        conn, err := s.FDial("localhost:50055")
×
590
                        if err == nil {
×
591
                                defer conn.Close()
×
592
                                client := pbd.NewDiscoveryServiceV2Client(conn)
×
593
                                client.Unregister(ctx, &pbd.UnregisterRequest{Reason: "gbs-restart", Service: &pbd.RegistryEntry{Identifier: s.Registry.Identifier}})
×
594
                                time.Sleep(time.Second * 5)
×
595
                                s.RegisterServerV2(false)
×
596
                        }
×
597
                }
598

599
                time.Sleep(time.Minute)
×
600
        }
601

602
        /*if strings.HasPrefix(s.Registry.Identifier, "clust") {
603
                s.maxJobs = 100
604
        }*/
605

606
        s.version = &prodVersion{s.FDialServer, s.Registry.Identifier, s.CtxLog}
×
607
}
608

609
func (s *Server) updateAccess() {
×
610
        ctx, cancel := utils.ManualContext("gbs-update-access", time.Hour)
×
611
        defer cancel()
×
612

×
613
        for {
×
614
                output, err := exec.Command("sudo", "vcgencmd", "measure_volts").CombinedOutput()
×
615
                if err != nil {
×
616
                        s.CtxLog(ctx, fmt.Sprintf("Unable to measure voltage: %v", err))
×
617
                } else {
×
618
                        bits := strings.Split(string(output), "=")
×
619
                        val, err := strconv.ParseFloat(bits[1][:len(bits[1])-2], 64)
×
620
                        if err != nil {
×
621
                                s.CtxLog(ctx, fmt.Sprintf("Unable to pars voltage: %v", err))
×
622
                        } else {
×
623
                                voltage.Set(val)
×
624
                        }
×
625
                }
626

NEW
627
                url := "https://www.google.com"
×
628
                r, err := http.Get(url)
×
629

×
630
                if err == nil {
×
631
                        s.lastAccess = time.Now()
×
632
                        r.Body.Close()
×
633
                } else {
×
634
                        s.CtxLog(ctx, fmt.Sprintf("Ping fail %v (%v = %v)", err, s.lastAccess, time.Now().Sub(s.lastAccess).Minutes()))
×
635
                        fails.Inc()
×
636
                }
×
637

638
                if time.Now().Sub(s.lastAccess) > time.Minute*5 && time.Now().Hour() < 22 && time.Now().Hour() >= 6 {
×
639
                        s.CtxLog(ctx, fmt.Sprintf("REBOOTING -> %v, %v\n", err, s.lastAccess))
×
640
                        cmd := exec.Command("sudo", "reboot")
×
641
                        cmd.Run()
×
642
                }
×
643

644
                foundIP := false
×
645
                ifaces, err := net.Interfaces()
×
646
                if err != nil {
×
647
                        s.CtxLog(ctx, fmt.Sprintf("NETINT ERROR: %v", err))
×
648
                        foundIP = true
×
649
                } else {
×
650
                        for _, i := range ifaces {
×
651
                                addrs, err := i.Addrs()
×
652
                                if err != nil {
×
653
                                        s.CtxLog(ctx, fmt.Sprintf("ADDR ERROR: %v", err))
×
654
                                        foundIP = true
×
655
                                } else {
×
656
                                        for _, addr := range addrs {
×
657
                                                var ip net.IP
×
658
                                                switch v := addr.(type) {
×
659
                                                case *net.IPNet:
×
660
                                                        ip = v.IP
×
661
                                                case *net.IPAddr:
×
662
                                                        ip = v.IP
×
663
                                                }
664
                                                // process IP address
665

666
                                                if ip != nil && !ip.IsLoopback() && ip.String() != "127.0.0.1" {
×
667
                                                        foundIP = true
×
668
                                                        s.CtxLog(ctx, fmt.Sprintf("FOUNDIP %v", ip))
×
669
                                                }
×
670
                                        }
671
                                }
672
                        }
673
                }
674
                if foundIP {
×
675
                        s.CtxLog(ctx, fmt.Sprintf("NOIP"))
×
676
                }
×
677

678
                time.Sleep(time.Second * 30)
×
679
        }
680
}
681

682
func (s *Server) lookForDiscover(ctx context.Context) error {
×
683
        for _, job := range s.njobs {
×
684
                if job.GetJob().GetName() == "discovery" {
×
685
                        if job.GetState() == pb.State_RUNNING {
×
686
                                return nil
×
687
                        }
×
688
                        if time.Now().Sub(time.Unix(job.GetLastTransitionTime(), 0)) > time.Minute*10 {
×
689
                                s.RaiseIssue("Discover is in a bad state", fmt.Sprintf("[%v] %v is the current state at %v (trans at %v)", s.Registry, job, time.Now(), time.Unix(job.GetLastTransitionTime(), 0)))
×
690
                        }
×
691
                        return nil
×
692
                }
693
        }
694

695
        s.RaiseIssue("Missing discover", fmt.Sprintf("Discover is missing on %v (%v)", s.Registry, s.njobs))
×
696
        return nil
×
697
}
698

699
func (s *Server) sleepDisplay() {
×
700
        for !s.LameDuck {
×
701
                command := []string{"-display", ":0.0", "dpms", "force", "on"}
×
702
                if time.Now().Hour() >= 22 || time.Now().Hour() < 7 {
×
703
                        command = []string{"-display", ":0.0", "dpms", "force", "off"}
×
704
                }
×
705
                exec.Command("xset", command...).Run()
×
706

×
707
                time.Sleep(time.Minute * 5)
×
708
        }
709
}
710

711
func main() {
×
712
        var quiet = flag.Bool("quiet", false, "Show all output")
×
713
        var build = flag.Bool("builds", true, "Responds to build requests")
×
714
        var maxnum = flag.Int("max_jobs", 10, "Maxiumum jobs")
×
715
        flag.Parse()
×
716

×
717
        if *quiet {
×
718
                log.SetFlags(0)
×
719
                log.SetOutput(ioutil.Discard)
×
720
        }
×
721

722
        s := InitServer(*build)
×
723

×
724
        s.scheduler.Log = s.CtxLog
×
725
        s.builder = &prodBuilder{Log: s.CtxLog, server: s.getServerName, dial: s.FDialServer}
×
726
        s.runner.getip = s.GetIP
×
727
        s.runner.logger = s.CtxLog
×
728
        s.Register = s
×
729
        s.PrepServer("gobuildslave")
×
730
        s.Killme = false
×
731

×
732
        s.maxJobs = *maxnum
×
733
        dets, err := ioutil.ReadFile("/sys/firmware/devicetree/base/model")
×
734
        if err == nil {
×
735
                model := string(dets)
×
736
                if strings.HasPrefix(model, "Raspberry Pi 4") {
×
737
                        s.maxJobs = 100
×
738
                } else {
×
739
                        s.maxJobs = 0
×
740
                }
×
741

742
        }
743

744
        go s.backgroundRegister()
×
745

×
746
        s.loadCurrentVersions()
×
747

×
748
        // Run a discover server to allow us to do a local register
×
749
        ctx, cancel := utils.ManualContext("gbs", time.Minute)
×
750
        defer cancel()
×
751
        _, err = s.RunJob(ctx, &pb.RunRequest{Job: &pb.Job{
×
752
                Name:             "discovery",
×
753
                GoPath:           "github.com/brotherlogic/discovery",
×
754
                PartialBootstrap: true,
×
755
                Breakout:         true,
×
756
        }})
×
757
        if err != nil {
×
758
                log.Fatalf("Error in setup:%v", err)
×
759
        }
×
760
        // Run a gobuildmaster to get jobs running
761
        _, err = s.RunJob(ctx, &pb.RunRequest{Job: &pb.Job{
×
762
                Name:             "gobuildmaster",
×
763
                GoPath:           "github.com/brotherlogic/gobuildmaster",
×
764
                PartialBootstrap: true,
×
765
                Breakout:         true,
×
766
        }})
×
767
        if err != nil {
×
768
                log.Fatalf("Error in setup: %v", err)
×
769
        }
×
770

771
        // Wait until we can register
772
        for s.Registry == nil {
×
773
                time.Sleep(time.Minute)
×
774
        }
×
775

776
        go s.procAcks()
×
777
        go s.updateAccess()
×
778
        if strings.Contains(s.Registry.Identifier, "display") || strings.Contains(s.Registry.Identifier, "personal") {
×
779
                go s.sleepDisplay()
×
780
        }
×
781

782
        err = s.Serve()
×
783
        log.Fatalf("Unable to serve: %v", err)
×
784
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc