-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtaurus.go
151 lines (132 loc) · 3.78 KB
/
taurus.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package taurus
import (
"crypto/tls"
"fmt"
"log"
"os"
"os/signal"
"sync"
"syscall"
"github.com/gogo/protobuf/proto"
mesos "github.com/mesos/mesos-go/mesosproto"
scheduler "github.com/mesos/mesos-go/scheduler"
)
const (
FrameworkName = "taurus"
)
// Config allows to specify Taurus Framework configuration
type Config struct {
// Mesos master
Master string
// Framework API Listen Address
ListenAddr string
// Unix user the tasks should be launched as
User string
// Framework Job store
Store Store
// Framework Task Queue
Queue TaskQueue
// Framework Scheduler Worker
Worker Worker
// TLS configuration
TlsConfig *tls.Config
}
// Taurus is a Mesos Framework with simple REST API
type Taurus struct {
fwInfo *mesos.FrameworkInfo
driver *scheduler.MesosSchedulerDriver
scheduler *Scheduler
api *Api
}
// NewFramework initializes Taurus framework with the provided configuration options
//
// NewFramework initializes Mesos Scheduler driver and creates HTTP API server
// It returns error if either Mesos driver or HTTP API server could not be created
func NewFramework(config *Config) (*Taurus, error) {
fwInfo := &mesos.FrameworkInfo{
User: proto.String(config.User),
Name: proto.String(FrameworkName),
}
sched, err := NewScheduler(config.Worker, config.Master)
if err != nil {
return nil, fmt.Errorf("Unable to create %s Scheduler: %s", FrameworkName, err)
}
driverConfig := scheduler.DriverConfig{
Scheduler: sched,
Framework: fwInfo,
Master: config.Master,
}
driver, err := scheduler.NewMesosSchedulerDriver(driverConfig)
if err != nil {
return nil, fmt.Errorf("Unable to create a SchedulerDriver: %s", err)
}
api, err := NewApi(&ApiConfig{
Address: config.ListenAddr,
TlsConfig: config.TlsConfig,
Store: config.Store,
})
if err != nil {
return nil, fmt.Errorf("Could not create %s API server: %s", FrameworkName, err)
}
return &Taurus{
fwInfo: fwInfo,
driver: driver,
scheduler: sched,
api: api,
}, nil
}
// Run starts Taurus framework
//
// Run launches Mesos scheduler driver, Mesos task scheduler and framework's API server in separate goroutines
// Run blocks until either of the started goroutines fails with error or if the framework has been manually stopped by sending it either of SIGTERM, SIGKILL or SIGINT OS signals
// Run waits for all launched goroutines to finish cleanly and returns error back to the caller
func (t *Taurus) Run() error {
var err error
var wg sync.WaitGroup
// Create error channel
errChan := make(chan error, 3)
// Signal handler to stop API, Scanner and Killer goroutines
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
// start mesos driver
wg.Add(1)
go func() {
log.Printf("Starting %s scheduler driver", FrameworkName)
defer wg.Done()
if status, err := t.driver.Run(); err != nil {
errChan <- fmt.Errorf("Driver failed to start with status %s: %s",
status.String(), err)
}
}()
// Start Scheduler
wg.Add(1)
go func() {
defer wg.Done()
log.Printf("Starting %s Scheduler", FrameworkName)
errChan <- t.scheduler.Run(t.driver)
}()
// Start Taurus API
wg.Add(1)
go func() {
defer wg.Done()
log.Printf("Starting %s API server", FrameworkName)
errChan <- t.api.ListenAndServe()
}()
select {
case sig := <-sigc:
log.Printf("Taurus shutting down. Got signal: %s", sig)
case err = <-errChan:
log.Printf("Taurus failed with error: %s", err)
}
log.Printf("Stopping %s API server", FrameworkName)
t.api.listener.Close()
log.Printf("Stopping %s Scheduler", FrameworkName)
t.scheduler.Stop()
log.Printf("Stopping %s Scheduler driver", FrameworkName)
if _, err := t.driver.Stop(false); err != nil {
log.Printf("Stopping %s scheduler driver failed: %s", FrameworkName, err)
os.Exit(1)
}
wg.Wait()
return err
}