/* 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 ( "errors" "fmt" "os" "path/filepath" "strconv" "strings" "time" "github.com/cgrates/cgrates/utils" ) const ( DISABLED = "disabled" JSON = "json" GOB = "gob" POSTGRES = "postgres" MONGO = "mongo" REDIS = "redis" SAME = "same" FS = "freeswitch" ) var ( cgrCfg *CGRConfig // will be shared dfltFsConnConfig *FsConnConfig // Default FreeSWITCH Connection configuration, built out of json default configuration dfltKamConnConfig *KamConnConfig // Default Kamailio Connection configuration dfltHaPoolConfig *HaPoolConfig dfltAstConnCfg *AsteriskConnCfg ) func init() { cgrCfg, _ = NewDefaultCGRConfig() } // Used to retrieve system configuration from other packages func CgrConfig() *CGRConfig { return cgrCfg } // Used to set system configuration from other places func SetCgrConfig(cfg *CGRConfig) { cgrCfg = cfg } func NewDefaultCGRConfig() (*CGRConfig, error) { cfg := new(CGRConfig) cfg.InstanceID = utils.GenUUID() cfg.DataFolderPath = "/usr/share/cgrates/" cfg.SmGenericConfig = new(SmGenericConfig) cfg.CacheConfig = make(CacheConfig) cfg.SmFsConfig = new(SmFsConfig) cfg.SmKamConfig = new(SmKamConfig) cfg.SmOsipsConfig = new(SmOsipsConfig) cfg.smAsteriskCfg = new(SMAsteriskCfg) cfg.diameterAgentCfg = new(DiameterAgentCfg) cfg.radiusAgentCfg = new(RadiusAgentCfg) cfg.ConfigReloads = make(map[string]chan struct{}) cfg.ConfigReloads[utils.CDRC] = make(chan struct{}, 1) cfg.ConfigReloads[utils.CDRC] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.CDRE] = make(chan struct{}, 1) cfg.ConfigReloads[utils.CDRE] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.SURETAX] = make(chan struct{}, 1) cfg.ConfigReloads[utils.SURETAX] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.DIAMETER_AGENT] = make(chan struct{}, 1) cfg.ConfigReloads[utils.DIAMETER_AGENT] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.SMAsterisk] = make(chan struct{}, 1) cfg.ConfigReloads[utils.SMAsterisk] <- struct{}{} // Unlock the channel cgrJsonCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON)) if err != nil { return nil, err } cfg.MaxCallDuration = time.Duration(3) * time.Hour // Hardcoded for now if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil { return nil, err } cfg.dfltCdreProfile = cfg.CdreProfiles[utils.META_DEFAULT].Clone() // So default will stay unique, will have nil pointer in case of no defaults loaded which is an extra check cfg.dfltCdrcProfile = cfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0].Clone() dfltFsConnConfig = cfg.SmFsConfig.EventSocketConns[0] // We leave it crashing here on purpose if no Connection defaults defined dfltKamConnConfig = cfg.SmKamConfig.EvapiConns[0] dfltAstConnCfg = cfg.smAsteriskCfg.AsteriskConns[0] if err := cfg.checkConfigSanity(); err != nil { return nil, err } return cfg, nil } func NewCGRConfigFromJsonString(cfgJsonStr string) (*CGRConfig, error) { cfg := new(CGRConfig) if jsnCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(cfgJsonStr)); err != nil { return nil, err } else if err := cfg.loadFromJsonCfg(jsnCfg); err != nil { return nil, err } return cfg, nil } func NewCGRConfigFromJsonStringWithDefaults(cfgJsonStr string) (*CGRConfig, error) { cfg, _ := NewDefaultCGRConfig() if jsnCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(cfgJsonStr)); err != nil { return nil, err } else if err := cfg.loadFromJsonCfg(jsnCfg); err != nil { return nil, err } return cfg, nil } // Reads all .json files out of a folder/subfolders and loads them up in lexical order func NewCGRConfigFromFolder(cfgDir string) (*CGRConfig, error) { cfg, err := NewDefaultCGRConfig() if err != nil { return nil, err } fi, err := os.Stat(cfgDir) if err != nil { if strings.HasSuffix(err.Error(), "no such file or directory") { return cfg, nil } return nil, err } else if !fi.IsDir() && cfgDir != utils.CONFIG_DIR { // If config dir defined, needs to exist, not checking for default return nil, fmt.Errorf("Path: %s not a directory.", cfgDir) } if fi.IsDir() { jsonFilesFound := false err = filepath.Walk(cfgDir, func(path string, info os.FileInfo, err error) error { if !info.IsDir() { return nil } cfgFiles, err := filepath.Glob(filepath.Join(path, "*.json")) if err != nil { return err } if cfgFiles == nil { // No need of processing further since there are no config files in the folder return nil } if !jsonFilesFound { jsonFilesFound = true } for _, jsonFilePath := range cfgFiles { if cgrJsonCfg, err := NewCgrJsonCfgFromFile(jsonFilePath); err != nil { utils.Logger.Err(fmt.Sprintf(" Error <%s> reading config from path: <%s>", err.Error(), jsonFilePath)) return err } else if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil { utils.Logger.Err(fmt.Sprintf(" Error <%s> loading config from path: <%s>", err.Error(), jsonFilePath)) return err } } return nil }) if err != nil { return nil, err } else if !jsonFilesFound { return nil, fmt.Errorf("No config file found on path %s", cfgDir) } } if err := cfg.checkConfigSanity(); err != nil { return nil, err } return cfg, nil } // Holds system configuration, defaults are overwritten with values from config file if found type CGRConfig struct { InstanceID string // Identifier for this engine instance DataDbType string DataDbHost string // The host to connect to. Values that start with / are for UNIX domain sockets. DataDbPort string // The port to bind to. DataDbName string // The name of the database to connect to. DataDbUser string // The user to sign in as. DataDbPass string // The user's password. LoadHistorySize int // Maximum number of records to archive in load history StorDBType string // Should reflect the database type used to store logs StorDBHost string // The host to connect to. Values that start with / are for UNIX domain sockets. StorDBPort string // Th e port to bind to. StorDBName string // The name of the database to connect to. StorDBUser string // The user to sign in as. StorDBPass string // The user's password. StorDBMaxOpenConns int // Maximum database connections opened StorDBMaxIdleConns int // Maximum idle connections to keep opened StorDBConnMaxLifetime int StorDBCDRSIndexes []string DBDataEncoding string // The encoding used to store object data in strings: CacheConfig CacheConfig RPCJSONListen string // RPC JSON listening address RPCGOBListen string // RPC GOB listening address HTTPListen string // HTTP listening address HTTPJsonRPCURL string // JSON RPC relative URL ("" to disable) HTTPWSURL string // WebSocket relative URL ("" to disable) HTTPUseBasicAuth bool // Use basic auth for HTTP API HTTPAuthUsers map[string]string // Basic auth user:password map (base64 passwords) DefaultReqType string // Use this request type if not defined on top DefaultCategory string // set default type of record DefaultTenant string // set default tenant DefaultTimezone string // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB> Reconnects int // number of recconect attempts in case of connection lost <-1 for infinite | nb> ConnectTimeout time.Duration // timeout for RPC connection attempts ReplyTimeout time.Duration // timeout replies if not reaching back ConnectAttempts int // number of initial connection attempts before giving up ResponseCacheTTL time.Duration // the life span of a cached response InternalTtl time.Duration // maximum duration to wait for internal connections before giving up RoundingDecimals int // Number of decimals to round end prices at HttpSkipTlsVerify bool // If enabled Http Client will accept any TLS certificate TpExportPath string // Path towards export folder for offline Tariff Plans PosterAttempts int FailedPostsDir string // Directory path where we store failed http requests MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file LockingTimeout time.Duration // locking mechanism timeout to avoid deadlocks LogLevel int // system wide log level, nothing higher than this will be logged RALsEnabled bool // start standalone server (no balancer) RALsCDRStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> RALsStatSConns []*HaPoolConfig RALsHistorySConns []*HaPoolConfig RALsPubSubSConns []*HaPoolConfig RALsUserSConns []*HaPoolConfig RALsAliasSConns []*HaPoolConfig RpSubjectPrefixMatching bool // enables prefix matching for the rating profile subject LcrSubjectPrefixMatching bool // enables prefix matching for the lcr subject SchedulerEnabled bool CDRSEnabled bool // Enable CDR Server service CDRSExtraFields []*utils.RSRField // Extra fields to store in CDRs CDRSStoreCdrs bool // store cdrs in storDb CDRScdrAccountSummary bool CDRSSMCostRetries int CDRSRaterConns []*HaPoolConfig // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> CDRSPubSubSConns []*HaPoolConfig // address where to reach the pubsub service: <""|internal|x.y.z.y:1234> CDRSUserSConns []*HaPoolConfig // address where to reach the users service: <""|internal|x.y.z.y:1234> CDRSAliaseSConns []*HaPoolConfig // address where to reach the aliases service: <""|internal|x.y.z.y:1234> CDRSCDRStatSConns []*HaPoolConfig // address where to reach the cdrstats service. Empty to disable cdrstats gathering <""|internal|x.y.z.y:1234> CDRSStatSConns []*HaPoolConfig CDRSOnlineCDRExports []string // list of CDRE templates to use for real-time CDR exports CDRStatsEnabled bool // Enable CDR Stats service CDRStatsSaveInterval time.Duration // Save interval duration CdreProfiles map[string]*CdreConfig CdrcProfiles map[string][]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath][]{Configs} SmGenericConfig *SmGenericConfig SmFsConfig *SmFsConfig // SMFreeSWITCH configuration SmKamConfig *SmKamConfig // SM-Kamailio Configuration SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration smAsteriskCfg *SMAsteriskCfg // SMAsterisk Configuration diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration radiusAgentCfg *RadiusAgentCfg // RadiusAgent configuration HistoryServerEnabled bool // Starts History as server: . HistoryDir string // Location on disk where to store history files. HistorySaveInterval time.Duration // The timout duration between pubsub writes PubSubServerEnabled bool // Starts PubSub as server: . AliasesServerEnabled bool // Starts PubSub as server: . UserServerEnabled bool // Starts User as server: UserServerIndexes []string // List of user profile field indexes resourceSCfg *ResourceSConfig // Configuration for resource limiter statsCfg *StatSCfg // Configuration for StatS MailerServer string // The server to use when sending emails out MailerAuthUser string // Authenticate to email server using this user MailerAuthPass string // Authenticate to email server with this password MailerFromAddr string // From address used when sending emails out DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options sureTaxCfg *SureTaxCfg // Load here SureTax configuration, as pointer so we can have runtime reloads in the future ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur // Cache defaults loaded from json and needing clones dfltCdreProfile *CdreConfig // Default cdreConfig profile dfltCdrcProfile *CdrcConfig // Default cdrcConfig profile } func (self *CGRConfig) checkConfigSanity() error { // Rater checks if self.RALsEnabled { for _, connCfg := range self.RALsCDRStatSConns { if connCfg.Address == utils.MetaInternal && !self.CDRStatsEnabled { return errors.New("CDRStats not enabled but requested by RALs component.") } } for _, connCfg := range self.RALsStatSConns { if connCfg.Address == utils.MetaInternal && !self.statsCfg.Enabled { return errors.New("StatS not enabled but requested by RALs component.") } } for _, connCfg := range self.RALsHistorySConns { if connCfg.Address == utils.MetaInternal && !self.HistoryServerEnabled { return errors.New("History server not enabled but requested by RALs component.") } } for _, connCfg := range self.RALsPubSubSConns { if connCfg.Address == utils.MetaInternal && !self.PubSubServerEnabled { return errors.New("PubSub server not enabled but requested by RALs component.") } } for _, connCfg := range self.RALsAliasSConns { if connCfg.Address == utils.MetaInternal && !self.AliasesServerEnabled { return errors.New("Alias server not enabled but requested by RALs component.") } } for _, connCfg := range self.RALsUserSConns { if connCfg.Address == utils.MetaInternal && !self.UserServerEnabled { return errors.New("User service not enabled but requested by RALs component.") } } } // CDRServer checks if self.CDRSEnabled { for _, cdrsRaterConn := range self.CDRSRaterConns { if cdrsRaterConn.Address == utils.MetaInternal && !self.RALsEnabled { return errors.New("RALs not enabled but requested by CDRS component.") } } for _, connCfg := range self.CDRSPubSubSConns { if connCfg.Address == utils.MetaInternal && !self.PubSubServerEnabled { return errors.New("PubSubS not enabled but requested by CDRS component.") } } for _, connCfg := range self.CDRSUserSConns { if connCfg.Address == utils.MetaInternal && !self.UserServerEnabled { return errors.New("UserS not enabled but requested by CDRS component.") } } for _, connCfg := range self.CDRSAliaseSConns { if connCfg.Address == utils.MetaInternal && !self.AliasesServerEnabled { return errors.New("AliaseS not enabled but requested by CDRS component.") } } for _, connCfg := range self.CDRSCDRStatSConns { if connCfg.Address == utils.MetaInternal && !self.CDRStatsEnabled { return errors.New("CDRStatS not enabled but requested by CDRS component.") } } for _, connCfg := range self.CDRSStatSConns { if connCfg.Address == utils.MetaInternal && !self.statsCfg.Enabled { return errors.New("StatS not enabled but requested by CDRS component.") } } for _, cdrePrfl := range self.CDRSOnlineCDRExports { if _, hasIt := self.CdreProfiles[cdrePrfl]; !hasIt { return fmt.Errorf(" Cannot find CDR export template with ID: <%s>", cdrePrfl) } } } // CDRC sanity checks for _, cdrcCfgs := range self.CdrcProfiles { for _, cdrcInst := range cdrcCfgs { if !cdrcInst.Enabled { continue } if len(cdrcInst.CdrsConns) == 0 { return fmt.Errorf(" Instance: %s, CdrC enabled but no CDRS defined!", cdrcInst.ID) } for _, conn := range cdrcInst.CdrsConns { if conn.Address == utils.MetaInternal && !self.CDRSEnabled { return errors.New("CDRS not enabled but referenced from CDRC") } } if len(cdrcInst.ContentFields) == 0 { return errors.New("CdrC enabled but no fields to be processed defined!") } if cdrcInst.CdrFormat == utils.CSV { for _, cdrFld := range cdrcInst.ContentFields { for _, rsrFld := range cdrFld.Value { if _, errConv := strconv.Atoi(rsrFld.Id); errConv != nil && !rsrFld.IsStatic() { return fmt.Errorf("CDR fields must be indices in case of .csv files, have instead: %s", rsrFld.Id) } } } } } } // SMGeneric checks if self.SmGenericConfig.Enabled { if len(self.SmGenericConfig.RALsConns) == 0 { return errors.New(" RALs definition is mandatory!") } for _, smgRALsConn := range self.SmGenericConfig.RALsConns { if smgRALsConn.Address == utils.MetaInternal && !self.RALsEnabled { return errors.New(" RALs not enabled but requested by SMGeneric component.") } } if len(self.SmGenericConfig.CDRsConns) == 0 { return errors.New(" CDRs definition is mandatory!") } for _, smgCDRSConn := range self.SmGenericConfig.CDRsConns { if smgCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled { return errors.New(" CDRS not enabled but referenced by SMGeneric component") } } } // SMFreeSWITCH checks if self.SmFsConfig.Enabled { if len(self.SmFsConfig.RALsConns) == 0 { return errors.New(" RALs definition is mandatory!") } for _, smFSRaterConn := range self.SmFsConfig.RALsConns { if smFSRaterConn.Address == utils.MetaInternal && !self.RALsEnabled { return errors.New(" RALs not enabled but requested by SMFreeSWITCH component.") } } if len(self.SmFsConfig.CDRsConns) == 0 { return errors.New(" CDRS definition is mandatory!") } for _, smFSCDRSConn := range self.SmFsConfig.CDRsConns { if smFSCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled { return errors.New("CDRS not enabled but referenced by SMFreeSWITCH component") } } for _, smFSRLsConn := range self.SmFsConfig.RLsConns { if smFSRLsConn.Address == utils.MetaInternal && !self.resourceSCfg.Enabled { return errors.New("RLs not enabled but referenced by SMFreeSWITCH component") } } } // SM-Kamailio checks if self.SmKamConfig.Enabled { if len(self.SmKamConfig.RALsConns) == 0 { return errors.New("Rater definition is mandatory!") } for _, smKamRaterConn := range self.SmKamConfig.RALsConns { if smKamRaterConn.Address == utils.MetaInternal && !self.RALsEnabled { return errors.New("Rater not enabled but requested by SM-Kamailio component") } } if len(self.SmKamConfig.CDRsConns) == 0 { return errors.New("Cdrs definition is mandatory!") } for _, smKamCDRSConn := range self.SmKamConfig.CDRsConns { if smKamCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled { return errors.New("CDRS not enabled but referenced by SM-Kamailio component") } } for _, smKamRLsConn := range self.SmKamConfig.RLsConns { if smKamRLsConn.Address == utils.MetaInternal && !self.resourceSCfg.Enabled { return errors.New("RLs not enabled but requested by SM-Kamailio component") } } } // SMOpenSIPS checks if self.SmOsipsConfig.Enabled { if len(self.SmOsipsConfig.RALsConns) == 0 { return errors.New(" Rater definition is mandatory!") } for _, smOsipsRaterConn := range self.SmOsipsConfig.RALsConns { if smOsipsRaterConn.Address == utils.MetaInternal && !self.RALsEnabled { return errors.New(" RALs not enabled.") } } if len(self.SmOsipsConfig.CDRsConns) == 0 { return errors.New(" CDRs definition is mandatory!") } for _, smOsipsCDRSConn := range self.SmOsipsConfig.CDRsConns { if smOsipsCDRSConn.Address == utils.MetaInternal && !self.CDRSEnabled { return errors.New(" CDRS not enabled.") } } } // SMAsterisk checks if self.smAsteriskCfg.Enabled { /*if len(self.smAsteriskCfg.SMGConns) == 0 { return errors.New(" SMG definition is mandatory!") } for _, smAstSMGConn := range self.smAsteriskCfg.SMGConns { if smAstSMGConn.Address == utils.MetaInternal && !self.SmGenericConfig.Enabled { return errors.New(" SMG not enabled.") } } */ if !self.SmGenericConfig.Enabled { return errors.New(" SMG not enabled.") } } // DAgent checks if self.diameterAgentCfg.Enabled { for _, daSMGConn := range self.diameterAgentCfg.SMGenericConns { if daSMGConn.Address == utils.MetaInternal && !self.SmGenericConfig.Enabled { return errors.New("SMGeneric not enabled but referenced by DiameterAgent component") } } for _, daPubSubSConn := range self.diameterAgentCfg.PubSubConns { if daPubSubSConn.Address == utils.MetaInternal && !self.PubSubServerEnabled { return errors.New("PubSubS not enabled but requested by DiameterAgent component.") } } } if self.radiusAgentCfg.Enabled { for _, raSMGConn := range self.radiusAgentCfg.SMGenericConns { if raSMGConn.Address == utils.MetaInternal && !self.SmGenericConfig.Enabled { return errors.New("SMGeneric not enabled but referenced by RadiusAgent component") } } } // ResourceLimiter checks if self.resourceSCfg != nil && self.resourceSCfg.Enabled { for _, connCfg := range self.resourceSCfg.StatSConns { if connCfg.Address == utils.MetaInternal && !self.statsCfg.Enabled { return errors.New("StatS not enabled but requested by ResourceLimiter component.") } } } return nil } // Loads from json configuration object, will be used for defaults, config from file and reload, might need lock func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error { // Load sections out of JSON config, stop on error jsnGeneralCfg, err := jsnCfg.GeneralJsonCfg() if err != nil { return err } // Load sections out of JSON config, stop on error jsnCacheCfg, err := jsnCfg.CacheJsonCfg() if err != nil { return err } jsnListenCfg, err := jsnCfg.ListenJsonCfg() if err != nil { return err } jsnHttpCfg, err := jsnCfg.HttpJsonCfg() if err != nil { return err } jsnDataDbCfg, err := jsnCfg.DbJsonCfg(DATADB_JSN) if err != nil { return err } jsnStorDbCfg, err := jsnCfg.DbJsonCfg(STORDB_JSN) if err != nil { return err } jsnRALsCfg, err := jsnCfg.RalsJsonCfg() if err != nil { return err } jsnSchedCfg, err := jsnCfg.SchedulerJsonCfg() if err != nil { return err } jsnCdrsCfg, err := jsnCfg.CdrsJsonCfg() if err != nil { return err } jsnCdrstatsCfg, err := jsnCfg.CdrStatsJsonCfg() if err != nil { return err } jsnCdreCfg, err := jsnCfg.CdreJsonCfgs() if err != nil { return err } jsnCdrcCfg, err := jsnCfg.CdrcJsonCfg() if err != nil { return err } jsnSmGenericCfg, err := jsnCfg.SmGenericJsonCfg() if err != nil { return err } jsnSmFsCfg, err := jsnCfg.SmFsJsonCfg() if err != nil { return err } jsnSmKamCfg, err := jsnCfg.SmKamJsonCfg() if err != nil { return err } jsnSmOsipsCfg, err := jsnCfg.SmOsipsJsonCfg() if err != nil { return err } jsnSMAstCfg, err := jsnCfg.SmAsteriskJsonCfg() if err != nil { return err } jsnDACfg, err := jsnCfg.DiameterAgentJsonCfg() if err != nil { return err } jsnRACfg, err := jsnCfg.RadiusAgentJsonCfg() if err != nil { return err } jsnHistServCfg, err := jsnCfg.HistServJsonCfg() if err != nil { return err } jsnPubSubServCfg, err := jsnCfg.PubSubServJsonCfg() if err != nil { return err } jsnAliasesServCfg, err := jsnCfg.AliasesServJsonCfg() if err != nil { return err } jsnUserServCfg, err := jsnCfg.UserServJsonCfg() if err != nil { return err } jsnRLSCfg, err := jsnCfg.ResourceSJsonCfg() if err != nil { return err } jsnStatSCfg, err := jsnCfg.StatSJsonCfg() if err != nil { return err } jsnMailerCfg, err := jsnCfg.MailerJsonCfg() if err != nil { return err } jsnSureTaxCfg, err := jsnCfg.SureTaxJsonCfg() if err != nil { return err } if jsnDataDbCfg != nil { if jsnDataDbCfg.Db_type != nil { self.DataDbType = *jsnDataDbCfg.Db_type } if jsnDataDbCfg.Db_host != nil { self.DataDbHost = *jsnDataDbCfg.Db_host } if jsnDataDbCfg.Db_port != nil { self.DataDbPort = strconv.Itoa(*jsnDataDbCfg.Db_port) } if jsnDataDbCfg.Db_name != nil { self.DataDbName = *jsnDataDbCfg.Db_name } if jsnDataDbCfg.Db_user != nil { self.DataDbUser = *jsnDataDbCfg.Db_user } if jsnDataDbCfg.Db_password != nil { self.DataDbPass = *jsnDataDbCfg.Db_password } if jsnDataDbCfg.Load_history_size != nil { self.LoadHistorySize = *jsnDataDbCfg.Load_history_size } } if jsnStorDbCfg != nil { if jsnStorDbCfg.Db_type != nil { self.StorDBType = *jsnStorDbCfg.Db_type } if jsnStorDbCfg.Db_host != nil { self.StorDBHost = *jsnStorDbCfg.Db_host } if jsnStorDbCfg.Db_port != nil { self.StorDBPort = strconv.Itoa(*jsnStorDbCfg.Db_port) } if jsnStorDbCfg.Db_name != nil { self.StorDBName = *jsnStorDbCfg.Db_name } if jsnStorDbCfg.Db_user != nil { self.StorDBUser = *jsnStorDbCfg.Db_user } if jsnStorDbCfg.Db_password != nil { self.StorDBPass = *jsnStorDbCfg.Db_password } if jsnStorDbCfg.Max_open_conns != nil { self.StorDBMaxOpenConns = *jsnStorDbCfg.Max_open_conns } if jsnStorDbCfg.Max_idle_conns != nil { self.StorDBMaxIdleConns = *jsnStorDbCfg.Max_idle_conns } if jsnStorDbCfg.Conn_max_lifetime != nil { self.StorDBConnMaxLifetime = *jsnStorDbCfg.Conn_max_lifetime } if jsnStorDbCfg.Cdrs_indexes != nil { self.StorDBCDRSIndexes = *jsnStorDbCfg.Cdrs_indexes } } if jsnGeneralCfg != nil { if jsnGeneralCfg.Instance_id != nil && *jsnGeneralCfg.Instance_id != "" { self.InstanceID = *jsnGeneralCfg.Instance_id } if jsnGeneralCfg.Dbdata_encoding != nil { self.DBDataEncoding = *jsnGeneralCfg.Dbdata_encoding } if jsnGeneralCfg.Default_request_type != nil { self.DefaultReqType = *jsnGeneralCfg.Default_request_type } if jsnGeneralCfg.Default_category != nil { self.DefaultCategory = *jsnGeneralCfg.Default_category } if jsnGeneralCfg.Default_tenant != nil { self.DefaultTenant = *jsnGeneralCfg.Default_tenant } if jsnGeneralCfg.Connect_attempts != nil { self.ConnectAttempts = *jsnGeneralCfg.Connect_attempts } if jsnGeneralCfg.Response_cache_ttl != nil { if self.ResponseCacheTTL, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Response_cache_ttl); err != nil { return err } } if jsnGeneralCfg.Reconnects != nil { self.Reconnects = *jsnGeneralCfg.Reconnects } if jsnGeneralCfg.Connect_timeout != nil { if self.ConnectTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Connect_timeout); err != nil { return err } } if jsnGeneralCfg.Reply_timeout != nil { if self.ReplyTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Reply_timeout); err != nil { return err } } if jsnGeneralCfg.Rounding_decimals != nil { self.RoundingDecimals = *jsnGeneralCfg.Rounding_decimals } if jsnGeneralCfg.Http_skip_tls_verify != nil { self.HttpSkipTlsVerify = *jsnGeneralCfg.Http_skip_tls_verify } if jsnGeneralCfg.Tpexport_dir != nil { self.TpExportPath = *jsnGeneralCfg.Tpexport_dir } if jsnGeneralCfg.Poster_attempts != nil { self.PosterAttempts = *jsnGeneralCfg.Poster_attempts } if jsnGeneralCfg.Failed_posts_dir != nil { self.FailedPostsDir = *jsnGeneralCfg.Failed_posts_dir } if jsnGeneralCfg.Default_timezone != nil { self.DefaultTimezone = *jsnGeneralCfg.Default_timezone } if jsnGeneralCfg.Internal_ttl != nil { if self.InternalTtl, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Internal_ttl); err != nil { return err } } if jsnGeneralCfg.Locking_timeout != nil { if self.LockingTimeout, err = utils.ParseDurationWithSecs(*jsnGeneralCfg.Locking_timeout); err != nil { return err } } if jsnGeneralCfg.Log_level != nil { self.LogLevel = *jsnGeneralCfg.Log_level } } if jsnCacheCfg != nil { if err := self.CacheConfig.loadFromJsonCfg(jsnCacheCfg); err != nil { return err } } if jsnListenCfg != nil { if jsnListenCfg.Rpc_json != nil { self.RPCJSONListen = *jsnListenCfg.Rpc_json } if jsnListenCfg.Rpc_gob != nil { self.RPCGOBListen = *jsnListenCfg.Rpc_gob } if jsnListenCfg.Http != nil { self.HTTPListen = *jsnListenCfg.Http } } if jsnHttpCfg != nil { if jsnHttpCfg.Json_rpc_url != nil { self.HTTPJsonRPCURL = *jsnHttpCfg.Json_rpc_url } if jsnHttpCfg.Ws_url != nil { self.HTTPWSURL = *jsnHttpCfg.Ws_url } if jsnHttpCfg.Use_basic_auth != nil { self.HTTPUseBasicAuth = *jsnHttpCfg.Use_basic_auth } if jsnHttpCfg.Auth_users != nil { self.HTTPAuthUsers = *jsnHttpCfg.Auth_users } } if jsnRALsCfg != nil { if jsnRALsCfg.Enabled != nil { self.RALsEnabled = *jsnRALsCfg.Enabled } if jsnRALsCfg.Cdrstats_conns != nil { self.RALsCDRStatSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Cdrstats_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Cdrstats_conns { self.RALsCDRStatSConns[idx] = NewDfltHaPoolConfig() self.RALsCDRStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Stats_conns != nil { self.RALsStatSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Stats_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Stats_conns { self.RALsStatSConns[idx] = NewDfltHaPoolConfig() self.RALsStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Historys_conns != nil { self.RALsHistorySConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Historys_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Historys_conns { self.RALsHistorySConns[idx] = NewDfltHaPoolConfig() self.RALsHistorySConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Pubsubs_conns != nil { self.RALsPubSubSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Pubsubs_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Pubsubs_conns { self.RALsPubSubSConns[idx] = NewDfltHaPoolConfig() self.RALsPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Aliases_conns != nil { self.RALsAliasSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Aliases_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Aliases_conns { self.RALsAliasSConns[idx] = NewDfltHaPoolConfig() self.RALsAliasSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Users_conns != nil { self.RALsUserSConns = make([]*HaPoolConfig, len(*jsnRALsCfg.Users_conns)) for idx, jsnHaCfg := range *jsnRALsCfg.Users_conns { self.RALsUserSConns[idx] = NewDfltHaPoolConfig() self.RALsUserSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnRALsCfg.Rp_subject_prefix_matching != nil { self.RpSubjectPrefixMatching = *jsnRALsCfg.Rp_subject_prefix_matching } if jsnRALsCfg.Lcr_subject_prefix_matching != nil { self.LcrSubjectPrefixMatching = *jsnRALsCfg.Lcr_subject_prefix_matching } } if jsnSchedCfg != nil && jsnSchedCfg.Enabled != nil { self.SchedulerEnabled = *jsnSchedCfg.Enabled } if jsnCdrsCfg != nil { if jsnCdrsCfg.Enabled != nil { self.CDRSEnabled = *jsnCdrsCfg.Enabled } if jsnCdrsCfg.Extra_fields != nil { if self.CDRSExtraFields, err = utils.ParseRSRFieldsFromSlice(*jsnCdrsCfg.Extra_fields); err != nil { return err } } if jsnCdrsCfg.Store_cdrs != nil { self.CDRSStoreCdrs = *jsnCdrsCfg.Store_cdrs } if jsnCdrsCfg.Cdr_account_summary != nil { self.CDRScdrAccountSummary = *jsnCdrsCfg.Cdr_account_summary } if jsnCdrsCfg.Sm_cost_retries != nil { self.CDRSSMCostRetries = *jsnCdrsCfg.Sm_cost_retries } if jsnCdrsCfg.Rals_conns != nil { self.CDRSRaterConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Rals_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Rals_conns { self.CDRSRaterConns[idx] = NewDfltHaPoolConfig() self.CDRSRaterConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Pubsubs_conns != nil { self.CDRSPubSubSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Pubsubs_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Pubsubs_conns { self.CDRSPubSubSConns[idx] = NewDfltHaPoolConfig() self.CDRSPubSubSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Users_conns != nil { self.CDRSUserSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Users_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Users_conns { self.CDRSUserSConns[idx] = NewDfltHaPoolConfig() self.CDRSUserSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Aliases_conns != nil { self.CDRSAliaseSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Aliases_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Aliases_conns { self.CDRSAliaseSConns[idx] = NewDfltHaPoolConfig() self.CDRSAliaseSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Cdrstats_conns != nil { self.CDRSCDRStatSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Cdrstats_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Cdrstats_conns { self.CDRSCDRStatSConns[idx] = NewDfltHaPoolConfig() self.CDRSCDRStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Stats_conns != nil { self.CDRSStatSConns = make([]*HaPoolConfig, len(*jsnCdrsCfg.Stats_conns)) for idx, jsnHaCfg := range *jsnCdrsCfg.Stats_conns { self.CDRSStatSConns[idx] = NewDfltHaPoolConfig() self.CDRSStatSConns[idx].loadFromJsonCfg(jsnHaCfg) } } if jsnCdrsCfg.Online_cdr_exports != nil { for _, expProfile := range *jsnCdrsCfg.Online_cdr_exports { self.CDRSOnlineCDRExports = append(self.CDRSOnlineCDRExports, expProfile) } } } if jsnCdrstatsCfg != nil { if jsnCdrstatsCfg.Enabled != nil { self.CDRStatsEnabled = *jsnCdrstatsCfg.Enabled if jsnCdrstatsCfg.Save_Interval != nil { if self.CDRStatsSaveInterval, err = utils.ParseDurationWithSecs(*jsnCdrstatsCfg.Save_Interval); err != nil { return err } } } } if jsnCdreCfg != nil { if self.CdreProfiles == nil { self.CdreProfiles = make(map[string]*CdreConfig) } for profileName, jsnCdre1Cfg := range jsnCdreCfg { if _, hasProfile := self.CdreProfiles[profileName]; !hasProfile { // New profile, create before loading from json self.CdreProfiles[profileName] = new(CdreConfig) if profileName != utils.META_DEFAULT { self.CdreProfiles[profileName] = self.dfltCdreProfile.Clone() // Clone default so we do not inherit pointers } } if err = self.CdreProfiles[profileName].loadFromJsonCfg(jsnCdre1Cfg); err != nil { // Update the existing profile with content from json config return err } } } if jsnCdrcCfg != nil { if self.CdrcProfiles == nil { self.CdrcProfiles = make(map[string][]*CdrcConfig) } for _, jsnCrc1Cfg := range jsnCdrcCfg { if jsnCrc1Cfg.Id == nil || *jsnCrc1Cfg.Id == "" { return errors.New("CDRC profile without an id") } if *jsnCrc1Cfg.Id == utils.META_DEFAULT { if self.dfltCdrcProfile == nil { self.dfltCdrcProfile = new(CdrcConfig) } } indxFound := -1 // Will be different than -1 if an instance with same id will be found pathFound := "" // Will be populated with the path where slice of cfgs was found var cdrcInstCfg *CdrcConfig for path := range self.CdrcProfiles { for i := range self.CdrcProfiles[path] { if self.CdrcProfiles[path][i].ID == *jsnCrc1Cfg.Id { indxFound = i pathFound = path cdrcInstCfg = self.CdrcProfiles[path][i] break } } } if cdrcInstCfg == nil { cdrcInstCfg = self.dfltCdrcProfile.Clone() } if err := cdrcInstCfg.loadFromJsonCfg(jsnCrc1Cfg); err != nil { return err } if cdrcInstCfg.CdrInDir == "" { return errors.New("CDRC profile without cdr_in_dir") } if _, hasDir := self.CdrcProfiles[cdrcInstCfg.CdrInDir]; !hasDir { self.CdrcProfiles[cdrcInstCfg.CdrInDir] = make([]*CdrcConfig, 0) } if indxFound != -1 { // Replace previous config so we have inheritance self.CdrcProfiles[pathFound][indxFound] = cdrcInstCfg } else { self.CdrcProfiles[cdrcInstCfg.CdrInDir] = append(self.CdrcProfiles[cdrcInstCfg.CdrInDir], cdrcInstCfg) } } } if jsnSmGenericCfg != nil { if err := self.SmGenericConfig.loadFromJsonCfg(jsnSmGenericCfg); err != nil { return err } } if jsnSmFsCfg != nil { if err := self.SmFsConfig.loadFromJsonCfg(jsnSmFsCfg); err != nil { return err } } if jsnSmKamCfg != nil { if err := self.SmKamConfig.loadFromJsonCfg(jsnSmKamCfg); err != nil { return err } } if jsnSmOsipsCfg != nil { if err := self.SmOsipsConfig.loadFromJsonCfg(jsnSmOsipsCfg); err != nil { return err } } if jsnSMAstCfg != nil { if err := self.smAsteriskCfg.loadFromJsonCfg(jsnSMAstCfg); err != nil { return err } } if jsnDACfg != nil { if err := self.diameterAgentCfg.loadFromJsonCfg(jsnDACfg); err != nil { return err } } if jsnRACfg != nil { if err := self.radiusAgentCfg.loadFromJsonCfg(jsnRACfg); err != nil { return err } } if jsnHistServCfg != nil { if jsnHistServCfg.Enabled != nil { self.HistoryServerEnabled = *jsnHistServCfg.Enabled } if jsnHistServCfg.History_dir != nil { self.HistoryDir = *jsnHistServCfg.History_dir } if jsnHistServCfg.Save_interval != nil { if self.HistorySaveInterval, err = utils.ParseDurationWithSecs(*jsnHistServCfg.Save_interval); err != nil { return err } } } if jsnPubSubServCfg != nil { if jsnPubSubServCfg.Enabled != nil { self.PubSubServerEnabled = *jsnPubSubServCfg.Enabled } } if jsnAliasesServCfg != nil { if jsnAliasesServCfg.Enabled != nil { self.AliasesServerEnabled = *jsnAliasesServCfg.Enabled } } if jsnRLSCfg != nil { if self.resourceSCfg == nil { self.resourceSCfg = new(ResourceSConfig) } if self.resourceSCfg.loadFromJsonCfg(jsnRLSCfg); err != nil { return err } } if jsnStatSCfg != nil { if self.statsCfg == nil { self.statsCfg = new(StatSCfg) } if self.statsCfg.loadFromJsonCfg(jsnStatSCfg); err != nil { return err } } if jsnUserServCfg != nil { if jsnUserServCfg.Enabled != nil { self.UserServerEnabled = *jsnUserServCfg.Enabled } if jsnUserServCfg.Indexes != nil { self.UserServerIndexes = *jsnUserServCfg.Indexes } } if jsnMailerCfg != nil { if jsnMailerCfg.Server != nil { self.MailerServer = *jsnMailerCfg.Server } if jsnMailerCfg.Auth_user != nil { self.MailerAuthUser = *jsnMailerCfg.Auth_user } if jsnMailerCfg.Auth_password != nil { self.MailerAuthPass = *jsnMailerCfg.Auth_password } if jsnMailerCfg.From_address != nil { self.MailerFromAddr = *jsnMailerCfg.From_address } } if jsnSureTaxCfg != nil { // New config for SureTax if self.sureTaxCfg, err = NewSureTaxCfgWithDefaults(); err != nil { return err } if err := self.sureTaxCfg.loadFromJsonCfg(jsnSureTaxCfg); err != nil { return err } } return nil } // Use locking to retrieve the configuration, possibility later for runtime reload func (self *CGRConfig) SureTaxCfg() *SureTaxCfg { cfgChan := <-self.ConfigReloads[utils.SURETAX] // Lock config for read or reloads defer func() { self.ConfigReloads[utils.SURETAX] <- cfgChan }() return self.sureTaxCfg } func (self *CGRConfig) DiameterAgentCfg() *DiameterAgentCfg { cfgChan := <-self.ConfigReloads[utils.DIAMETER_AGENT] // Lock config for read or reloads defer func() { self.ConfigReloads[utils.DIAMETER_AGENT] <- cfgChan }() return self.diameterAgentCfg } func (self *CGRConfig) RadiusAgentCfg() *RadiusAgentCfg { return self.radiusAgentCfg } // ToDo: fix locking here func (self *CGRConfig) ResourceSCfg() *ResourceSConfig { return self.resourceSCfg } // ToDo: fix locking func (cfg *CGRConfig) StatSCfg() *StatSCfg { return cfg.statsCfg } // ToDo: fix locking here func (self *CGRConfig) SMAsteriskCfg() *SMAsteriskCfg { cfgChan := <-self.ConfigReloads[utils.SMAsterisk] // Lock config for read or reloads defer func() { self.ConfigReloads[utils.SMAsterisk] <- cfgChan }() return self.smAsteriskCfg }