#!/usr/bin/env escript
%% -*- erlang -*-
%%%! -sname gridos_util
%%-------------------------------------------------------
%%
%% Copyright 2010, CA Incorporated. All rights reserved.
%%
%% $Id:$
%%
%%-------------------------------------------------------
-module(gridos_util).
-export([main/1]).
%%
%% Defines
%%
-define(GRIDOS_XEN_RESOURCE_DRIVER, 'core/bbc.gridos_xen.resource.driver').
-define(GRIDOS_ESX_RESOURCE_DRIVER, 'core/bbc.gridos_esx.resource.driver').
-define(GRIDOS_BACKBONE_IP, 'bbc/properties.gridos_backbone_ip').
-define(GRIDOS_VERSION, 'bbc/properties.gridos_version').
-define(GRID_VERSION_RESOURCE, 'bbc/applogic_version_resource').
-define(GRID_VERSION_NAME, 'bbc/properties.grid_version_name').
-define(GRID_VERSION_ESX_ENABLED, 'bbc/properties.grid_version_esx_enabled').
-define(STATE_INFO, 'core/properties.component_state_information').
-define(GRIDOS_XEN_SERVICE_DRIVER, 'core/bbc.gridos_xen.service.driver').
-define(GRIDOS_ESX_SERVICE_DRIVER, 'core/bbc.gridos_esx.service.driver').
-define(GRIDOS_SERVICE_DEPLOYER_TIMEOUT,
'core/gridos.service.deployer.timeout').
-define(GRIDOS_SERVICE_DEPLOYER_RETRIES,
'core/gridos.service.deployer.retries').
list_timeouts() ->
FmtStr = "~-5s ~-20s ~-8s ~-8s~n",
io:format("GridOS Service Timeouts~n~n"),
io:format(FmtStr, ["id", "service", "timeout", "retries"]),
lists:foreach(
fun(GridOSService) ->
[GridOSId] = instances_for_component_type(GridOSService),
%io:format("GridOS ESX Service Timeouts: ~p:~p~n",
% [GridOSService, GridOSId]),
Timeout = property_get(GridOSId, ?GRIDOS_SERVICE_DEPLOYER_TIMEOUT),
Retries = property_get(GridOSId, ?GRIDOS_SERVICE_DEPLOYER_RETRIES),
% io:format(" timeout: ~p~n", [Timeout]),
% io:format(" retries: ~p~n", [Retries]),
io:format(FmtStr, [integer_to_list(GridOSId),
GridOSService,
integer_to_list(Timeout),
integer_to_list(Retries)]),
ok
end,
[?GRIDOS_XEN_SERVICE_DRIVER, ?GRIDOS_ESX_SERVICE_DRIVER]),
ok.
list_versions() ->
FmtStr = "~-5s ~-7s ~-6s ~s~n",
io:format(FmtStr, ["id", "name", "esx", "resource state"]),
lists:foreach(
fun(VersId) ->
io:format(FmtStr, [
integer_to_list(VersId),
property_get(VersId, ?GRID_VERSION_NAME),
property_get(VersId, ?GRID_VERSION_ESX_ENABLED),
get_state(VersId)
])
end,
instances_for_component_type(?GRID_VERSION_RESOURCE)),
ok.
list_gridos_servers() ->
FmtStr = "~-5s ~-5s ~-14s ~-7s ~-25s ~-40s~n",
io:format(FmtStr, ["id", "type", "backbone ip", "version",
"resource state", "info"]),
ESXIds = instances_for_component_type(?GRIDOS_ESX_RESOURCE_DRIVER),
display_each_instance(ESXIds, "esx", FmtStr),
XenIds = instances_for_component_type(?GRIDOS_XEN_RESOURCE_DRIVER),
display_each_instance(XenIds, "xen", FmtStr),
ok.
display_each_instance([], _Type, _FmtStr) ->
ok;
display_each_instance([Id|Tail], Type, FmtStr)->
IP = property:array_get(1, property_get(Id, ?GRIDOS_BACKBONE_IP)),
io:format(FmtStr, [integer_to_list(Id), Type, IP,
property_get(Id, ?GRIDOS_VERSION), get_state(Id),
get_state_info_msg(Id)]),
display_each_instance(Tail, Type, FmtStr).
update_timeoutes(Options) ->
GridOSServiceId = orddict:fetch(gridosserviceid, Options),
TimeoutValue = orddict:fetch(timeoutvalue, Options),
RetriesValue = orddict:fetch(retriesvalue, Options),
update_timeouts(GridOSServiceId, TimeoutValue, RetriesValue),
ok.
update_timeouts(Id, undefined, undefined) ->
io:format("Undefined,Undefined~n"),
throw({badarg, "GridOS Service Id specified without either a "
"Timeout or a Retries value",
{id, Id}});
update_timeouts(Id, Timeout, undefined) ->
property_set(Id, ?GRIDOS_SERVICE_DEPLOYER_TIMEOUT, Timeout);
update_timeouts(Id, undefined, Retries) ->
property_set(Id, ?GRIDOS_SERVICE_DEPLOYER_RETRIES, Retries);
update_timeouts(Id, Timeout, Retries) ->
property_set(Id, ?GRIDOS_SERVICE_DEPLOYER_TIMEOUT, Timeout),
property_set(Id, ?GRIDOS_SERVICE_DEPLOYER_RETRIES, Retries).
release(Options) ->
ComponentId = orddict:fetch(id, Options),
io:format("Releasing component: ~b~n", [ComponentId]),
% validate it is a existing component id
CurState = get_state(ComponentId),
case CurState of
{badrpc, Error} ->
io:format("Error: component id not valid: ~n~p~n", [Error]),
throw({release_failed, Error});
_ ->
ok
end,
% release it
Result = rpc:call(get(nodename), find, release, [ComponentId]),
io:format("release result: ~p~n", [Result]),
ok.
send_event(Options) ->
CompId = orddict:fetch(id, Options),
EventName = case orddict:fetch(eventname, Options) of
undefined ->
io:format("Error: --send-event=<id> requires "
"the --event=<event_name> option~n"),
throw({no_event_name});
Name -> list_to_atom(Name)
end,
Result = component_send_event(CompId, EventName),
io:format("Sending event ~p to component ~p -> Result: ~p~n",
[EventName, CompId, Result]),
ok.
allocate_esx(Options) ->
LicenseKey = case orddict:fetch(licensekey, Options) of
undefined ->
io:format("Error: ESX GridOS servers require a "
"<licenseKey>~n"),
throw({no_license_key});
Key -> Key
end,
allocate_gridos(Options, ?GRIDOS_ESX_RESOURCE_DRIVER, LicenseKey).
allocate_xen(Options) ->
allocate_gridos(Options, ?GRIDOS_XEN_RESOURCE_DRIVER, "undefined").
allocate_gridos(Options, Type, LicenseKey) ->
GridOSId = rpc:call(get(nodename), find, find_confirmed, [Type]),
case GridOSId of
none ->
io:format("Error: allocation failed.~n"),
throw({allocation_failed});
_ ->
io:format("[id:~p] AllocateGridOS complete~n", [GridOSId])
end,
component_call(GridOSId, setGridVersion, [orddict:fetch(versid, Options)]),
component_call(GridOSId, setLicenseKey, [LicenseKey]),
component_send_event(GridOSId, resource_start_event),
io:format("[id:~p] resource_start_event sent, "
"polling for running state...~n", [GridOSId]),
wait_for_running_or_failed(GridOSId, get_state(GridOSId), "GridOS"),
component_call(GridOSId, setInGrid, [true]),
ok.
get_state_info_msg(Id) ->
StateInfo = property_get(Id, ?STATE_INFO),
case property_get(Id, ?STATE_INFO) of
none -> "";
StateInfo -> orddict:fetch(<<"fmt">>, StateInfo)
end.
wait_for_running_or_failed(Id, resource_running_state, ResourceName) ->
io:format("~s:~p has reached the Running state~n", [ResourceName, Id]),
ok;
wait_for_running_or_failed(Id, resource_failed_state, ResourceName) ->
io:format("Error: ~s:~p has reached the Failed state, info: ~s~n",
[ResourceName, Id, get_state_info_msg(Id)]),
throw({gridos_failed_node, Id});
wait_for_running_or_failed(Id, State, ResourceName) ->
io:format("[id:~p][~s] -> ~-28s:~-45s~n",
[Id, time_stamp(), State, get_state_info_msg(Id)]),
timer:sleep(30*1000), % pause 30 seconds
wait_for_running_or_failed(Id, get_state(Id), ResourceName).
activate_esx(Options) ->
VersId = orddict:fetch(versid, Options),
EsxCD = case orddict:fetch(esxCD, Options) of
undefined ->
io:format("Error: --esx-cd <...> not specified, required "
"for --activate-esx~n"),
throw({activate_esx_failed});
E -> E
end,
verboseMsg("activate_esx(vers=~b, esxcd=~s)~n", [VersId, EsxCD], Options),
Res = component_call(VersId, importEsxVersion, [EsxCD]),
verboseMsg("result: ~p~n", [Res], Options).
upgrade_gridos(Options) ->
GridOSID = orddict:fetch(id, Options),
VersId = case orddict:fetch(upgradeVers, Options) of
undefined ->
io:format("Error: --upgrade-vers <versid> not specified, required "
"for --upgrade...~n"),
throw(upgrade_failed);
VId -> VId
end,
io:format("Upgrading Gridos:~b -> ~b~n", [GridOSID, VersId]),
Res = component_call(GridOSID, upgrade, [VersId]),
verboseMsg("result: ~p~n", [Res], Options).
import_version(Options) ->
VersId = orddict:fetch(versid, Options),
component_send_event(VersId, resource_start_event),
io:format("[id:~p] resource_start_event sent, "
"polling for running state...~n", [VersId]),
wait_for_running_or_failed(VersId, get_state(VersId), "Version").
time_stamp() ->
{H, M, S} = time(),
io_lib:format("~2.10.0b:~2.10.0b:~2.10.0b", [H, M, S]).
%%
%% BFC Access
%%
property_get(Id, Name) ->
case rpc:call(get(nodename), property, get, [Id, Name]) of
{value, Value} -> Value;
none -> none
end.
property_set(Id, Name, Value) ->
rpc:call(get(nodename), property, set, [Id, Name, Value]).
get_state(Id) ->
rpc:call(get(nodename), component, get_state, [Id]).
instances_for_component_type(Type) ->
rpc:call(get(nodename), component_impl, instances_for_component_type,
[Type]).
component_call(Id, Op, Args) ->
rpc:call(get(nodename), component, call, [Id, Op, Args]).
component_send_event(Id, Event) ->
rpc:call(get(nodename), component, send_event, [Id, Event]).
%%
%% Options Parsing
%%
parse_opts(Args) ->
Options = orddict:from_list([
{verbose, false},
{help, false},
{allocateXen, false},
{allocateESX, false},
{versid, undefiend},
{release, false},
{licensekey, undefined},
{importVersion, false},
{activateEsx, false},
{esxCD, undefined},
{upgrade, false},
{upgradeVers, undefined},
{listgridos, false},
{listversions, false},
{sendevent, false},
{eventname, undefined},
{listtimeouts, false},
{gridosserviceid, undefined},
{timeoutvalue, undefined},
{retriesvalue, undefined}
]),
parse_opts(Args, Options).
parse_opts(["-h"|Tail], Options) ->
parse_opts(Tail, orddict:store(help, true, Options));
parse_opts(["--help"|Tail], Options) ->
parse_opts(Tail, orddict:store(help, true, Options));
parse_opts(["--verbose"|Tail], Options) ->
parse_opts(Tail, orddict:store(verbose, true, Options));
parse_opts(["--list-gridos"|Tail], Options) ->
parse_opts(Tail, orddict:store(listgridos, true, Options));
parse_opts(["--list-versions"|Tail], Options) ->
parse_opts(Tail, orddict:store(listversions, true, Options));
parse_opts(["--license-key=" ++ LicKey|Tail], Options) ->
parse_opts(Tail,
parse_str_arg(LicKey, licensekey, "--license-key", Options));
parse_opts(["--import-version=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, versid, "--import-version",
orddict:store(importVersion, true, Options)));
parse_opts(["--activate-esx=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, versid, "--activate-esx",
orddict:store(activateEsx, true, Options)));
parse_opts(["--esx-cd=" ++ EsxCd|Tail], Options) ->
parse_opts(Tail, parse_str_arg(EsxCd, esxCD, "--esx-cd=", Options));
parse_opts(["--allocate-xen=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, versid, "--allocate-xen=",
orddict:store(allocateXen, true, Options)));
parse_opts(["--allocate-esx=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, versid, "--allocate-esx=",
orddict:store(allocateESX, true, Options)));
parse_opts(["--upgrade=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, id, "--upgrade",
orddict:store(upgrade, true, Options)));
parse_opts(["--upgrade-vers=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, 'upgradeVers', "--upgrade-vers=", Options));
parse_opts(["--release=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, id, "--release=",
orddict:store(release, true, Options)));
parse_opts(["--send-event=" ++ Id|Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, id, "--send-event=",
orddict:store(sendevent, true, Options)));
parse_opts(["--event=" ++ EventName|Tail], Options) ->
parse_opts(Tail,
parse_str_arg(EventName, eventname, "--event=", Options));
parse_opts(["--list-timeouts"|Tail], Options) ->
parse_opts(Tail, orddict:store(listtimeouts, true, Options));
parse_opts(["--gridos-service-id=" ++ Id | Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Id, gridosserviceid, "--grid-service-id=",
Options));
parse_opts(["--set-timeout=" ++ Val | Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Val, timeoutvalue, "--set-timeout=", Options));
parse_opts(["--set-retries=" ++ Val | Tail], Options) ->
parse_opts(Tail,
parse_int_arg(Val, retriesvalue, "--set-retries=", Options));
parse_opts([BadOpt| _Tail], _Options) ->
io:format("Error: unexpected option: ~s~n", [BadOpt]),
usage(),
throw({badoption, BadOpt});
parse_opts([], Options) ->
Options.
parse_str_arg(Str, OptKey, OptTag, Options) ->
case Str of
[] ->
io:format("Error: no ~s spefieid for ~s~n", [OptKey, OptTag]),
throw({badoptions, missing_arg});
_ -> orddict:store(OptKey, Str, Options)
end.
parse_int_arg(IntStr, OptKey, OptTag, Options) ->
case string:to_integer(IntStr) of
{error, _} ->
io:format("Error: bad ~s listed for ~s~n", [OptKey, OptTag]),
usage(),
throw({badoption, bad_versid});
{Int, _Rest} ->
orddict:store(OptKey, Int, Options)
end;
parse_int_arg([], OptKey, OptTag, _Options) ->
io:format("Error: no ~s listed for ~s~n", [OptKey, OptTag]),
usage(),
throw({badoption, no_versid}).
help() ->
usage(),
halt(1).
usage() ->
io:format(
"Usage: gridos_util [Options]~n"
" --help~n"
" This usage message~n"
" --list-gridos~n"
" List all GridOs Resources~n"
" --list-versions~n"
" List all Versions~n"
" --import-version=<versId>~n"
" Import a specific version, driving it to the running~n"
" state.~n"
" --activate-esx=<versId>~n"
" Activate ESX for a specific <versId>, you must~n"
" also specify the --esx-cd ... option when~n"
" doing this~n"
" --esx-cd=<pathToEsxCdimage>~n"
" Path to ESX Install CD, to be used with~n"
" --activate-esx...~n"
" --allocate-xen=<versId>~n"
" Allocate a Xen based GridOS resource and drive it to~n"
" the running state. The version to be installed is~n"
" <versId>~n"
" --allocate-esx=<versId>~n"
" Allocate a ESX based GridOS resource and drive it to~n"
" the running state. The version to be installed is~n"
" <versid>. ESX also requires that you specify~n"
" a <licenseKey>~n"
" --license-key=<LicenseKey>~n"
" A license key to be given to a GridOS resource durring~n"
" allocation.~n"
" --upgrade=<id>~n"
" Upgrade a GridOS resource <id> to a new version,~n"
" The new version is identified by --upgrade-vers=<id>~n"
" --upgrade-vers=<versid>~n"
" New version to upgrade to~n"
" --release=<id>~n"
" Release the specified component and its~n"
" assocaited hardware~n"
" --send-event=<id>~n"
" Send a event to the component <id>. The event~n"
" sent is identified by the --event=<event_name>~n"
" arguement, this option is required.~n"
" --event=<event_name>~n"
" Name of event to be sent.~n"
" --list-timeouts~n"
" List ESX and Xen GridOS timeouts and retry counts~n"
" --gridos-service-id=<id>~n"
" ID of GridOS Service to be updates, see set-timeout~n"
" and set-retries~n"
" --set-timeout=<value>~n"
" Set timeout of GridOS Service to <value>~n"
" --set-retries=<value>~n"
" Set retries of GridOS Service to <value>~n"
).
verboseMsg(FmtStr, Args, Options) ->
Verbose = orddict:fetch(verbose, Options),
if
Verbose -> io:format(FmtStr, Args);
true -> ok
end.
set_node_name(Options) ->
{N1, N2, N3} = now(),
MyNode = "gridos_util" ++ integer_to_list(N1) ++
integer_to_list(N2) ++ integer_to_list(N3),
verboseMsg("NodeName: ~s~n", [MyNode], Options),
net_kernel:start([list_to_atom(MyNode), shortnames]).
%%
%% Main
%%
main(Args) ->
Options = try parse_opts(Args)
catch throw:_ -> halt(1)
end,
verboseMsg("Options: ~p~n", [Options], Options),
set_node_name(Options),
NodeName = list_to_atom("bfc@" ++
string:strip(os:cmd("hostname -s"), right, $\n)),
put(nodename, NodeName),
HelpOption = orddict:fetch(help, Options),
ListGridOS = orddict:fetch(listgridos, Options),
ListVersions = orddict:fetch(listversions, Options),
AllocateXen = orddict:fetch(allocateXen, Options),
AllocateESX = orddict:fetch(allocateESX, Options),
Release = orddict:fetch(release, Options),
ImportVersion = orddict:fetch(importVersion, Options),
ActivateEsx = orddict:fetch(activateEsx, Options),
Upgrade = orddict:fetch(upgrade, Options),
SendEvent = orddict:fetch(sendevent, Options),
ListTimeouts = orddict:fetch(listtimeouts, Options),
UpdateTimeouts =
case orddict:fetch(gridosserviceid, Options) of
undefined -> false;
_ -> true
end,
try
if
HelpOption -> help();
ListGridOS -> list_gridos_servers();
ListVersions -> list_versions();
ListTimeouts -> list_timeouts();
Release -> release(Options);
AllocateXen -> allocate_xen(Options);
AllocateESX -> allocate_esx(Options);
ImportVersion -> import_version(Options);
ActivateEsx -> activate_esx(Options);
Upgrade -> upgrade_gridos(Options);
SendEvent -> send_event(Options);
UpdateTimeouts -> update_timeoutes(Options);
true ->
io:format("Error: no options specified~n"),
usage()
end
catch throw:Msg ->
io:format("Failure Thrown: ~p~n", [Msg]),
halt(1)
end,
halt(0).
|
Copyright © 2013 CA Technologies.
All rights reserved.
|
|