import (
"encoding/json"
"flag"
- "io/ioutil"
"log"
"os"
"os/signal"
"time"
"git.curoverse.com/arvados.git/sdk/go/arvados"
+ "git.curoverse.com/arvados.git/sdk/go/config"
)
+const defaultConfigPath = "/etc/arvados/keep-balance/keep-balance.yml"
+
// Config specifies site configuration, like API credentials and the
// choice of which servers are to be balanced.
//
CommitTrash bool
Logger *log.Logger
Dumper *log.Logger
+
+ // SafeRendezvousState from the most recent balance operation,
+ // or "" if unknown. If this changes from one run to the next,
+ // we need to watch out for races. See
+ // (*Balancer)ClearTrashLists.
+ SafeRendezvousState string
}
var debugf = func(string, ...interface{}) {}
func main() {
- var config Config
+ var cfg Config
var runOptions RunOptions
- configPath := flag.String("config", "",
- "`path` of json configuration file")
+ configPath := flag.String("config", defaultConfigPath,
+ "`path` of JSON or YAML configuration file")
serviceListPath := flag.String("config.KeepServiceList", "",
- "`path` of json file with list of keep services to balance, as given by \"arv keep_service list\" "+
+ "`path` of JSON or YAML file with list of keep services to balance, as given by \"arv keep_service list\" "+
"(default: config[\"KeepServiceList\"], or if none given, get all available services and filter by config[\"KeepServiceTypes\"])")
flag.BoolVar(&runOptions.Once, "once", false,
"balance once and then exit")
"send pull requests (make more replicas of blocks that are underreplicated or are not in optimal rendezvous probe order)")
flag.BoolVar(&runOptions.CommitTrash, "commit-trash", false,
"send trash requests (delete unreferenced old blocks, and excess replicas of overreplicated blocks)")
+ dumpConfig := flag.Bool("dump-config", false, "write current configuration to stdout and exit")
dumpFlag := flag.Bool("dump", false, "dump details for each block to stdout")
debugFlag := flag.Bool("debug", false, "enable debug messages")
flag.Usage = usage
flag.Parse()
- if *configPath == "" {
- log.Fatal("You must specify a config file (see `keep-balance -help`)")
- }
- mustReadJSON(&config, *configPath)
+ mustReadConfig(&cfg, *configPath)
if *serviceListPath != "" {
- mustReadJSON(&config.KeepServiceList, *serviceListPath)
+ mustReadConfig(&cfg.KeepServiceList, *serviceListPath)
+ }
+
+ if *dumpConfig {
+ log.Fatal(config.DumpAndExit(cfg))
}
if *debugFlag {
debugf = log.Printf
- if j, err := json.Marshal(config); err != nil {
+ if j, err := json.Marshal(cfg); err != nil {
log.Fatal(err)
} else {
log.Printf("config is %s", j)
if *dumpFlag {
runOptions.Dumper = log.New(os.Stdout, "", log.LstdFlags)
}
- err := CheckConfig(config, runOptions)
+ err := CheckConfig(cfg, runOptions)
if err != nil {
// (don't run)
} else if runOptions.Once {
- err = (&Balancer{}).Run(config, runOptions)
+ _, err = (&Balancer{}).Run(cfg, runOptions)
} else {
- err = RunForever(config, runOptions, nil)
+ err = RunForever(cfg, runOptions, nil)
}
if err != nil {
log.Fatal(err)
}
}
-func mustReadJSON(dst interface{}, path string) {
- if buf, err := ioutil.ReadFile(path); err != nil {
- log.Fatalf("Reading %q: %v", path, err)
- } else if err = json.Unmarshal(buf, dst); err != nil {
- log.Fatalf("Decoding %q: %v", path, err)
+func mustReadConfig(dst interface{}, path string) {
+ if err := config.LoadFile(dst, path); err != nil {
+ log.Fatal(err)
}
}
logger.Print("======= Consider using -commit-pulls and -commit-trash flags.")
}
- err := (&Balancer{}).Run(config, runOptions)
+ bal := &Balancer{}
+ var err error
+ runOptions, err = bal.Run(config, runOptions)
if err != nil {
logger.Print("run failed: ", err)
} else {