-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
173 lines (148 loc) · 6.48 KB
/
main.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package main
import (
"flag"
"log"
"math/rand"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"github.com/Automattic/cron-control-runner/locker"
"github.com/Automattic/cron-control-runner/logger"
"github.com/Automattic/cron-control-runner/metrics"
"github.com/Automattic/cron-control-runner/orchestrator"
"github.com/Automattic/cron-control-runner/performer"
"github.com/Automattic/cron-control-runner/remote"
)
type options struct {
metricsAddress string
useMockData bool
debug bool
wpCLIPath string
wpPath string
fpmURL string
orchestratorConfig orchestrator.Config
remoteToken string
useWebsockets bool
eventsWebhookURL string
useLocker bool
dataConfigPath string
lockerRefreshInterval time.Duration
}
func main() {
rand.Seed(time.Now().UnixNano())
// Listen for termination signals.
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
defer signal.Stop(sigChan)
options := getCliOptions()
logger := logger.Logger{Logger: log.Default(), DebugMode: options.debug}
// Setup metrics.
var metricsManager metrics.Manager
if options.metricsAddress == "" {
logger.Infof("Using Mock Metrics")
metricsManager = metrics.Mock{Log: false}
} else {
metricsManager = metrics.NewProm()
go metrics.StartPromServer(options.metricsAddress)
}
// Setup the performer.
var perf performer.Performer
if options.useMockData {
logger.Infof("Using Mock Performer")
perf = &performer.Mock{UseSleeps: true, LogCommands: false, RotateSites: true}
} else {
perf = performer.NewCLI(options.wpCLIPath, options.wpPath, options.fpmURL, metricsManager, logger)
}
// Setup the locker, if enabled.
var lock locker.Locker
if options.useLocker {
lock = locker.NewMemcache(logger, "__ccr", options.dataConfigPath, options.lockerRefreshInterval)
defer lock.Close()
}
// Launch the orchestrator.
orch := orchestrator.New(perf, metricsManager, logger, lock, options.orchestratorConfig)
defer orch.Close()
// Setup the remote CLI module if enabled.
if 0 < len(options.remoteToken) {
// TODO: This module could definitely use some general refactoring, but namely a graceful shutdown would be good.
remote.Setup(options.remoteToken, options.useWebsockets, options.wpCLIPath, options.wpPath, options.eventsWebhookURL)
go remote.ListenForConnections()
}
logger.Infof("cron runner has started all processes, running with debug mode set to %t", options.debug)
// Wait for cancel signal
sig := <-sigChan
logger.Infof("caught termination signal %v, starting shutdown", sig)
}
func getCliOptions() options {
// Set defaults
options := options{
metricsAddress: "",
useMockData: false,
debug: false,
wpCLIPath: "/usr/local/bin/wp",
wpPath: "/var/www/html",
fpmURL: "",
orchestratorConfig: orchestrator.Config{
GetSitesInterval: 60 * time.Second,
GetEventsInterval: 30 * time.Second,
GetEventsParallelism: 4,
NumRunWorkers: 8,
EventBacklog: 0,
},
remoteToken: "",
useWebsockets: false,
useLocker: false,
dataConfigPath: "/etc/wpvip-data-config/config.json",
lockerRefreshInterval: 10 * time.Second,
}
// General purpose
flag.StringVar(&(options.metricsAddress), "prom-metrics-address", options.metricsAddress, "Listen address for prometheus metrics (e.g. :4444); if set, can scrape http://:4444/metrics.")
flag.BoolVar(&(options.useMockData), "use-mock-data", options.useMockData, "use the mock performer for testing")
flag.BoolVar(&(options.debug), "debug", options.debug, "enables debug mode (extra logging)")
// Locker
flag.BoolVar(&(options.useLocker), "use-locker", options.useLocker, "use the memcached locker")
flag.StringVar(&(options.dataConfigPath), "data-config-path", options.dataConfigPath, "Data-config path for locker memcache client configuration")
flag.DurationVar(&(options.lockerRefreshInterval), "locker-refresh-interval", options.lockerRefreshInterval, "Refresh interval for locker config")
// Used for the Performer
flag.StringVar(&(options.wpCLIPath), "wp-cli-path", options.wpCLIPath, "path to WP-CLI binary")
flag.StringVar(&(options.wpPath), "wp-path", options.wpPath, "path to the WordPress installation")
flag.StringVar(&(options.fpmURL), "fpm-url", options.fpmURL, "URL for the php-fpm server or socket (e.g. unix:///var/run/fastcgi.sock)")
// Used for the Orchestrator
flag.DurationVar(&(options.orchestratorConfig.GetSitesInterval), "get-sites-interval", options.orchestratorConfig.GetSitesInterval, "get-sites interval")
flag.DurationVar(&(options.orchestratorConfig.GetEventsInterval), "get-events-interval", options.orchestratorConfig.GetEventsInterval, "get-events interval")
flag.IntVar(&(options.orchestratorConfig.GetEventsParallelism), "get-events-parallelism", options.orchestratorConfig.GetEventsParallelism, "number of get-events calls (across sites) that may run concurrently")
flag.IntVar(&(options.orchestratorConfig.NumRunWorkers), "num-run-workers", options.orchestratorConfig.NumRunWorkers, "number of run-events workers to run")
flag.IntVar(&(options.orchestratorConfig.EventBacklog), "event-backlog", options.orchestratorConfig.EventBacklog, "depth of events channel, 0 is unbuffered")
// Used for remote CLI
flag.StringVar(&(options.remoteToken), "token", options.remoteToken, "Token to authenticate remote WP CLI requests")
flag.BoolVar(&(options.useWebsockets), "use-websockets", options.useWebsockets, "Use the websocket listener instead of raw tcp for remote WP CLI requests")
flag.StringVar(&(options.eventsWebhookURL), "events-webhook-url", options.eventsWebhookURL, "Webhook URL used to send WP CLI events")
// NOTE: this will exit if options are invalid or if help is requested, etc.
flag.Parse()
if !options.useMockData {
// Need to do these regardless of fpm because remote.go will still invoke wp-cli directly.
validatePath(&(options.wpCLIPath), "WP-CLI path")
validatePath(&(options.wpPath), "WordPress path")
}
return options
}
func validatePath(path *string, label string) {
if len(*path) < 1 {
log.Printf("Empty path provided for %s\n", label)
flag.Usage()
os.Exit(3)
}
var err error
*path, err = filepath.Abs(*path)
if err != nil {
log.Printf("Error for %s: %s\n", label, err.Error())
os.Exit(3)
}
if _, err = os.Stat(*path); os.IsNotExist(err) {
log.Printf("Error for %s: '%s' does not exist\n", label, *path)
flag.Usage()
os.Exit(3)
}
}