storagenode/db: explicitly open and create dbs

To prevent storagenode from implicitly recreating missing dbs and storage,
as such behaviour leads to audit failures. Do not allow storagenode to
start if any of dbs or storage is missing, corrupted, or dedicated storage disk is
unmounted, to get downtime instead.

Change-Id: Ic64e1f0ff4d8ef5b2fddbe7a7e53df4f4bd8652e
This commit is contained in:
Yaroslav Vorobiov 2020-07-21 17:43:33 +03:00
parent e982173d61
commit 4d2a505788
3 changed files with 185 additions and 67 deletions

View File

@ -147,7 +147,7 @@ func cmdRun(cmd *cobra.Command, args []string) (err error) {
return err
}
db, err := storagenodedb.New(log.Named("db"), runCfg.DatabaseConfig())
db, err := storagenodedb.Open(log.Named("db"), runCfg.DatabaseConfig())
if err != nil {
return errs.New("Error starting master database on storagenode: %+v", err)
}
@ -245,7 +245,13 @@ func cmdSetup(cmd *cobra.Command, args []string) (err error) {
return fpath.EditFile(configFile)
}
return err
// create db
db, err := storagenodedb.New(zap.L().Named("db"), setupCfg.DatabaseConfig())
if err != nil {
return err
}
return db.Close()
}
func cmdConfig(cmd *cobra.Command, args []string) (err error) {
@ -277,7 +283,7 @@ func cmdDiag(cmd *cobra.Command, args []string) (err error) {
return err
}
db, err := storagenodedb.New(zap.L().Named("db"), diagCfg.DatabaseConfig())
db, err := storagenodedb.Open(zap.L().Named("db"), diagCfg.DatabaseConfig())
if err != nil {
return errs.New("Error starting master database on storage node: %v", err)
}

View File

@ -43,6 +43,27 @@ type Dir struct {
trashnow func() time.Time // the function used by trash to determine "now"
}
// OpenDir opens existing folder for storing blobs.
func OpenDir(log *zap.Logger, path string) (*Dir, error) {
dir := &Dir{
log: log,
path: path,
trashnow: time.Now,
}
stat := func(path string) error {
_, err := os.Stat(path)
return err
}
return dir, errs.Combine(
stat(dir.blobsdir()),
stat(dir.tempdir()),
stat(dir.garbagedir()),
stat(dir.trashdir()),
)
}
// NewDir returns folder for storing blobs.
func NewDir(log *zap.Logger, path string) (*Dir, error) {
dir := &Dir{

View File

@ -116,6 +116,77 @@ func New(log *zap.Logger, config Config) (*DB, error) {
if err != nil {
return nil, err
}
pieces := filestore.New(log, piecesDir, config.Filestore)
deprecatedInfoDB := &deprecatedInfoDB{}
v0PieceInfoDB := &v0PieceInfoDB{}
bandwidthDB := &bandwidthDB{}
ordersDB := &ordersDB{}
pieceExpirationDB := &pieceExpirationDB{}
pieceSpaceUsedDB := &pieceSpaceUsedDB{}
reputationDB := &reputationDB{}
storageUsageDB := &storageUsageDB{}
usedSerialsDB := &usedSerialsDB{}
satellitesDB := &satellitesDB{}
notificationsDB := &notificationDB{}
heldamountDB := &heldamountDB{}
pricingDB := &pricingDB{}
db := &DB{
log: log,
config: config,
pieces: pieces,
dbDirectory: filepath.Dir(config.Info2),
deprecatedInfoDB: deprecatedInfoDB,
v0PieceInfoDB: v0PieceInfoDB,
bandwidthDB: bandwidthDB,
ordersDB: ordersDB,
pieceExpirationDB: pieceExpirationDB,
pieceSpaceUsedDB: pieceSpaceUsedDB,
reputationDB: reputationDB,
storageUsageDB: storageUsageDB,
usedSerialsDB: usedSerialsDB,
satellitesDB: satellitesDB,
notificationsDB: notificationsDB,
heldamountDB: heldamountDB,
pricingDB: pricingDB,
SQLDBs: map[string]DBContainer{
DeprecatedInfoDBName: deprecatedInfoDB,
PieceInfoDBName: v0PieceInfoDB,
BandwidthDBName: bandwidthDB,
OrdersDBName: ordersDB,
PieceExpirationDBName: pieceExpirationDB,
PieceSpaceUsedDBName: pieceSpaceUsedDB,
ReputationDBName: reputationDB,
StorageUsageDBName: storageUsageDB,
UsedSerialsDBName: usedSerialsDB,
SatellitesDBName: satellitesDB,
NotificationsDBName: notificationsDB,
HeldAmountDBName: heldamountDB,
PricingDBName: pricingDB,
},
}
err = db.createDatabases()
if err != nil {
return nil, err
}
return db, nil
}
// Open opens a new master database for storage node.
func Open(log *zap.Logger, config Config) (*DB, error) {
piecesDir, err := filestore.OpenDir(log, config.Pieces)
if err != nil {
return nil, err
}
pieces := filestore.New(log, piecesDir, config.Filestore)
deprecatedInfoDB := &deprecatedInfoDB{}
@ -175,79 +246,76 @@ func New(log *zap.Logger, config Config) (*DB, error) {
if err != nil {
return nil, err
}
return db, nil
}
// createDatabases creates all the SQLite3 storage node databases and returns if any fails to create successfully.
func (db *DB) createDatabases() error {
// These objects have a Configure method to allow setting the underlining SQLDB connection
// that each uses internally to do data access to the SQLite3 databases.
// The reason it was done this way was because there's some outside consumers that are
// taking a reference to the business object.
if err := os.MkdirAll(filepath.Dir(db.dbDirectory), 0700); err != nil {
return ErrDatabase.Wrap(err)
}
dbs := []string{
DeprecatedInfoDBName,
BandwidthDBName,
OrdersDBName,
PieceExpirationDBName,
PieceInfoDBName,
PieceSpaceUsedDBName,
ReputationDBName,
StorageUsageDBName,
UsedSerialsDBName,
SatellitesDBName,
NotificationsDBName,
HeldAmountDBName,
PricingDBName,
}
for _, dbName := range dbs {
err := db.createDatabase(dbName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
}
return nil
}
// openDatabases opens all the SQLite3 storage node databases and returns if any fails to open successfully.
func (db *DB) openDatabases() error {
// These objects have a Configure method to allow setting the underlining SQLDB connection
// that each uses internally to do data access to the SQLite3 databases.
// The reason it was done this way was because there's some outside consumers that are
// taking a reference to the business object.
err := db.openDatabase(DeprecatedInfoDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
dbs := []string{
DeprecatedInfoDBName,
BandwidthDBName,
OrdersDBName,
PieceExpirationDBName,
PieceInfoDBName,
PieceSpaceUsedDBName,
ReputationDBName,
StorageUsageDBName,
UsedSerialsDBName,
SatellitesDBName,
NotificationsDBName,
HeldAmountDBName,
PricingDBName,
}
err = db.openDatabase(BandwidthDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
for _, dbName := range dbs {
err := db.openExistingDatabase(dbName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
}
err = db.openDatabase(OrdersDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(PieceExpirationDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(PieceInfoDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(PieceSpaceUsedDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(ReputationDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(StorageUsageDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(UsedSerialsDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(SatellitesDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(NotificationsDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(HeldAmountDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
err = db.openDatabase(PricingDBName)
if err != nil {
return errs.Combine(err, db.closeDatabases())
}
return nil
}
@ -255,12 +323,35 @@ func (db *DB) rawDatabaseFromName(dbName string) tagsql.DB {
return db.SQLDBs[dbName].GetDB()
}
// createDatabase creates new database at the specified path, returns err if db exists.
func (db *DB) createDatabase(dbName string) error {
path := db.filepathFromDBName(dbName)
if _, err := os.Stat(path); err == nil {
return ErrDatabase.New("database %s already exists", dbName)
} else if !os.IsNotExist(err) {
return ErrDatabase.Wrap(err)
}
return db.openDatabase(dbName)
}
// openExistingDatabase opens existing database at the specified path.
func (db *DB) openExistingDatabase(dbName string) error {
path := db.filepathFromDBName(dbName)
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
return ErrDatabase.New("database %s does not exist %+v", dbName, err)
}
return ErrDatabase.Wrap(err)
}
return db.openDatabase(dbName)
}
// openDatabase opens or creates a database at the specified path.
func (db *DB) openDatabase(dbName string) error {
path := db.filepathFromDBName(dbName)
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return ErrDatabase.Wrap(err)
}
driver := db.config.Driver
if driver == "" {
@ -528,7 +619,7 @@ func (db *DB) migrateToDB(ctx context.Context, dbName string, tablesToKeep ...st
return ErrDatabase.Wrap(err)
}
err = db.openDatabase(dbName)
err = db.openExistingDatabase(dbName)
if err != nil {
return ErrDatabase.Wrap(err)
}