mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
ips: add ClearAllocations API
This commit is contained in:
committed by
Dan Christian Bogos
parent
82cfff3cff
commit
707826359b
@@ -211,3 +211,9 @@ func (ipS *IPSv1) V1ReleaseIP(ctx *context.Context, args *utils.CGREvent, reply
|
||||
func (ipS *IPSv1) V1GetIPAllocations(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.IPAllocations) error {
|
||||
return ipS.ips.V1GetIPAllocations(ctx, arg, reply)
|
||||
}
|
||||
|
||||
// V1ClearIPAllocations clears IP allocations from an IPAllocations object.
|
||||
// If args.AllocationIDs is empty or nil, all allocations will be cleared.
|
||||
func (ipS *IPSv1) V1ClearIPAllocations(ctx *context.Context, arg *utils.ClearIPAllocationsArgs, reply *string) error {
|
||||
return ipS.ips.V1ClearIPAllocations(ctx, arg, reply)
|
||||
}
|
||||
|
||||
58
docs/ips.rst
58
docs/ips.rst
@@ -154,15 +154,21 @@ Checks if an IP can be allocated without actually allocating it (dry run).
|
||||
::
|
||||
|
||||
{
|
||||
"Tenant": "cgrates.org",
|
||||
"ID": "unique_event_id",
|
||||
"Event": {
|
||||
"Account": "1001",
|
||||
"Destination": "1002"
|
||||
},
|
||||
"APIOpts": {
|
||||
"*ipAllocationID": "ip_allocation_abc123"
|
||||
}
|
||||
"method": "IPsV1.AuthorizeIP",
|
||||
"params": [
|
||||
{
|
||||
"Tenant": "cgrates.org",
|
||||
"ID": "unique_event_id",
|
||||
"Event": {
|
||||
"Account": "1001",
|
||||
"Destination": "1002"
|
||||
},
|
||||
"APIOpts": {
|
||||
"*ipAllocationID": "ip_allocation_abc123"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": 1
|
||||
}
|
||||
|
||||
**Returns:**
|
||||
@@ -236,6 +242,40 @@ Gets the matching IPAllocations object for a specific event.
|
||||
|
||||
- IPAllocations object for the matching profile
|
||||
|
||||
V1ClearIPAllocations
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Clears IP allocations from an IPAllocations object.
|
||||
|
||||
**Request:**
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
"method": "IPsV1.ClearIPAllocations",
|
||||
"params": [
|
||||
{
|
||||
"Tenant": "cgrates.org",
|
||||
"ID": "profile_id",
|
||||
"AllocationIDs": [
|
||||
"alloc1",
|
||||
"alloc2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"id": 6
|
||||
}
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- Tenant and Profile ID (required)
|
||||
- AllocationIDs: Array of specific allocation IDs to clear (optional - if empty or omitted, all allocations will be cleared)
|
||||
|
||||
**Returns:**
|
||||
|
||||
- Success confirmation
|
||||
- Error if any specified allocation IDs don't exist
|
||||
|
||||
Use Cases
|
||||
---------
|
||||
|
||||
|
||||
34
ips/apis.go
34
ips/apis.go
@@ -275,7 +275,7 @@ func (s *IPService) V1ReleaseIP(ctx *context.Context, args *utils.CGREvent, repl
|
||||
return nil
|
||||
}
|
||||
|
||||
// V1GetIPAllocations returns a resource configuration
|
||||
// V1GetIPAllocations returns all IP allocations for a tenantID.
|
||||
func (s *IPService) V1GetIPAllocations(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.IPAllocations) error {
|
||||
if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
@@ -298,3 +298,35 @@ func (s *IPService) V1GetIPAllocations(ctx *context.Context, arg *utils.TenantID
|
||||
*reply = *ip
|
||||
return nil
|
||||
}
|
||||
|
||||
// V1ClearIPAllocations clears IP allocations from an IPAllocations object.
|
||||
// If args.AllocationIDs is empty or nil, all allocations will be cleared.
|
||||
func (s *IPService) V1ClearIPAllocations(ctx *context.Context, args *utils.ClearIPAllocationsArgs, reply *string) error {
|
||||
if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
|
||||
tnt := args.Tenant
|
||||
if tnt == utils.EmptyString {
|
||||
tnt = s.cfg.GeneralCfg().DefaultTenant
|
||||
}
|
||||
|
||||
lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
|
||||
config.CgrConfig().GeneralCfg().LockingTimeout,
|
||||
utils.IPAllocationsLockKey(tnt, args.ID))
|
||||
defer guardian.Guardian.UnguardIDs(lkID)
|
||||
|
||||
allocs, err := s.dm.GetIPAllocations(ctx, tnt, args.ID, true, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := allocs.ClearAllocations(args.AllocationIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.storeIPAllocations(ctx, allocs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -95,26 +95,12 @@ func TestIPsIT(t *testing.T) {
|
||||
"exists_indexed_fields": [],
|
||||
"notexists_indexed_fields": [],
|
||||
"opts":{
|
||||
"*allocationID": [
|
||||
{
|
||||
"Tenant": "cgrates.org",
|
||||
"FilterIDs": ["*string:~*req.Account:1001"],
|
||||
"Value": "cfg_allocation"
|
||||
}
|
||||
],
|
||||
// "*ttl": [
|
||||
// {
|
||||
// "Tenant": "*any",
|
||||
// "FilterIDs": [],
|
||||
// "Value": "72h"
|
||||
// }
|
||||
// ],
|
||||
// "*units": [
|
||||
// {
|
||||
// "Tenant": "*any",
|
||||
// "FilterIDs": [],
|
||||
// "Value": 1
|
||||
// }
|
||||
// "*allocationID": [
|
||||
// {
|
||||
// "Tenant": "cgrates.org",
|
||||
// "FilterIDs": ["*string:~*req.Account:1001"],
|
||||
// "Value": "cfg_allocation"
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
},
|
||||
@@ -236,6 +222,7 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
ID: "GetIPsForEvent1",
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "2001",
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
utils.OptsIPsAllocationID: allocID,
|
||||
@@ -251,8 +238,11 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
ID: "AuthorizeIP1",
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "2001",
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
utils.OptsIPsAllocationID: allocID,
|
||||
},
|
||||
APIOpts: map[string]any{},
|
||||
}, &allocIP); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -263,8 +253,11 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
ID: "AllocateIP1",
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "2001",
|
||||
},
|
||||
APIOpts: map[string]any{
|
||||
utils.OptsIPsAllocationID: allocID,
|
||||
},
|
||||
APIOpts: map[string]any{},
|
||||
}, &allocIP); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -276,8 +269,20 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
ID: "ReleaseIP1",
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "2001",
|
||||
},
|
||||
APIOpts: map[string]any{},
|
||||
APIOpts: map[string]any{
|
||||
utils.OptsIPsAllocationID: allocID,
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := client.Call(context.Background(), utils.IPsV1ClearIPAllocations,
|
||||
&utils.ClearIPAllocationsArgs{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "IPs1",
|
||||
// AllocationIDs: []string{allocID},
|
||||
}, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -298,7 +303,7 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
},
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.Destination: "2001",
|
||||
utils.SetupTime: "2018-01-07T17:00:00Z",
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
@@ -313,7 +318,7 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
},
|
||||
Event: map[string]any{
|
||||
utils.AccountField: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.Destination: "2001",
|
||||
utils.SetupTime: "2018-01-07T17:00:00Z",
|
||||
},
|
||||
}, &reply); err != nil {
|
||||
@@ -321,6 +326,7 @@ cgrates.org,IPs2,*string:~*req.Account:1002,;20,2s,false,POOL1,*string:~*req.Des
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkIPsAuthorize(b *testing.B) {
|
||||
cfg := config.NewDefaultCGRConfig()
|
||||
dataDB, _ := engine.NewInternalDB(nil, nil, nil, cfg.DataDbCfg().Items)
|
||||
|
||||
@@ -1679,6 +1679,7 @@ const (
|
||||
IPsV1AuthorizeIP = "IPsV1.AuthorizeIP"
|
||||
IPsV1AllocateIP = "IPsV1.AllocateIP"
|
||||
IPsV1ReleaseIP = "IPsV1.ReleaseIP"
|
||||
IPsV1ClearIPAllocations = "IPsV1.ClearIPAllocations"
|
||||
AdminSv1SetIPProfile = "AdminSv1.SetIPProfile"
|
||||
AdminSv1GetIPProfiles = "AdminSv1.GetIPProfiles"
|
||||
AdminSv1RemoveIPProfile = "AdminSv1.RemoveIPProfile"
|
||||
|
||||
49
utils/ips.go
49
utils/ips.go
@@ -416,6 +416,15 @@ type IPAllocationsWithAPIOpts struct {
|
||||
APIOpts map[string]any
|
||||
}
|
||||
|
||||
// ClearIPAllocationsArgs contains arguments for clearing IP allocations.
|
||||
// If AllocationIDs is empty or nil, all allocations will be cleared.
|
||||
type ClearIPAllocationsArgs struct {
|
||||
Tenant string
|
||||
ID string
|
||||
AllocationIDs []string
|
||||
APIOpts map[string]any
|
||||
}
|
||||
|
||||
// ComputeUnexported populates lookup maps and profile reference from exported fields.
|
||||
// Must be called after retrieving from DB.
|
||||
func (a *IPAllocations) ComputeUnexported(prfl *IPProfile) error {
|
||||
@@ -459,6 +468,46 @@ func (a *IPAllocations) ReleaseAllocation(allocID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearAllocations clears specified IP allocations or all allocations if allocIDs is empty/nil.
|
||||
// Either all specified IDs exist and get cleared, or none are cleared and an error is returned.
|
||||
func (a *IPAllocations) ClearAllocations(allocIDs []string) error {
|
||||
if len(allocIDs) == 0 {
|
||||
clear(a.Allocations)
|
||||
clear(a.poolAllocs)
|
||||
a.TTLIndex = a.TTLIndex[:0] // maintain capacity
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate all IDs exist before clearing any.
|
||||
var notFound []string
|
||||
for _, allocID := range allocIDs {
|
||||
if _, has := a.Allocations[allocID]; !has {
|
||||
notFound = append(notFound, allocID)
|
||||
}
|
||||
}
|
||||
if len(notFound) > 0 {
|
||||
return fmt.Errorf("cannot find allocation records with ids: %v", notFound)
|
||||
}
|
||||
|
||||
for _, allocID := range allocIDs {
|
||||
alloc := a.Allocations[allocID]
|
||||
if poolMap, hasPool := a.poolAllocs[alloc.PoolID]; hasPool {
|
||||
delete(poolMap, alloc.Address)
|
||||
}
|
||||
if a.prfl.TTL > 0 {
|
||||
for i, refID := range a.TTLIndex {
|
||||
if refID == allocID {
|
||||
a.TTLIndex = slices.Delete(a.TTLIndex, i, i+1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
delete(a.Allocations, allocID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllocateIPOnPool allocates an IP from the specified pool or refreshes
|
||||
// existing allocation. If dryRun is true, checks availability without
|
||||
// allocating.
|
||||
|
||||
Reference in New Issue
Block a user