From 3ac0dbe54d064f26e482c946f9d2147705ca66ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Sterba?= <hda@andre-sterba.de>
Date: Mon, 10 Jun 2024 09:44:20 +0000
Subject: [PATCH] Don't crash on not working database connection
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

See merge request danet/gosdn!902

Co-authored-by: Neil-Jocelyn Schark <neil.schark@h-da.de>
Co-authored-by: André Sterba <andre@sterba.dev>
---
 controller/controller.go                      |  5 ++-
 .../nucleus/database/mongo-connection.go      | 33 +++++++++++--------
 .../nucleus/databaseNetworkElementStore.go    |  2 +-
 controller/rbac/databaseUserStore.go          |  2 +-
 .../topology/nodes/databaseNodeStore.go       |  2 +-
 5 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/controller/controller.go b/controller/controller.go
index 7eca04715..5dc392461 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -99,7 +99,10 @@ func initialize() error {
 		return err
 	}
 
-	db := database.GetDatabaseConnection()
+	db, err := database.GetDatabaseConnection()
+	if err != nil {
+		return err
+	}
 
 	nodeService := nodes.NewNodeService(nodes.NewNodeStore(db), eventService)
 	portService := ports.NewPortService(ports.NewPortStore(db), eventService)
diff --git a/controller/nucleus/database/mongo-connection.go b/controller/nucleus/database/mongo-connection.go
index 43b3a5132..0482d3003 100644
--- a/controller/nucleus/database/mongo-connection.go
+++ b/controller/nucleus/database/mongo-connection.go
@@ -3,7 +3,6 @@ package database
 import (
 	"context"
 	"fmt"
-	"log"
 	"time"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/config"
@@ -18,6 +17,9 @@ const (
 	timeout = 5 * time.Second
 	// DatabaseName is the name of the mongoDB database used.
 	DatabaseName = "gosdn"
+
+	connectionRetries = 60
+	connectionTimeout = time.Second * 2
 )
 
 // Connect Retrieves a client to the MongoDB.
@@ -28,15 +30,13 @@ func Connect() (*mongo.Database, error) {
 
 	client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoConnection))
 	if err != nil {
-		log.Printf("Failed to create client: %v", err)
-		return nil, err
+		return nil, fmt.Errorf("failed to create client: %w", err)
 	}
 
 	// Force a connection to verify our connection string
 	err = client.Ping(ctx, nil)
 	if err != nil {
-		log.Printf("Failed to connect to database: %v\n", err)
-		return nil, err
+		return nil, fmt.Errorf("failed to connect to database: %w", err)
 	}
 
 	db := client.Database(DatabaseName)
@@ -47,18 +47,25 @@ func Connect() (*mongo.Database, error) {
 	return db, nil
 }
 
-func GetDatabaseConnection() *mongo.Database {
+func GetDatabaseConnection() (*mongo.Database, error) {
 	var db *mongo.Database
 
 	storeMode := store.GetStoreMode()
-	if storeMode == store.Database {
-		db, err := Connect()
-		if err != nil {
-			logrus.Infof("Could not connect to database")
+
+	switch storeMode {
+	case store.Database:
+		for i := 0; i < connectionRetries; i++ {
+			db, err := Connect()
+			if err == nil {
+				return db, nil
+			}
+			logrus.Errorf("could not connect to mongo with error: %s. Retrying in 2 seconds.", err.Error())
+			time.Sleep(connectionTimeout)
 		}
 
-		return db
-	}
+		return nil, fmt.Errorf("could not connect to mongo after %d retries", connectionRetries)
 
-	return db
+	default:
+		return db, nil
+	}
 }
diff --git a/controller/nucleus/databaseNetworkElementStore.go b/controller/nucleus/databaseNetworkElementStore.go
index 70dd9a7a1..a5bc5cb07 100644
--- a/controller/nucleus/databaseNetworkElementStore.go
+++ b/controller/nucleus/databaseNetworkElementStore.go
@@ -122,7 +122,7 @@ func (s *DatabaseNetworkElementStore) Add(ctx context.Context, networkElementToA
 func (s *DatabaseNetworkElementStore) Update(ctx context.Context, networkElementToUpdate networkelement.NetworkElement) (err error) {
 	var updatedLoadedNetworkElement networkelement.LoadedNetworkElement
 
-	db, err := database.Connect()
+	db, err := database.GetDatabaseConnection()
 	if err != nil {
 		return err
 	}
diff --git a/controller/rbac/databaseUserStore.go b/controller/rbac/databaseUserStore.go
index 8f4b7c93b..cfa592de9 100644
--- a/controller/rbac/databaseUserStore.go
+++ b/controller/rbac/databaseUserStore.go
@@ -134,7 +134,7 @@ func (s *DatabaseUserStore) GetAll(ctx context.Context) (loadedUsers []rbac.Load
 func (s *DatabaseUserStore) Update(ctx context.Context, userToUpdate rbac.User) (err error) {
 	var updatedLoadedUser rbac.LoadedUser
 
-	db, err := database.Connect()
+	db, err := database.GetDatabaseConnection()
 	if err != nil {
 		return err
 	}
diff --git a/controller/topology/nodes/databaseNodeStore.go b/controller/topology/nodes/databaseNodeStore.go
index 41271c9e0..b0389082c 100644
--- a/controller/topology/nodes/databaseNodeStore.go
+++ b/controller/topology/nodes/databaseNodeStore.go
@@ -133,7 +133,7 @@ func (s *DatabaseNodeStore) Add(ctx context.Context, node Node) (err error) {
 func (s *DatabaseNodeStore) Update(ctx context.Context, node Node) (err error) {
 	var updatedLoadedNodes Node
 
-	db, err := database.Connect()
+	db, err := database.GetDatabaseConnection()
 	if err != nil {
 		return err
 	}
-- 
GitLab