Beispiel #1
0
func (srvMngr *ServiceManager) StartScheduler(waitCache bool) error {
	srvMngr.RLock()
	schedRunning := srvMngr.sched != nil
	srvMngr.RUnlock()
	if schedRunning {
		return utils.NewCGRError(utils.ServiceManager,
			utils.CapitalizedMessage(utils.ServiceAlreadyRunning),
			utils.ServiceAlreadyRunning,
			"the scheduler is already running")
	}
	if waitCache { // Wait for cache to load data before starting
		cacheDone := <-srvMngr.cacheDoneChan
		srvMngr.cacheDoneChan <- cacheDone
	}
	utils.Logger.Info("<ServiceManager> Starting CGRateS Scheduler.")
	sched := scheduler.NewScheduler(srvMngr.ratingDB)
	srvMngr.Lock()
	srvMngr.sched = sched
	srvMngr.Unlock()
	go func() {
		sched.Loop()
		srvMngr.Lock()
		srvMngr.sched = nil // if we are after loop, the service is down
		srvMngr.Unlock()
		if srvMngr.cfg.SchedulerEnabled {
			srvMngr.engineShutdown <- true // shutdown engine since this service should be running
		}
	}()
	return nil
}
Beispiel #2
0
func (m *Migrator) Migrate(taskID string) (err error) {
	switch taskID {
	default: // unsupported taskID
		err = utils.NewCGRError(utils.Migrator,
			utils.MandatoryIEMissingCaps,
			utils.UnsupportedMigrationTask,
			fmt.Sprintf("task <%s> is not a supported migration task", taskID))
	case utils.MetaSetVersions:
		if err := m.storDB.SetVersions(engine.CurrentStorDBVersions()); err != nil {
			return utils.NewCGRError(utils.Migrator,
				utils.ServerErrorCaps,
				err.Error(),
				fmt.Sprintf("error: <%s> when updating CostDetails version into StorDB", err.Error()))
		}
	case utils.MetaCostDetails:
		err = m.migrateCostDetails()
	}
	return
}
Beispiel #3
0
func GetCloned(key string) (cln interface{}, err error) {
	cacheMux.RLock()
	defer cacheMux.RUnlock()
	origVal, hasIt := cache.Get(key)
	if !hasIt {
		return nil, utils.NewCGRError(utils.Cache,
			utils.NotFoundCaps, utils.ItemNotFound,
			fmt.Sprintf("item with key <%s> was not found in <%s>", key))
	} else if origVal == nil {
		return nil, nil
	}
	if _, canClone := origVal.(utils.Cloner); !canClone {
		return nil, utils.NewCGRError(utils.Cache,
			utils.NotCloneableCaps, utils.ItemNotCloneable,
			fmt.Sprintf("item with key <%s> is not following cloner interface", key))
	}
	retVals := reflect.ValueOf(origVal).MethodByName("Clone").Call(nil) // Call Clone method on the object
	errIf := retVals[1].Interface()
	var notNil bool
	if err, notNil = errIf.(error); notNil {
		return
	}
	return retVals[0].Interface(), nil
}
Beispiel #4
0
func (srvMngr *ServiceManager) StopScheduler() error {
	var sched *scheduler.Scheduler
	srvMngr.Lock()
	if srvMngr.sched != nil {
		sched = srvMngr.sched
		srvMngr.sched = nil // optimize the lock and release here
	}
	srvMngr.Unlock()
	if sched == nil {
		return utils.NewCGRError(utils.ServiceManager,
			utils.CapitalizedMessage(utils.ServiceAlreadyRunning),
			utils.ServiceAlreadyRunning,
			"the scheduler is not running")
	}
	srvMngr.cfg.SchedulerEnabled = false
	sched.Shutdown()
	return nil
}
Beispiel #5
0
// RPC method, differs from storeSMCost through it's signature
func (self *CdrServer) V1StoreSMCost(attr AttrCDRSStoreSMCost, reply *string) error {
	if attr.Cost.CGRID == "" {
		return utils.NewCGRError(utils.CDRSCtx,
			utils.MandatoryIEMissingCaps, fmt.Sprintf("%s: CGRID", utils.MandatoryInfoMissing),
			"SMCost: %+v with empty CGRID")
	}
	cacheKey := "V1StoreSMCost" + attr.Cost.CGRID + attr.Cost.RunID + attr.Cost.OriginID
	if item, err := self.getCache().Get(cacheKey); err == nil && item != nil {
		if item.Value != nil {
			*reply = item.Value.(string)
		}
		return item.Err
	}
	if err := self.storeSMCost(attr.Cost, attr.CheckDuplicate); err != nil {
		self.getCache().Cache(cacheKey, &cache.CacheItem{Err: err})
		return utils.NewErrServerError(err)
	}
	self.getCache().Cache(cacheKey, &cache.CacheItem{Value: utils.OK})
	*reply = utils.OK
	return nil
}
Beispiel #6
0
func (m *Migrator) migrateCostDetails() (err error) {
	if m.storDB == nil {
		return utils.NewCGRError(utils.Migrator,
			utils.MandatoryIEMissingCaps,
			utils.NoStorDBConnection,
			"no connection to StorDB")
	}
	vrs, err := m.storDB.GetVersions(utils.COST_DETAILS)
	if err != nil {
		return utils.NewCGRError(utils.Migrator,
			utils.ServerErrorCaps,
			err.Error(),
			fmt.Sprintf("error: <%s> when querying storDB for versions", err.Error()))
	} else if len(vrs) == 0 {
		return utils.NewCGRError(utils.Migrator,
			utils.MandatoryIEMissingCaps,
			utils.UndefinedVersion,
			"version number is not defined for CostDetails model")
	}
	if vrs[utils.COST_DETAILS] != 1 { // Right now we only support migrating from version 1
		return
	}
	var storSQL *sql.DB
	switch m.storDBType {
	case utils.MYSQL:
		storSQL = m.storDB.(*engine.MySQLStorage).Db
	case utils.POSTGRES:
		storSQL = m.storDB.(*engine.PostgresStorage).Db
	default:
		return utils.NewCGRError(utils.Migrator,
			utils.MandatoryIEMissingCaps,
			utils.UnsupportedDB,
			fmt.Sprintf("unsupported database type: <%s>", m.storDBType))
	}
	rows, err := storSQL.Query("SELECT id, tor, direction, tenant, category, account, subject, destination, cost, cost_details FROM cdrs WHERE run_id!= '*raw' and cost_details IS NOT NULL AND deleted_at IS NULL")
	if err != nil {
		return utils.NewCGRError(utils.Migrator,
			utils.ServerErrorCaps,
			err.Error(),
			fmt.Sprintf("error: <%s> when querying storDB for cdrs", err.Error()))
	}
	defer rows.Close()
	for cnt := 0; rows.Next(); cnt++ {
		var id int64
		var ccDirection, ccCategory, ccTenant, ccSubject, ccAccount, ccDestination, ccTor sql.NullString
		var ccCost sql.NullFloat64
		var tts []byte
		if err := rows.Scan(&id, &ccTor, &ccDirection, &ccTenant, &ccCategory, &ccAccount, &ccSubject, &ccDestination, &ccCost, &tts); err != nil {
			return utils.NewCGRError(utils.Migrator,
				utils.ServerErrorCaps,
				err.Error(),
				fmt.Sprintf("error: <%s> when scanning at count: <%d>", err.Error(), cnt))
		}
		var v1tmsps v1TimeSpans
		if err := json.Unmarshal(tts, &v1tmsps); err != nil {
			utils.Logger.Warning(
				fmt.Sprintf("<Migrator> Unmarshalling timespans at CDR with id: <%d>, error: <%s>", id, err.Error()))
			continue
		}
		v1CC := &v1CallCost{Direction: ccDirection.String, Category: ccCategory.String, Tenant: ccTenant.String,
			Subject: ccSubject.String, Account: ccAccount.String, Destination: ccDestination.String, TOR: ccTor.String,
			Cost: ccCost.Float64, Timespans: v1tmsps}
		cc, err := v1CC.AsCallCost()
		if err != nil {
			utils.Logger.Warning(
				fmt.Sprintf("<Migrator> Error: <%s> when converting into CallCost CDR with id: <%d>", err.Error(), id))
			continue
		}
		if _, err := storSQL.Exec(fmt.Sprintf("UPDATE cdrs SET cost_details='%s' WHERE id=%d", cc.AsJSON(), id)); err != nil {
			utils.Logger.Warning(
				fmt.Sprintf("<Migrator> Error: <%s> updating CDR with id <%d> into StorDB", err.Error(), id))
			continue
		}
	}
	// All done, update version wtih current one
	vrs = engine.Versions{utils.COST_DETAILS: engine.CurrentStorDBVersions()[utils.COST_DETAILS]}
	if err := m.storDB.SetVersions(vrs); err != nil {
		return utils.NewCGRError(utils.Migrator,
			utils.ServerErrorCaps,
			err.Error(),
			fmt.Sprintf("error: <%s> when updating CostDetails version into StorDB", err.Error()))
	}
	return
}
Beispiel #7
0
// CacheDataFromDB loads data to cache
// prfx represents the cache prefix, ids should be nil if all available data should be loaded
// mustBeCached specifies that data needs to be cached in order to be retrieved from db
func (rs *RedisStorage) CacheDataFromDB(prfx string, ids []string, mustBeCached bool) (err error) {
	if !utils.IsSliceMember([]string{utils.DESTINATION_PREFIX,
		utils.REVERSE_DESTINATION_PREFIX,
		utils.RATING_PLAN_PREFIX,
		utils.RATING_PROFILE_PREFIX,
		utils.ACTION_PREFIX,
		utils.ACTION_PLAN_PREFIX,
		utils.SHARED_GROUP_PREFIX,
		utils.DERIVEDCHARGERS_PREFIX,
		utils.LCR_PREFIX,
		utils.ALIASES_PREFIX,
		utils.REVERSE_ALIASES_PREFIX,
		utils.ResourceLimitsPrefix}, prfx) {
		return utils.NewCGRError(utils.REDIS,
			utils.MandatoryIEMissingCaps,
			utils.UnsupportedCachePrefix,
			fmt.Sprintf("prefix <%s> is not a supported cache prefix", prfx))
	}
	if ids == nil {
		if ids, err = rs.GetKeysForPrefix(prfx); err != nil {
			return utils.NewCGRError(utils.REDIS,
				utils.ServerErrorCaps,
				err.Error(),
				fmt.Sprintf("redis error <%s> querying keys for prefix: <%s>", prfx))
		}
		cache.RemPrefixKey(prfx, true, utils.NonTransactional)
	}
	for _, dataID := range ids {
		if mustBeCached {
			if _, hasIt := cache.Get(prfx + dataID); !hasIt { // only cache if previously there
				continue
			}
		}
		switch prfx {
		case utils.DESTINATION_PREFIX:
			_, err = rs.GetDestination(dataID, false, utils.NonTransactional)
		case utils.REVERSE_DESTINATION_PREFIX:
			_, err = rs.GetReverseDestination(dataID, false, utils.NonTransactional)
		case utils.RATING_PLAN_PREFIX:
			_, err = rs.GetRatingPlan(dataID, false, utils.NonTransactional)
		case utils.RATING_PROFILE_PREFIX:
			_, err = rs.GetRatingProfile(dataID, false, utils.NonTransactional)
		case utils.ACTION_PREFIX:
			_, err = rs.GetActions(dataID, false, utils.NonTransactional)
		case utils.ACTION_PLAN_PREFIX:
			_, err = rs.GetActionPlan(dataID, false, utils.NonTransactional)
		case utils.SHARED_GROUP_PREFIX:
			_, err = rs.GetSharedGroup(dataID, false, utils.NonTransactional)
		case utils.DERIVEDCHARGERS_PREFIX:
			_, err = rs.GetDerivedChargers(dataID, false, utils.NonTransactional)
		case utils.LCR_PREFIX:
			_, err = rs.GetLCR(dataID, false, utils.NonTransactional)
		case utils.ALIASES_PREFIX:
			_, err = rs.GetAlias(dataID, false, utils.NonTransactional)
		case utils.REVERSE_ALIASES_PREFIX:
			_, err = rs.GetReverseAlias(dataID, false, utils.NonTransactional)
		case utils.ResourceLimitsPrefix:
			_, err = rs.GetResourceLimit(dataID, false, utils.NonTransactional)
		}
		if err != nil {
			return utils.NewCGRError(utils.REDIS,
				utils.ServerErrorCaps,
				err.Error(),
				fmt.Sprintf("error <%s> querying redis for category: <%s>, dataID: <%s>", prfx, dataID))
		}
	}
	return
}