diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 5d5e33212..04fc4ad9b 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -452,7 +452,7 @@ func main() { cfg.GeneralCfg().NodeID = *nodeID } - if cfg.ConfigDBCfg().Enabled { + if cfg.ConfigDBCfg().Type != utils.MetaInternal { d, err := engine.NewDataDBConn(cfg.ConfigDBCfg().Type, cfg.ConfigDBCfg().Host, cfg.ConfigDBCfg().Port, cfg.ConfigDBCfg().Name, cfg.ConfigDBCfg().User, diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index 6fef3a907..135050c78 100755 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -120,7 +120,7 @@ func loadConfig() (ldrCfg *config.CGRConfig) { if ldrCfg, err = config.NewCGRConfigFromPath(*cfgPath); err != nil { log.Fatalf("Error loading config file %s", err) } - if ldrCfg.ConfigDBCfg().Enabled { + if ldrCfg.ConfigDBCfg().Type != utils.MetaInternal { d, err := engine.NewDataDBConn(ldrCfg.ConfigDBCfg().Type, ldrCfg.ConfigDBCfg().Host, ldrCfg.ConfigDBCfg().Port, ldrCfg.ConfigDBCfg().Name, ldrCfg.ConfigDBCfg().User, diff --git a/cmd/cgr-migrator/cgr-migrator.go b/cmd/cgr-migrator/cgr-migrator.go index 9f9b5eecb..74ca39f88 100755 --- a/cmd/cgr-migrator/cgr-migrator.go +++ b/cmd/cgr-migrator/cgr-migrator.go @@ -145,7 +145,7 @@ func main() { if mgrCfg, err = config.NewCGRConfigFromPath(*cfgPath); err != nil { log.Fatalf("error loading config file %s", err.Error()) } - if mgrCfg.ConfigDBCfg().Enabled { + if mgrCfg.ConfigDBCfg().Type != utils.MetaInternal { d, err := engine.NewDataDBConn(mgrCfg.ConfigDBCfg().Type, mgrCfg.ConfigDBCfg().Host, mgrCfg.ConfigDBCfg().Port, mgrCfg.ConfigDBCfg().Name, mgrCfg.ConfigDBCfg().User, diff --git a/config/config.go b/config/config.go index 532420e67..9094de40c 100644 --- a/config/config.go +++ b/config/config.go @@ -19,9 +19,6 @@ along with this program. If not, see package config import ( - "bytes" - "encoding/json" - "errors" "fmt" "io" "net/http" @@ -33,7 +30,6 @@ import ( "sync" "time" - "github.com/cgrates/birpc/context" "github.com/cgrates/rpcclient" "github.com/cgrates/cgrates/utils" @@ -201,12 +197,11 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) { cfg.apiBanCfg = new(APIBanCfg) cfg.coreSCfg = new(CoreSCfg) cfg.accountSCfg = new(AccountSCfg) - cfg.configDBCfg = new(ConfigDBCfg) - cfg.configDBCfg.DataDbCfg = new(DataDbCfg) - cfg.configDBCfg.DataDbCfg.Items = make(map[string]*ItemOpt) - cfg.configDBCfg.DataDbCfg.Opts = make(map[string]interface{}) + cfg.configDBCfg = new(DataDbCfg) + cfg.configDBCfg.Items = make(map[string]*ItemOpt) + cfg.configDBCfg.Opts = make(map[string]interface{}) - cfg.cacheDP = make(map[string]utils.MapStorage) + cfg.cacheDP = make(utils.MapStorage) var cgrJSONCfg *CgrJsonCfg if cgrJSONCfg, err = NewCgrJsonCfgFromBytes(config); err != nil { @@ -339,9 +334,9 @@ type CGRConfig struct { apiBanCfg *APIBanCfg // APIBan config coreSCfg *CoreSCfg // CoreS config accountSCfg *AccountSCfg // AccountS config - configDBCfg *ConfigDBCfg // ConfigDB conifg + configDBCfg *DataDbCfg // ConfigDB conifg - cacheDP map[string]utils.MapStorage + cacheDP utils.MapStorage cacheDPMux sync.RWMutex db ConfigDB // to store the last dbConn that executed an config update @@ -861,8 +856,8 @@ func (cfg *CGRConfig) loadAccountSCfg(jsnCfg ConfigDB) (err error) { // loadConfigDBCfg loads the ConfigDB section of the configuration func (cfg *CGRConfig) loadConfigDBCfg(jsnCfg ConfigDB) (err error) { - var jsnDBCfg *ConfigDBJsonCfg - if jsnDBCfg, err = jsnCfg.ConfigDBJsonCfg(); err != nil { + var jsnDBCfg *DbJsonCfg + if jsnDBCfg, err = jsnCfg.DbJsonCfg(ConfigDBJSON); err != nil { return } return cfg.configDBCfg.loadFromJSONCfg(jsnDBCfg) @@ -1175,7 +1170,7 @@ func (cfg *CGRConfig) CoreSCfg() *CoreSCfg { } // ConfigDBCfg reads the CoreS configuration -func (cfg *CGRConfig) ConfigDBCfg() *ConfigDBCfg { +func (cfg *CGRConfig) ConfigDBCfg() *DataDbCfg { cfg.lks[ConfigDBJSON].Lock() defer cfg.lks[ConfigDBJSON].Unlock() return cfg.configDBCfg @@ -1592,208 +1587,6 @@ func (cfg *CGRConfig) AsMapInterface(separator string) (mp map[string]interface{ } } -// ReloadArgs the API params for V1ReloadConfig -type ReloadArgs struct { - APIOpts map[string]interface{} - Tenant string - Path string - Section string - DryRun bool -} - -// V1ReloadConfig reloads the configuration -func (cfg *CGRConfig) V1ReloadConfig(ctx *context.Context, args *ReloadArgs, reply *string) (err error) { - if missing := utils.MissingStructFields(args, []string{"Path"}); len(missing) != 0 { - return utils.NewErrMandatoryIeMissing(missing...) - } - cfgV := cfg - if args.DryRun { - cfgV = cfg.Clone() - } - cfgV.reloadDPCache(args.Section) - if err = cfgV.loadCfgWithLocks(args.Path, args.Section); err != nil { - return - } - // lock all sections - cfgV.rLockSections() - - err = cfgV.checkConfigSanity() - - cfgV.rUnlockSections() // unlock before checking the error - - if err != nil { - return - } - if !args.DryRun { - if args.Section == utils.EmptyString || args.Section == utils.MetaAll { - cfgV.reloadSections(sortedCfgSections...) - } else { - cfgV.reloadSections(args.Section) - } - } - *reply = utils.OK - return -} - -// SectionWithAPIOpts the API params for GetConfig -type SectionWithAPIOpts struct { - APIOpts map[string]interface{} - Tenant string - Section string -} - -// V1GetConfig will retrieve from CGRConfig a section -func (cfg *CGRConfig) V1GetConfig(ctx *context.Context, args *SectionWithAPIOpts, reply *map[string]interface{}) (err error) { - args.Section = utils.FirstNonEmpty(args.Section, utils.MetaAll) - cfg.cacheDPMux.RLock() - if mp, has := cfg.cacheDP[args.Section]; has && mp != nil { - *reply = mp - cfg.cacheDPMux.RUnlock() - return - } - cfg.cacheDPMux.RUnlock() - defer func() { - if err != nil { - return - } - cfg.cacheDPMux.Lock() - cfg.cacheDP[args.Section] = *reply - cfg.cacheDPMux.Unlock() - }() - var mp interface{} - if args.Section == utils.MetaAll { - *reply = cfg.AsMapInterface(cfg.GeneralCfg().RSRSep) - return - } - if mp, err = cfg.getSectionAsMap(args.Section); err != nil { - return - } - *reply = map[string]interface{}{args.Section: mp} - return -} - -// SetConfigArgs the API params for V1SetConfig -type SetConfigArgs struct { - APIOpts map[string]interface{} - Tenant string - Config map[string]interface{} - DryRun bool -} - -// V1SetConfig reloads the sections of config -func (cfg *CGRConfig) V1SetConfig(ctx *context.Context, args *SetConfigArgs, reply *string) (err error) { - if len(args.Config) == 0 { - *reply = utils.OK - return - } - sections := make([]string, 0, len(args.Config)) - for section := range args.Config { - if !sortedSectionsSet.Has(section) { - return fmt.Errorf("Invalid section <%s> ", section) - } - sections = append(sections, section) - } - var b []byte - if b, err = json.Marshal(args.Config); err != nil { - return - } - cfgV := cfg - if args.DryRun { - cfgV = cfg.Clone() - } - - cfgV.reloadDPCache(sections...) - if err = cfgV.loadCfgFromJSONWithLocks(bytes.NewBuffer(b), sections); err != nil { - return - } - - // lock all sections - cfgV.rLockSections() - - err = cfgV.checkConfigSanity() - - cfgV.rUnlockSections() // unlock before checking the error - if err != nil { - return - } - if !args.DryRun { - cfgV.reloadSections(sections...) - } - *reply = utils.OK - return -} - -//V1GetConfigAsJSON will retrieve from CGRConfig a section as a string -func (cfg *CGRConfig) V1GetConfigAsJSON(ctx *context.Context, args *SectionWithAPIOpts, reply *string) (err error) { - args.Section = utils.FirstNonEmpty(args.Section, utils.MetaAll) - cfg.cacheDPMux.RLock() - if mp, has := cfg.cacheDP[args.Section]; has && mp != nil { - *reply = utils.ToJSON(mp) - cfg.cacheDPMux.RUnlock() - return - } - cfg.cacheDPMux.RUnlock() - var rplyMap utils.MapStorage - defer func() { - if err != nil { - return - } - cfg.cacheDPMux.Lock() - cfg.cacheDP[args.Section] = rplyMap - cfg.cacheDPMux.Unlock() - }() - var mp interface{} - if args.Section == utils.MetaAll { - rplyMap = cfg.AsMapInterface(cfg.GeneralCfg().RSRSep) - *reply = utils.ToJSON(rplyMap) - return - } - if mp, err = cfg.getSectionAsMap(args.Section); err != nil { - return - } - rplyMap = map[string]interface{}{args.Section: mp} - *reply = utils.ToJSON(rplyMap) - return -} - -// SetConfigFromJSONArgs the API params for V1SetConfigFromJSON -type SetConfigFromJSONArgs struct { - APIOpts map[string]interface{} - Tenant string - Config string - DryRun bool -} - -// V1SetConfigFromJSON reloads the sections of config -func (cfg *CGRConfig) V1SetConfigFromJSON(ctx *context.Context, args *SetConfigFromJSONArgs, reply *string) (err error) { - if len(args.Config) == 0 { - *reply = utils.OK - return - } - cfgV := cfg - if args.DryRun { - cfgV = cfg.Clone() - } - - cfgV.reloadDPCache(sortedCfgSections...) - if err = cfgV.loadCfgFromJSONWithLocks(bytes.NewBufferString(args.Config), sortedCfgSections); err != nil { - return - } - - // lock all sections - cfgV.rLockSections() - err = cfgV.checkConfigSanity() - cfgV.rUnlockSections() // unlock before checking the error - if err != nil { - return - } - if !args.DryRun { - cfgV.reloadSections(sortedCfgSections...) - } - *reply = utils.OK - return -} - // Clone returns a deep copy of CGRConfig func (cfg *CGRConfig) Clone() (cln *CGRConfig) { cln = &CGRConfig{ @@ -1847,578 +1640,19 @@ func (cfg *CGRConfig) Clone() (cln *CGRConfig) { accountSCfg: cfg.accountSCfg.Clone(), configDBCfg: cfg.configDBCfg.Clone(), - cacheDP: make(map[string]utils.MapStorage), + cacheDP: make(utils.MapStorage), } cln.initChanels() return } -func (cfg *CGRConfig) reloadDPCache(sections ...string) { - cfg.cacheDPMux.Lock() - delete(cfg.cacheDP, utils.MetaAll) - for _, sec := range sections { - delete(cfg.cacheDP, sec) - } - cfg.cacheDPMux.Unlock() -} - // GetDataProvider returns the config as a data provider interface func (cfg *CGRConfig) GetDataProvider() utils.DataProvider { cfg.cacheDPMux.RLock() - val, has := cfg.cacheDP[utils.MetaAll] - cfg.cacheDPMux.RUnlock() - if !has || val == nil { - cfg.cacheDPMux.Lock() - val = cfg.AsMapInterface(cfg.GeneralCfg().RSRSep) - cfg.cacheDP[utils.MetaAll] = val - cfg.cacheDPMux.Unlock() + if len(cfg.cacheDP) < len(sortedCfgSections) { + cfg.cacheDP = cfg.AsMapInterface(cfg.GeneralCfg().RSRSep) } - return val -} - -// loadFromJSONDB Loads from json configuration object, will be used for defaults, config from file and reload, might need lock -// this function ignores the data_db section -// this will be called from the DataDB service -func (cfg *CGRConfig) LoadFromDB(jsnCfg ConfigDB) (err error) { - // Load sections out of JSON config, stop on error - cfg.lockSections() - defer cfg.unlockSections() - cfg.db = jsnCfg - for _, loadFunc := range []func(ConfigDB) error{ - cfg.loadRPCConns, - cfg.loadGeneralCfg, cfg.loadTemplateSCfg, cfg.loadCacheCfg, cfg.loadListenCfg, - cfg.loadHTTPCfg, cfg.loadDataDBCfg, cfg.loadStorDBCfg, - cfg.loadFilterSCfg, - cfg.loadCdrsCfg, cfg.loadSessionSCfg, - cfg.loadFreeswitchAgentCfg, cfg.loadKamAgentCfg, - cfg.loadAsteriskAgentCfg, cfg.loadDiameterAgentCfg, cfg.loadRadiusAgentCfg, - cfg.loadDNSAgentCfg, cfg.loadHTTPAgentCfg, cfg.loadAttributeSCfg, - cfg.loadChargerSCfg, cfg.loadResourceSCfg, cfg.loadStatSCfg, - cfg.loadThresholdSCfg, cfg.loadRouteSCfg, cfg.loadLoaderSCfg, - cfg.loadMailerCfg, cfg.loadSureTaxCfg, cfg.loadDispatcherSCfg, - cfg.loadLoaderCgrCfg, cfg.loadMigratorCgrCfg, cfg.loadTLSCgrCfg, - cfg.loadAnalyzerCgrCfg, cfg.loadApierCfg, cfg.loadErsCfg, cfg.loadEesCfg, - cfg.loadRateSCfg, cfg.loadSIPAgentCfg, cfg.loadRegistrarCCfg, - cfg.loadConfigSCfg, cfg.loadAPIBanCgrCfg, cfg.loadCoreSCfg, cfg.loadActionSCfg, - cfg.loadAccountSCfg} { - if err = loadFunc(jsnCfg); err != nil { - return - } - } - return cfg.checkConfigSanity() -} - -// ReloadAllSectionsForDB sends a signal to the reload channel for the all sections except the datadb -func (cfg *CGRConfig) ReloadAllSectionsForDB() { - cfg.rldChans[StorDBJSON] <- struct{}{} // reload stordb before - runtime.Gosched() - for _, section := range sortedCfgSections { - switch section { - case ConfigSJSON: - case GeneralJSON: // nothing to reload - case RPCConnsJSON: // nothing to reload - cfg.rldChans[RPCConnsJSON] <- struct{}{} - case DataDBJSON: // reloaded before - case StorDBJSON: // reloaded before - case ListenJSON: - case CacheJSON: - case FilterSJSON: - case MailerJSON: - case SureTaxJSON: - case LoaderJSON: - case MigratorJSON: - case TemplatesJSON: - case TlsJSON: // nothing to reload - case APIBanJSON: // nothing to reload - case CoreSJSON: // nothing to reload - case HTTPJSON: - cfg.rldChans[HTTPJSON] <- struct{}{} - case CDRsJSON: - cfg.rldChans[CDRsJSON] <- struct{}{} - case ERsJSON: - cfg.rldChans[ERsJSON] <- struct{}{} - case SessionSJSON: - cfg.rldChans[SessionSJSON] <- struct{}{} - case AsteriskAgentJSON: - cfg.rldChans[AsteriskAgentJSON] <- struct{}{} - case FreeSWITCHAgentJSON: - cfg.rldChans[FreeSWITCHAgentJSON] <- struct{}{} - case KamailioAgentJSON: - cfg.rldChans[KamailioAgentJSON] <- struct{}{} - case DiameterAgentJSON: - cfg.rldChans[DiameterAgentJSON] <- struct{}{} - case RadiusAgentJSON: - cfg.rldChans[RadiusAgentJSON] <- struct{}{} - case HTTPAgentJSON: - cfg.rldChans[HTTPAgentJSON] <- struct{}{} - case DNSAgentJSON: - cfg.rldChans[DNSAgentJSON] <- struct{}{} - case AttributeSJSON: - cfg.rldChans[AttributeSJSON] <- struct{}{} - case ChargerSJSON: - cfg.rldChans[ChargerSJSON] <- struct{}{} - case ResourceSJSON: - cfg.rldChans[ResourceSJSON] <- struct{}{} - case StatSJSON: - cfg.rldChans[StatSJSON] <- struct{}{} - case ThresholdSJSON: - cfg.rldChans[ThresholdSJSON] <- struct{}{} - case RouteSJSON: - cfg.rldChans[RouteSJSON] <- struct{}{} - case LoaderSJSON: - cfg.rldChans[LoaderSJSON] <- struct{}{} - case DispatcherSJSON: - cfg.rldChans[DispatcherSJSON] <- struct{}{} - case AnalyzerSJSON: - cfg.rldChans[AnalyzerSJSON] <- struct{}{} - case AdminSJSON: - cfg.rldChans[AdminSJSON] <- struct{}{} - case EEsJSON: - cfg.rldChans[EEsJSON] <- struct{}{} - case SIPAgentJSON: - cfg.rldChans[SIPAgentJSON] <- struct{}{} - case RateSJSON: - cfg.rldChans[RateSJSON] <- struct{}{} - case RegistrarCJSON: - cfg.rldChans[RegistrarCJSON] <- struct{}{} - case AccountSJSON: - cfg.rldChans[AccountSJSON] <- struct{}{} - case ActionSJSON: - cfg.rldChans[ActionSJSON] <- struct{}{} - case ConfigDBJSON: // no reload for this - } - } -} - -func (cfg *CGRConfig) V1StoreCfgInDB(ctx *context.Context, args *SectionWithAPIOpts, rply *string) (err error) { - if cfg.db == nil { - return errors.New("no DB connection for config") - } - if args.Section != utils.MetaEmpty && args.Section != utils.MetaAll { - if args.Section == DataDBJSON { - return errors.New("invalid section") - } - var mp interface{} - if mp, err = cfg.getSectionAsMap(args.Section); err != nil { - return - } - var data []byte - if data, err = json.Marshal(mp); err != nil { - return - } - var cfgSec interface{} - switch args.Section { - case GeneralJSON: - cfgSec = new(GeneralJsonCfg) - case RPCConnsJSON: - cfgSec = make(RPCConnsJson) - case CacheJSON: - cfgSec = new(CacheJsonCfg) - case ListenJSON: - cfgSec = new(ListenJsonCfg) - case HTTPJSON: - cfgSec = new(HTTPJsonCfg) - case StorDBJSON: - cfgSec = new(DbJsonCfg) - case FilterSJSON: - cfgSec = new(FilterSJsonCfg) - case CDRsJSON: - cfgSec = new(CdrsJsonCfg) - case ERsJSON: - cfgSec = new(ERsJsonCfg) - case EEsJSON: - cfgSec = new(EEsJsonCfg) - case SessionSJSON: - cfgSec = new(SessionSJsonCfg) - case FreeSWITCHAgentJSON: - cfgSec = new(FreeswitchAgentJsonCfg) - case KamailioAgentJSON: - cfgSec = new(KamAgentJsonCfg) - case AsteriskAgentJSON: - cfgSec = new(AsteriskAgentJsonCfg) - case DiameterAgentJSON: - cfgSec = new(DiameterAgentJsonCfg) - case RadiusAgentJSON: - cfgSec = new(RadiusAgentJsonCfg) - case HTTPAgentJSON: - cfgSec = new([]*HttpAgentJsonCfg) - case DNSAgentJSON: - cfgSec = new(DNSAgentJsonCfg) - case AttributeSJSON: - cfgSec = new(AttributeSJsonCfg) - case ChargerSJSON: - cfgSec = new(ChargerSJsonCfg) - case ResourceSJSON: - cfgSec = new(ResourceSJsonCfg) - case StatSJSON: - cfgSec = new(StatServJsonCfg) - case ThresholdSJSON: - cfgSec = new(ThresholdSJsonCfg) - case RouteSJSON: - cfgSec = new(RouteSJsonCfg) - case LoaderSJSON: - cfgSec = make([]*LoaderJsonCfg, 0) - case MailerJSON: - cfgSec = new(MailerJsonCfg) - case SureTaxJSON: - cfgSec = new(SureTaxJsonCfg) - case DispatcherSJSON: - cfgSec = new(DispatcherSJsonCfg) - case RegistrarCJSON: - cfgSec = new(RegistrarCJsonCfgs) - case LoaderJSON: - cfgSec = new(LoaderCfgJson) - case MigratorJSON: - cfgSec = new(MigratorCfgJson) - case TlsJSON: - cfgSec = new(TlsJsonCfg) - case AnalyzerSJSON: - cfgSec = new(AnalyzerSJsonCfg) - case AdminSJSON: - cfgSec = new(AdminSJsonCfg) - case RateSJSON: - cfgSec = new(RateSJsonCfg) - case SIPAgentJSON: - cfgSec = new(SIPAgentJsonCfg) - case TemplatesJSON: - cfgSec = make(FcTemplatesJsonCfg) - case ConfigSJSON: - cfgSec = new(ConfigSCfgJson) - case APIBanJSON: - cfgSec = new(APIBanJsonCfg) - case CoreSJSON: - cfgSec = new(CoreSJsonCfg) - case ActionSJSON: - cfgSec = new(ActionSJsonCfg) - case AccountSJSON: - cfgSec = new(AccountSJsonCfg) - } - - if err = json.Unmarshal(data, cfgSec); err != nil { - return - } - if err = cfg.db.SetSection(ctx, args.Section, cfgSec); err != nil { - return - } - } - cfg.rLockSections() - mp := cfg.AsMapInterface(cfg.generalCfg.RSRSep) - cfg.rUnlockSections() - var data []byte - if data, err = json.Marshal(mp); err != nil { - return - } - var dp ConfigDB - if dp, err = NewCgrJsonCfgFromBytes(data); err != nil { - return - } - var sc interface{} - if sc, err = dp.GeneralJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, GeneralJSON, sc); err != nil { - return - } - if sc, err = dp.RPCConnJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, RPCConnsJSON, sc); err != nil { - return - } - if sc, err = dp.CacheJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, CacheJSON, sc); err != nil { - return - } - if sc, err = dp.ListenJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ListenJSON, sc); err != nil { - return - } - if sc, err = dp.HttpJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, HTTPJSON, sc); err != nil { - return - } - if sc, err = dp.DbJsonCfg(StorDBJSON); err != nil { - return - } else if err = cfg.db.SetSection(ctx, StorDBJSON, sc); err != nil { - return - } - if sc, err = dp.FilterSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, FilterSJSON, sc); err != nil { - return - } - if sc, err = dp.CdrsJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, CDRsJSON, sc); err != nil { - return - } - if sc, err = dp.ERsJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ERsJSON, sc); err != nil { - return - } - if sc, err = dp.EEsJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, EEsJSON, sc); err != nil { - return - } - if sc, err = dp.SessionSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, SessionSJSON, sc); err != nil { - return - } - if sc, err = dp.FreeswitchAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, FreeSWITCHAgentJSON, sc); err != nil { - return - } - if sc, err = dp.KamAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, KamailioAgentJSON, sc); err != nil { - return - } - if sc, err = dp.AsteriskAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, AsteriskAgentJSON, sc); err != nil { - return - } - if sc, err = dp.DiameterAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, DiameterAgentJSON, sc); err != nil { - return - } - if sc, err = dp.RadiusAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, RadiusAgentJSON, sc); err != nil { - return - } - if sc, err = dp.HttpAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, HTTPAgentJSON, sc); err != nil { - return - } - if sc, err = dp.DNSAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, DNSAgentJSON, sc); err != nil { - return - } - if sc, err = dp.AttributeServJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, AttributeSJSON, sc); err != nil { - return - } - if sc, err = dp.ChargerServJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ChargerSJSON, sc); err != nil { - return - } - if sc, err = dp.ResourceSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ResourceSJSON, sc); err != nil { - return - } - if sc, err = dp.StatSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, StatSJSON, sc); err != nil { - return - } - if sc, err = dp.ThresholdSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ThresholdSJSON, sc); err != nil { - return - } - if sc, err = dp.RouteSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, RouteSJSON, sc); err != nil { - return - } - if sc, err = dp.LoaderJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, LoaderSJSON, sc); err != nil { - return - } - if sc, err = dp.MailerJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, MailerJSON, sc); err != nil { - return - } - if sc, err = dp.SureTaxJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, SureTaxJSON, sc); err != nil { - return - } - if sc, err = dp.DispatcherSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, DispatcherSJSON, sc); err != nil { - return - } - if sc, err = dp.RegistrarCJsonCfgs(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, RegistrarCJSON, sc); err != nil { - return - } - if sc, err = dp.LoaderCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, LoaderJSON, sc); err != nil { - return - } - if sc, err = dp.MigratorCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, MigratorJSON, sc); err != nil { - return - } - if sc, err = dp.TlsCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, TlsJSON, sc); err != nil { - return - } - if sc, err = dp.AnalyzerCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, AnalyzerSJSON, sc); err != nil { - return - } - if sc, err = dp.AdminSCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, AdminSJSON, sc); err != nil { - return - } - if sc, err = dp.RateCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, RateSJSON, sc); err != nil { - return - } - if sc, err = dp.SIPAgentJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, SIPAgentJSON, sc); err != nil { - return - } - if sc, err = dp.TemplateSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, TemplatesJSON, sc); err != nil { - return - } - if sc, err = dp.ConfigSJsonCfg(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ConfigSJSON, sc); err != nil { - return - } - if sc, err = dp.ApiBanCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, APIBanJSON, sc); err != nil { - return - } - if sc, err = dp.CoreSJSON(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, CoreSJSON, sc); err != nil { - return - } - if sc, err = dp.ActionSCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, ActionSJSON, sc); err != nil { - return - } - if sc, err = dp.AccountSCfgJson(); err != nil { - return - } else if err = cfg.db.SetSection(ctx, AccountSJSON, sc); err != nil { - return - } - *rply = utils.OK - return -} - -func (cfg *CGRConfig) getSectionAsMap(section string) (mp interface{}, err error) { - switch section { - case GeneralJSON: - mp = cfg.GeneralCfg().AsMapInterface() - case DataDBJSON: - mp = cfg.DataDbCfg().AsMapInterface() - case StorDBJSON: - mp = cfg.StorDbCfg().AsMapInterface() - case TlsJSON: - mp = cfg.TLSCfg().AsMapInterface() - case CacheJSON: - mp = cfg.CacheCfg().AsMapInterface() - case ListenJSON: - mp = cfg.ListenCfg().AsMapInterface() - case HTTPJSON: - mp = cfg.HTTPCfg().AsMapInterface() - case FilterSJSON: - mp = cfg.FilterSCfg().AsMapInterface() - case CDRsJSON: - mp = cfg.CdrsCfg().AsMapInterface() - case SessionSJSON: - mp = cfg.SessionSCfg().AsMapInterface() - case FreeSWITCHAgentJSON: - mp = cfg.FsAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case KamailioAgentJSON: - mp = cfg.KamAgentCfg().AsMapInterface() - case AsteriskAgentJSON: - mp = cfg.AsteriskAgentCfg().AsMapInterface() - case DiameterAgentJSON: - mp = cfg.DiameterAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case RadiusAgentJSON: - mp = cfg.RadiusAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case DNSAgentJSON: - mp = cfg.DNSAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case AttributeSJSON: - mp = cfg.AttributeSCfg().AsMapInterface() - case ChargerSJSON: - mp = cfg.ChargerSCfg().AsMapInterface() - case ResourceSJSON: - mp = cfg.ResourceSCfg().AsMapInterface() - case StatSJSON: - mp = cfg.StatSCfg().AsMapInterface() - case ThresholdSJSON: - mp = cfg.ThresholdSCfg().AsMapInterface() - case RouteSJSON: - mp = cfg.RouteSCfg().AsMapInterface() - case SureTaxJSON: - mp = cfg.SureTaxCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case DispatcherSJSON: - mp = cfg.DispatcherSCfg().AsMapInterface() - case RegistrarCJSON: - mp = cfg.RegistrarCCfg().AsMapInterface() - case LoaderSJSON: - mp = cfg.LoaderCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case LoaderJSON: - mp = cfg.LoaderCgrCfg().AsMapInterface() - case MigratorJSON: - mp = cfg.MigratorCgrCfg().AsMapInterface() - case AdminSJSON: - mp = cfg.AdminSCfg().AsMapInterface() - case EEsJSON: - mp = cfg.EEsCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case ERsJSON: - mp = cfg.ERsCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case RPCConnsJSON: - mp = cfg.RPCConns().AsMapInterface() - case SIPAgentJSON: - mp = cfg.SIPAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case TemplatesJSON: - mp = cfg.TemplatesCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case ConfigSJSON: - mp = cfg.ConfigSCfg().AsMapInterface() - case APIBanJSON: - mp = cfg.APIBanCfg().AsMapInterface() - case HTTPAgentJSON: - mp = cfg.HTTPAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) - case MailerJSON: - mp = cfg.MailerCfg().AsMapInterface() - case AnalyzerSJSON: - mp = cfg.AnalyzerSCfg().AsMapInterface() - case RateSJSON: - mp = cfg.RateSCfg().AsMapInterface() - case CoreSJSON: - mp = cfg.CoreSCfg().AsMapInterface() - case ActionSJSON: - mp = cfg.ActionSCfg().AsMapInterface() - case AccountSJSON: - mp = cfg.AccountSCfg().AsMapInterface() - case ConfigDBJSON: - mp = cfg.ConfigDBCfg().AsMapInterface() - default: - err = errors.New("Invalid section ") - } - return + mp := cfg.cacheDP.Clone() + cfg.cacheDPMux.Unlock() + return mp } diff --git a/config/config_apis.go b/config/config_apis.go new file mode 100644 index 000000000..0d934bafa --- /dev/null +++ b/config/config_apis.go @@ -0,0 +1,869 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package config + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/utils" +) + +// getSectionAsMap returns a section from config as a map[string]interface +func (cfg *CGRConfig) getSectionAsMap(section string) (mp interface{}, err error) { + switch section { + case GeneralJSON: + mp = cfg.GeneralCfg().AsMapInterface() + case DataDBJSON: + mp = cfg.DataDbCfg().AsMapInterface() + case StorDBJSON: + mp = cfg.StorDbCfg().AsMapInterface() + case TlsJSON: + mp = cfg.TLSCfg().AsMapInterface() + case CacheJSON: + mp = cfg.CacheCfg().AsMapInterface() + case ListenJSON: + mp = cfg.ListenCfg().AsMapInterface() + case HTTPJSON: + mp = cfg.HTTPCfg().AsMapInterface() + case FilterSJSON: + mp = cfg.FilterSCfg().AsMapInterface() + case CDRsJSON: + mp = cfg.CdrsCfg().AsMapInterface() + case SessionSJSON: + mp = cfg.SessionSCfg().AsMapInterface() + case FreeSWITCHAgentJSON: + mp = cfg.FsAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case KamailioAgentJSON: + mp = cfg.KamAgentCfg().AsMapInterface() + case AsteriskAgentJSON: + mp = cfg.AsteriskAgentCfg().AsMapInterface() + case DiameterAgentJSON: + mp = cfg.DiameterAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case RadiusAgentJSON: + mp = cfg.RadiusAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case DNSAgentJSON: + mp = cfg.DNSAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case AttributeSJSON: + mp = cfg.AttributeSCfg().AsMapInterface() + case ChargerSJSON: + mp = cfg.ChargerSCfg().AsMapInterface() + case ResourceSJSON: + mp = cfg.ResourceSCfg().AsMapInterface() + case StatSJSON: + mp = cfg.StatSCfg().AsMapInterface() + case ThresholdSJSON: + mp = cfg.ThresholdSCfg().AsMapInterface() + case RouteSJSON: + mp = cfg.RouteSCfg().AsMapInterface() + case SureTaxJSON: + mp = cfg.SureTaxCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case DispatcherSJSON: + mp = cfg.DispatcherSCfg().AsMapInterface() + case RegistrarCJSON: + mp = cfg.RegistrarCCfg().AsMapInterface() + case LoaderSJSON: + mp = cfg.LoaderCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case LoaderJSON: + mp = cfg.LoaderCgrCfg().AsMapInterface() + case MigratorJSON: + mp = cfg.MigratorCgrCfg().AsMapInterface() + case AdminSJSON: + mp = cfg.AdminSCfg().AsMapInterface() + case EEsJSON: + mp = cfg.EEsCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case ERsJSON: + mp = cfg.ERsCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case RPCConnsJSON: + mp = cfg.RPCConns().AsMapInterface() + case SIPAgentJSON: + mp = cfg.SIPAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case TemplatesJSON: + mp = cfg.TemplatesCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case ConfigSJSON: + mp = cfg.ConfigSCfg().AsMapInterface() + case APIBanJSON: + mp = cfg.APIBanCfg().AsMapInterface() + case HTTPAgentJSON: + mp = cfg.HTTPAgentCfg().AsMapInterface(cfg.GeneralCfg().RSRSep) + case MailerJSON: + mp = cfg.MailerCfg().AsMapInterface() + case AnalyzerSJSON: + mp = cfg.AnalyzerSCfg().AsMapInterface() + case RateSJSON: + mp = cfg.RateSCfg().AsMapInterface() + case CoreSJSON: + mp = cfg.CoreSCfg().AsMapInterface() + case ActionSJSON: + mp = cfg.ActionSCfg().AsMapInterface() + case AccountSJSON: + mp = cfg.AccountSCfg().AsMapInterface() + case ConfigDBJSON: + mp = cfg.ConfigDBCfg().AsMapInterface() + default: + err = errors.New("Invalid section ") + } + return +} + +// ReloadArgs the API params for V1ReloadConfig +type ReloadArgs struct { + APIOpts map[string]interface{} + Tenant string + Path string + Section string + DryRun bool +} + +// V1ReloadConfig reloads the configuration +func (cfg *CGRConfig) V1ReloadConfig(ctx *context.Context, args *ReloadArgs, reply *string) (err error) { + updateDB := cfg.db != nil + if !updateDB && + args.Path == utils.EmptyString { + return utils.NewErrMandatoryIeMissing("Path") + } else if updateDB && + args.Path != utils.EmptyString { + return fmt.Errorf("Reload from the path is disabled when the configDB is enabled") + } + cfgV := cfg + if args.DryRun { + cfgV = cfg.Clone() + } + cfgV.reloadDPCache(args.Section) + if updateDB { + sections := []string{args.Section} + if args.Section == utils.MetaEmpty || + args.Section == utils.MetaAll { + sections = sortedCfgSections[:len(sortedCfgSections)-1] // all exept the configDB section + } + err = cfgV.loadCfgFromDB(cfg.db, sections) + } else { + err = cfgV.loadCfgWithLocks(args.Path, args.Section) + } + if err != nil { + return + } + // lock all sections + cfgV.rLockSections() + + err = cfgV.checkConfigSanity() + + cfgV.rUnlockSections() // unlock before checking the error + + if err != nil { + return + } + if !args.DryRun { + if args.Section == utils.EmptyString || args.Section == utils.MetaAll { + cfgV.reloadSections(sortedCfgSections...) + } else { + cfgV.reloadSections(args.Section) + } + } + *reply = utils.OK + return +} + +// SectionWithAPIOpts the API params for GetConfig +type SectionWithAPIOpts struct { + APIOpts map[string]interface{} + Tenant string + Sections []string +} + +// V1GetConfig will retrieve from CGRConfig a section +func (cfg *CGRConfig) V1GetConfig(ctx *context.Context, args *SectionWithAPIOpts, reply *map[string]interface{}) (err error) { + if len(args.Sections) == 0 || + args.Sections[0] == utils.MetaAll { + args.Sections = sortedCfgSections + } + mp := make(map[string]interface{}) + sections := utils.StringSet{} + cfg.cacheDPMux.RLock() + for _, section := range args.Sections { + if val, has := cfg.cacheDP[section]; has && val != nil { + mp[section] = val + } else { + sections.Add(section) + } + } + cfg.cacheDPMux.RUnlock() + if sections.Size() == 0 { // all sections were cached + *reply = mp + return + } + if sections.Size() == len(sortedCfgSections) { + mp = cfg.AsMapInterface(cfg.GeneralCfg().RSRSep) + } else { + for section := range sections { + var val interface{} + if val, err = cfg.getSectionAsMap(section); err != nil { + return + } + mp[section] = val + cfg.cacheDPMux.Lock() + cfg.cacheDP[section] = val + cfg.cacheDPMux.Unlock() + } + } + *reply = mp + return +} + +// SetConfigArgs the API params for V1SetConfig +type SetConfigArgs struct { + APIOpts map[string]interface{} + Tenant string + Config map[string]interface{} + DryRun bool +} + +// V1SetConfig reloads the sections of config +func (cfg *CGRConfig) V1SetConfig(ctx *context.Context, args *SetConfigArgs, reply *string) (err error) { + if len(args.Config) == 0 { + *reply = utils.OK + return + } + sections := make([]string, 0, len(args.Config)) + for section := range args.Config { + if !sortedSectionsSet.Has(section) { + return fmt.Errorf("Invalid section <%s> ", section) + } + sections = append(sections, section) + } + var b []byte + if b, err = json.Marshal(args.Config); err != nil { + return + } + + var mp map[string]interface{} + updateDB := cfg.db != nil + if !args.DryRun && updateDB { // need to update the DB but only parts + if err = cfg.V1GetConfig(ctx, &SectionWithAPIOpts{Sections: sections}, &mp); err != nil { + return + } + } + + cfgV := cfg + if args.DryRun { + cfgV = cfg.Clone() + } + + cfgV.reloadDPCache(sections...) + if err = cfgV.loadCfgFromJSONWithLocks(bytes.NewBuffer(b), sections); err != nil { + return + } + + // lock all sections + cfgV.rLockSections() + + err = cfgV.checkConfigSanity() + + cfgV.rUnlockSections() // unlock before checking the error + if err != nil { + return + } + if !args.DryRun { + cfgV.reloadSections(sections...) + if updateDB { // need to update the DB but only parts + // ToDo: add here the call + } + } + *reply = utils.OK + return +} + +//V1GetConfigAsJSON will retrieve from CGRConfig a section as a string +func (cfg *CGRConfig) V1GetConfigAsJSON(ctx *context.Context, args *SectionWithAPIOpts, reply *string) (err error) { + var mp map[string]interface{} + if err = cfg.V1GetConfig(ctx, args, &mp); err != nil { + return + } + *reply = utils.ToJSON(mp) + return +} + +// SetConfigFromJSONArgs the API params for V1SetConfigFromJSON +type SetConfigFromJSONArgs struct { + APIOpts map[string]interface{} + Tenant string + Config string + DryRun bool +} + +// V1SetConfigFromJSON reloads the sections of config +func (cfg *CGRConfig) V1SetConfigFromJSON(ctx *context.Context, args *SetConfigFromJSONArgs, reply *string) (err error) { + if len(args.Config) == 0 { + *reply = utils.OK + return + } + var mp map[string]interface{} + updateDB := cfg.db != nil + if !args.DryRun && updateDB { // need to update the DB but only parts + if err = cfg.V1GetConfig(ctx, &SectionWithAPIOpts{Sections: sortedCfgSections}, &mp); err != nil { + return + } + } + cfgV := cfg + if args.DryRun { + cfgV = cfg.Clone() + } + + cfgV.reloadDPCache(sortedCfgSections...) + if err = cfgV.loadCfgFromJSONWithLocks(bytes.NewBufferString(args.Config), sortedCfgSections); err != nil { + return + } + + // lock all sections + cfgV.rLockSections() + err = cfgV.checkConfigSanity() + cfgV.rUnlockSections() // unlock before checking the error + if err != nil { + return + } + if !args.DryRun { + cfgV.reloadSections(sortedCfgSections...) + if updateDB { // need to update the DB but only parts + // ToDo: add here the call + } + } + *reply = utils.OK + return +} + +func (cfg *CGRConfig) reloadDPCache(sections ...string) { + cfg.cacheDPMux.Lock() + delete(cfg.cacheDP, utils.MetaAll) + for _, sec := range sections { + delete(cfg.cacheDP, sec) + } + cfg.cacheDPMux.Unlock() +} + +// loadFromJSONDB Loads from json configuration object, will be used for defaults, config from file and reload +// this function ignores the config_db section +func (cfg *CGRConfig) LoadFromDB(jsnCfg ConfigDB) (err error) { + // Load sections out of JSON config, stop on error + cfg.lockSections() + defer cfg.unlockSections() + cfg.db = jsnCfg + for _, loadFunc := range []func(ConfigDB) error{ + cfg.loadRPCConns, + cfg.loadGeneralCfg, cfg.loadTemplateSCfg, cfg.loadCacheCfg, cfg.loadListenCfg, + cfg.loadHTTPCfg, cfg.loadDataDBCfg, cfg.loadStorDBCfg, + cfg.loadFilterSCfg, + cfg.loadCdrsCfg, cfg.loadSessionSCfg, + cfg.loadFreeswitchAgentCfg, cfg.loadKamAgentCfg, + cfg.loadAsteriskAgentCfg, cfg.loadDiameterAgentCfg, cfg.loadRadiusAgentCfg, + cfg.loadDNSAgentCfg, cfg.loadHTTPAgentCfg, cfg.loadAttributeSCfg, + cfg.loadChargerSCfg, cfg.loadResourceSCfg, cfg.loadStatSCfg, + cfg.loadThresholdSCfg, cfg.loadRouteSCfg, cfg.loadLoaderSCfg, + cfg.loadMailerCfg, cfg.loadSureTaxCfg, cfg.loadDispatcherSCfg, + cfg.loadLoaderCgrCfg, cfg.loadMigratorCgrCfg, cfg.loadTLSCgrCfg, + cfg.loadAnalyzerCgrCfg, cfg.loadApierCfg, cfg.loadErsCfg, cfg.loadEesCfg, + cfg.loadRateSCfg, cfg.loadSIPAgentCfg, cfg.loadRegistrarCCfg, + cfg.loadConfigSCfg, cfg.loadAPIBanCgrCfg, cfg.loadCoreSCfg, cfg.loadActionSCfg, + cfg.loadAccountSCfg} { + if err = loadFunc(jsnCfg); err != nil { + return + } + } + return cfg.checkConfigSanity() +} + +func (cfg *CGRConfig) loadCfgFromDB(db ConfigDB, sections []string) (err error) { + loadMap := cfg.getLoadFunctions() + for _, section := range sections { + if fnct, has := loadMap[section]; !has || + section == ConfigDBJSON { + return fmt.Errorf("Invalid section: <%s> ", section) + } else { + cfg.lks[section].Lock() + err = fnct(db) + cfg.lks[section].Unlock() + if err != nil { + return + } + } + } + return +} + +func (cfg *CGRConfig) V1StoreCfgInDB(ctx *context.Context, args *SectionWithAPIOpts, rply *string) (err error) { + if cfg.db == nil { + return errors.New("no DB connection for config") + } + if len(args.Sections) != 0 && args.Sections[0] != utils.MetaAll { + for _, section := range args.Sections { + var mp interface{} + if mp, err = cfg.getSectionAsMap(section); err != nil { + return + } + var cfgSec interface{} + if cfgSec, err = prepareSectionFromMap(section, mp); err != nil { + return + } + if err = cfg.db.SetSection(ctx, section, cfgSec); err != nil { + return + } + } + } + cfg.rLockSections() + mp := cfg.AsMapInterface(cfg.generalCfg.RSRSep) + cfg.rUnlockSections() + var data []byte + if data, err = json.Marshal(mp); err != nil { + return + } + var dp ConfigDB + if dp, err = NewCgrJsonCfgFromBytes(data); err != nil { + return + } + var sc interface{} + if sc, err = dp.GeneralJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, GeneralJSON, sc); err != nil { + return + } + if sc, err = dp.RPCConnJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, RPCConnsJSON, sc); err != nil { + return + } + if sc, err = dp.CacheJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, CacheJSON, sc); err != nil { + return + } + if sc, err = dp.ListenJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ListenJSON, sc); err != nil { + return + } + if sc, err = dp.HttpJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, HTTPJSON, sc); err != nil { + return + } + if sc, err = dp.DbJsonCfg(StorDBJSON); err != nil { + return + } else if err = cfg.db.SetSection(ctx, StorDBJSON, sc); err != nil { + return + } + if sc, err = dp.DbJsonCfg(DataDBJSON); err != nil { + return + } else if err = cfg.db.SetSection(ctx, DataDBJSON, sc); err != nil { + return + } + if sc, err = dp.FilterSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, FilterSJSON, sc); err != nil { + return + } + if sc, err = dp.CdrsJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, CDRsJSON, sc); err != nil { + return + } + if sc, err = dp.ERsJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ERsJSON, sc); err != nil { + return + } + if sc, err = dp.EEsJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, EEsJSON, sc); err != nil { + return + } + if sc, err = dp.SessionSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, SessionSJSON, sc); err != nil { + return + } + if sc, err = dp.FreeswitchAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, FreeSWITCHAgentJSON, sc); err != nil { + return + } + if sc, err = dp.KamAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, KamailioAgentJSON, sc); err != nil { + return + } + if sc, err = dp.AsteriskAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, AsteriskAgentJSON, sc); err != nil { + return + } + if sc, err = dp.DiameterAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, DiameterAgentJSON, sc); err != nil { + return + } + if sc, err = dp.RadiusAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, RadiusAgentJSON, sc); err != nil { + return + } + if sc, err = dp.HttpAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, HTTPAgentJSON, sc); err != nil { + return + } + if sc, err = dp.DNSAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, DNSAgentJSON, sc); err != nil { + return + } + if sc, err = dp.AttributeServJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, AttributeSJSON, sc); err != nil { + return + } + if sc, err = dp.ChargerServJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ChargerSJSON, sc); err != nil { + return + } + if sc, err = dp.ResourceSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ResourceSJSON, sc); err != nil { + return + } + if sc, err = dp.StatSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, StatSJSON, sc); err != nil { + return + } + if sc, err = dp.ThresholdSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ThresholdSJSON, sc); err != nil { + return + } + if sc, err = dp.RouteSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, RouteSJSON, sc); err != nil { + return + } + if sc, err = dp.LoaderJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, LoaderSJSON, sc); err != nil { + return + } + if sc, err = dp.MailerJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, MailerJSON, sc); err != nil { + return + } + if sc, err = dp.SureTaxJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, SureTaxJSON, sc); err != nil { + return + } + if sc, err = dp.DispatcherSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, DispatcherSJSON, sc); err != nil { + return + } + if sc, err = dp.RegistrarCJsonCfgs(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, RegistrarCJSON, sc); err != nil { + return + } + if sc, err = dp.LoaderCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, LoaderJSON, sc); err != nil { + return + } + if sc, err = dp.MigratorCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, MigratorJSON, sc); err != nil { + return + } + if sc, err = dp.TlsCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, TlsJSON, sc); err != nil { + return + } + if sc, err = dp.AnalyzerCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, AnalyzerSJSON, sc); err != nil { + return + } + if sc, err = dp.AdminSCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, AdminSJSON, sc); err != nil { + return + } + if sc, err = dp.RateCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, RateSJSON, sc); err != nil { + return + } + if sc, err = dp.SIPAgentJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, SIPAgentJSON, sc); err != nil { + return + } + if sc, err = dp.TemplateSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, TemplatesJSON, sc); err != nil { + return + } + if sc, err = dp.ConfigSJsonCfg(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ConfigSJSON, sc); err != nil { + return + } + if sc, err = dp.ApiBanCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, APIBanJSON, sc); err != nil { + return + } + if sc, err = dp.CoreSJSON(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, CoreSJSON, sc); err != nil { + return + } + if sc, err = dp.ActionSCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, ActionSJSON, sc); err != nil { + return + } + if sc, err = dp.AccountSCfgJson(); err != nil { + return + } else if err = cfg.db.SetSection(ctx, AccountSJSON, sc); err != nil { + return + } + *rply = utils.OK + return +} + +func prepareSectionFromMap(section string, mp interface{}) (cfgSec interface{}, err error) { + var data []byte + if data, err = json.Marshal(mp); err != nil { + return + } + switch section { + case GeneralJSON: + cfgSec = new(GeneralJsonCfg) + case RPCConnsJSON: + cfgSec = make(RPCConnsJson) + case CacheJSON: + cfgSec = new(CacheJsonCfg) + case ListenJSON: + cfgSec = new(ListenJsonCfg) + case HTTPJSON: + cfgSec = new(HTTPJsonCfg) + case StorDBJSON: + cfgSec = new(DbJsonCfg) + case DataDBJSON: + cfgSec = new(DbJsonCfg) + case FilterSJSON: + cfgSec = new(FilterSJsonCfg) + case CDRsJSON: + cfgSec = new(CdrsJsonCfg) + case ERsJSON: + cfgSec = new(ERsJsonCfg) + case EEsJSON: + cfgSec = new(EEsJsonCfg) + case SessionSJSON: + cfgSec = new(SessionSJsonCfg) + case FreeSWITCHAgentJSON: + cfgSec = new(FreeswitchAgentJsonCfg) + case KamailioAgentJSON: + cfgSec = new(KamAgentJsonCfg) + case AsteriskAgentJSON: + cfgSec = new(AsteriskAgentJsonCfg) + case DiameterAgentJSON: + cfgSec = new(DiameterAgentJsonCfg) + case RadiusAgentJSON: + cfgSec = new(RadiusAgentJsonCfg) + case HTTPAgentJSON: + cfgSec = new([]*HttpAgentJsonCfg) + case DNSAgentJSON: + cfgSec = new(DNSAgentJsonCfg) + case AttributeSJSON: + cfgSec = new(AttributeSJsonCfg) + case ChargerSJSON: + cfgSec = new(ChargerSJsonCfg) + case ResourceSJSON: + cfgSec = new(ResourceSJsonCfg) + case StatSJSON: + cfgSec = new(StatServJsonCfg) + case ThresholdSJSON: + cfgSec = new(ThresholdSJsonCfg) + case RouteSJSON: + cfgSec = new(RouteSJsonCfg) + case LoaderSJSON: + cfgSec = make([]*LoaderJsonCfg, 0) + case MailerJSON: + cfgSec = new(MailerJsonCfg) + case SureTaxJSON: + cfgSec = new(SureTaxJsonCfg) + case DispatcherSJSON: + cfgSec = new(DispatcherSJsonCfg) + case RegistrarCJSON: + cfgSec = new(RegistrarCJsonCfgs) + case LoaderJSON: + cfgSec = new(LoaderCfgJson) + case MigratorJSON: + cfgSec = new(MigratorCfgJson) + case TlsJSON: + cfgSec = new(TlsJsonCfg) + case AnalyzerSJSON: + cfgSec = new(AnalyzerSJsonCfg) + case AdminSJSON: + cfgSec = new(AdminSJsonCfg) + case RateSJSON: + cfgSec = new(RateSJsonCfg) + case SIPAgentJSON: + cfgSec = new(SIPAgentJsonCfg) + case TemplatesJSON: + cfgSec = make(FcTemplatesJsonCfg) + case ConfigSJSON: + cfgSec = new(ConfigSCfgJson) + case APIBanJSON: + cfgSec = new(APIBanJsonCfg) + case CoreSJSON: + cfgSec = new(CoreSJsonCfg) + case ActionSJSON: + cfgSec = new(ActionSJsonCfg) + case AccountSJSON: + cfgSec = new(AccountSJsonCfg) + } + + err = json.Unmarshal(data, cfgSec) + return +} + +func updateSections(ctx *context.Context, db ConfigDB, mp map[string]interface{}) (err error) { + for section, val := range mp { + var sec interface{} + if sec, err = prepareSectionFromDB(section, db); err != nil { + return + } + var data []byte + if data, err = json.Marshal(val); err != nil { + return + } + if err = json.Unmarshal(data, &sec); err != nil { + return + } + if err = db.SetSection(ctx, section, sec); err != nil { + return + } + } + return +} + +func prepareSectionFromDB(section string, db ConfigDB) (cfgSec interface{}, err error) { + switch section { + case GeneralJSON: + cfgSec, err = db.GeneralJsonCfg() + case RPCConnsJSON: + cfgSec, err = db.RPCConnJsonCfg() + case CacheJSON: + cfgSec, err = db.CacheJsonCfg() + case ListenJSON: + cfgSec, err = db.ListenJsonCfg() + case HTTPJSON: + cfgSec, err = db.HttpJsonCfg() + case StorDBJSON: + cfgSec, err = db.DbJsonCfg(StorDBJSON) + case DataDBJSON: + cfgSec, err = db.DbJsonCfg(DataDBJSON) + case FilterSJSON: + cfgSec, err = db.FilterSJsonCfg() + case CDRsJSON: + cfgSec, err = db.CdrsJsonCfg() + case ERsJSON: + cfgSec, err = db.ERsJsonCfg() + case EEsJSON: + cfgSec, err = db.EEsJsonCfg() + case SessionSJSON: + cfgSec, err = db.SessionSJsonCfg() + case FreeSWITCHAgentJSON: + cfgSec, err = db.FreeswitchAgentJsonCfg() + case KamailioAgentJSON: + cfgSec, err = db.KamAgentJsonCfg() + case AsteriskAgentJSON: + cfgSec, err = db.AsteriskAgentJsonCfg() + case DiameterAgentJSON: + cfgSec, err = db.DiameterAgentJsonCfg() + case RadiusAgentJSON: + cfgSec, err = db.RadiusAgentJsonCfg() + case HTTPAgentJSON: + cfgSec, err = db.HttpAgentJsonCfg() + case DNSAgentJSON: + cfgSec, err = db.DNSAgentJsonCfg() + case AttributeSJSON: + cfgSec, err = db.AttributeServJsonCfg() + case ChargerSJSON: + cfgSec, err = db.ChargerServJsonCfg() + case ResourceSJSON: + cfgSec, err = db.ResourceSJsonCfg() + case StatSJSON: + cfgSec, err = db.StatSJsonCfg() + case ThresholdSJSON: + cfgSec, err = db.ThresholdSJsonCfg() + case RouteSJSON: + cfgSec, err = db.RouteSJsonCfg() + case LoaderSJSON: + cfgSec, err = db.LoaderJsonCfg() + case MailerJSON: + cfgSec, err = db.MailerJsonCfg() + case SureTaxJSON: + cfgSec, err = db.SureTaxJsonCfg() + case DispatcherSJSON: + cfgSec, err = db.DispatcherSJsonCfg() + case RegistrarCJSON: + cfgSec, err = db.RegistrarCJsonCfgs() + case LoaderJSON: + cfgSec, err = db.LoaderCfgJson() + case MigratorJSON: + cfgSec, err = db.MigratorCfgJson() + case TlsJSON: + cfgSec, err = db.TlsCfgJson() + case AnalyzerSJSON: + cfgSec, err = db.AnalyzerCfgJson() + case AdminSJSON: + cfgSec, err = db.AdminSCfgJson() + case RateSJSON: + cfgSec, err = db.RateCfgJson() + case SIPAgentJSON: + cfgSec, err = db.SIPAgentJsonCfg() + case TemplatesJSON: + cfgSec, err = db.TemplateSJsonCfg() + case ConfigSJSON: + cfgSec, err = db.ConfigSJsonCfg() + case APIBanJSON: + cfgSec, err = db.ApiBanCfgJson() + case CoreSJSON: + cfgSec, err = db.CoreSJSON() + case ActionSJSON: + cfgSec, err = db.ActionSCfgJson() + case AccountSJSON: + cfgSec, err = db.AccountSCfgJson() + } + return +} diff --git a/config/config_defaults.go b/config/config_defaults.go index c42c94c59..e0da6369e 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -1098,18 +1098,12 @@ const CGRATES_CFG_JSON = ` "config_db": { // database used to store runtime data (eg: accounts) - "enabled": false, // starts service: - "db_type": "*redis", // data_db type: <*redis|*mongo> - "db_host": "127.0.0.1", // data_db host address - "db_port": 6379, // data_db port to reach the database - "db_name": "10", // data_db database name to connect to - "db_user": "cgrates", // username to use when connecting to data_db + "db_type": "*internal", // data_db type: <*redis|*mongo> + "db_host": "", // data_db host address + "db_port": 0, // data_db port to reach the database + "db_name": "", // data_db database name to connect to + "db_user": "", // username to use when connecting to data_db "db_password": "", // password to use when connecting to data_db - "remote_conns":[], // the conns that are queried when the items are not found in local DB - "remote_conn_id": "", // the ID to be sent to remote_conns to identify the connection - "replication_conns":[], // the conns the items are replicated - "replication_filtered": false, // if this is enabled the replication will be made only to the conns that received a get - "replication_cache": "", // the caching action that is executed on the replication_conns when the items are replicated "opts":{ "redis_sentinel": "", // the name of sentinel when used "redis_cluster": false, // if enabled the datadb will try to connect to the redis cluster diff --git a/config/config_json.go b/config/config_json.go index 9064538ac..480303b45 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -126,7 +126,6 @@ type ConfigDB interface { ActionSCfgJson() (*ActionSJsonCfg, error) AccountSCfgJson() (*AccountSJsonCfg, error) SetSection(*context.Context, string, interface{}) error - ConfigDBJsonCfg() (*ConfigDBJsonCfg, error) // only used when loading from file } // Loads the json config out of io.Reader, eg other sources than file, maybe over http @@ -646,15 +645,3 @@ func (jsnCfg CgrJsonCfg) SetSection(_ *context.Context, section string, jsn inte jsnCfg[section] = &d return nil } - -func (jsnCfg CgrJsonCfg) ConfigDBJsonCfg() (*ConfigDBJsonCfg, error) { - rawCfg, hasKey := jsnCfg[ConfigDBJSON] - if !hasKey { - return nil, nil - } - cfg := new(ConfigDBJsonCfg) - if err := json.Unmarshal(*rawCfg, cfg); err != nil { - return nil, err - } - return cfg, nil -} diff --git a/config/configdbcfg.go b/config/configdbcfg.go deleted file mode 100644 index 80c219c94..000000000 --- a/config/configdbcfg.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package config - -import "github.com/cgrates/cgrates/utils" - -type ConfigDBCfg struct { - Enabled bool - *DataDbCfg -} - -func (cdb *ConfigDBCfg) loadFromJSONCfg(jsnCfg *ConfigDBJsonCfg) (err error) { - if jsnCfg == nil { - return - } - if jsnCfg.Enabled != nil { - cdb.Enabled = *jsnCfg.Enabled - } - return cdb.DataDbCfg.loadFromJSONCfg(jsnCfg.DbJsonCfg) -} - -// Clone returns a deep copy of ConfigDB -func (cdb *ConfigDBCfg) Clone() (cln *ConfigDBCfg) { - return &ConfigDBCfg{ - Enabled: cdb.Enabled, - DataDbCfg: cdb.DataDbCfg.Clone(), - } -} - -// AsMapInterface returns the config as a map[string]interface{} -func (cdb *ConfigDBCfg) AsMapInterface() (mp map[string]interface{}) { - mp = cdb.DataDbCfg.AsMapInterface() - mp[utils.EnabledCfg] = cdb.Enabled - return -} diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 8c224e7c1..0106c2446 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -676,8 +676,3 @@ type AccountSJsonCfg struct { Max_iterations *int Max_usage *string } - -type ConfigDBJsonCfg struct { - Enabled *bool - *DbJsonCfg -} diff --git a/engine/storage_internal_config.go b/engine/storage_internal_config.go index da50b1837..eee004714 100644 --- a/engine/storage_internal_config.go +++ b/engine/storage_internal_config.go @@ -241,6 +241,3 @@ func (*InternalDB) SetSection(_ *context.Context, section string, jsn interface{ Cache.SetWithoutReplicate(utils.MetaConfig, section, jsn, nil, true, utils.NonTransactional) return nil } -func (*InternalDB) ConfigDBJsonCfg() (*config.ConfigDBJsonCfg, error) { - return nil, utils.ErrNotImplemented -} diff --git a/engine/storage_mongo_config.go b/engine/storage_mongo_config.go index 3f30d6153..ca38b397f 100644 --- a/engine/storage_mongo_config.go +++ b/engine/storage_mongo_config.go @@ -21,7 +21,6 @@ package engine import ( "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -842,6 +841,3 @@ func (ms *MongoStorage) SetSection(ctx *context.Context, section string, jsn int return err }) } -func (ms *MongoStorage) ConfigDBJsonCfg() (*config.ConfigDBJsonCfg, error) { - return nil, utils.ErrNotImplemented -} diff --git a/engine/storage_redis_config.go b/engine/storage_redis_config.go index 641065362..73ae40999 100644 --- a/engine/storage_redis_config.go +++ b/engine/storage_redis_config.go @@ -21,7 +21,6 @@ package engine import ( "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" - "github.com/cgrates/cgrates/utils" ) const ( @@ -372,6 +371,3 @@ func (rs *RedisStorage) SetSection(_ *context.Context, section string, jsn inter } return rs.Cmd(nil, redisSET, configPrefix+section, string(result)) } -func (rs *RedisStorage) ConfigDBJsonCfg() (*config.ConfigDBJsonCfg, error) { - return nil, utils.ErrNotImplemented -}