blob: 82f02dbde964f46c8d1b518c5ddc13f978fe5f0e [file] [log] [blame]
package main
import (
"context"
"fmt"
"os"
"go.chromium.org/luci/common/logging"
"go.chromium.org/luci/common/logging/gologger"
"go.chromium.org/luci/common/logging/teelogger"
"go.chromium.org/luci/common/tsmon"
"go.chromium.org/luci/common/tsmon/metric"
"go.chromium.org/luci/common/tsmon/types"
// Replace clock_gettime for OSX 10.11.
_ "go.chromium.org/luci/hacks/osx_clock_gettime_fix"
)
type gitMode int
const (
gitModeKeep gitMode = iota
gitModeSkip
gitModeChanged
)
var (
gitModes = map[string]gitMode{
"keep": gitModeKeep,
"skip": gitModeSkip,
"changed": gitModeChanged,
}
)
var (
success = metric.NewBool("backups/success",
"Whether or not the backup completed successfully",
&types.MetricMetadata{})
)
// error codes returned by the process
const (
optionsError int = iota
logfileError
tsmonError
jobError
backupError
saveStateError
)
func main() {
ctx := context.Background()
// Create options from flags
opts, err := newOptionsFromArgs(os.Args[1:])
if err != nil {
fmt.Printf("Failed to initialize options: %v", err)
os.Exit(optionsError)
}
// Add timeout to context
if opts.timeout > 0 {
var cancelContext func()
ctx, cancelContext = context.WithTimeout(ctx, opts.timeout)
defer cancelContext()
}
// Init Logging
ctx = gologger.StdConfig.Use(ctx) // Stdout logger
if opts.logfile != "" {
f, err := os.OpenFile(opts.logfile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Failed to open logfile '%s' for append: %v\n", opts.logfile, err)
os.Exit(logfileError)
}
defer func() {
if err := f.Close(); err != nil {
fmt.Printf("Failed to close logfile '%s': %v\n", opts.logfile, err)
}
}()
fileLogger := gologger.LoggerConfig{Out: f}
ctx = teelogger.Use(ctx, fileLogger.NewLogger)
}
ctx = opts.loggingConfig.Set(ctx)
// Init Tsmon
if err = tsmon.InitializeFromFlags(ctx, &opts.tsmonFlags); err != nil {
logging.Errorf(ctx, "Failed to initialize tsmon: %v", err)
os.Exit(tsmonError)
}
defer func() {
if err = tsmon.Flush(ctx); err != nil {
logging.Errorf(ctx, "Failed to flush tsmon: %v", err)
}
tsmon.Shutdown(ctx)
}()
// Init backup job from options
job, err := opts.makeJob(ctx)
if err != nil {
logging.Errorf(ctx, "Failed to make job from options: %v", err)
os.Exit(jobError)
}
logging.Infof(ctx, "Starting backup of '%s' to bucket '%s' using name prefix '%s'",
opts.root, opts.bucket, opts.prefix)
// Run the backup
state, err := job.run(ctx)
if err != nil {
logging.Errorf(ctx, "Backup failed: %v", err)
os.Exit(backupError)
}
// Save backup state
if opts.newState != "" {
if err = state.Save(ctx, opts.newState); err != nil {
logging.Errorf(ctx, "Failed to save Backup State to file: %v", err)
os.Exit(saveStateError)
}
}
success.Set(ctx, true)
logging.Infof(ctx, "Finished backup of '%s' to bucket '%s' using name prefix '%s'",
opts.root, opts.bucket, opts.prefix)
}