// chanStartServer will report when server is up, useful for internal requests func startHistoryAgent(chanServerStarted chan struct{}) { if cfg.HistoryServer == utils.INTERNAL { // For internal requests, wait for server to come online before connecting engine.Logger.Crit(fmt.Sprintf("<HistoryAgent> Connecting internally to HistoryServer")) select { case <-time.After(1 * time.Minute): engine.Logger.Crit(fmt.Sprintf("<HistoryAgent> Timeout waiting for server to start.")) exitChan <- true return case <-chanServerStarted: } //<-chanServerStarted // If server is not enabled, will have deadlock here } else { // Connect in iteration since there are chances of concurrency here for i := 0; i < 3; i++ { //ToDo: Make it globally configurable //engine.Logger.Crit(fmt.Sprintf("<HistoryAgent> Trying to connect, iteration: %d, time %s", i, time.Now())) if scribeServer, err = history.NewProxyScribe(cfg.HistoryServer); err == nil { break //Connected so no need to reiterate } else if i == 2 && err != nil { engine.Logger.Crit(fmt.Sprintf("<HistoryAgent> Could not connect to the server, error: %s", err.Error())) exitChan <- true return } time.Sleep(time.Duration(i) * time.Second) } } engine.SetHistoryScribe(scribeServer) // scribeServer comes from global variable return }
func main() { flag.Parse() if *version { fmt.Println("CGRateS " + utils.VERSION) return } var errRatingDb, errAccDb, errStorDb, err error var ratingDb engine.RatingStorage var accountDb engine.AccountingStorage var storDb engine.LoadStorage var rater, cdrstats, users *rpc.Client var loader engine.LoadReader if *migrateRC8 != "" { var db_nb int db_nb, err = strconv.Atoi(*datadb_name) if err != nil { log.Print("Redis db name must be an integer!") return } host := *datadb_host if *datadb_port != "" { host += ":" + *datadb_port } migratorRC8acc, err := NewMigratorRC8(host, db_nb, *datadb_pass, *dbdata_encoding) if err != nil { log.Print(err.Error()) return } if strings.Contains(*migrateRC8, "acc") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8acc.migrateAccounts(); err != nil { log.Print(err.Error()) } } db_nb, err = strconv.Atoi(*tpdb_name) if err != nil { log.Print("Redis db name must be an integer!") return } host = *tpdb_host if *tpdb_port != "" { host += ":" + *tpdb_port } migratorRC8rat, err := NewMigratorRC8(host, db_nb, *tpdb_pass, *dbdata_encoding) if err != nil { log.Print(err.Error()) return } if strings.Contains(*migrateRC8, "atr") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActionTriggers(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "act") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActions(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "dcs") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateDerivedChargers(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "apl") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActionPlans(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "shg") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateSharedGroups(); err != nil { log.Print(err.Error()) } } log.Print("Done!") return } // Init necessary db connections, only if not already if !*dryRun { // make sure we do not need db connections on dry run, also not importing into any stordb if *fromStorDb { ratingDb, errRatingDb = engine.ConfigureRatingStorage(*tpdb_type, *tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass, *dbdata_encoding) accountDb, errAccDb = engine.ConfigureAccountingStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding) storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding, cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns, cgrConfig.StorDBCDRSIndexes) } else if *toStorDb { // Import from csv files to storDb storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding, cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns, cgrConfig.StorDBCDRSIndexes) } else { // Default load from csv files to dataDb ratingDb, errRatingDb = engine.ConfigureRatingStorage(*tpdb_type, *tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass, *dbdata_encoding) accountDb, errAccDb = engine.ConfigureAccountingStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding) } // Defer databases opened to be closed when we are done for _, db := range []engine.Storage{ratingDb, accountDb, storDb} { if db != nil { defer db.Close() } } // Stop on db errors for _, err = range []error{errRatingDb, errAccDb, errStorDb} { if err != nil { log.Fatalf("Could not open database connection: %v", err) } } if *toStorDb { // Import files from a directory into storDb if *tpid == "" { log.Fatal("TPid required, please define it via *-tpid* command argument.") } csvImporter := engine.TPCSVImporter{ TPid: *tpid, StorDb: storDb, DirPath: *dataPath, Sep: ',', Verbose: *verbose, ImportId: *runId, } if errImport := csvImporter.Run(); errImport != nil { log.Fatal(errImport) } return } } if *fromStorDb { // Load Tariff Plan from storDb into dataDb loader = storDb } else { // Default load from csv files to dataDb /*for fn, v := range engine.FileValidators { err := engine.ValidateCSVData(path.Join(*dataPath, fn), v.Rule) if err != nil { log.Fatal(err, "\n\t", v.Message) } }*/ loader = engine.NewFileCSVStorage(',', path.Join(*dataPath, utils.DESTINATIONS_CSV), path.Join(*dataPath, utils.TIMINGS_CSV), path.Join(*dataPath, utils.RATES_CSV), path.Join(*dataPath, utils.DESTINATION_RATES_CSV), path.Join(*dataPath, utils.RATING_PLANS_CSV), path.Join(*dataPath, utils.RATING_PROFILES_CSV), path.Join(*dataPath, utils.SHARED_GROUPS_CSV), path.Join(*dataPath, utils.LCRS_CSV), path.Join(*dataPath, utils.ACTIONS_CSV), path.Join(*dataPath, utils.ACTION_PLANS_CSV), path.Join(*dataPath, utils.ACTION_TRIGGERS_CSV), path.Join(*dataPath, utils.ACCOUNT_ACTIONS_CSV), path.Join(*dataPath, utils.DERIVED_CHARGERS_CSV), path.Join(*dataPath, utils.CDR_STATS_CSV), path.Join(*dataPath, utils.USERS_CSV), path.Join(*dataPath, utils.ALIASES_CSV), ) } tpReader := engine.NewTpReader(ratingDb, accountDb, loader, *tpid, *timezone, *loadHistorySize) err = tpReader.LoadAll() if err != nil { log.Fatal(err) } if *stats { tpReader.ShowStatistics() } if *validate { if !tpReader.IsValid() { return } } if *dryRun { // We were just asked to parse the data, not saving it return } if *historyServer != "" { // Init scribeAgent so we can store the differences if scribeAgent, err := history.NewProxyScribe(*historyServer, 3, 3); err != nil { log.Fatalf("Could not connect to history server, error: %s. Make sure you have properly configured it via -history_server flag.", err.Error()) return } else { engine.SetHistoryScribe(scribeAgent) //defer scribeAgent.Client.Close() } } else { log.Print("WARNING: Rates history archiving is disabled!") } if *raterAddress != "" { // Init connection to rater so we can reload it's data rater, err = rpc.Dial("tcp", *raterAddress) if err != nil { log.Fatalf("Could not connect to rater: %s", err.Error()) return } } else { log.Print("WARNING: Rates automatic cache reloading is disabled!") } if *cdrstatsAddress != "" { // Init connection to rater so we can reload it's data if *cdrstatsAddress == *raterAddress { cdrstats = rater } else { cdrstats, err = rpc.Dial("tcp", *cdrstatsAddress) if err != nil { log.Fatalf("Could not connect to CDRStats API: %s", err.Error()) return } } } else { log.Print("WARNING: CDRStats automatic data reload is disabled!") } if *usersAddress != "" { // Init connection to rater so we can reload it's data if *usersAddress == *raterAddress { users = rater } else { users, err = rpc.Dial("tcp", *usersAddress) if err != nil { log.Fatalf("Could not connect to Users API: %s", err.Error()) return } } } else { log.Print("WARNING: Users automatic data reload is disabled!") } // write maps to database if err := tpReader.WriteToDatabase(*flush, *verbose); err != nil { log.Fatal("Could not write to database: ", err) } if len(*historyServer) != 0 && *verbose { log.Print("Wrote history.") } var dstIds, rplIds, rpfIds, actIds, shgIds, alsIds, lcrIds, dcsIds []string if rater != nil { dstIds, _ = tpReader.GetLoadedIds(utils.DESTINATION_PREFIX) rplIds, _ = tpReader.GetLoadedIds(utils.RATING_PLAN_PREFIX) rpfIds, _ = tpReader.GetLoadedIds(utils.RATING_PROFILE_PREFIX) actIds, _ = tpReader.GetLoadedIds(utils.ACTION_PREFIX) shgIds, _ = tpReader.GetLoadedIds(utils.SHARED_GROUP_PREFIX) alsIds, _ = tpReader.GetLoadedIds(utils.ALIASES_PREFIX) lcrIds, _ = tpReader.GetLoadedIds(utils.LCR_PREFIX) dcsIds, _ = tpReader.GetLoadedIds(utils.DERIVEDCHARGERS_PREFIX) } actTmgIds, _ := tpReader.GetLoadedIds(utils.ACTION_PLAN_PREFIX) var statsQueueIds []string if cdrstats != nil { statsQueueIds, _ = tpReader.GetLoadedIds(utils.CDR_STATS_PREFIX) } var userIds []string if users != nil { userIds, _ = tpReader.GetLoadedIds(utils.USERS_PREFIX) } // release the reader with it's structures tpReader.Init() // Reload scheduler and cache if rater != nil { reply := "" // Reload cache first since actions could be calling info from within if *verbose { log.Print("Reloading cache") } if *flush { dstIds, rplIds, rpfIds, lcrIds = nil, nil, nil, nil // Should reload all these on flush } if err = rater.Call("ApierV1.ReloadCache", utils.ApiReloadCache{ DestinationIds: dstIds, RatingPlanIds: rplIds, RatingProfileIds: rpfIds, ActionIds: actIds, SharedGroupIds: shgIds, Aliases: alsIds, LCRIds: lcrIds, DerivedChargers: dcsIds, }, &reply); err != nil { log.Printf("WARNING: Got error on cache reload: %s\n", err.Error()) } if len(actTmgIds) != 0 { if *verbose { log.Print("Reloading scheduler") } if err = rater.Call("ApierV1.ReloadScheduler", "", &reply); err != nil { log.Printf("WARNING: Got error on scheduler reload: %s\n", err.Error()) } } } if cdrstats != nil { if *flush { statsQueueIds = []string{} // Force reload all } if len(statsQueueIds) != 0 { if *verbose { log.Print("Reloading CDRStats data") } var reply string if err := cdrstats.Call("CDRStatsV1.ReloadQueues", utils.AttrCDRStatsReloadQueues{StatsQueueIds: statsQueueIds}, &reply); err != nil { log.Printf("WARNING: Failed reloading stat queues, error: %s\n", err.Error()) } } } if users != nil { if len(userIds) > 0 { if *verbose { log.Print("Reloading Users data") } var reply string if err := cdrstats.Call("UsersV1.ReloadUsers", "", &reply); err != nil { log.Printf("WARNING: Failed reloading users data, error: %s\n", err.Error()) } } } }
// Starts rater and reports on chan func startRater(internalRaterChan chan rpcclient.RpcClientConnection, cacheDoneChan chan struct{}, internalBalancerChan chan *balancer2go.Balancer, internalSchedulerChan chan *scheduler.Scheduler, internalCdrStatSChan chan rpcclient.RpcClientConnection, internalHistorySChan chan rpcclient.RpcClientConnection, internalPubSubSChan chan rpcclient.RpcClientConnection, internalUserSChan chan rpcclient.RpcClientConnection, internalAliaseSChan chan rpcclient.RpcClientConnection, server *utils.Server, ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, loadDb engine.LoadStorage, cdrDb engine.CdrStorage, logDb engine.LogStorage, stopHandled *bool, exitChan chan bool) { var waitTasks []chan struct{} //Cache load cacheTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) loadHist, err := accountDb.GetLoadHistory(1, true) if err != nil || len(loadHist) == 0 { utils.Logger.Info(fmt.Sprintf("could not get load history: %v (%v)", loadHist, err)) cacheDoneChan <- struct{}{} return } cfi, err := utils.LoadCacheFileInfo(cfg.CacheDumpDir) if err != nil || cfi.LoadInfo.RatingLoadID != loadHist[0].RatingLoadID { if err := ratingDb.CacheRatingAll("StartRater"); err != nil { utils.Logger.Crit(fmt.Sprintf("Cache rating error: %s", err.Error())) exitChan <- true return } } else { if err := engine.CacheLoad(cfg.CacheDumpDir, []string{utils.DESTINATION_PREFIX, utils.RATING_PLAN_PREFIX, utils.RATING_PROFILE_PREFIX, utils.LCR_PREFIX, utils.DERIVEDCHARGERS_PREFIX, utils.ACTION_PREFIX, utils.ACTION_PLAN_PREFIX, utils.SHARED_GROUP_PREFIX}); err != nil { utils.Logger.Crit("could not load cache file: " + err.Error()) exitChan <- true return } } cacheDoneChan <- struct{}{} }() // Retrieve scheduler for it's API methods var sched *scheduler.Scheduler // Need the scheduler in APIer if cfg.SchedulerEnabled { schedTaskChan := make(chan struct{}) waitTasks = append(waitTasks, schedTaskChan) go func() { defer close(schedTaskChan) select { case sched = <-internalSchedulerChan: internalSchedulerChan <- sched case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal scheduler connection timeout.") exitChan <- true return } }() } var bal *balancer2go.Balancer if cfg.RALsBalancer != "" { // Connection to balancer balTaskChan := make(chan struct{}) waitTasks = append(waitTasks, balTaskChan) go func() { defer close(balTaskChan) if cfg.RALsBalancer == utils.MetaInternal { select { case bal = <-internalBalancerChan: internalBalancerChan <- bal // Put it back if someone else is interested about case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal balancer connection timeout.") exitChan <- true return } } else { go registerToBalancer(exitChan) go stopRaterSignalHandler(internalCdrStatSChan, exitChan) *stopHandled = true } }() } var cdrStats *rpcclient.RpcClientPool if len(cfg.RALsCDRStatSConns) != 0 { // Connections to CDRStats cdrstatTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cdrstatTaskChan) go func() { defer close(cdrstatTaskChan) cdrStats, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RALsCDRStatSConns, internalCdrStatSChan, cfg.InternalTtl) if err != nil { utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to CDRStatS, error: %s", err.Error())) exitChan <- true return } }() } if len(cfg.RALsHistorySConns) != 0 { // Connection to HistoryS, histTaskChan := make(chan struct{}) waitTasks = append(waitTasks, histTaskChan) go func() { defer close(histTaskChan) if historySConns, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RALsHistorySConns, internalHistorySChan, cfg.InternalTtl); err != nil { utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect HistoryS, error: %s", err.Error())) exitChan <- true return } else { engine.SetHistoryScribe(historySConns) } }() } if len(cfg.RALsPubSubSConns) != 0 { // Connection to pubsubs pubsubTaskChan := make(chan struct{}) waitTasks = append(waitTasks, pubsubTaskChan) go func() { defer close(pubsubTaskChan) if pubSubSConns, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RALsPubSubSConns, internalPubSubSChan, cfg.InternalTtl); err != nil { utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to PubSubS: %s", err.Error())) exitChan <- true return } else { engine.SetPubSub(pubSubSConns) } }() } if len(cfg.RALsAliasSConns) != 0 { // Connection to AliasService aliasesTaskChan := make(chan struct{}) waitTasks = append(waitTasks, aliasesTaskChan) go func() { defer close(aliasesTaskChan) if aliaseSCons, err := engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RALsAliasSConns, internalAliaseSChan, cfg.InternalTtl); err != nil { utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect to AliaseS, error: %s", err.Error())) exitChan <- true return } else { engine.SetAliasService(aliaseSCons) } }() } var usersConns rpcclient.RpcClientConnection if len(cfg.RALsUserSConns) != 0 { // Connection to UserService usersTaskChan := make(chan struct{}) waitTasks = append(waitTasks, usersTaskChan) go func() { defer close(usersTaskChan) if usersConns, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.RALsUserSConns, internalUserSChan, cfg.InternalTtl); err != nil { utils.Logger.Crit(fmt.Sprintf("<RALs> Could not connect UserS, error: %s", err.Error())) exitChan <- true return } engine.SetUserService(usersConns) }() } // Wait for all connections to complete before going further for _, chn := range waitTasks { <-chn } responder := &engine.Responder{Bal: bal, ExitChan: exitChan} responder.SetTimeToLive(cfg.ResponseCacheTTL, nil) apierRpcV1 := &v1.ApierV1{StorDb: loadDb, RatingDb: ratingDb, AccountDb: accountDb, CdrDb: cdrDb, LogDb: logDb, Sched: sched, Config: cfg, Responder: responder} if cdrStats != nil { // ToDo: Fix here properly the init of stats responder.Stats = cdrStats apierRpcV1.CdrStatsSrv = cdrStats } if usersConns != nil { apierRpcV1.Users = usersConns } apierRpcV2 := &v2.ApierV2{ ApierV1: *apierRpcV1} // internalSchedulerChan shared here server.RpcRegister(responder) server.RpcRegister(apierRpcV1) server.RpcRegister(apierRpcV2) utils.RegisterRpcParams("", &engine.Stats{}) utils.RegisterRpcParams("", &v1.CDRStatsV1{}) utils.RegisterRpcParams("ScribeV1", &history.FileScribe{}) utils.RegisterRpcParams("PubSubV1", &engine.PubSub{}) utils.RegisterRpcParams("AliasesV1", &engine.AliasHandler{}) utils.RegisterRpcParams("UsersV1", &engine.UserMap{}) utils.RegisterRpcParams("", &v1.CdrsV1{}) utils.RegisterRpcParams("", &v2.CdrsV2{}) utils.RegisterRpcParams("", &v1.SessionManagerV1{}) utils.RegisterRpcParams("", &v1.SMGenericV1{}) utils.RegisterRpcParams("", responder) utils.RegisterRpcParams("", apierRpcV1) utils.RegisterRpcParams("", apierRpcV2) utils.GetRpcParams("") internalRaterChan <- responder // Rater done }
// Starts rater and reports on chan func startRater(internalRaterChan chan *engine.Responder, internalBalancerChan chan *balancer2go.Balancer, internalSchedulerChan chan *scheduler.Scheduler, internalCdrStatSChan chan engine.StatsInterface, internalHistorySChan chan history.Scribe, internalPubSubSChan chan engine.PublisherSubscriber, internalUserSChan chan engine.UserService, internalAliaseSChan chan engine.AliasService, server *utils.Server, ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, loadDb engine.LoadStorage, cdrDb engine.CdrStorage, logDb engine.LogStorage, stopHandled *bool, exitChan chan bool) { waitTasks := make([]chan struct{}, 0) //Cache load cacheTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) if err := ratingDb.CacheRatingAll(); err != nil { utils.Logger.Crit(fmt.Sprintf("Cache rating error: %s", err.Error())) exitChan <- true return } if err := accountDb.CacheAccountingPrefixes(); err != nil { // Used to cache load history utils.Logger.Crit(fmt.Sprintf("Cache accounting error: %s", err.Error())) exitChan <- true return } }() // Retrieve scheduler for it's API methods var sched *scheduler.Scheduler // Need the scheduler in APIer if cfg.SchedulerEnabled { schedTaskChan := make(chan struct{}) waitTasks = append(waitTasks, schedTaskChan) go func() { defer close(schedTaskChan) select { case sched = <-internalSchedulerChan: internalSchedulerChan <- sched case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal scheduler connection timeout.") exitChan <- true return } }() } // Connection to balancer var bal *balancer2go.Balancer if cfg.RaterBalancer != "" { balTaskChan := make(chan struct{}) waitTasks = append(waitTasks, balTaskChan) go func() { defer close(balTaskChan) if cfg.RaterBalancer == utils.INTERNAL { select { case bal = <-internalBalancerChan: internalBalancerChan <- bal // Put it back if someone else is interested about case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal balancer connection timeout.") exitChan <- true return } } else { go registerToBalancer(exitChan) go stopRaterSignalHandler(internalCdrStatSChan, exitChan) *stopHandled = true } }() } // Connection to CDRStats var cdrStats engine.StatsInterface if cfg.RaterCdrStats != "" { cdrstatTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cdrstatTaskChan) go func() { defer close(cdrstatTaskChan) if cfg.RaterCdrStats == utils.INTERNAL { select { case cdrStats = <-internalCdrStatSChan: internalCdrStatSChan <- cdrStats case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal cdrstats connection timeout.") exitChan <- true return } } else if cdrStats, err = engine.NewProxyStats(cfg.RaterCdrStats, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to cdrstats, error: %s", err.Error())) exitChan <- true return } }() } // Connection to HistoryS if cfg.RaterHistoryServer != "" { histTaskChan := make(chan struct{}) waitTasks = append(waitTasks, histTaskChan) go func() { defer close(histTaskChan) var scribeServer history.Scribe if cfg.RaterHistoryServer == utils.INTERNAL { select { case scribeServer = <-internalHistorySChan: internalHistorySChan <- scribeServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal historys connection timeout.") exitChan <- true return } } else if scribeServer, err = history.NewProxyScribe(cfg.RaterHistoryServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect historys, error: %s", err.Error())) exitChan <- true return } engine.SetHistoryScribe(scribeServer) // ToDo: replace package sharing with connection based one }() } // Connection to pubsubs if cfg.RaterPubSubServer != "" { pubsubTaskChan := make(chan struct{}) waitTasks = append(waitTasks, pubsubTaskChan) go func() { defer close(pubsubTaskChan) var pubSubServer engine.PublisherSubscriber if cfg.RaterPubSubServer == utils.INTERNAL { select { case pubSubServer = <-internalPubSubSChan: internalPubSubSChan <- pubSubServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal pubsub connection timeout.") exitChan <- true return } } else if pubSubServer, err = engine.NewProxyPubSub(cfg.RaterPubSubServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to pubsubs: %s", err.Error())) exitChan <- true return } engine.SetPubSub(pubSubServer) // ToDo: replace package sharing with connection based one }() } // Connection to AliasService if cfg.RaterAliasesServer != "" { aliasesTaskChan := make(chan struct{}) waitTasks = append(waitTasks, aliasesTaskChan) go func() { defer close(aliasesTaskChan) var aliasesServer engine.AliasService if cfg.RaterAliasesServer == utils.INTERNAL { select { case aliasesServer = <-internalAliaseSChan: internalAliaseSChan <- aliasesServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal aliases connection timeout.") exitChan <- true return } } else if aliasesServer, err = engine.NewProxyAliasService(cfg.RaterAliasesServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to aliases, error: %s", err.Error())) exitChan <- true return } engine.SetAliasService(aliasesServer) // ToDo: replace package sharing with connection based one }() } // Connection to UserService var userServer engine.UserService if cfg.RaterUserServer != "" { usersTaskChan := make(chan struct{}) waitTasks = append(waitTasks, usersTaskChan) go func() { defer close(usersTaskChan) if cfg.RaterUserServer == utils.INTERNAL { select { case userServer = <-internalUserSChan: internalUserSChan <- userServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal users connection timeout.") exitChan <- true return } } else if userServer, err = engine.NewProxyUserService(cfg.RaterUserServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect users, error: %s", err.Error())) exitChan <- true return } engine.SetUserService(userServer) }() } // Wait for all connections to complete before going further for _, chn := range waitTasks { <-chn } responder := &engine.Responder{Bal: bal, ExitChan: exitChan, Stats: cdrStats} apierRpcV1 := &v1.ApierV1{StorDb: loadDb, RatingDb: ratingDb, AccountDb: accountDb, CdrDb: cdrDb, LogDb: logDb, Sched: sched, Config: cfg, Responder: responder, CdrStatsSrv: cdrStats, Users: userServer} apierRpcV2 := &v2.ApierV2{ ApierV1: *apierRpcV1} // internalSchedulerChan shared here server.RpcRegister(responder) server.RpcRegister(apierRpcV1) server.RpcRegister(apierRpcV2) internalRaterChan <- responder // Rater done }
func main() { flag.Parse() if *version { fmt.Println("CGRateS " + utils.VERSION) return } var errRatingDb, errAccDb, errStorDb, err error var ratingDb engine.RatingStorage var accountDb engine.AccountingStorage var storDb engine.LoadStorage var rater, cdrstats *rpc.Client var loader engine.TPLoader // Init necessary db connections, only if not already if !*dryRun { // make sure we do not need db connections on dry run, also not importing into any stordb if *fromStorDb { ratingDb, errRatingDb = engine.ConfigureRatingStorage(*ratingdb_type, *ratingdb_host, *ratingdb_port, *ratingdb_name, *ratingdb_user, *ratingdb_pass, *dbdata_encoding) accountDb, errAccDb = engine.ConfigureAccountingStorage(*accountdb_type, *accountdb_host, *accountdb_port, *accountdb_name, *accountdb_user, *accountdb_pass, *dbdata_encoding) storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding) } else if *toStorDb { // Import from csv files to storDb storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding) } else { // Default load from csv files to dataDb ratingDb, errRatingDb = engine.ConfigureRatingStorage(*ratingdb_type, *ratingdb_host, *ratingdb_port, *ratingdb_name, *ratingdb_user, *ratingdb_pass, *dbdata_encoding) accountDb, errAccDb = engine.ConfigureAccountingStorage(*accountdb_type, *accountdb_host, *accountdb_port, *accountdb_name, *accountdb_user, *accountdb_pass, *dbdata_encoding) } // Defer databases opened to be closed when we are done for _, db := range []engine.Storage{ratingDb, accountDb, storDb} { if db != nil { defer db.Close() } } // Stop on db errors for _, err = range []error{errRatingDb, errAccDb, errStorDb} { if err != nil { log.Fatalf("Could not open database connection: %v", err) } } if *toStorDb { // Import files from a directory into storDb if *tpid == "" { log.Fatal("TPid required, please define it via *-tpid* command argument.") } csvImporter := engine.TPCSVImporter{*tpid, storDb, *dataPath, ',', *verbose, *runId} if errImport := csvImporter.Run(); errImport != nil { log.Fatal(errImport) } return } } if *fromStorDb { // Load Tariff Plan from storDb into dataDb loader = engine.NewDbReader(storDb, ratingDb, accountDb, *tpid) } else { // Default load from csv files to dataDb for fn, v := range engine.FileValidators { err := engine.ValidateCSVData(path.Join(*dataPath, fn), v.Rule) if err != nil { log.Fatal(err, "\n\t", v.Message) } } loader = engine.NewFileCSVReader(ratingDb, accountDb, ',', path.Join(*dataPath, utils.DESTINATIONS_CSV), path.Join(*dataPath, utils.TIMINGS_CSV), path.Join(*dataPath, utils.RATES_CSV), path.Join(*dataPath, utils.DESTINATION_RATES_CSV), path.Join(*dataPath, utils.RATING_PLANS_CSV), path.Join(*dataPath, utils.RATING_PROFILES_CSV), path.Join(*dataPath, utils.SHARED_GROUPS_CSV), path.Join(*dataPath, utils.LCRS_CSV), path.Join(*dataPath, utils.ACTIONS_CSV), path.Join(*dataPath, utils.ACTION_PLANS_CSV), path.Join(*dataPath, utils.ACTION_TRIGGERS_CSV), path.Join(*dataPath, utils.ACCOUNT_ACTIONS_CSV), path.Join(*dataPath, utils.DERIVED_CHARGERS_CSV), path.Join(*dataPath, utils.CDR_STATS_CSV)) } err = loader.LoadAll() if err != nil { log.Fatal(err) } if *stats { loader.ShowStatistics() } if *dryRun { // We were just asked to parse the data, not saving it return } if *historyServer != "" { // Init scribeAgent so we can store the differences if scribeAgent, err := history.NewProxyScribe(*historyServer); err != nil { log.Fatalf("Could not connect to history server, error: %s. Make sure you have properly configured it via -history_server flag.", err.Error()) return } else { engine.SetHistoryScribe(scribeAgent) defer scribeAgent.Client.Close() } } else { log.Print("WARNING: Rates history archiving is disabled!") } if *raterAddress != "" { // Init connection to rater so we can reload it's data rater, err = rpc.Dial("tcp", *raterAddress) if err != nil { log.Fatalf("Could not connect to rater: %s", err.Error()) return } } else { log.Print("WARNING: Rates automatic cache reloading is disabled!") } if *cdrstatsAddress != "" { // Init connection to rater so we can reload it's data if *cdrstatsAddress == *raterAddress { cdrstats = rater } else { cdrstats, err = rpc.Dial("tcp", *cdrstatsAddress) if err != nil { log.Fatalf("Could not connect to CDRStats API: %s", err.Error()) return } } } else { log.Print("WARNING: CDRStats automatic data reload is disabled!") } // write maps to database if err := loader.WriteToDatabase(*flush, *verbose); err != nil { log.Fatal("Could not write to database: ", err) } if len(*historyServer) != 0 && *verbose { log.Print("Wrote history.") } // Reload scheduler and cache if rater != nil { reply := "" dstIds, _ := loader.GetLoadedIds(engine.DESTINATION_PREFIX) rplIds, _ := loader.GetLoadedIds(engine.RATING_PLAN_PREFIX) rpfIds, _ := loader.GetLoadedIds(engine.RATING_PROFILE_PREFIX) actIds, _ := loader.GetLoadedIds(engine.ACTION_PREFIX) shgIds, _ := loader.GetLoadedIds(engine.SHARED_GROUP_PREFIX) rpAliases, _ := loader.GetLoadedIds(engine.RP_ALIAS_PREFIX) accAliases, _ := loader.GetLoadedIds(engine.ACC_ALIAS_PREFIX) lcrIds, _ := loader.GetLoadedIds(engine.LCR_PREFIX) dcs, _ := loader.GetLoadedIds(engine.DERIVEDCHARGERS_PREFIX) // Reload cache first since actions could be calling info from within if *verbose { log.Print("Reloading cache") } if *flush { dstIds, rplIds, rpfIds, rpAliases, lcrIds = nil, nil, nil, nil, nil // Should reload all these on flush } if err = rater.Call("ApierV1.ReloadCache", utils.ApiReloadCache{dstIds, rplIds, rpfIds, actIds, shgIds, rpAliases, accAliases, lcrIds, dcs}, &reply); err != nil { log.Printf("WARNING: Got error on cache reload: %s\n", err.Error()) } actTmgIds, _ := loader.GetLoadedIds(engine.ACTION_TIMING_PREFIX) if len(actTmgIds) != 0 { if *verbose { log.Print("Reloading scheduler") } if err = rater.Call("ApierV1.ReloadScheduler", "", &reply); err != nil { log.Printf("WARNING: Got error on scheduler reload: %s\n", err.Error()) } } } if cdrstats != nil { statsQueueIds, _ := loader.GetLoadedIds(engine.CDR_STATS_PREFIX) if *flush { statsQueueIds = []string{} // Force reload all } if len(statsQueueIds) != 0 { if *verbose { log.Print("Reloading CDRStats data") } var reply string if err := cdrstats.Call("CDRStatsV1.ReloadQueues", utils.AttrCDRStatsReloadQueues{StatsQueueIds: statsQueueIds}, &reply); err != nil { log.Printf("WARNING: Failed reloading stat queues, error: %s\n", err.Error()) } } } }