2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-07-26 15:21:35 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-11-08 13:20:23 +00:00
|
|
|
"context"
|
2018-08-08 23:22:59 +01:00
|
|
|
"fmt"
|
2018-07-26 15:21:35 +01:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2018-11-08 13:20:23 +00:00
|
|
|
"text/tabwriter"
|
2019-01-30 21:44:50 +00:00
|
|
|
"time"
|
2018-07-26 15:21:35 +01:00
|
|
|
|
2019-06-25 21:58:38 +01:00
|
|
|
"github.com/skyrings/skyring-common/tools/uuid"
|
2018-07-26 15:21:35 +01:00
|
|
|
"github.com/spf13/cobra"
|
2018-11-15 19:06:09 +00:00
|
|
|
"github.com/zeebo/errs"
|
2019-01-15 15:02:54 +00:00
|
|
|
"go.uber.org/zap"
|
2018-10-04 22:40:34 +01:00
|
|
|
|
2019-06-25 21:58:38 +01:00
|
|
|
"storj.io/storj/cmd/satellite/reports"
|
2018-10-16 12:43:44 +01:00
|
|
|
"storj.io/storj/pkg/cfgstruct"
|
2018-07-26 15:21:35 +01:00
|
|
|
"storj.io/storj/pkg/process"
|
2019-08-19 23:10:38 +01:00
|
|
|
"storj.io/storj/pkg/revocation"
|
2019-12-03 22:09:39 +00:00
|
|
|
"storj.io/storj/pkg/storj"
|
2019-11-14 19:46:15 +00:00
|
|
|
"storj.io/storj/private/fpath"
|
|
|
|
"storj.io/storj/private/version"
|
2019-01-23 19:58:44 +00:00
|
|
|
"storj.io/storj/satellite"
|
2019-10-16 17:50:29 +01:00
|
|
|
"storj.io/storj/satellite/accounting/live"
|
2019-10-10 19:06:26 +01:00
|
|
|
"storj.io/storj/satellite/metainfo"
|
2018-12-05 09:35:50 +00:00
|
|
|
"storj.io/storj/satellite/satellitedb"
|
2018-07-26 15:21:35 +01:00
|
|
|
)
|
|
|
|
|
2019-01-07 11:06:10 +00:00
|
|
|
// Satellite defines satellite configuration
|
2019-01-07 09:48:16 +00:00
|
|
|
type Satellite struct {
|
2019-10-18 20:03:10 +01:00
|
|
|
Database string `help:"satellite database connection string" releaseDefault:"postgres://" devDefault:"postgres://"`
|
2019-01-23 19:58:44 +00:00
|
|
|
|
|
|
|
satellite.Config
|
2019-01-07 09:48:16 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 15:21:35 +01:00
|
|
|
var (
|
|
|
|
rootCmd = &cobra.Command{
|
2018-08-29 19:32:41 +01:00
|
|
|
Use: "satellite",
|
|
|
|
Short: "Satellite",
|
2018-07-26 15:21:35 +01:00
|
|
|
}
|
2018-07-30 08:38:31 +01:00
|
|
|
runCmd = &cobra.Command{
|
|
|
|
Use: "run",
|
2018-08-29 19:32:41 +01:00
|
|
|
Short: "Run the satellite",
|
2018-07-30 08:38:31 +01:00
|
|
|
RunE: cmdRun,
|
|
|
|
}
|
2019-11-02 20:09:07 +00:00
|
|
|
runMigrationCmd = &cobra.Command{
|
|
|
|
Use: "migration",
|
|
|
|
Short: "Run the satellite database migration",
|
|
|
|
RunE: cmdMigrationRun,
|
|
|
|
}
|
2019-10-16 21:34:25 +01:00
|
|
|
runAPICmd = &cobra.Command{
|
|
|
|
Use: "api",
|
|
|
|
Short: "Run the satellite API",
|
|
|
|
RunE: cmdAPIRun,
|
|
|
|
}
|
2019-10-29 14:55:57 +00:00
|
|
|
runRepairerCmd = &cobra.Command{
|
|
|
|
Use: "repair",
|
|
|
|
Short: "Run the repair service",
|
|
|
|
RunE: cmdRepairerRun,
|
|
|
|
}
|
2018-07-30 08:38:31 +01:00
|
|
|
setupCmd = &cobra.Command{
|
2018-12-14 21:14:59 +00:00
|
|
|
Use: "setup",
|
|
|
|
Short: "Create config files",
|
|
|
|
RunE: cmdSetup,
|
|
|
|
Annotations: map[string]string{"type": "setup"},
|
2018-07-30 08:38:31 +01:00
|
|
|
}
|
2018-11-16 13:31:33 +00:00
|
|
|
qdiagCmd = &cobra.Command{
|
|
|
|
Use: "qdiag",
|
|
|
|
Short: "Repair Queue Diagnostic Tool support",
|
|
|
|
RunE: cmdQDiag,
|
|
|
|
}
|
2019-01-30 21:44:50 +00:00
|
|
|
reportsCmd = &cobra.Command{
|
|
|
|
Use: "reports",
|
|
|
|
Short: "Generate a report",
|
|
|
|
}
|
2019-02-27 21:55:19 +00:00
|
|
|
nodeUsageCmd = &cobra.Command{
|
|
|
|
Use: "storagenode-usage [start] [end]",
|
|
|
|
Short: "Generate a node usage report for a given period to use for payments",
|
|
|
|
Long: "Generate a node usage report for a given period to use for payments. Format dates using YYYY-MM-DD",
|
2019-01-30 21:44:50 +00:00
|
|
|
Args: cobra.MinimumNArgs(2),
|
2019-02-27 21:55:19 +00:00
|
|
|
RunE: cmdNodeUsage,
|
2019-01-30 21:44:50 +00:00
|
|
|
}
|
2019-06-25 21:58:38 +01:00
|
|
|
partnerAttributionCmd = &cobra.Command{
|
|
|
|
Use: "partner-attribution [partner ID] [start] [end]",
|
|
|
|
Short: "Generate a partner attribution report for a given period to use for payments",
|
|
|
|
Long: "Generate a partner attribution report for a given period to use for payments. Format dates using YYYY-MM-DD",
|
|
|
|
Args: cobra.MinimumNArgs(3),
|
|
|
|
RunE: cmdValueAttribution,
|
|
|
|
}
|
2019-10-23 02:06:01 +01:00
|
|
|
gracefulExitCmd = &cobra.Command{
|
|
|
|
Use: "graceful-exit [start] [end]",
|
|
|
|
Short: "Generate a graceful exit report",
|
|
|
|
Long: "Generate a node usage report for a given period to use for payments. Format dates using YYYY-MM-DD",
|
|
|
|
Args: cobra.MinimumNArgs(2),
|
|
|
|
RunE: cmdGracefulExit,
|
|
|
|
}
|
2018-07-26 15:21:35 +01:00
|
|
|
|
2019-12-03 22:09:39 +00:00
|
|
|
verifyGracefulExitReceiptCmd = &cobra.Command{
|
|
|
|
Use: "verify-exit-receipt [storage node ID] [receipt]",
|
|
|
|
Short: "Verify a graceful exit receipt",
|
|
|
|
Long: "Verify a graceful exit receipt is valid.",
|
|
|
|
Args: cobra.MinimumNArgs(2),
|
|
|
|
RunE: cmdVerifyGracefulExitReceipt,
|
|
|
|
}
|
|
|
|
|
2019-01-07 09:48:16 +00:00
|
|
|
runCfg Satellite
|
2019-01-07 11:06:10 +00:00
|
|
|
setupCfg Satellite
|
2019-01-07 09:48:16 +00:00
|
|
|
|
2018-11-16 13:31:33 +00:00
|
|
|
qdiagCfg struct {
|
2019-10-18 20:03:10 +01:00
|
|
|
Database string `help:"satellite database connection string" releaseDefault:"postgres://" devDefault:"postgres://"`
|
2018-12-21 15:11:19 +00:00
|
|
|
QListLimit int `help:"maximum segments that can be requested" default:"1000"`
|
2018-11-16 13:31:33 +00:00
|
|
|
}
|
2019-02-27 21:55:19 +00:00
|
|
|
nodeUsageCfg struct {
|
2019-10-18 20:03:10 +01:00
|
|
|
Database string `help:"satellite database connection string" releaseDefault:"postgres://" devDefault:"postgres://"`
|
2019-01-30 21:44:50 +00:00
|
|
|
Output string `help:"destination of report output" default:""`
|
|
|
|
}
|
2019-06-25 21:58:38 +01:00
|
|
|
partnerAttribtionCfg struct {
|
2019-10-18 20:03:10 +01:00
|
|
|
Database string `help:"satellite database connection string" releaseDefault:"postgres://" devDefault:"postgres://"`
|
2019-06-25 21:58:38 +01:00
|
|
|
Output string `help:"destination of report output" default:""`
|
|
|
|
}
|
2019-10-23 02:06:01 +01:00
|
|
|
gracefulExitCfg struct {
|
2019-12-03 22:09:39 +00:00
|
|
|
Database string `help:"satellite database connection string" releaseDefault:"postgres://" devDefault:"postgres://"`
|
2019-10-23 02:06:01 +01:00
|
|
|
Output string `help:"destination of report output" default:""`
|
|
|
|
Completed bool `help:"whether to output (initiated and completed) or (initiated and not completed)" default:"false"`
|
|
|
|
}
|
2019-12-03 22:09:39 +00:00
|
|
|
verifyGracefulExitReceiptCfg struct {
|
|
|
|
}
|
2019-03-12 12:51:06 +00:00
|
|
|
confDir string
|
|
|
|
identityDir string
|
2018-07-26 15:21:35 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2019-03-12 12:51:06 +00:00
|
|
|
defaultConfDir := fpath.ApplicationDir("storj", "satellite")
|
|
|
|
defaultIdentityDir := fpath.ApplicationDir("storj", "identity", "satellite")
|
|
|
|
cfgstruct.SetupFlag(zap.L(), rootCmd, &confDir, "config-dir", defaultConfDir, "main directory for satellite configuration")
|
|
|
|
cfgstruct.SetupFlag(zap.L(), rootCmd, &identityDir, "identity-dir", defaultIdentityDir, "main directory for satellite identity credentials")
|
2019-04-19 19:17:30 +01:00
|
|
|
defaults := cfgstruct.DefaultsFlag(rootCmd)
|
2018-07-30 08:38:31 +01:00
|
|
|
rootCmd.AddCommand(runCmd)
|
2019-11-02 20:09:07 +00:00
|
|
|
runCmd.AddCommand(runMigrationCmd)
|
2019-10-16 21:34:25 +01:00
|
|
|
runCmd.AddCommand(runAPICmd)
|
2019-10-29 14:55:57 +00:00
|
|
|
runCmd.AddCommand(runRepairerCmd)
|
2018-07-30 08:38:31 +01:00
|
|
|
rootCmd.AddCommand(setupCmd)
|
2018-11-16 13:31:33 +00:00
|
|
|
rootCmd.AddCommand(qdiagCmd)
|
2019-01-30 21:44:50 +00:00
|
|
|
rootCmd.AddCommand(reportsCmd)
|
2019-02-27 21:55:19 +00:00
|
|
|
reportsCmd.AddCommand(nodeUsageCmd)
|
2019-06-25 21:58:38 +01:00
|
|
|
reportsCmd.AddCommand(partnerAttributionCmd)
|
2019-10-23 02:06:01 +01:00
|
|
|
reportsCmd.AddCommand(gracefulExitCmd)
|
2019-12-03 22:09:39 +00:00
|
|
|
reportsCmd.AddCommand(verifyGracefulExitReceiptCmd)
|
Command line flags features and cleanup (#2068)
* change BindSetup to be an option to Bind
* add process.Bind to allow composite structures
* hack fix for noprefix flags
* used tagged version of structs
Before this PR, some flags were created by calling `cfgstruct.Bind` and having their fields create a flag. Once the flags were parsed, `viper` was used to acquire all the values from them and config files, and the fields in the struct were set through the flag interface.
This doesn't work for slices of things on config structs very well, since it can only set strings, and for a string slice, it turns out that the implementation in `pflag` appends an entry rather than setting it.
This changes three things:
1. Only have a `Bind` call instead of `Bind` and `BindSetup`, and make `BindSetup` an option instead.
2. Add a `process.Bind` call that takes in a `*cobra.Cmd`, binds the struct to the command's flags, and keeps track of that struct in a global map keyed by the command.
3. Use `viper` to get the values and load them into the bound configuration structs instead of using the flags to propagate the changes.
In this way, we can support whatever rich configuration we want in the config yaml files, while still getting command like flags when important.
2019-05-29 18:56:22 +01:00
|
|
|
process.Bind(runCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-11-02 20:09:07 +00:00
|
|
|
process.Bind(runMigrationCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-10-16 21:34:25 +01:00
|
|
|
process.Bind(runAPICmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-10-29 14:55:57 +00:00
|
|
|
process.Bind(runRepairerCmd, &runCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
Command line flags features and cleanup (#2068)
* change BindSetup to be an option to Bind
* add process.Bind to allow composite structures
* hack fix for noprefix flags
* used tagged version of structs
Before this PR, some flags were created by calling `cfgstruct.Bind` and having their fields create a flag. Once the flags were parsed, `viper` was used to acquire all the values from them and config files, and the fields in the struct were set through the flag interface.
This doesn't work for slices of things on config structs very well, since it can only set strings, and for a string slice, it turns out that the implementation in `pflag` appends an entry rather than setting it.
This changes three things:
1. Only have a `Bind` call instead of `Bind` and `BindSetup`, and make `BindSetup` an option instead.
2. Add a `process.Bind` call that takes in a `*cobra.Cmd`, binds the struct to the command's flags, and keeps track of that struct in a global map keyed by the command.
3. Use `viper` to get the values and load them into the bound configuration structs instead of using the flags to propagate the changes.
In this way, we can support whatever rich configuration we want in the config yaml files, while still getting command like flags when important.
2019-05-29 18:56:22 +01:00
|
|
|
process.Bind(setupCmd, &setupCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir), cfgstruct.SetupMode())
|
|
|
|
process.Bind(qdiagCmd, &qdiagCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
|
|
|
process.Bind(nodeUsageCmd, &nodeUsageCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-10-23 02:06:01 +01:00
|
|
|
process.Bind(gracefulExitCmd, &gracefulExitCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-12-03 22:09:39 +00:00
|
|
|
process.Bind(verifyGracefulExitReceiptCmd, &verifyGracefulExitReceiptCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2019-06-25 21:58:38 +01:00
|
|
|
process.Bind(partnerAttributionCmd, &partnerAttribtionCfg, defaults, cfgstruct.ConfDir(confDir), cfgstruct.IdentityDir(identityDir))
|
2018-07-26 15:21:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func cmdRun(cmd *cobra.Command, args []string) (err error) {
|
2019-04-04 16:40:07 +01:00
|
|
|
// inert constructors only ====
|
|
|
|
|
2019-09-19 17:37:40 +01:00
|
|
|
ctx, _ := process.Ctx(cmd)
|
2019-01-23 19:58:44 +00:00
|
|
|
log := zap.L()
|
|
|
|
|
2019-01-25 14:54:54 +00:00
|
|
|
identity, err := runCfg.Identity.Load()
|
2019-01-23 19:58:44 +00:00
|
|
|
if err != nil {
|
2019-01-22 12:35:48 +00:00
|
|
|
zap.S().Fatal(err)
|
|
|
|
}
|
2018-12-05 09:35:50 +00:00
|
|
|
|
2019-02-14 21:55:21 +00:00
|
|
|
db, err := satellitedb.New(log.Named("db"), runCfg.Database)
|
2018-12-05 09:35:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error starting master database on satellite: %+v", err)
|
|
|
|
}
|
2019-10-10 19:06:26 +01:00
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, db.Close())
|
|
|
|
}()
|
2019-01-24 20:28:06 +00:00
|
|
|
|
2019-12-05 20:42:12 +00:00
|
|
|
pointerDB, err := metainfo.NewStore(log.Named("pointerdb"), runCfg.Metainfo.DatabaseURL)
|
2019-10-10 19:06:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error creating revocation database: %+v", err)
|
|
|
|
}
|
2019-01-30 05:22:58 +00:00
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, db.Close())
|
|
|
|
}()
|
|
|
|
|
2019-12-05 20:42:12 +00:00
|
|
|
revocationDB, err := revocation.NewDBFromCfg(runCfg.Server.Config)
|
2019-08-19 23:10:38 +01:00
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error creating revocation database: %+v", err)
|
|
|
|
}
|
2019-08-20 16:04:17 +01:00
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, revocationDB.Close())
|
|
|
|
}()
|
2019-08-19 23:10:38 +01:00
|
|
|
|
2019-10-16 17:50:29 +01:00
|
|
|
liveAccounting, err := live.NewCache(log.Named("live-accounting"), runCfg.LiveAccounting)
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error creating live accounting cache: %+v", err)
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, liveAccounting.Close())
|
|
|
|
}()
|
|
|
|
|
|
|
|
peer, err := satellite.New(log, identity, db, pointerDB, revocationDB, liveAccounting, version.Build, &runCfg.Config)
|
2018-12-05 09:35:50 +00:00
|
|
|
if err != nil {
|
2019-04-04 16:40:07 +01:00
|
|
|
return err
|
2018-12-05 09:35:50 +00:00
|
|
|
}
|
2019-01-23 19:58:44 +00:00
|
|
|
|
2019-04-04 16:40:07 +01:00
|
|
|
// okay, start doing stuff ====
|
|
|
|
|
|
|
|
err = peer.Version.CheckVersion(ctx)
|
2019-01-23 19:58:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-01-15 15:02:54 +00:00
|
|
|
}
|
2018-12-05 09:35:50 +00:00
|
|
|
|
2019-07-31 15:38:44 +01:00
|
|
|
if err := process.InitMetricsWithCertPath(ctx, log, nil, runCfg.Identity.CertPath); err != nil {
|
2019-08-27 10:24:47 +01:00
|
|
|
zap.S().Warn("Failed to initialize telemetry batcher: ", err)
|
2019-04-04 16:40:07 +01:00
|
|
|
}
|
|
|
|
|
2019-11-02 20:09:07 +00:00
|
|
|
err = db.CheckVersion()
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Fatal("failed satellite database version check: ", err)
|
|
|
|
return errs.New("Error checking version for satellitedb: %+v", err)
|
|
|
|
}
|
|
|
|
|
2019-01-23 19:58:44 +00:00
|
|
|
runError := peer.Run(ctx)
|
|
|
|
closeError := peer.Close()
|
2019-01-30 05:22:58 +00:00
|
|
|
return errs.Combine(runError, closeError)
|
2018-07-26 15:21:35 +01:00
|
|
|
}
|
|
|
|
|
2019-11-02 20:09:07 +00:00
|
|
|
func cmdMigrationRun(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
log := zap.L()
|
|
|
|
db, err := satellitedb.New(log.Named("db migration"), runCfg.Database)
|
|
|
|
if err != nil {
|
2019-11-04 19:01:02 +00:00
|
|
|
return errs.New("Error creating new master database connection for satellitedb migration: %+v", err)
|
2019-11-02 20:09:07 +00:00
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, db.Close())
|
|
|
|
}()
|
|
|
|
|
|
|
|
err = db.CreateTables()
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error creating tables for master database on satellite: %+v", err)
|
|
|
|
}
|
2019-12-05 20:42:12 +00:00
|
|
|
|
|
|
|
// There should be an explicit CreateTables call for the pointerdb as well.
|
|
|
|
// This is tracked in jira ticket #3337.
|
|
|
|
pdb, err := metainfo.NewStore(log.Named("db migration"), runCfg.Metainfo.DatabaseURL)
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Error creating tables for pointer database on satellite: %+v", err)
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, pdb.Close())
|
|
|
|
}()
|
|
|
|
|
2019-11-02 20:09:07 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-26 15:21:35 +01:00
|
|
|
func cmdSetup(cmd *cobra.Command, args []string) (err error) {
|
2019-01-22 12:35:48 +00:00
|
|
|
setupDir, err := filepath.Abs(confDir)
|
2018-08-13 19:29:13 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-14 15:57:58 +00:00
|
|
|
valid, _ := fpath.IsValidSetupDir(setupDir)
|
|
|
|
if !valid {
|
|
|
|
return fmt.Errorf("satellite configuration already exists (%v)", setupDir)
|
2018-08-08 23:22:59 +01:00
|
|
|
}
|
|
|
|
|
2018-12-14 21:14:59 +00:00
|
|
|
err = os.MkdirAll(setupDir, 0700)
|
2018-07-26 15:21:35 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-05 18:01:20 +01:00
|
|
|
return process.SaveConfig(cmd, filepath.Join(setupDir, "config.yaml"))
|
2018-07-26 15:21:35 +01:00
|
|
|
}
|
|
|
|
|
2018-11-16 13:31:33 +00:00
|
|
|
func cmdQDiag(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
|
2018-12-21 15:11:19 +00:00
|
|
|
// open the master db
|
2019-02-14 21:55:21 +00:00
|
|
|
database, err := satellitedb.New(zap.L().Named("db"), qdiagCfg.Database)
|
2018-11-16 13:31:33 +00:00
|
|
|
if err != nil {
|
2018-12-21 15:11:19 +00:00
|
|
|
return errs.New("error connecting to master database on satellite: %+v", err)
|
2018-11-16 13:31:33 +00:00
|
|
|
}
|
2018-12-21 15:11:19 +00:00
|
|
|
defer func() {
|
|
|
|
err := database.Close()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("error closing connection to master database on satellite: %+v\n", err)
|
|
|
|
}
|
|
|
|
}()
|
2018-11-16 13:31:33 +00:00
|
|
|
|
2019-04-16 19:14:09 +01:00
|
|
|
list, err := database.RepairQueue().SelectN(context.Background(), qdiagCfg.QListLimit)
|
2018-11-16 13:31:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize the table header (fields)
|
|
|
|
const padding = 3
|
|
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, ' ', tabwriter.AlignRight|tabwriter.Debug)
|
|
|
|
fmt.Fprintln(w, "Path\tLost Pieces\t")
|
|
|
|
|
|
|
|
// populate the row fields
|
|
|
|
for _, v := range list {
|
|
|
|
fmt.Fprint(w, v.GetPath(), "\t", v.GetLostPieces(), "\t")
|
|
|
|
}
|
|
|
|
|
|
|
|
// display the data
|
|
|
|
return w.Flush()
|
2018-11-08 13:20:23 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 22:09:39 +00:00
|
|
|
func cmdVerifyGracefulExitReceipt(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
ctx, _ := process.Ctx(cmd)
|
|
|
|
|
|
|
|
identity, err := runCfg.Identity.Load()
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the node ID is valid
|
|
|
|
nodeID, err := storj.NodeIDFromString(args[0])
|
|
|
|
if err != nil {
|
|
|
|
return errs.Combine(err, errs.New("Invalid node ID."))
|
|
|
|
}
|
|
|
|
|
|
|
|
return verifyGracefulExitReceipt(ctx, identity, nodeID, args[1])
|
|
|
|
}
|
|
|
|
|
2019-10-23 02:06:01 +01:00
|
|
|
func cmdGracefulExit(cmd *cobra.Command, args []string) (err error) {
|
|
|
|
ctx, _ := process.Ctx(cmd)
|
|
|
|
|
|
|
|
layout := "2006-01-02"
|
|
|
|
start, err := time.Parse(layout, args[0])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
end, err := time.Parse(layout, args[1])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
|
|
|
|
// adding one day to properly account for the entire end day
|
|
|
|
end = end.AddDate(0, 0, 1)
|
|
|
|
|
|
|
|
// ensure that start date is not after end date
|
|
|
|
if start.After(end) {
|
|
|
|
return errs.New("Invalid time period (%v) - (%v)", start, end)
|
|
|
|
}
|
|
|
|
|
|
|
|
// send output to stdout
|
|
|
|
if gracefulExitCfg.Output == "" {
|
|
|
|
return generateGracefulExitCSV(ctx, gracefulExitCfg.Completed, start, end, os.Stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// send output to file
|
|
|
|
file, err := os.Create(gracefulExitCfg.Output)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, file.Close())
|
|
|
|
}()
|
|
|
|
|
|
|
|
return generateGracefulExitCSV(ctx, gracefulExitCfg.Completed, start, end, file)
|
|
|
|
}
|
|
|
|
|
2019-02-27 21:55:19 +00:00
|
|
|
func cmdNodeUsage(cmd *cobra.Command, args []string) (err error) {
|
2019-09-19 17:37:40 +01:00
|
|
|
ctx, _ := process.Ctx(cmd)
|
2019-01-30 21:44:50 +00:00
|
|
|
|
|
|
|
layout := "2006-01-02"
|
|
|
|
start, err := time.Parse(layout, args[0])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
end, err := time.Parse(layout, args[1])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
|
2019-08-02 15:27:36 +01:00
|
|
|
//Adding one day to properly account for the entire end day
|
|
|
|
end = end.Add(time.Hour * 24)
|
|
|
|
|
2019-01-30 21:44:50 +00:00
|
|
|
// Ensure that start date is not after end date
|
|
|
|
if start.After(end) {
|
|
|
|
return errs.New("Invalid time period (%v) - (%v)", start, end)
|
|
|
|
}
|
|
|
|
|
|
|
|
// send output to stdout
|
2019-02-27 21:55:19 +00:00
|
|
|
if nodeUsageCfg.Output == "" {
|
2019-10-23 02:06:01 +01:00
|
|
|
return generateNodeUsageCSV(ctx, start, end, os.Stdout)
|
2019-01-30 21:44:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// send output to file
|
2019-02-27 21:55:19 +00:00
|
|
|
file, err := os.Create(nodeUsageCfg.Output)
|
2019-01-30 21:44:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, file.Close())
|
|
|
|
}()
|
|
|
|
|
2019-10-23 02:06:01 +01:00
|
|
|
return generateNodeUsageCSV(ctx, start, end, file)
|
2019-01-30 21:44:50 +00:00
|
|
|
}
|
|
|
|
|
2019-06-25 21:58:38 +01:00
|
|
|
func cmdValueAttribution(cmd *cobra.Command, args []string) (err error) {
|
2019-09-19 17:37:40 +01:00
|
|
|
ctx, _ := process.Ctx(cmd)
|
2019-06-25 21:58:38 +01:00
|
|
|
log := zap.L().Named("satellite-cli")
|
|
|
|
// Parse the UUID
|
|
|
|
partnerID, err := uuid.Parse(args[0])
|
|
|
|
if err != nil {
|
|
|
|
return errs.Combine(errs.New("Invalid Partner ID format. %s", args[0]), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
layout := "2006-01-02"
|
|
|
|
start, err := time.Parse(layout, args[1])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid start date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
end, err := time.Parse(layout, args[2])
|
|
|
|
if err != nil {
|
|
|
|
return errs.New("Invalid end date format. Please use YYYY-MM-DD")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that start date is not after end date
|
|
|
|
if start.After(end) {
|
|
|
|
return errs.New("Invalid time period (%v) - (%v)", start, end)
|
|
|
|
}
|
|
|
|
|
|
|
|
// send output to stdout
|
|
|
|
if partnerAttribtionCfg.Output == "" {
|
|
|
|
return reports.GenerateAttributionCSV(ctx, partnerAttribtionCfg.Database, *partnerID, start, end, os.Stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
// send output to file
|
|
|
|
file, err := os.Create(partnerAttribtionCfg.Output)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err = errs.Combine(err, file.Close())
|
|
|
|
if err != nil {
|
|
|
|
log.Sugar().Errorf("error closing the file %v after retrieving partner value attribution data: %+v", partnerAttribtionCfg.Output, err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return reports.GenerateAttributionCSV(ctx, partnerAttribtionCfg.Database, *partnerID, start, end, file)
|
|
|
|
}
|
|
|
|
|
2018-07-26 15:21:35 +01:00
|
|
|
func main() {
|
2018-07-30 08:38:31 +01:00
|
|
|
process.Exec(rootCmd)
|
2018-07-26 15:21:35 +01:00
|
|
|
}
|