#!/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).
|
Copyright © 2012 CA.
All rights reserved.
|
|