This commit is contained in:
mr 2024-09-16 16:59:12 +02:00
commit 754925c32c
10 changed files with 217 additions and 86 deletions

View File

@ -1,5 +1,61 @@
# oc-lib # oc-lib
oc-lib allows read/write/search operations into the main OpenCloud databases.
It also provides common initialization and configuration utilities for all OpenCloud components
## Usage example in a beego API
```go
const appname = "oc-mycomponent"
func main() {
// Init the oc-lib
oclib.Init(appname)
// Load the right config file
/* The configuration loader will load the configuration from the following sources:
* - the environment variables with the prefix OCAPPNAME_ - ex: OCMYCOMPONENT_MONGOURL
* - the file /etc/oc/appname.json - ex: /etc/oc/mycomponent.json
* - the file ./appname.json - ex: ./mycomponent.json
* The configuration loader will merge the configuration from the different sources
* The configuration loader will give priority to the environment variables
* The configuration loader will give priority to the local file over the default file
*/
o := oclib.GetConfLoader()
// init the local config object
models.GetConfig().Port = o.GetIntDefault("port", 8080)
models.GetConfig().LokiUrl = o.GetStringDefault("lokiurl", "")
models.GetConfig().LogLevel = o.GetStringDefault("loglevel", "info")
models.GetConfig().MongoUrl = o.GetStringDefault("mongourl", "mongodb://127.0.0.1:27017")
models.GetConfig().MongoDatabase = o.GetStringDefault("mongodatabase", "myDb")
models.GetConfig().NatsUrl = o.GetStringDefault("natsurl", "nats://localhost:4222")
models.GetConfig().mycomponentparam1 = o.GetStringDefault("mycomponentparam1", "mycomponentdefault1")
models.GetConfig().mycomponentparam2 = o.GetStringDefault("mycomponentparam2", "mycomponentdefault2")
// feed the library with the loaded config,
// this will also initialize a logger available via oclib.GetLogger()
oclib.SetConfig(
models.GetConfig().MongoUrl
models.GetConfig().MongoDatabase
models.GetConfig().NatsUrl
models.GetConfig().LokiUrl
models.GetConfig().LogLevel
)
// Beego init
beego.BConfig.AppName = appname
beego.BConfig.Listen.HTTPPort = models.GetConfig().Port
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
beego.Run()
}
```
## SPECIAL FLOWS IN OC-LIB RESUME : ## SPECIAL FLOWS IN OC-LIB RESUME :
### WORKFLOW AS ITS OWN WORKSPACE ### WORKFLOW AS ITS OWN WORKSPACE

19
config/app.go Normal file
View File

@ -0,0 +1,19 @@
package config
var appname string
// logs.CreateLogger
// Create a new logger
// Parameters:
// - appname: string : the name of the application using oclib
// - url: string : the url of a loki logger, console log only if ""
// Returns:
// - zerolog.Logger : the logger that will log for the library and the app
func SetAppName(name string) {
appname = name
}
func GetAppName() string {
return appname
}

View File

