diff --git a/Dockerfile b/Dockerfile index e3050ed..4f2be75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,25 +38,27 @@ COPY --from=builder /go/src/github.com/cloud-barista/cm-beetle/scripts/ /app/scr COPY --from=builder /go/src/github.com/cloud-barista/cm-beetle/cmd/cm-beetle /app/ -#RUN /bin/bash -c "source /app/conf/setup.env" -## Logger configuration -# Set log file path (default ./cm-beetle.log) -ENV CM_BEETLE_LOG_PATH cm-beetle.log -ENV CM_BEETLE_LOG_MAX_SIZE 10 -ENV CM_BEETLE_LOG_MAX_BACKUPS 3 -ENV CM_BEETLE_LOG_MAX_AGE 30 -ENV CM_BEETLE_LOG_COMPRESS false -# Set execution environment, such as development or production -ENV CM_BEETLE_APP_ENV production -# Set log level, such as trace, debug info, warn, error, fatal, and panic -ENV CM_BEETLE_LOG_LEVEL info - ## Set system endpoints ENV CMBEETLE_ROOT /app ENV CBSTORE_ROOT /app ENV CBLOG_ROOT /app -# ENV SPIDER_CALL_METHOD REST -# ENV SPIDER_REST_URL http://cb-spider:1024/spider +# ENV CBSPIDER_CALLMETHOD REST +# ENV CBSPIDER_REST_URL http://cb-spider:1024/spider +# ENV CBTUMBLEBUG_CALLMETHOD REST +# ENV CBTUMBLEBUG_REST_URL http://localhost:1323/tumblebug + +#RUN /bin/bash -c "source /app/conf/setup.env" +## Logger configuration +# Set log file path (default logfile path: ./cm-beetle.log) +ENV LOGFILE_PATH cm-beetle.log +ENV LOGFILE_MAXSIZE 10 +ENV LOGFILE_MAXBACKUPS 3 +ENV LOGFILE_MAXAGE 30 +ENV LOGFILE_COMPRESS false +# Set log level, such as trace, debug info, warn, error, fatal, and panic +ENV LOGLEVEL info +# Set execution environment, such as development or production +ENV NODE_ENV production ## Set internal DB config (SQLlite) ENV DB_URL localhost:3306 @@ -65,10 +67,10 @@ ENV DB_USER cm_beetle ENV DB_PASSWORD cm_beetle ## Set API access config -# ALLOW_ORIGINS (ex: https://cloud-barista.org,xxx.xxx.xxx.xxx or * for all) -ENV ALLOW_ORIGINS * +# API_ALLOW_ORIGINS (ex: https://cloud-barista.org,xxx.xxx.xxx.xxx or * for all) +ENV API_ALLOW_ORIGINS * # Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) -ENV ENABLE_AUTH true +ENV API_AUTH_ENABLED true ENV API_USERNAME default ENV API_PASSWORD default @@ -80,7 +82,7 @@ ENV SELF_ENDPOINT localhost:8056 ## Environment variables that you don't need to touch # Swagger UI API document file path -ENV API_DOC_PATH /app/pkg/api/rest/docs/swagger.json +ENV APIDOC_PATH /app/pkg/api/rest/docs/swagger.json ENTRYPOINT [ "/app/cm-beetle" ] diff --git a/conf/setup.env b/conf/setup.env index 6f95637..efff2c4 100644 --- a/conf/setup.env +++ b/conf/setup.env @@ -1,26 +1,25 @@ -## Set CMBEETLE_ROOT based on path of setup.env relatively +## Set system endpoints +# Set CMBEETLE_ROOT based on path of setup.env relatively SCRIPT_DIR=`dirname ${BASH_SOURCE[0]-$0}` export CMBEETLE_ROOT=`cd $SCRIPT_DIR && cd .. && pwd` -# Use CMBEETLE_ROOT directly if the SCRIPT_DIR does not work -# export CMBEETLE_ROOT=$HOME/go/src/github.com/cloud-barista/cm-beetle +export CBSTORE_ROOT=$CMBEETLE_ROOT +export CBLOG_ROOT=$CMBEETLE_ROOT +#export CBSPIDER_CALLMETHOD=REST +#export CBSPIDER_REST_URL=http://localhost:1024/spider +#export CBTUMBLEBUG_CALLMETHOD=REST +#export CBTUMBLEBUG_REST_URL=http://localhost:1323/tumblebug ## Logger configuration -# Set log file path (default ./cm-beetle.log) -export CM_BEETLE_LOG_PATH=cm-beetle.log -export CM_BEETLE_LOG_MAX_SIZE=10 -export CM_BEETLE_LOG_MAX_BACKUPS=3 -export CM_BEETLE_LOG_MAX_AGE=30 -export CM_BEETLE_LOG_COMPRESS=false -# Set execution environment, such as development or production -export CM_BEETLE_APP_ENV=development +# Set log file path (default logfile path: ./cm-beetle.log) +export LOGFILE_PATH=cm-beetle.log +export LOGFILE_MAXSIZE=10 +export LOGFILE_MAXBACKUPS=3 +export LOGFILE_MAXAGE=30 +export LOGFILE_COMPRESS=false # Set log level, such as trace, debug info, warn, error, fatal, and panic -export CM_BEETLE_LOG_LEVEL=debug - -## Set system endpoints -export CBSTORE_ROOT=$CMBEETLE_ROOT -export CBLOG_ROOT=$CMBEETLE_ROOT -#export SPIDER_CALL_METHOD=REST -#export SPIDER_REST_URL=http://localhost:1024/spider +export LOGLEVEL=debug +# Set execution environment, such as development or production +export NODE_ENV=development ## Set internal DB config (SQLlite) export DB_URL=localhost:3306 @@ -29,10 +28,10 @@ export DB_USER=cm_beetlee export DB_PASSWORD=cm_beetle ## Set API access config -# ALLOW_ORIGINS (ex: https://cloud-barista.org,http://localhost:8080 or * for all) -export ALLOW_ORIGINS=* -# Set ENABLE_AUTH=true currently for basic auth for all routes (i.e., url or path) -export ENABLE_AUTH=true +# API_ALLOW_ORIGINS (ex: https://cloud-barista.org,http://localhost:8080 or * for all) +export API_ALLOW_ORIGINS=* +# Set API_AUTH_ENABLED=true currently for basic auth for all routes (i.e., url or path) +export API_AUTH_ENABLED=true export API_USERNAME=default export API_PASSWORD=default @@ -44,4 +43,4 @@ export SELF_ENDPOINT=localhost:8056 ## Environment variables that you don't need to touch # Swagger UI API document file path -export API_DOC_PATH=$CMBEETLE_ROOT/src/api/rest/docs/swagger.json \ No newline at end of file +export APIDOC_PATH=$CMBEETLE_ROOT/src/api/rest/docs/swagger.json \ No newline at end of file diff --git a/go.work.sum b/go.work.sum index a162d14..b806edb 100644 --- a/go.work.sum +++ b/go.work.sum @@ -9,11 +9,13 @@ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9 github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/cloud-barista/cb-log v0.6.3 h1:6FEzJFOOWl2a4oA1+fDvibgthChIEq7JH/Evnh6LlGY= +github.com/cloud-barista/cb-log v0.6.3/go.mod h1:nGgfTFMPwl1MpCO3FBjexUkNdOYA0BNJoyM9Pd0lMms= github.com/cloud-barista/cb-log v0.6.4 h1:HblyslcRLeD2tib4UcZszJ8ZNfB4W0CRVvbKlf9uY78= github.com/cloud-barista/cb-log v0.6.4/go.mod h1:nGgfTFMPwl1MpCO3FBjexUkNdOYA0BNJoyM9Pd0lMms= github.com/cloud-barista/cm-beetle/src v0.0.0-20230724172618-8f225d0127e8/go.mod h1:XQuz7L64MNUu04FmG5gB0z41VcrfaLuQP80EGyQTDgo= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= @@ -70,18 +72,26 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc= github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg= github.com/xujiajun/nutsdb v0.10.0 h1:kSxd7MyZiAVQM2I79FK74WneGI+uaHsUdak8dbjzKJc= +github.com/xujiajun/nutsdb v0.10.0/go.mod h1:8ZdTTF0cEQO+wN940htfHYKswFql2iB6Osckx+GmOoU= github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b h1:jKG9OiL4T4xQN3IUrhUpc1tG+HfDXppkgVcrAiiaI/0= +github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b/go.mod h1:AZd87GYJlUzl82Yab2kTjx1EyXSQCAfZDhpTo1SQC4k= github.com/yumaojun03/dmidecode v0.1.4/go.mod h1:34bbsMNMNjDbijDpRuqd+2ZapDKxvhO+FlgGgOgS6G8= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -97,8 +107,11 @@ golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/api/rest/common/utility.go b/pkg/api/rest/common/utility.go index ab143c6..c3b0763 100644 --- a/pkg/api/rest/common/utility.go +++ b/pkg/api/rest/common/utility.go @@ -116,7 +116,7 @@ func RestCheckHTTPVersion(c echo.Context) error { // // @Failure 500 {object} common.SimpleMsg // // @Router /swaggerActive [get] // func RestGetSwagger(c echo.Context) error { -// docFile := os.Getenv("API_DOC_PATH") +// docFile := os.Getenv("APIDOC_PATH") // f, err := os.Open(docFile) // if err != nil { diff --git a/pkg/api/rest/controller/migration.go b/pkg/api/rest/controller/migration.go index fcf65d9..515f1a4 100644 --- a/pkg/api/rest/controller/migration.go +++ b/pkg/api/rest/controller/migration.go @@ -23,6 +23,10 @@ import ( "github.com/cloud-barista/cm-beetle/pkg/core/common" "github.com/go-resty/resty/v2" "github.com/labstack/echo/v4" + + // Black import (_) is for running a package's init() function without using its other contents. + _ "github.com/cloud-barista/cm-beetle/pkg/logger" + "github.com/rs/zerolog/log" ) type MigrateInfraRequest struct { @@ -55,9 +59,8 @@ func MigrateInfra(c echo.Context) error { return err } - fmt.Printf("RequestBody: %v\n", req) - fmt.Print(req) - fmt.Print(req.TbMcisDynamicReq) + log.Trace().Msgf("req: %v\n", req) + log.Trace().Msgf("req.TbMcisDynamicReq: %v\n", req.TbMcisDynamicReq) // [Note] Process section // Call CB-Tumblebug API, which can be "/mcisDynamic" @@ -65,11 +68,11 @@ func MigrateInfra(c echo.Context) error { nsId := "ns01" result, err := createVMInfra(nsId, &req.TbMcisDynamicReq) - fmt.Print(result) + log.Trace().Msgf("result: %v\n", result) // [Note] Ouput section if err != nil { - common.CBLog.Error(err) + log.Error().Err(err).Msg("Failed to create VM infrastructure") mapA := map[string]string{"message": err.Error()} return c.JSON(http.StatusInternalServerError, &mapA) } @@ -147,9 +150,8 @@ func MigrateNetwork(c echo.Context) error { return err } - fmt.Printf("RequestBody: %v\n", req) - fmt.Print(req) - fmt.Print(req.DummyNetwork) + log.Trace().Msgf("req: %v\n", req) + log.Trace().Msgf("req.DummyNetwork: %v\n", req.DummyNetwork) // [Note] Process section // Something to process here like, @@ -157,8 +159,8 @@ func MigrateNetwork(c echo.Context) error { // Calls external APIs and so on res := &MigrateNetworkResponse{} - fmt.Print(res) - fmt.Print(res.DummyNetwork) + log.Trace().Msgf("res: %v\n", res) + log.Trace().Msgf("res.DummyNetwork: %v\n", res.DummyNetwork) // This is an intentionally created variable. // You will have to delete this later. @@ -166,7 +168,7 @@ func MigrateNetwork(c echo.Context) error { // [Note] Ouput section if err != nil { - common.CBLog.Error(err) + log.Error().Err(err).Msg("Failed to migrate network on a cloud platform") mapA := map[string]string{"message": err.Error()} return c.JSON(http.StatusInternalServerError, &mapA) } @@ -206,9 +208,8 @@ func MigrateStorage(c echo.Context) error { return err } - fmt.Printf("RequestBody: %v\n", req) - fmt.Print(req) - fmt.Print(req.DummyStorage) + log.Trace().Msgf("req: %v\n", req) + log.Trace().Msgf("req.DummyStorage: %v\n", req.DummyStorage) // [Note] Process section // Something to process here like, @@ -216,8 +217,8 @@ func MigrateStorage(c echo.Context) error { // Calls external APIs and so on res := &MigrateStorageResponse{} - fmt.Print(res) - fmt.Print(res.DummyStorage) + log.Trace().Msgf("res: %v\n", res) + log.Trace().Msgf("res.DummyStorage: %v\n", res.DummyStorage) // This is an intentionally created variable. // You will have to delete this later. @@ -225,7 +226,7 @@ func MigrateStorage(c echo.Context) error { // [Note] Ouput section if err != nil { - common.CBLog.Error(err) + log.Error().Err(err).Msg("Failed to migrate storage on a cloud platform") mapA := map[string]string{"message": err.Error()} return c.JSON(http.StatusInternalServerError, &mapA) } @@ -265,9 +266,8 @@ func MigrateInstance(c echo.Context) error { return err } - fmt.Printf("RequestBody: %v\n", req) - fmt.Print(req) - fmt.Print(req.DummyInstance) + log.Trace().Msgf("req: %v\n", req) + log.Trace().Msgf("req.DummyInstance: %v\n", req.DummyInstance) // [Note] Process section // Something to process here like, @@ -275,8 +275,8 @@ func MigrateInstance(c echo.Context) error { // Calls external APIs and so on res := &MigrateInstanceResponse{} - fmt.Print(res) - fmt.Print(res.DummyInstance) + log.Trace().Msgf("res: %v\n", res) + log.Trace().Msgf("res.DummyInstance: %v\n", res.DummyInstance) // This is an intentionally created variable. // You will have to delete this later. @@ -284,7 +284,7 @@ func MigrateInstance(c echo.Context) error { // [Note] Ouput section if err != nil { - common.CBLog.Error(err) + log.Error().Err(err).Msg("Failed to migrate instance on a cloud platform") mapA := map[string]string{"message": err.Error()} return c.JSON(http.StatusInternalServerError, &mapA) } diff --git a/pkg/api/rest/controller/recommendation.go b/pkg/api/rest/controller/recommendation.go index 8150672..1a829a1 100644 --- a/pkg/api/rest/controller/recommendation.go +++ b/pkg/api/rest/controller/recommendation.go @@ -64,12 +64,10 @@ func RecommendInfra(c echo.Context) error { return c.JSON(http.StatusBadRequest, res) } - log.Debug().Msgf("RequestBody: %v\n", req) - log.Debug().Msgf("req.Infra.Compute: %v\n", req.Infra.Compute) - // log.Debug().Msgf("req.Infra.Network: %v\n", req.Infra.Network) - // log.Debug().Msgf("req.Infra.GPU: %v\n", req.Infra.GPU) - // fmt.Print(req.Network) - // fmt.Print(req.GPU) + log.Trace().Msgf("req: %v\n", req) + log.Trace().Msgf("req.Infra.Compute: %v\n", req.Infra.Compute) + // log.Trace().Msgf("req.Infra.Network: %v\n", req.Infra.Network) + // log.Trace().Msgf("req.Infra.GPU: %v\n", req.Infra.GPU) // Process recommendedInfra, err := recommendation.Recommend(req.Infra) diff --git a/pkg/api/rest/server/server.go b/pkg/api/rest/server/server.go index f9c5942..45152b0 100644 --- a/pkg/api/rest/server/server.go +++ b/pkg/api/rest/server/server.go @@ -23,6 +23,7 @@ import ( rest_common "github.com/cloud-barista/cm-beetle/pkg/api/rest/common" "github.com/cloud-barista/cm-beetle/pkg/api/rest/route" + "github.com/spf13/viper" "crypto/subtle" "fmt" @@ -39,6 +40,7 @@ import ( echoSwagger "github.com/swaggo/echo-swagger" // Black import (_) is for running a package's init() function without using its other contents. + _ "github.com/cloud-barista/cm-beetle/pkg/config" _ "github.com/cloud-barista/cm-beetle/pkg/logger" "github.com/rs/zerolog/log" ) @@ -99,7 +101,7 @@ func RunServer(port string) { e.HideBanner = true //e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website)) - allowedOrigins := os.Getenv("ALLOW_ORIGINS") + allowedOrigins := viper.GetString("api.allow.origins") if allowedOrigins == "" { log.Fatal().Msg("allow_ORIGINS env variable for CORS is " + allowedOrigins + ". Please provide a proper value and source setup.env again. EXITING...") @@ -111,10 +113,10 @@ func RunServer(port string) { })) // Conditions to prevent abnormal operation due to typos (e.g., ture, falss, etc.) - enableAuth := os.Getenv("ENABLE_AUTH") == "true" + enableAuth := viper.GetString("api.auth.enabled") == "true" - apiUser := os.Getenv("API_USERNAME") - apiPass := os.Getenv("API_PASSWORD") + apiUser := viper.GetString("api.username") + apiPass := viper.GetString("api.password") if enableAuth { e.Use(middleware.BasicAuthWithConfig(middleware.BasicAuthConfig{ @@ -189,7 +191,7 @@ func RunServer(port string) { // g.POST("/:nsId/mcis/:mcisId/subgroup/:subgroupId", rest_mcis.RestPostMcisSubGroupScaleOut) // g.DELETE("/:nsId/mcis", rest_mcis.RestDelAllMcis) - selfEndpoint := os.Getenv("SELF_ENDPOINT") + selfEndpoint := viper.GetString("self.endpoint") apidashboard := " http://" + selfEndpoint + "/beetle/swagger/index.html" if enableAuth { diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..59e4f61 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,94 @@ +package config + +import ( + "errors" + "log" + "os" + "path/filepath" + "strings" + + "github.com/spf13/viper" +) + +func init() { + Init() +} + +func Init() { + viper.AddConfigPath("../../conf/") // config for development + viper.AddConfigPath(".") // config for production optionally looking for the configuration in the working directory + viper.AddConfigPath("./conf/") // config for production optionally looking for the configuration in the working directory/conf/ + viper.SetConfigName("config") + viper.SetConfigType("yaml") + + // Map environment variable names to config file key names + replacer := strings.NewReplacer(".", "_") + viper.SetEnvKeyReplacer(replacer) + + // Automatically recognize environment variables + viper.AutomaticEnv() + + // Try to read the config file in development environment + if viper.GetString("node.env") != "production" { + if err := viper.ReadInConfig(); err != nil { + log.Printf("Error reading config file, using default settings: %s", err) + } + } + + // Values set in runtime + if viper.GetString("cmbeetle.root") == "" { + log.Println("cmbeetle.root is not set in config file or environment variable") + + log.Println("find project root by using project name") + projectName := "cm-beetle" + projectRoot, err := findProjectRoot(projectName) + if err != nil { + log.Fatalf("Error finding project root directory: %v", err) + } + // Set the binary path + viper.Set("cmbeetle.root", projectRoot) + viper.Set("cbstore.root", projectRoot) + viper.Set("cblog.root", projectRoot) + viper.Set("apidoc.path", projectRoot+"/pkg/api/rest/docs/swagger.json") + } + + // Recursively print all keys and values in Viper + settings := viper.AllSettings() + recursivePrintMap(settings, "") +} + +func findProjectRoot(projectName string) (string, error) { + // Get the executable path + execPath, err := os.Executable() + if err != nil { + log.Fatalf("Error getting executable path: %v", err) + } + execDir := filepath.Dir(execPath) + + // find last index of project name + index := strings.LastIndex(execDir, projectName) + if index == -1 { + log.Println("project name not found the path") + return "", errors.New("proejct name not found in the path") + } + + // Cut the string up to the index + result := execDir[:index+len(projectName)] + + log.Printf("project root directory: %s\n", result) + + return result, nil +} + +func recursivePrintMap(m map[string]interface{}, prefix string) { + for k, v := range m { + fullKey := prefix + k + if nestedMap, ok := v.(map[string]interface{}); ok { + // Recursive call for nested maps + recursivePrintMap(nestedMap, fullKey+".") + } else { + // Print current key-value pair + log.Printf("Key: %s, Value: %v\n", fullKey, v) + } + } +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 4f89cc4..8e5672b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -5,8 +5,10 @@ import ( "strconv" "time" + _ "github.com/cloud-barista/cm-beetle/pkg/config" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "github.com/spf13/viper" "gopkg.in/natefinch/lumberjack.v2" ) @@ -16,6 +18,10 @@ var ( func init() { + // Set config values + logLevel := viper.GetString("loglevel") + env := viper.GetString("node.env") + // Set the global logger to use JSON format. zerolog.TimeFieldFormat = time.RFC3339 @@ -32,7 +38,6 @@ func init() { } // Set the log level - logLevel := os.Getenv("CM_BEETLE_LOG_LEVEL") var level zerolog.Level switch logLevel { case "trace": @@ -50,7 +55,7 @@ func init() { case "panic": level = zerolog.PanicLevel default: - log.Warn().Msgf("Invalid CM_BEETLE_LOG_LEVEL value: %s. Using default value: info", logLevel) + log.Warn().Msgf("Invalid LOGLEVEL value: %s. Using default value: info", logLevel) level = zerolog.InfoLevel } @@ -60,8 +65,6 @@ func init() { log.Logger = *logger // Check the execution environment from the environment variable - env := os.Getenv("CM_BEETLE_APP_ENV") - // Log a message log.Info(). Str("logLevel", level.String()). @@ -88,6 +91,9 @@ func init() { // Create a new logger func NewLogger(level zerolog.Level) *zerolog.Logger { + // Set config values + env := viper.GetString("node.env") + // Multi-writer setup: logs to both file and console multi := zerolog.MultiLevelWriter( sharedLogFile, @@ -97,8 +103,6 @@ func NewLogger(level zerolog.Level) *zerolog.Logger { var logger zerolog.Logger // Check the execution environment from the environment variable - env := os.Getenv("CM_BEETLE_APP_ENV") - // Configure the log output if env == "production" { // Apply multi-writer to the global logger @@ -130,38 +134,40 @@ func NewLogger(level zerolog.Level) *zerolog.Logger { // Get log file configuration from environment variables func getLogFileConfig() (string, int, int, int, bool) { + // Set config values + logFilePath := viper.GetString("logfile.path") + maxSize, err := strconv.Atoi(viper.GetString("logfile.maxsize")) + maxBackups, err := strconv.Atoi(viper.GetString("logfile.maxbackups")) + maxAge, err := strconv.Atoi(viper.GetString("logfile.maxage")) + compress, err := strconv.ParseBool(viper.GetString("logfile.compress")) + // Default: cm-beetle.log - logFilePath := os.Getenv("CM_BEETLE_LOG_PATH") if logFilePath == "" { - log.Info().Msg("CM_BEETLE_LOG_PATH is not set. Using default value: cm-beetle.log") + log.Warn().Msg("LOGFILE_PATH is not set. Using default value: cm-beetle.log") logFilePath = "cm-beetle.log" } // Default: 10 MB - maxSize, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_SIZE")) if err != nil { - log.Warn().Msgf("Invalid CM_BEETLE_LOG_MAX_SIZE value: %s. Using default value: 10 MB", os.Getenv("CM_BEETLE_LOG_MAX_SIZE")) + log.Warn().Msgf("Invalid LOGFILE_MAXSIZE value: %s. Using default value: 10 MB", viper.GetString("logfile.maxsize")) maxSize = 10 } // Default: 3 backups - maxBackups, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_BACKUPS")) if err != nil { - log.Warn().Msgf("Invalid CM_BEETLE_LOG_MAX_BACKUPS value: %s. Using default value: 3 backups", os.Getenv("CM_BEETLE_LOG_MAX_BACKUPS")) + log.Warn().Msgf("Invalid LOGFILE_MAXBACKUPS value: %s. Using default value: 3 backups", viper.GetString("logfile.maxbackups")) maxBackups = 3 } // Default: 30 days - maxAge, err := strconv.Atoi(os.Getenv("CM_BEETLE_LOG_MAX_AGE")) if err != nil { - log.Warn().Msgf("Invalid CM_BEETLE_LOG_MAX_AGE value: %s. Using default value: 30 days", os.Getenv("CM_BEETLE_LOG_MAX_AGE")) + log.Warn().Msgf("Invalid LOGFILE_MAXAGE value: %s. Using default value: 30 days", viper.GetString("logfile.maxage")) maxAge = 30 } // Default: false - compress, err := strconv.ParseBool(os.Getenv("CM_BEETLE_LOG_COMPRESS")) if err != nil { - log.Warn().Msgf("Invalid CM_BEETLE_LOG_COMPRESS value: %s. Using default value: false", os.Getenv("CM_BEETLE_LOG_COMPRESS")) + log.Warn().Msgf("Invalid LOGFILE_COMPRESS value: %s. Using default value: false", viper.GetString("logfile.compress")) compress = false }