Previous Topic: BFC Finding and Cleaning Orphaned IP PoolsNext Topic: BFC Glossary


cleanup_ip_pools Script

#!/usr/bin/env escript

%% -*- erlang -*-

%%! -sname cleanup_ip_pools

-define(IP_RESERVATION_POOL, 'drivers/networking.components.ip_reservation_pool').

-define(GRID, 'bbc/applogic_grid_resource').

-define(DESIGNATOR, 'drivers/networking.properties.pool.designator').

-define(ANCESTRY, 'drivers/networking.properties.pool.ancestry').

-define(POOL_RANGES, 'drivers/networking.properties.pool.ranges').

-define(RESERVED_RANGES, 'drivers/networking.properties.pool.reserved_ips').

-define(UNRESERVED_RANGES, 'drivers/networking.properties.pool.unreserved_ips').

-define(ALLOCATION_MAP, 'drivers/networking.properties.pool.allocations').

-define(SUBNET_ADDRESS, 'drivers/networking.properties.subnet.subnet_address').

-define(CIDR, 'drivers/networking.properties.subnet.cidr').

-define(SUBNET_DEFAULT, "core/subnet_default_pool").

-define(GRID_NAME, 'bbc/properties.grid_name').

-define(GRID_APPLICATION_IP_SUBPOOL, "bbc/applogic_app_ip_subpool").

main(Args) ->

case Args of

["show"] ->

orphaned_pools(false),

app_ip_pools_with_allocations(false);

["cleanup"] ->

orphaned_pools(true),

app_ip_pools_with_allocations(true);

_ -> usage()

end.

orphaned_pools(Cleanup) ->

OrphanedPools =

lists:filter(

fun(Pool) ->

Designator = binary_to_list(property_get(Pool, ?DESIGNATOR)),

{Grid, _} =

string:to_integer(string:sub_word(Designator, 2, $_)),

is_grid_pool(Designator) andalso not grid_exists(Grid)

end,

get_pools()),

case OrphanedPools of

[] -> io:fwrite("~nNO ORPHANED GRID POOLS~n", []);

_ -> io:fwrite("~nORPHANED GRID POOLS ~p~n", [OrphanedPools])

end,

[show_orphaned_pool(P, Cleanup) || P <- OrphanedPools],

ok.

show_orphaned_pool(Pool, Cleanup) ->

Designator = binary_to_list(property_get(Pool, ?DESIGNATOR)),

{Grid, []} = string:to_integer(string:sub_word(Designator, 2, $_)),

{Subnet, []} = string:to_integer(string:sub_word(Designator, 3, $_)),

SubnetAddr = binary_to_list(property_get(Subnet, ?SUBNET_ADDRESS)),

CIDR = property_get(Subnet, ?CIDR),

TopPool = get_top_pool(Pool),

VLAN = binary_to_list(property_get(TopPool, ?DESIGNATOR)),

{Grid, []} = string:to_integer(string:sub_word(Designator, 2, $_)),

io:fwrite("Grid Pool...~n", []),

io:fwrite(" IP Pool ID: (~p) ~s~n", [Pool, Designator]),

io:fwrite(" Subnet ID: (~p) ~s/~p", [Subnet, SubnetAddr, CIDR]),

case VLAN of

?SUBNET_DEFAULT ->

io:fwrite("~n",[]);

_ ->

io:fwrite(" VLAN: ~s~n", [VLAN])

end,

io:fwrite(" Grid ID: (~p)", [Grid]),

io:fwrite(" ***GRID NOT FOUND***~n", []),

io:fwrite(" FOUND orphaned IP Pool: (~p)~n",

[Pool]),

if Cleanup ->

io:fwrite(" Deallocating IPs and deleting Pool: (~p)...", [Pool]),

component_call(Pool, deallocateAll, []),

component_call(get_pool_parent(Pool),

deleteSubPool, [Pool]),

io:fwrite("done.~n", []);

true -> ok

end.

app_ip_pools_with_allocations(Cleanup) ->

%% There is at least one way in which we can have IP allocations set on

%% the application ip subpool. If a customer adds a range to a grid

%% and subsequently resizes that range such that it is smaller than the

%% previous range, andy excess IP allocation on the grid subpool will be

%% transferred up to the application ip subbpool because the grid code was

%% (prior to the fix for bug 7721 in 3.5.2) calling setPoolRanges prior

%% to deallocating IPs from the pool. The implementation of setPoolRanges

%% transfers the excess allocations to its parent pool, which in this case

%% is the application ip subpool. Unfortunately, the there is no customer-