@ -1,4 +1,4 @@
package tools package config
import "sync" import "sync"
@ -14,6 +14,8 @@ type Config struct {
MongoDatabase string MongoDatabase string
Host string Host string
Port string Port string
LokiUrl string
LogLevel string
} }
func (c Config) GetUrl() string { func (c Config) GetUrl() string {
@ -34,13 +36,20 @@ func GetConfig() *Config {
return instance return instance
} }
func SetConfig(url string, database string, natsUrl string) *Config { func SetConfig(mongoUrl string, database string, natsUrl string, lokiUrl string, logLevel string) *Config {
once.Do(func() { /*once.Do(func() {
instance = &Config{ instance = &Config{
MongoUrl: url, MongoUrl: mongoUrl,
MongoDatabase: database, MongoDatabase: database,
NATSUrl: natsUrl, NATSUrl: natsUrl,
LokiUrl: lokiUrl,
LogLevel: logLevel,
} }
}) })*/
return instance GetConfig().MongoUrl = mongoUrl
GetConfig().MongoDatabase = database
GetConfig().NATSUrl = natsUrl
GetConfig().LokiUrl = lokiUrl
GetConfig().LogLevel = logLevel
return GetConfig()
} }

56
config/conf_loader.go Normal file
View File

@ -0,0 +1,56 @@
package config
import (
"os"
"strings"
"github.com/goraz/onion"
"github.com/rs/zerolog"
)
/* GetConfLoader
* Get the configuration loader for the application
* Parameters:
* - AppName: string : the name of the application
* Returns:
* - *onion.Onion : the configuration loader
* The configuration loader will load the configuration from the following sources:
* - the environment variables with the prefix APPNAME_
* - the file /etc/oc/appname.json
* - the file ./appname.json
* The configuration loader will merge the configuration from the different sources
* The configuration loader will give priority to the environment variables
* The configuration loader will give priority to the local file over the default file
*/
func GetConfLoader() *onion.Onion {
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()
AppName := GetAppName()
EnvPrefix := strings.ToUpper(AppName[0:2]+AppName[3:]) + "_"
defaultConfigFile := "/etc/oc/" + AppName[3:] + ".json"
localConfigFile := "./" + AppName[3:] + ".json"
var configFile string
var o *onion.Onion
l3 := onion.NewEnvLayerPrefix("_", EnvPrefix)
l2, err := onion.NewFileLayer(localConfigFile, nil)
if err == nil {
logger.Info().Msg("Local config file found " + localConfigFile + ", overriding default file")
configFile = localConfigFile
}
l1, err := onion.NewFileLayer(defaultConfigFile, nil)
if err == nil {
logger.Info().Msg("Config file found : " + defaultConfigFile)
configFile = defaultConfigFile
}
if configFile == "" {
logger.Info().Msg("No config file found, using env")
o = onion.New(l3)
} else if l1 != nil && l2 != nil {
o = onion.New(l1, l2, l3)
} else if l1 == nil {
o = onion.New(l2, l3)
} else if l2 == nil {
o = onion.New(l1, l3)
}
return o
}

View File

@ -6,6 +6,7 @@ import (
"runtime/debug" "runtime/debug"
"cloud.o-forge.io/core/oc-lib/config"
"cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/dbs"
"cloud.o-forge.io/core/oc-lib/dbs/mongo" "cloud.o-forge.io/core/oc-lib/dbs/mongo"
"cloud.o-forge.io/core/oc-lib/logs" "cloud.o-forge.io/core/oc-lib/logs"
@ -24,6 +25,7 @@ import (
shared_workspace "cloud.o-forge.io/core/oc-lib/models/workspace/shared" shared_workspace "cloud.o-forge.io/core/oc-lib/models/workspace/shared"
"cloud.o-forge.io/core/oc-lib/models/workspace/shared/rules/rule" "cloud.o-forge.io/core/oc-lib/models/workspace/shared/rules/rule"
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
"github.com/goraz/onion"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
@ -95,18 +97,42 @@ func AddPath(collection LibDataEnum, path string) {
paths[collection] = path paths[collection] = path
} }
func Init(appName string, hostname string, port string) { func Init(appName string) {
config.SetAppName(appName) // set the app name to the logger to define the main log chan
// create a temporary console logger for init
logs.SetLogger(logs.CreateLogger("main"))
}
//
// Expose subpackages
//
/* GetLogger returns the main logger
* @return zerolog.Logger
*/
func GetLogger() zerolog.Logger {
return logs.GetLogger()
}
/* SetConfig will set the config and create a logger according to app configuration and initialize mongo accessor
* @param url string
* @param database string
* @param natsUrl string
* @param lokiUrl string
* @param logLevel string
* @return *Config
*/
func SetConfig(mongoUrl string, database string, natsUrl string, lokiUrl string, logLevel string) *config.Config {
cfg := config.SetConfig(mongoUrl, database, natsUrl, lokiUrl, logLevel)
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
tools.UncatchedError = append(tools.UncatchedError, errors.New("Panic recovered in Init : "+fmt.Sprintf("%v", r)+" - "+string(debug.Stack()))) tools.UncatchedError = append(tools.UncatchedError, errors.New("Panic recovered in Init : "+fmt.Sprintf("%v", r)+" - "+string(debug.Stack())))
fmt.Printf("Panic recovered in Init : %v - %v\n", r, string(debug.Stack())) fmt.Printf("Panic recovered in Init : %v - %v\n", r, string(debug.Stack()))
} }
}() }()
logs.SetAppName(appName) // set the app name to the logger to define the main log chan logs.CreateLogger("main")
logs.SetLogger(logs.CreateLogger("main", "")) // create the logger mongo.MONGOService.Init(models.GetModelsNames(), config.GetConfig()) // init the mongo service
tools.GetConfig().Host = hostname // set the hostname to the config for inner discovery purpose actually not used
tools.GetConfig().Port = port // set the port to the config for inner discovery purpose actually not used
mongo.MONGOService.Init(models.GetModelsNames(), tools.GetConfig()) // init the mongo service
/* /*
Here we will check if the resource model is already stored in the database Here we will check if the resource model is already stored in the database
If not we will store it If not we will store it
@ -143,11 +169,33 @@ func Init(appName string, hostname string, port string) {
}) })
} }
} }
return cfg
} }
// GetLogger returns the main logger /* GetConfig will get the config
func GetLogger() zerolog.Logger { * @return *Config
return logs.GetLogger() */
func GetConfig() *config.Config {
return config.GetConfig()
}
/* GetConfLoader
* Get the configuration loader for the application
* Parameters:
* - AppName: string : the name of the application
* Returns:
* - *onion.Onion : the configuration loader
* The configuration loader will load the configuration from the following sources:
* - the environment variables with the prefix OCAPPNAME_
* - the file /etc/oc/appname.json
* - the file ./appname.json
* The configuration loader will merge the configuration from the different sources
* The configuration loader will give priority to the environment variables
* The configuration loader will give priority to the local file over the default file
*/
func GetConfLoader() *onion.Onion {
return config.GetConfLoader()
} }
/* /*

View File

@ -5,11 +5,12 @@ import (
"runtime" "runtime"
"time" "time"
"cloud.o-forge.io/core/oc-lib/config"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
var logger zerolog.Logger var logger zerolog.Logger
var appname string
// logs.CreateLogger // logs.CreateLogger
// Create a new logger // Create a new logger
// Parameters: // Parameters:
@ -18,14 +19,6 @@ var appname string
// Returns: // Returns:
// - zerolog.Logger : the logger that will log for the library and the app // - zerolog.Logger : the logger that will log for the library and the app
func SetAppName(name string) {
appname = name
}
func GetAppName() string {
return appname
}
func GetLogger() zerolog.Logger { func GetLogger() zerolog.Logger {
return logger return logger
} }
@ -34,10 +27,11 @@ func SetLogger(l zerolog.Logger) {
logger = l logger = l
} }
func CreateLogger(funcName string, url string) zerolog.Logger { func CreateLogger(funcName string) zerolog.Logger {
url := config.GetConfig().LokiUrl
if url != "" { if url != "" {
labels := map[string]string{ labels := map[string]string{
"app": appname, "app": config.GetAppName(),
"code": "go", "code": "go",
"platform": runtime.GOOS, "platform": runtime.GOOS,
"function": funcName, "function": funcName,

View File

@ -82,9 +82,9 @@ func (dma *AbstractAccessor) GetCaller() *tools.HTTPCaller {
// Init initializes the accessor with the data type and the http caller // Init initializes the accessor with the data type and the http caller
func (dma *AbstractAccessor) Init(t DataType, caller *tools.HTTPCaller) { func (dma *AbstractAccessor) Init(t DataType, caller *tools.HTTPCaller) {
dma.Logger = logs.CreateLogger(t.String(), "") // Create a logger with the data type dma.Logger = logs.CreateLogger(t.String()) // Create a logger with the data type
dma.Caller = caller // Set the caller dma.Caller = caller // Set the caller
dma.Type = t.String() // Set the data type dma.Type = t.String() // Set the data type
} }
// GenericLoadOne loads one object from the database (generic) // GenericLoadOne loads one object from the database (generic)

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"cloud.o-forge.io/core/oc-lib/config"
"cloud.o-forge.io/core/oc-lib/dbs/mongo" "cloud.o-forge.io/core/oc-lib/dbs/mongo"
) )
@ -51,11 +52,11 @@ type API struct{}
// GetState returns the state of the API // GetState returns the state of the API
func (a *API) GetState() (State, int, error) { func (a *API) GetState() (State, int, error) {
// Check if the database is up // Check if the database is up
err := mongo.MONGOService.TestDB(GetConfig()) err := mongo.MONGOService.TestDB(config.GetConfig())
if err != nil { if err != nil {
return DB_FALLOUT, 200, err // If the database is not up, return database fallout return DB_FALLOUT, 200, err // If the database is not up, return database fallout
} }
err = mongo.MONGOService.TestCollections(GetConfig(), []string{}) // Check if the collections are up err = mongo.MONGOService.TestCollections(config.GetConfig(), []string{}) // Check if the collections are up
if err != nil { if err != nil {
return UNPROCESSABLE_ENTITY, 200, err // If the collections are not up, return unprocessable entity return UNPROCESSABLE_ENTITY, 200, err // If the collections are not up, return unprocessable entity
} }

View File

@ -1,53 +0,0 @@
package tools
import (
"strings"
"cloud.o-forge.io/core/oc-lib/logs"
"github.com/goraz/onion"
)
// GetConfLoader
// Get the configuration loader for the application
// Parameters:
// - AppName: string : the name of the application
// Returns:
// - *onion.Onion : the configuration loader
// The configuration loader will load the configuration from the following sources:
// - the environment variables with the prefix APPNAME_
// - the file /etc/oc/appname.json
// - the file ./appname.json
// The configuration loader will merge the configuration from the different sources
// The configuration loader will give priority to the environment variables
// The configuration loader will give priority to the local file over the default file
func GetConfLoader(AppName string) *onion.Onion {
logger := logs.GetLogger()
EnvPrefix := strings.ToUpper(AppName[0:2]+AppName[3:]) + "_"
defaultConfigFile := "/etc/oc/" + AppName[0:2] + ".json"
localConfigFile := "./" + AppName[0:2] + ".json"
var configFile string
var o *onion.Onion
l3 := onion.NewEnvLayerPrefix("_", EnvPrefix)
l2, err := onion.NewFileLayer(localConfigFile, nil)
if err == nil {
logger.Info().Msg("Local config file found " + localConfigFile + ", overriding default file")
configFile = localConfigFile
}
l1, err := onion.NewFileLayer(defaultConfigFile, nil)
if err == nil {
logger.Info().Msg("Config file found : " + defaultConfigFile)
configFile = defaultConfigFile
}
if configFile == "" {
logger.Info().Msg("No config file found, using env")
o = onion.New(l3)
} else if l1 != nil && l2 != nil {
o = onion.New(l1, l2, l3)
} else if l1 == nil {
o = onion.New(l2, l3)
} else if l2 == nil {
o = onion.New(l1, l3)
}
return o
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"strings" "strings"
"cloud.o-forge.io/core/oc-lib/config"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
) )
@ -44,10 +45,10 @@ func NewNATSCaller() *natsCaller {
// SetNATSPub sets a message to the NATS server // SetNATSPub sets a message to the NATS server
func (o *natsCaller) SetNATSPub(dataName string, method NATSMethod, data interface{}) string { func (o *natsCaller) SetNATSPub(dataName string, method NATSMethod, data interface{}) string {
if GetConfig().NATSUrl == "" { if config.GetConfig().NATSUrl == "" {
return " -> NATS_SERVER is not set" return " -> NATS_SERVER is not set"
} }
nc, err := nats.Connect(GetConfig().NATSUrl) nc, err := nats.Connect(config.GetConfig().NATSUrl)
if err != nil { if err != nil {
return " -> Could not reach NATS server : " + err.Error() return " -> Could not reach NATS server : " + err.Error()
} }