2019-11-07 20:05:39 +01:00
package main
import (
"flag"
"fmt"
2020-05-16 10:59:30 +02:00
"os"
2021-12-02 10:55:58 +01:00
"time"
2019-11-07 20:05:39 +01:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/actions"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/common"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/backup/fslocal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo"
2020-02-10 12:26:18 +01:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/envflag"
2020-08-16 16:05:52 +02:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/flagutil"
2021-12-02 10:55:58 +01:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
2019-11-07 20:05:39 +01:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
2022-07-21 18:58:22 +02:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/pushmetrics"
2019-11-07 20:05:39 +01:00
)
var (
2021-12-02 10:55:58 +01:00
httpListenAddr = flag . String ( "httpListenAddr" , ":8421" , "TCP address for exporting metrics at /metrics page" )
src = flag . String ( "src" , "" , "Source path with backup on the remote storage. " +
2022-10-05 23:34:05 +02:00
"Example: gs://bucket/path/to/backup, s3://bucket/path/to/backup, azblob://bucket/path/to/backup or fs:///path/to/local/backup" )
2019-11-07 20:05:39 +01:00
storageDataPath = flag . String ( "storageDataPath" , "victoria-metrics-data" , "Destination path where backup must be restored. " +
2020-05-16 08:02:27 +02:00
"VictoriaMetrics must be stopped when restoring from backup. -storageDataPath dir can be non-empty. In this case the contents of -storageDataPath dir " +
"is synchronized with -src contents, i.e. it works like 'rsync --delete'" )
2020-01-09 14:24:26 +01:00
concurrency = flag . Int ( "concurrency" , 10 , "The number of concurrent workers. Higher concurrency may reduce restore duration" )
2020-08-16 16:05:52 +02:00
maxBytesPerSecond = flagutil . NewBytes ( "maxBytesPerSecond" , 0 , "The maximum download speed. There is no limit if it is set to 0" )
2020-02-04 14:46:13 +01:00
skipBackupCompleteCheck = flag . Bool ( "skipBackupCompleteCheck" , false , "Whether to skip checking for 'backup complete' file in -src. This may be useful for restoring from old backups, which were created without 'backup complete' file" )
2019-11-07 20:05:39 +01:00
)
func main ( ) {
2020-05-16 10:59:30 +02:00
// Write flags and help message to stdout, since it is easier to grep or pipe.
flag . CommandLine . SetOutput ( os . Stdout )
2019-11-07 20:05:39 +01:00
flag . Usage = usage
2020-02-10 12:26:18 +01:00
envflag . Parse ( )
2019-11-07 20:05:39 +01:00
buildinfo . Init ( )
2020-08-11 21:54:13 +02:00
logger . Init ( )
2022-07-22 12:35:58 +02:00
pushmetrics . Init ( )
2019-11-07 20:05:39 +01:00
2021-12-02 10:55:58 +01:00
go httpserver . Serve ( * httpListenAddr , nil )
2019-11-07 20:05:39 +01:00
srcFS , err := newSrcFS ( )
if err != nil {
logger . Fatalf ( "%s" , err )
}
dstFS , err := newDstFS ( )
if err != nil {
logger . Fatalf ( "%s" , err )
}
a := & actions . Restore {
2020-01-09 14:24:26 +01:00
Concurrency : * concurrency ,
Src : srcFS ,
Dst : dstFS ,
SkipBackupCompleteCheck : * skipBackupCompleteCheck ,
2019-11-07 20:05:39 +01:00
}
if err := a . Run ( ) ; err != nil {
logger . Fatalf ( "cannot restore from backup: %s" , err )
}
2020-10-09 14:31:39 +02:00
srcFS . MustStop ( )
2020-10-09 14:11:28 +02:00
dstFS . MustStop ( )
2021-12-02 10:55:58 +01:00
startTime := time . Now ( )
logger . Infof ( "gracefully shutting down http server for metrics at %q" , * httpListenAddr )
if err := httpserver . Stop ( * httpListenAddr ) ; err != nil {
logger . Fatalf ( "cannot stop http server for metrics: %s" , err )
}
logger . Infof ( "successfully shut down http server for metrics in %.3f seconds" , time . Since ( startTime ) . Seconds ( ) )
2019-11-07 20:05:39 +01:00
}
func usage ( ) {
const s = `
vmrestore restores VictoriaMetrics data from backups made by vmbackup .
2021-04-20 19:16:17 +02:00
See the docs at https : //docs.victoriametrics.com/vmrestore.html .
2019-11-07 20:05:39 +01:00
`
2020-12-03 20:40:30 +01:00
flagutil . Usage ( s )
2019-11-07 20:05:39 +01:00
}
func newDstFS ( ) ( * fslocal . FS , error ) {
if len ( * storageDataPath ) == 0 {
return nil , fmt . Errorf ( "`-storageDataPath` cannot be empty" )
}
fs := & fslocal . FS {
2019-11-19 19:31:52 +01:00
Dir : * storageDataPath ,
2020-08-16 16:05:52 +02:00
MaxBytesPerSecond : maxBytesPerSecond . N ,
2019-11-19 19:31:52 +01:00
}
if err := fs . Init ( ) ; err != nil {
2020-06-30 21:58:18 +02:00
return nil , fmt . Errorf ( "cannot initialize local fs: %w" , err )
2019-11-07 20:05:39 +01:00
}
return fs , nil
}
func newSrcFS ( ) ( common . RemoteFS , error ) {
fs , err := actions . NewRemoteFS ( * src )
if err != nil {
2020-06-30 21:58:18 +02:00
return nil , fmt . Errorf ( "cannot parse `-src`=%q: %w" , * src , err )
2019-11-07 20:05:39 +01:00
}
return fs , nil
}