diff --git a/apier/v1/accounts.go b/apier/v1/accounts.go index 08640f219..39acaf5ae 100644 --- a/apier/v1/accounts.go +++ b/apier/v1/accounts.go @@ -45,17 +45,24 @@ func (self *ApierV1) GetAccountActionPlan(attrs AttrAcntAction, reply *[]*Accoun if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(strings.Join(missing, ","), "") } - accountATs := make([]*AccountActionTiming, 0) - allATs, err := self.RatingDb.GetAllActionPlans() + accountATs := make([]*AccountActionTiming, 0) // needs to be initialized if remains empty + allAPs, err := self.RatingDb.GetAllActionPlans() if err != nil { return utils.NewErrServerError(err) } - for _, ats := range allATs { - for _, at := range ats { - if utils.IsSliceMember(at.AccountIds, utils.AccountKey(attrs.Tenant, attrs.Account)) { - accountATs = append(accountATs, &AccountActionTiming{Uuid: at.Uuid, ActionPlanId: at.Id, ActionsId: at.ActionsId, NextExecTime: at.GetNextStartTime(time.Now())}) + accID := utils.AccountKey(attrs.Tenant, attrs.Account) + for _, ap := range allAPs { + if _, exists := ap.AccountIDs[accID]; exists { + for _, at := range ap.ActionTimings { + accountATs = append(accountATs, &AccountActionTiming{ + ActionPlanId: ap.Id, + Uuid: at.Uuid, + ActionsId: at.ActionsID, + NextExecTime: at.GetNextStartTime(time.Now()), + }) } } + } *reply = accountATs return nil @@ -80,22 +87,41 @@ func (self *ApierV1) RemActionTiming(attrs AttrRemActionTiming, reply *string) e } } _, err := engine.Guardian.Guard(func() (interface{}, error) { - ats, err := self.RatingDb.GetActionPlans(attrs.ActionPlanId, false) + ap, err := self.RatingDb.GetActionPlan(attrs.ActionPlanId, false) if err != nil { return 0, err - } else if len(ats) == 0 { + } else if ap == nil { return 0, utils.ErrNotFound } - ats = engine.RemActionPlan(ats, attrs.ActionTimingId, utils.AccountKey(attrs.Tenant, attrs.Account)) - if err := self.RatingDb.SetActionPlans(attrs.ActionPlanId, ats); err != nil { - return 0, err + + if attrs.ActionPlanId != "" { // delete the entire action plan + ap.ActionTimings = nil // will delete the action plan + return 0, self.RatingDb.SetActionPlan(ap.Id, ap) } - if len(ats) > 0 { // update cache - self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + attrs.ActionPlanId}}) + + if attrs.ActionTimingId != "" { // delete only a action timing from action plan + for i, at := range ap.ActionTimings { + if at.Uuid == attrs.ActionTimingId { + ap.ActionTimings[i] = ap.ActionTimings[len(ap.ActionTimings)-1] + ap.ActionTimings = ap.ActionTimings[:len(ap.ActionTimings)-1] + break + } + } + return 0, self.RatingDb.SetActionPlan(ap.Id, ap) } + + if attrs.Tenant != "" && attrs.Account != "" { + accID := utils.AccountKey(attrs.Tenant, attrs.Account) + delete(ap.AccountIDs, accID) + return 0, self.RatingDb.SetActionPlan(ap.Id, ap) + } + + // update cache + self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + attrs.ActionPlanId}}) return 0, nil }, 0, utils.ACTION_PLAN_PREFIX) if err != nil { + *reply = err.Error() return utils.NewErrServerError(err) } if attrs.ReloadScheduler && self.Sched != nil { @@ -130,9 +156,9 @@ func (self *ApierV1) RemAccountActionTriggers(attrs AttrRemAcntActionTriggers, r if missing := utils.MissingStructFields(&attrs, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - accId := utils.AccountKey(attrs.Tenant, attrs.Account) + accID := utils.AccountKey(attrs.Tenant, attrs.Account) _, err := engine.Guardian.Guard(func() (interface{}, error) { - ub, err := self.AccountDb.GetAccount(accId) + ub, err := self.AccountDb.GetAccount(accID) if err != nil { return 0, err } @@ -152,7 +178,7 @@ func (self *ApierV1) RemAccountActionTriggers(attrs AttrRemAcntActionTriggers, r return 0, err } return 0, nil - }, 0, accId) + }, 0, accID) if err != nil { return utils.NewErrServerError(err) } @@ -166,30 +192,28 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error return utils.NewErrMandatoryIeMissing(missing...) } var schedulerReloadNeeded = false - accId := utils.AccountKey(attr.Tenant, attr.Account) + accID := utils.AccountKey(attr.Tenant, attr.Account) var ub *engine.Account _, err := engine.Guardian.Guard(func() (interface{}, error) { - if bal, _ := self.AccountDb.GetAccount(accId); bal != nil { + if bal, _ := self.AccountDb.GetAccount(accID); bal != nil { ub = bal } else { // Not found in db, create it here ub = &engine.Account{ - Id: accId, + Id: accID, } } if len(attr.ActionPlanId) != 0 { _, err := engine.Guardian.Guard(func() (interface{}, error) { - var ats engine.ActionPlans + var ap *engine.ActionPlan var err error - ats, err = self.RatingDb.GetActionPlans(attr.ActionPlanId, false) + ap, err = self.RatingDb.GetActionPlan(attr.ActionPlanId, false) if err != nil { return 0, err } - for _, at := range ats { - at.AccountIds = append(at.AccountIds, accId) - } - if len(ats) != 0 { + if _, exists := ap.AccountIDs[accID]; !exists { + ap.AccountIDs[accID] = struct{}{} schedulerReloadNeeded = true - if err := self.RatingDb.SetActionPlans(attr.ActionPlanId, ats); err != nil { + if err := self.RatingDb.SetActionPlan(attr.ActionPlanId, ap); err != nil { return 0, err } // update cache @@ -221,11 +245,11 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error return 0, err } return 0, nil - }, 0, accId) + }, 0, accID) if err != nil { return utils.NewErrServerError(err) } - if schedulerReloadNeeded { + if attr.ReloadScheduler && schedulerReloadNeeded { // reload scheduler if self.Sched != nil { self.Sched.Reload(true) @@ -239,32 +263,20 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - accountId := utils.AccountKey(attr.Tenant, attr.Account) + accID := utils.AccountKey(attr.Tenant, attr.Account) var schedulerReloadNeeded bool _, err := engine.Guardian.Guard(func() (interface{}, error) { // remove it from all action plans - allATs, err := self.RatingDb.GetAllActionPlans() + allAPs, err := self.RatingDb.GetAllActionPlans() if err != nil && err != utils.ErrNotFound { return 0, err } - for key, ats := range allATs { - changed := false - for _, at := range ats { - for i := 0; i < len(at.AccountIds); i++ { - if at.AccountIds[i] == accountId { - // delete without preserving order - at.AccountIds[i] = at.AccountIds[len(at.AccountIds)-1] - at.AccountIds = at.AccountIds[:len(at.AccountIds)-1] - i-- - changed = true - } - } - } - if changed { + for key, ap := range allAPs { + if _, exists := ap.AccountIDs[accID]; !exists { schedulerReloadNeeded = true _, err := engine.Guardian.Guard(func() (interface{}, error) { // save action plan - self.RatingDb.SetActionPlans(key, ats) + self.RatingDb.SetActionPlan(key, ap) // cache self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + key}}) return 0, nil @@ -274,11 +286,11 @@ func (self *ApierV1) RemoveAccount(attr utils.AttrRemoveAccount, reply *string) } } } - if err := self.AccountDb.RemoveAccount(accountId); err != nil { + if err := self.AccountDb.RemoveAccount(accID); err != nil { return 0, err } return 0, nil - }, 0, accountId) + }, 0, accID) // FIXME: remove from all actionplans? if err != nil { return utils.NewErrServerError(err) @@ -344,3 +356,153 @@ func (self *ApierV1) GetAccount(attr *utils.AttrGetAccount, reply *interface{}) *reply = userBalance.AsOldStructure() return nil } + +type AttrAddBalance struct { + Tenant string + Account string + BalanceUuid string + BalanceId string + BalanceType string + Directions string + Value float64 + ExpiryTime string + RatingSubject string + Categories string + DestinationIds string + Weight float64 + SharedGroups string + Overwrite bool // When true it will reset if the balance is already there + Disabled bool +} + +func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { + expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone) + if err != nil { + *reply = err.Error() + return err + } + accID := utils.AccountKey(attr.Tenant, attr.Account) + if _, err := self.AccountDb.GetAccount(accID); err != nil { + // create account if not exists + account := &engine.Account{ + Id: accID, + } + if err := self.AccountDb.SetAccount(account); err != nil { + *reply = err.Error() + return err + } + } + at := &engine.ActionTiming{} + at.SetAccountIDs(map[string]struct{}{accID: struct{}{}}) + + aType := engine.DEBIT + // reverse the sign as it is a debit + attr.Value = -attr.Value + + if attr.Overwrite { + aType = engine.DEBIT_RESET + } + at.SetActions(engine.Actions{ + &engine.Action{ + ActionType: aType, + BalanceType: attr.BalanceType, + Balance: &engine.Balance{ + Uuid: attr.BalanceUuid, + Id: attr.BalanceId, + Value: attr.Value, + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Directions: utils.ParseStringMap(attr.Directions), + DestinationIds: utils.ParseStringMap(attr.DestinationIds), + Categories: utils.ParseStringMap(attr.Categories), + Weight: attr.Weight, + SharedGroups: utils.ParseStringMap(attr.SharedGroups), + Disabled: attr.Disabled, + }, + }, + }) + if err := at.Execute(); err != nil { + *reply = err.Error() + return err + } + *reply = OK + return nil +} + +func (self *ApierV1) EnableDisableBalance(attr *AttrAddBalance, reply *string) error { + expTime, err := utils.ParseDate(attr.ExpiryTime) + if err != nil { + *reply = err.Error() + return err + } + accID := utils.ConcatenatedKey(attr.Tenant, attr.Account) + if _, err := self.AccountDb.GetAccount(accID); err != nil { + return utils.ErrNotFound + } + at := &engine.ActionTiming{} + at.SetAccountIDs(map[string]struct{}{accID: struct{}{}}) + + at.SetActions(engine.Actions{ + &engine.Action{ + ActionType: engine.ENABLE_DISABLE_BALANCE, + BalanceType: attr.BalanceType, + Balance: &engine.Balance{ + Uuid: attr.BalanceUuid, + Id: attr.BalanceId, + Value: attr.Value, + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Directions: utils.ParseStringMap(attr.Directions), + DestinationIds: utils.ParseStringMap(attr.DestinationIds), + Weight: attr.Weight, + SharedGroups: utils.ParseStringMap(attr.SharedGroups), + Disabled: attr.Disabled, + }, + }, + }) + if err := at.Execute(); err != nil { + *reply = err.Error() + return err + } + *reply = OK + return nil +} + +func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error { + expTime, err := utils.ParseDate(attr.ExpiryTime) + if err != nil { + *reply = err.Error() + return err + } + accID := utils.AccountKey(attr.Tenant, attr.Account) + if _, err := self.AccountDb.GetAccount(accID); err != nil { + return utils.ErrNotFound + } + + at := &engine.ActionTiming{} + at.SetAccountIDs(map[string]struct{}{accID: struct{}{}}) + at.SetActions(engine.Actions{ + &engine.Action{ + ActionType: engine.REMOVE_BALANCE, + BalanceType: attr.BalanceType, + Balance: &engine.Balance{ + Uuid: attr.BalanceUuid, + Id: attr.BalanceId, + Value: attr.Value, + ExpirationDate: expTime, + RatingSubject: attr.RatingSubject, + Directions: utils.ParseStringMap(attr.Directions), + DestinationIds: utils.ParseStringMap(attr.DestinationIds), + Weight: attr.Weight, + SharedGroups: utils.ParseStringMap(attr.SharedGroups), + Disabled: attr.Disabled, + }, + }, + }) + if err := at.Execute(); err != nil { + *reply = err.Error() + return err + } + *reply = OK + return nil +} diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 7b58735d8..e1e4e7bfb 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -102,162 +102,12 @@ func (self *ApierV1) GetRatingPlan(rplnId string, reply *engine.RatingPlan) erro return nil } -type AttrAddBalance struct { - Tenant string - Account string - BalanceUuid string - BalanceId string - BalanceType string - Directions string - Value float64 - ExpiryTime string - RatingSubject string - Categories string - DestinationIds string - Weight float64 - SharedGroups string - Overwrite bool // When true it will reset if the balance is already there - Disabled bool -} - -func (self *ApierV1) AddBalance(attr *AttrAddBalance, reply *string) error { - expTime, err := utils.ParseTimeDetectLayout(attr.ExpiryTime, self.Config.DefaultTimezone) - if err != nil { - *reply = err.Error() - return err - } - tag := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.AccountDb.GetAccount(tag); err != nil { - // create account if not exists - account := &engine.Account{ - Id: tag, - } - if err := self.AccountDb.SetAccount(account); err != nil { - *reply = err.Error() - return err - } - } - at := &engine.ActionPlan{ - AccountIds: []string{tag}, - } - aType := engine.DEBIT - // reverse the sign as it is a debit - attr.Value = -attr.Value - - if attr.Overwrite { - aType = engine.DEBIT_RESET - } - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: aType, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuid: attr.BalanceUuid, - Id: attr.BalanceId, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIds: utils.ParseStringMap(attr.DestinationIds), - Categories: utils.ParseStringMap(attr.Categories), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - Disabled: attr.Disabled, - }, - }, - }) - if err := at.Execute(); err != nil { - *reply = err.Error() - return err - } - *reply = OK - return nil -} - -func (self *ApierV1) EnableDisableBalance(attr *AttrAddBalance, reply *string) error { - expTime, err := utils.ParseDate(attr.ExpiryTime) - if err != nil { - *reply = err.Error() - return err - } - tag := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.AccountDb.GetAccount(tag); err != nil { - return utils.ErrNotFound - } - at := &engine.ActionPlan{ - AccountIds: []string{tag}, - } - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: engine.ENABLE_DISABLE_BALANCE, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuid: attr.BalanceUuid, - Id: attr.BalanceId, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIds: utils.ParseStringMap(attr.DestinationIds), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - Disabled: attr.Disabled, - }, - }, - }) - if err := at.Execute(); err != nil { - *reply = err.Error() - return err - } - *reply = OK - return nil -} - -func (self *ApierV1) RemoveBalances(attr *AttrAddBalance, reply *string) error { - expTime, err := utils.ParseDate(attr.ExpiryTime) - if err != nil { - *reply = err.Error() - return err - } - accId := utils.ConcatenatedKey(attr.Tenant, attr.Account) - if _, err := self.AccountDb.GetAccount(accId); err != nil { - return utils.ErrNotFound - } - at := &engine.ActionPlan{ - AccountIds: []string{accId}, - } - at.SetActions(engine.Actions{ - &engine.Action{ - ActionType: engine.REMOVE_BALANCE, - BalanceType: attr.BalanceType, - Balance: &engine.Balance{ - Uuid: attr.BalanceUuid, - Id: attr.BalanceId, - Value: attr.Value, - ExpirationDate: expTime, - RatingSubject: attr.RatingSubject, - Directions: utils.ParseStringMap(attr.Directions), - DestinationIds: utils.ParseStringMap(attr.DestinationIds), - Weight: attr.Weight, - SharedGroups: utils.ParseStringMap(attr.SharedGroups), - Disabled: attr.Disabled, - }, - }, - }) - if err := at.Execute(); err != nil { - *reply = err.Error() - return err - } - *reply = OK - return nil -} - func (self *ApierV1) ExecuteAction(attr *utils.AttrExecuteAction, reply *string) error { - accId := utils.AccountKey(attr.Tenant, attr.Account) - at := &engine.ActionPlan{ - AccountIds: []string{accId}, - ActionsId: attr.ActionsId, + accID := utils.AccountKey(attr.Tenant, attr.Account) + at := &engine.ActionTiming{ + ActionsID: attr.ActionsId, } + at.SetAccountIDs(map[string]struct{}{accID: struct{}{}}) if err := at.Execute(); err != nil { *reply = err.Error() return err @@ -745,8 +595,10 @@ func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) error return utils.ErrExists } } - storeAtms := make(engine.ActionPlans, len(attrs.ActionPlan)) - for idx, apiAtm := range attrs.ActionPlan { + ap := &engine.ActionPlan{ + Id: attrs.Id, + } + for _, apiAtm := range attrs.ActionPlan { if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, apiAtm.ActionsId); err != nil { return utils.NewErrServerError(err) } else if !exists { @@ -758,16 +610,14 @@ func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) error timing.MonthDays.Parse(apiAtm.MonthDays, ";") timing.WeekDays.Parse(apiAtm.WeekDays, ";") timing.StartTime = apiAtm.Time - at := &engine.ActionPlan{ + ap.ActionTimings = append(ap.ActionTimings, &engine.ActionTiming{ Uuid: utils.GenUUID(), - Id: attrs.Id, Weight: apiAtm.Weight, Timing: &engine.RateInterval{Timing: timing}, - ActionsId: apiAtm.ActionsId, - } - storeAtms[idx] = at + ActionsID: apiAtm.ActionsId, + }) } - if err := self.RatingDb.SetActionPlans(attrs.Id, storeAtms); err != nil { + if err := self.RatingDb.SetActionPlan(ap.Id, ap); err != nil { return utils.NewErrServerError(err) } self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + attrs.Id}}) @@ -785,8 +635,8 @@ type AttrGetActionPlan struct { Id string } -func (self *ApierV1) GetActionPlan(attr AttrGetActionPlan, reply *[]engine.ActionPlans) error { - var result []engine.ActionPlans +func (self *ApierV1) GetActionPlan(attr AttrGetActionPlan, reply *[]*engine.ActionPlan) error { + var result []*engine.ActionPlan if attr.Id == "" || attr.Id == "*" { aplsMap, err := self.RatingDb.GetAllActionPlans() if err != nil { @@ -796,7 +646,7 @@ func (self *ApierV1) GetActionPlan(attr AttrGetActionPlan, reply *[]engine.Actio result = append(result, apls) } } else { - apls, err := self.RatingDb.GetActionPlans(attr.Id, false) + apls, err := self.RatingDb.GetActionPlan(attr.Id, false) if err != nil { return err } diff --git a/apier/v1/scheduler.go b/apier/v1/scheduler.go index ab4d0b9c4..a91701204 100644 --- a/apier/v1/scheduler.go +++ b/apier/v1/scheduler.go @@ -104,9 +104,9 @@ type AttrsGetScheduledActions struct { } type ScheduledActions struct { - NextRunTime time.Time - Accounts int - ActionsId, ActionPlanId, ActionPlanUuid string + NextRunTime time.Time + Accounts int + ActionsId, ActionPlanId, ActionTimingUuid string } func (self *ApierV1) GetScheduledActions(attrs AttrsGetScheduledActions, reply *[]*ScheduledActions) error { @@ -116,7 +116,7 @@ func (self *ApierV1) GetScheduledActions(attrs AttrsGetScheduledActions, reply * schedActions := make([]*ScheduledActions, 0) // needs to be initialized if remains empty scheduledActions := self.Sched.GetQueue() for _, qActions := range scheduledActions { - sas := &ScheduledActions{ActionsId: qActions.ActionsId, ActionPlanId: qActions.Id, ActionPlanUuid: qActions.Uuid, Accounts: len(qActions.AccountIds)} + sas := &ScheduledActions{ActionsId: qActions.ActionsID, ActionPlanId: qActions.GetActionPlanID(), ActionTimingUuid: qActions.Uuid, Accounts: len(qActions.GetAccountIDs())} if attrs.SearchTerm != "" && !(strings.Contains(sas.ActionPlanId, attrs.SearchTerm) || strings.Contains(sas.ActionsId, attrs.SearchTerm)) { @@ -132,7 +132,7 @@ func (self *ApierV1) GetScheduledActions(attrs AttrsGetScheduledActions, reply * // filter on account if attrs.Tenant != "" || attrs.Account != "" { found := false - for _, accID := range qActions.AccountIds { + for accID := range qActions.GetAccountIDs() { split := strings.Split(accID, utils.CONCATENATED_KEY_SEP) if len(split) != 2 { continue // malformed account id diff --git a/console/actionplan_get.go b/console/actionplan_get.go index af17a0aed..23b4b64a9 100644 --- a/console/actionplan_get.go +++ b/console/actionplan_get.go @@ -61,6 +61,6 @@ func (self *CmdGetActionPlan) PostprocessRpcParams() error { } func (self *CmdGetActionPlan) RpcResult() interface{} { - s := make([]*engine.ActionPlans, 0) + s := make([]*engine.ActionPlan, 0) return &s } diff --git a/engine/action_plan.go b/engine/action_plan.go index e5914c79c..c1e854cfa 100644 --- a/engine/action_plan.go +++ b/engine/action_plan.go @@ -32,13 +32,14 @@ const ( ) type ActionTiming struct { - Uuid string - Timing *RateInterval - ActionsID string - Weight float64 - actions Actions - accountIDs map[string]struct{} // copy of action plans accounts - stCache time.Time // cached time of the next start + Uuid string + Timing *RateInterval + ActionsID string + Weight float64 + actions Actions + accountIDs map[string]struct{} // copy of action plans accounts + actionPlanID string // the id of the belonging action plan (info only) + stCache time.Time // cached time of the next start } type Task struct { @@ -48,7 +49,6 @@ type Task struct { } type ActionPlan struct { - Uuid string // uniquely identify the timing Id string // informative purpose only AccountIDs map[string]struct{} ActionTimings []*ActionTiming @@ -254,6 +254,18 @@ func (at *ActionTiming) SetAccountIDs(accIDs map[string]struct{}) { at.accountIDs = accIDs } +func (at *ActionTiming) GetAccountIDs() map[string]struct{} { + return at.accountIDs +} + +func (at *ActionTiming) SetActionPlanID(id string) { + at.actionPlanID = id +} + +func (at *ActionTiming) GetActionPlanID() string { + return at.actionPlanID +} + func (at *ActionTiming) getActions() (as []*Action, err error) { if at.actions == nil { at.actions, err = ratingStorage.GetActions(at.ActionsID, false) @@ -364,34 +376,3 @@ func (atpl ActionTimingPriorityList) Less(i, j int) bool { func (atpl ActionTimingPriorityList) Sort() { sort.Sort(atpl) } - -// Helper to remove ActionPlan members based on specific filters, empty data means no always match -/*func RemActionPlan(apl ActionPlan, actionTimingId, accountId string) ActionPlan { - if len(actionTimingId) != 0 && apl.Uuid != actionTimingId { // No Match for ActionPlanId, no need to move further - continue - } - for idx, ats := range apl.ActionTimings { - if len(accountId) == 0 { // No account defined, considered match for complete removal - if len(ats) == 1 { // Removing last item, by init empty - return make([]*ActionPlan, 0) - } - ats[idx], ats = ats[len(ats)-1], ats[:len(ats)-1] - continue - } - for iAcc, accID := range at.AccountIds { - if accID == accountId { - if len(at.AccountIds) == 1 { // Only one balance, remove complete at - if len(ats) == 1 { // Removing last item, by init empty - return make([]*ActionPlan, 0) - } - ats[idx], ats = ats[len(ats)-1], ats[:len(ats)-1] - } else { - at.AccountIds[iAcc], at.AccountIds = at.AccountIds[len(at.AccountIds)-1], at.AccountIds[:len(at.AccountIds)-1] - } - // only remove the first one matching - break - } - } - } - return ats -}*/ diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index e0e24f13f..805cd1c46 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -987,7 +987,6 @@ func TestLoadActionTimings(t *testing.T) { } atm := csvr.actionPlans["MORE_MINUTES"] expected := &ActionPlan{ - Uuid: atm.Uuid, Id: "MORE_MINUTES", AccountIDs: map[string]struct{}{"vdf:minitsboy": struct{}{}}, ActionTimings: []*ActionTiming{ diff --git a/engine/tp_reader.go b/engine/tp_reader.go index abafa2811..4981d38ad 100644 --- a/engine/tp_reader.go +++ b/engine/tp_reader.go @@ -578,8 +578,7 @@ func (tpr *TpReader) LoadActionPlans() (err error) { var actPln *ActionPlan if actPln, exists = tpr.actionPlans[atId]; !exists { actPln = &ActionPlan{ - Uuid: utils.GenUUID(), - Id: atId, + Id: atId, } } actPln.ActionTimings = append(actPln.ActionTimings, &ActionTiming{ @@ -710,8 +709,7 @@ func (tpr *TpReader) LoadAccountActionsFiltered(qriedAA *TpAccountAction) error } if actionPlan == nil { actionPlan = &ActionPlan{ - Uuid: utils.GenUUID(), - Id: accountAction.ActionPlanId, + Id: accountAction.ActionPlanId, } } actionPlan.ActionTimings = append(actionPlan.ActionTimings, &ActionTiming{ diff --git a/general_tests/acntacts_test.go b/general_tests/acntacts_test.go index 780560a59..4bfcd6ddd 100644 --- a/general_tests/acntacts_test.go +++ b/general_tests/acntacts_test.go @@ -74,10 +74,10 @@ ENABLE_ACNT,*enable_account,,,,,,,,,,,,,false,10` func TestAcntActsDisableAcnt(t *testing.T) { acnt1Tag := "cgrates.org:1" - at := &engine.ActionPlan{ - AccountIds: []string{acnt1Tag}, - ActionsId: "DISABLE_ACNT", + at := &engine.ActionTiming{ + ActionsID: "DISABLE_ACNT", } + at.SetAccountIDs(map[string]struct{}{acnt1Tag: struct{}{}}) if err := at.Execute(); err != nil { t.Error(err) } @@ -92,9 +92,9 @@ func TestAcntActsDisableAcnt(t *testing.T) { func TestAcntActsEnableAcnt(t *testing.T) { acnt1Tag := "cgrates.org:1" at := &engine.ActionPlan{ - AccountIds: []string{acnt1Tag}, - ActionsId: "ENABLE_ACNT", + ActionsID: "ENABLE_ACNT", } + at.SetAccountIDs(map[string]struct{}{acnt1Tag: struct{}{}}) if err := at.Execute(); err != nil { t.Error(err) } diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go index fecc15608..45583931f 100644 --- a/scheduler/scheduler.go +++ b/scheduler/scheduler.go @@ -34,8 +34,6 @@ type Scheduler struct { restartLoop chan bool sync.Mutex storage engine.RatingStorage - waitingReload bool - loopChecker chan int schedulerStarted bool } @@ -43,7 +41,6 @@ func NewScheduler(storage engine.RatingStorage) *Scheduler { return &Scheduler{ restartLoop: make(chan bool), storage: storage, - loopChecker: make(chan int), } } @@ -91,35 +88,13 @@ func (s *Scheduler) Loop() { } func (s *Scheduler) Reload(protect bool) { - s.Lock() - defer s.Unlock() - - if protect { - if s.waitingReload { - s.loopChecker <- 1 - } - s.waitingReload = true - go func() { - t := time.NewTicker(100 * time.Millisecond) // wait for loops before start - select { - case <-s.loopChecker: - t.Stop() // cancel reload - case <-t.C: - s.loadActionPlans() - s.restart() - t.Stop() - s.waitingReload = false - } - }() - } else { - go func() { - s.loadActionPlans() - s.restart() - }() - } + s.loadActionPlans() + s.restart() } func (s *Scheduler) loadActionPlans() { + s.Lock() + defer s.Unlock() // limit the number of concurrent tasks var limit = make(chan bool, 10) // execute existing tasks @@ -141,8 +116,6 @@ func (s *Scheduler) loadActionPlans() { } utils.Logger.Info(fmt.Sprintf(" processing %d action plans", len(actionPlans))) // recreate the queue - s.Lock() - defer s.Unlock() s.queue = engine.ActionTimingPriorityList{} for _, actionPlan := range actionPlans { for _, at := range actionPlan.ActionTimings { diff --git a/utils/apitpdata.go b/utils/apitpdata.go index d528fc739..65892955f 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -1099,11 +1099,13 @@ type AttrSetAccount struct { ActionTriggersId string AllowNegative *bool Disabled *bool + ReloadScheduler bool } type AttrRemoveAccount struct { - Tenant string - Account string + Tenant string + Account string + ReloadScheduler bool } type AttrGetSMASessions struct {