%% accessible method to deallocate these IP addresses from the application

%% IP pool and they are left unable to delete the network due to these

%% allocations. This function will (if called with cleanup = true) find

%% any such pools in the system and deallocate the erroneously allocated IPs

BadAppPools =

lists:filter(

fun(P) ->

D = binary_to_list(property_get(P, ?DESIGNATOR)),

Allocs = property_get(P, ?ALLOCATION_MAP),

D =:= ?GRID_APPLICATION_IP_SUBPOOL andalso Allocs =/= []

end,

get_pools()),

case BadAppPools of

[] ->

io:fwrite("~nNO APPLICATION IP POOLS WITH INVALID ALLOCATIONS~n~n",

[]);

_ ->

io:fwrite("~nAPPLICATION IP POOLS WITH INVALID ALLOCATIONS:~n", [])

end,

[show_pool(P, Cleanup) || P <- BadAppPools].

show_pool(P, Cleanup) ->

D = binary_to_list(property_get(P, ?DESIGNATOR)),

TopPool = get_top_pool(P),

VLAN = binary_to_list(property_get(TopPool, ?DESIGNATOR)),

Ranges = string_pool_ranges(property_get(P, ?POOL_RANGES)),

Res = string_pool_ranges(property_get(P, ?RESERVED_RANGES)),

UnRes = string_pool_ranges(property_get(P, ?UNRESERVED_RANGES)),

{Allocs, AllocPools} =

string_alloc_ranges(P, property_get(P, ?ALLOCATION_MAP)),

io:fwrite(" Application IP Pool...~n", []),

io:fwrite(" IP Pool ID: (~p) ~s~n", [P,D]),

case VLAN of

?SUBNET_DEFAULT -> ok;

_ -> io:fwrite(" VLAN: ~s~n", [VLAN])

end,

io:fwrite(" Total Pool Ranges: ~p~n", [Ranges]),

io:fwrite(" Reserved IP Ranges: ~p~n", [Res]),

io:fwrite(" Unreserved IP Ranges: ~p~n", [UnRes]),

io:fwrite(" Allocation Pools: ~p~n", [Allocs]),

io:fwrite(" IP Allocations: ~p~n~n", [AllocPools]),

if Cleanup ->

deallocate_all(P);

true -> ok

end.

deallocate_all(P) ->

io:fwrite("Cleaning up application IP pool: ~p ...", [P]),

component_call(P, deallocateAll, []),

io:fwrite(" Done~n~n", []).

string_pool_ranges(Ranges) ->

[{binary_to_list(S), binary_to_list(E)} || {S, E} <- Ranges].

string_alloc_ranges(P, Allocs) ->

{Ranges, AllocPools} =

lists:mapfoldl(

fun({IPBin, AP}, Acc) ->

IP = binary_to_list(IPBin),

{{IP, IP},

case lists:member(AP, Acc) of

true -> Acc;

_ -> [AP|Acc]

end}

end,

[], Allocs),

{AllocPools, component_call(P, combineRanges, [lists:reverse(Ranges)])}.

get_pool_parent(Pool) ->

Ancestry = property_get(Pool, ?ANCESTRY),

case orddict:size(Ancestry) of

0 -> none;

_ -> orddict:fetch(1, Ancestry)

end.

get_top_pool(Pool) ->

Ancestry = property_get(Pool, ?ANCESTRY),

case orddict:size(Ancestry) of

0 -> Pool;

Num -> orddict:fetch(Num, Ancestry)

end.

is_grid_pool(Designator) ->

string:str(Designator, "GridIpPool") =/= 0.

grid_exists(Grid) ->

lists:member(Grid, get_instances(?GRID)).

get_pools() ->

get_instances(?IP_RESERVATION_POOL).

get_instances(Name) ->

rpc:call(bfcnode(), component_impl, instances_for_component_type, [Name]).

component_call(Id, Op, Args) ->

rpc:call(bfcnode(), component, call, [Id, Op, Args]).

property_get(Id, Name) ->

case rpc:call(bfcnode(), property, get, [Id, Name]) of

{value, Value} -> Value;

none -> none

end.

bfcnode() ->

list_to_atom(

lists:concat(["bfc@", string:strip(os:cmd("hostname -s"), right, $\n)])).

usage() ->

io:fwrite("usage: cleanup_ip_pools show|cleanup~n"

"Show all IP Reservation Pools for which the owning Grid "

"has been deleted or where IP allocations exist erroneously. "

"Delete the orphaned pools and deallocate the allocated IP "

"addresses if the 'cleanup' option is passed.~n", []),

halt(1).