Current section

Files

Jump to
erlcloud src erlcloud_as.erl
Raw

src/erlcloud_as.erl

-module(erlcloud_as).
-include_lib("erlcloud/include/erlcloud_aws.hrl").
-include_lib("erlcloud/include/erlcloud_as.hrl").
%% AWS Autoscaling functions
-export([describe_groups/0, describe_groups/1, describe_groups/2, describe_groups/4,
set_desired_capacity/2, set_desired_capacity/3, set_desired_capacity/4,
describe_launch_configs/0, describe_launch_configs/1, describe_launch_configs/2,
describe_launch_configs/4,
describe_instances/0, describe_instances/1, describe_instances/2,
describe_instances/4,
terminate_instance/1, terminate_instance/2, terminate_instance/3,
suspend_processes/1, suspend_processes/2, suspend_processes/3,
resume_processes/1, resume_processes/2, resume_processes/3,
detach_instances/2, detach_instances/3, detach_instances/4]).
-define(API_VERSION, "2011-01-01").
-define(DEFAULT_MAX_RECORDS, 20).
% xpath for group descriptions used in describe_groups functions:
-define(DESCRIBE_GROUPS_PATH,
"/DescribeAutoScalingGroupsResponse/DescribeAutoScalingGroupsResult/AutoScalingGroups/member").
-define(DESCRIBE_GROUPS_NEXT_TOKEN,
"/DescribeAutoScalingGroupsResponse/DescribeAutoScalingGroupsResult/NextToken").
% xpath for the request ID returned from a SetDesiredCapacity operation:
-define(SET_SCALE_REQUEST_ID_PATH, "/SetDesiredCapacityResponse/ResponseMetadata/RequestId").
%% xpath for launch config functions:
-define(DESCRIBE_LAUNCH_CONFIG_PATH,
"/DescribeLaunchConfigurationsResponse/DescribeLaunchConfigurationsResult/LaunchConfigurations/member").
-define(LAUNCH_CONFIG_NEXT_TOKEN,
"/DescribeLaunchConfigurationsResponse/DescribeLaunchConfigurationsResult/NextToken").
%% xpath for autoscaling instance description:
-define(DESCRIBE_INSTANCES,
"/DescribeAutoScalingInstancesResponse/DescribeAutoScalingInstancesResult/AutoScalingInstances/member").
-define(DESCRIBE_INSTANCES_NEXT_TOKEN,
"/DescribeAutoScalingInstancesResponse/DescribeAutoScalingInstancesResult/NextToken").
%% xpath for terminate instance:
-define(TERMINATE_INSTANCE_ACTIVITY,
"/TerminateInstanceInAutoScalingGroupResponse/TerminateInstanceInAutoScalingGroupResult/Activity").
%% xpath for suspend and resume ScalingProcesses:
-define(SUSPEND_PROCESSES_ACTIVITY,
"/SuspendProcessesResponse/ResponseMetadata/RequestId").
-define(RESUME_PROCESSES_ACTIVITY,
"/ResumeProcessesResponse/ResponseMetadata/RequestId").
%% xpath for detach instances:
-define(DETACH_INSTANCES_ACTIVITY,
"/DetachInstancesResponse/DetachInstancesResult/Activities/member").
%% --------------------------------------------------------------------
%% @doc Calls describe_groups([], default_configuration())
%% @end
%% --------------------------------------------------------------------
describe_groups() ->
describe_groups([], erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc describe_groups with a specific configuration OR with a
%% specific list of members.
%% @end
%% --------------------------------------------------------------------
describe_groups(Config) when is_record(Config, aws_config) ->
describe_groups([], Config);
describe_groups(GroupNames) ->
describe_groups(GroupNames, erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Get descriptions of the given autoscaling groups.
%% The account calling this function needs permission for the
%% autoscaling:DescribeAutoScalingGroups action.
%%
%% Returns {{paged, NextPageId}, Results} if there are more than
%% the current maximum count of results, {ok, Results} if everything
%% fits and {error, Reason} if there was a problem.
%% @end
%% --------------------------------------------------------------------
-spec describe_groups(list(string()), aws_config()) ->
{ok, term()} | {{paged, string()}, term()} | {error, term()}.
describe_groups(GN, Config) ->
describe_groups(GN, ?DEFAULT_MAX_RECORDS, none, Config).
%% --------------------------------------------------------------------
%% @doc Get descriptions of the given autoscaling groups with a given
%% maximum number of results and optional paging offset.
%% @end
%% --------------------------------------------------------------------
-spec describe_groups(list(string()), integer(), string() | none, aws_config()) ->
{ok, term()} | {{paged, string()}, term()} | {error, term()}.
describe_groups(GN, MaxRecords, none, Config) ->
describe_groups(GN, [{"MaxRecords", MaxRecords}], Config);
describe_groups(GN, MaxRecords, NextToken, Config) ->
describe_groups(GN, [{"NextToken", NextToken}, {"MaxRecords", MaxRecords}], Config).
-spec describe_groups(list(string()), list({string(), term()}), aws_config()) ->
{ok, term()} | {{paged, string()}, term()} | {error, term()}.
describe_groups(GN, Params, Config) ->
P = member_params("AutoScalingGroupNames.member.", GN) ++ Params,
case as_query(Config, "DescribeAutoScalingGroups", P, ?API_VERSION) of
{ok, Doc} ->
Groups = xmerl_xpath:string(?DESCRIBE_GROUPS_PATH, Doc),
{next_token(?DESCRIBE_GROUPS_NEXT_TOKEN, Doc), [extract_group(G) || G <- Groups]};
{error, Reason} ->
{error, Reason}
end.
%% retrieve NextToken from the XML at Path location. Path is expected to lead to a
%% single occurrence and if it does not exist as such, this just returns ok.
-spec next_token(string(), term()) -> ok | {paged, string()}.
next_token(Path, XML) ->
case xmerl_xpath:string(Path, XML) of
[Next] ->
{paged, erlcloud_xml:get_text(Next)};
_ ->
ok
end.
extract_instance(I) ->
extract_instance(I, erlcloud_xml:get_text("AutoScalingGroupName", I)).
extract_instance(I, GroupName) ->
#aws_autoscaling_instance{
instance_id = erlcloud_xml:get_text("InstanceId", I),
launch_config_name = erlcloud_xml:get_text("LaunchConfigurationName", I),
group_name = GroupName,
availability_zone = erlcloud_xml:get_text("AvailabilityZone", I),
health_status = erlcloud_xml:get_text("HealthStatus", I),
lifecycle_state = erlcloud_xml:get_text("LifecycleState", I)
}.
extract_group(G) ->
#aws_autoscaling_group{
group_name = erlcloud_xml:get_text("AutoScalingGroupName", G),
tags = extract_tags_from_group(G),
availability_zones =
[erlcloud_xml:get_text(A) || A <- xmerl_xpath:string("AvailabilityZones/member", G)],
load_balancer_names =
[erlcloud_xml:get_text(L) || L <- xmerl_xpath:string("LoadBalancerNames/member", G)],
instances =
[extract_instance(I, group_name) || I <- xmerl_xpath:string("Instances/member", G)],
desired_capacity = erlcloud_xml:get_integer("DesiredCapacity", G),
min_size = erlcloud_xml:get_integer("MinSize", G),
max_size = erlcloud_xml:get_integer("MaxSize", G)}.
extract_tags_from_group(G) ->
[{erlcloud_xml:get_text("Key", T), erlcloud_xml:get_text("Value", T)} ||
T <- xmerl_xpath:string("Tags/member", G)].
%% --------------------------------------------------------------------
%% @doc set_desired_capacity(GroupName, Capacity, false, default_config())
%% @end
%% --------------------------------------------------------------------
-spec set_desired_capacity(string(), integer()) -> {ok, string()} | {error, term()}.
set_desired_capacity(GroupName, Capacity) ->
set_desired_capacity(GroupName, Capacity, false, erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc set_desired_capacity(GroupName, Capacity, false, Config)
%% @end
%% --------------------------------------------------------------------
-spec set_desired_capacity(string(), integer(), aws_config()) -> {ok, string()} | {error, term()}.
set_desired_capacity(GroupName, Capacity, Config) ->
set_desired_capacity(GroupName, Capacity, false, Config).
%% --------------------------------------------------------------------
%% @doc Change the desired capacity of the given autoscaling group,
%% optionally ignoring cooldown periods (set false to basically force
%% change).
%% Requires permission for the autoscaling:SetDesiredCapacity action.
%% @end
%% --------------------------------------------------------------------
-spec set_desired_capacity(string(), integer(), boolean(), aws_config()) -> {ok, string()} | {error, term()}.
set_desired_capacity(GroupName, Capacity, HonorCooldown, Config) ->
Params = [{"AutoScalingGroupName", GroupName},
{"DesiredCapacity", Capacity},
{"HonorCooldown", HonorCooldown}],
case as_query(Config, "SetDesiredCapacity", Params, ?API_VERSION) of
{ok, Doc} ->
[RequestId] = xmerl_xpath:string(?SET_SCALE_REQUEST_ID_PATH, Doc),
{ok, erlcloud_xml:get_text(RequestId)};
{error, Reason} ->
{error, Reason}
end.
describe_launch_configs() ->
describe_launch_configs([], erlcloud_aws:default_config()).
describe_launch_configs(Config) when is_record(Config, aws_config) ->
describe_launch_configs([], Config);
describe_launch_configs(GroupNames) ->
describe_launch_configs(GroupNames, erlcloud_aws:default_config()).
describe_launch_configs(LN, Config) ->
describe_launch_configs(LN, ?DEFAULT_MAX_RECORDS, none, Config).
%% --------------------------------------------------------------------
%% @doc Get descriptions of the given launch configurations with a given
%% maximum number of results and optional paging offset.
%% Pass an empty list of names to get all.
%% @end
%% --------------------------------------------------------------------
describe_launch_configs(LN, MaxRecords, none, Config) ->
describe_launch_configs(LN, [{"MaxRecords", MaxRecords}], Config);
describe_launch_configs(LN, MaxRecords, NextToken, Config) ->
describe_launch_configs(LN, [{"MaxRecords", MaxRecords}, {"NextToken", NextToken}], Config).
-spec describe_launch_configs(list(string()), list({string(), term()}), aws_config()) ->
{ok, list(aws_launch_config())} |
{{paged, string()}, list(aws_launch_config)} |
{error, term()}.
describe_launch_configs(LN, Params, Config) ->
P = member_params("LaunchConfigurationNames.member.", LN) ++ Params,
case as_query(Config, "DescribeLaunchConfigurations", P, ?API_VERSION) of
{ok, Doc} ->
Status = next_token(?LAUNCH_CONFIG_NEXT_TOKEN, Doc),
Configs = [extract_config(C) || C <- xmerl_xpath:string(?DESCRIBE_LAUNCH_CONFIG_PATH, Doc)],
{Status, Configs};
{error, Reason} ->
{error, Reason}
end.
%% --------------------------------------------------------------------
%% @doc describe_instances([], default max results, no paging offset, default config).
%% @end
%% --------------------------------------------------------------------
describe_instances() ->
describe_instances([], erlcloud_aws:default_config()).
describe_instances(I, Config) ->
describe_instances(I, ?DEFAULT_MAX_RECORDS, none, Config).
describe_instances(Config) when is_record(Config, aws_config) ->
describe_instances([], Config);
describe_instances(I) ->
describe_instances(I, erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Get more information on the given list of instances in your
%% autoscaling groups or all if an empty list is passed in I.
%% @end
%% --------------------------------------------------------------------
describe_instances(I, MaxRecords, none, Config) ->
describe_instances(I, [{"MaxRecords", MaxRecords}], Config);
describe_instances(I, MaxRecords, NextToken, Config) ->
describe_instances(I, [{"MaxRecords", MaxRecords}, {"NextToken", NextToken}], Config).
-spec describe_instances(list(string()), list({string(), term()}), aws_config()) ->
{ok, list(aws_launch_config())} |
{{paged, string()}, list(aws_launch_config)} |
{error, term()}.
describe_instances(I, Params, Config) ->
P = member_params("InstanceIds.member.", I) ++ Params,
case as_query(Config, "DescribeAutoScalingInstances", P, ?API_VERSION) of
{ok, Doc} ->
Status = next_token(?DESCRIBE_INSTANCES_NEXT_TOKEN, Doc),
Instances = [extract_instance(ID) || ID <- xmerl_xpath:string(?DESCRIBE_INSTANCES, Doc)],
{Status, Instances};
{error, Reason} ->
{error, Reason}
end.
%% --------------------------------------------------------------------
%% @doc Terminate the given instance using the default configuration
%% without decrementing the desired capacity of the group.
%% @end
%% --------------------------------------------------------------------
-spec terminate_instance(string()) -> aws_autoscaling_activity().
terminate_instance(InstanceId) ->
terminate_instance(InstanceId, erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Terminate the given instance. The 2nd parameter can be:
%% 'false' to not decrement the desired capacity of the group
%% 'true' to decrement the desired capacity of the group
%% Config a supplied AWS configuration.
%% @end
%% --------------------------------------------------------------------
terminate_instance(InstanceId, false) ->
terminate_instance(InstanceId, false, erlcloud_aws:default_config());
terminate_instance(InstanceId, true) ->
terminate_instance(InstanceId, true, erlcloud_aws:default_config());
terminate_instance(InstanceId, Config) ->
terminate_instance(InstanceId, false, Config).
terminate_instance(InstanceId, false, Config) ->
priv_terminate_instance([{"InstanceId", InstanceId}, {"ShouldDecrementDesiredCapacity", "false"}], Config);
terminate_instance(InstanceId, true, Config) ->
priv_terminate_instance([{"InstanceId", InstanceId}, {"ShouldDecrementDesiredCapacity", "true"}], Config).
priv_terminate_instance(Params, Config) ->
case as_query(Config, "TerminateInstanceInAutoScalingGroup", Params, ?API_VERSION) of
{ok, Doc} ->
[Activity] = [extract_as_activity(A) || A <- xmerl_xpath:string(?TERMINATE_INSTANCE_ACTIVITY, Doc)],
{ok, Activity};
{error, Reason} ->
{error, Reason}
end.
%% --------------------------------------------------------------------
%% @doc Suspends Auto Scaling processes for the specified
%% Auto Scaling group. To suspend specific processes, use the
%% ScalingProcesses parameter. To suspend all processes, omit the
%% ScalingProcesses parameter.
%% @end
%% --------------------------------------------------------------------
-spec suspend_processes(string()) -> {ok, string()} | {error, term()}.
suspend_processes(GroupName) ->
suspend_processes(GroupName, [], erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Suspend the processes. The 2nd parameter can be used to specify
%% a list of ScalingProcesses or [] to suspend all
%% Config a supplied AWS configuration.
%% @end
%% --------------------------------------------------------------------
suspend_processes(GroupName, Config) when is_record(Config, aws_config) ->
suspend_processes(GroupName, [], Config);
suspend_processes(GroupName, ScalingProcesses) when is_list(ScalingProcesses) ->
suspend_processes(GroupName, ScalingProcesses, erlcloud_aws:default_config()).
-spec suspend_processes(string(), list(string()), aws_config()) -> {ok, string()} | {error, term()}.
suspend_processes(GroupName, ScalingProcesses, Config) ->
Params = [{"AutoScalingGroupName", GroupName} | member_params("ScalingProcesses.member.", ScalingProcesses)],
case as_query(Config, "SuspendProcesses", Params, ?API_VERSION) of
{ok, Doc} ->
[RequestId] = xmerl_xpath:string(?SUSPEND_PROCESSES_ACTIVITY, Doc),
{ok, erlcloud_xml:get_text(RequestId)};
{error, Reason} ->
{error, Reason}
end.
%% --------------------------------------------------------------------
%% @doc Resumes Auto Scaling processes for the specified
%% Auto Scaling group. To resume specific processes, use the
%% ScalingProcesses parameter. To resume all processes, omit the
%% ScalingProcesses parameter.
%% @end
%% --------------------------------------------------------------------
-spec resume_processes(string()) -> {ok, string()} | {error, term()}.
resume_processes(GroupName) ->
resume_processes(GroupName, [], erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Resume the processes. The 2nd parameter can be used to specify
%% a list of ScalingProcesses or [] to resume all
%% Config a supplied AWS configuration.
%% @end
%% --------------------------------------------------------------------
resume_processes(GroupName, Config) when is_record(Config, aws_config) ->
resume_processes(GroupName, [], Config);
resume_processes(GroupName, ScalingProcesses) when is_list(ScalingProcesses) ->
resume_processes(GroupName, ScalingProcesses, erlcloud_aws:default_config()).
-spec resume_processes(string(), list(string()), aws_config()) -> {ok, string()} | {error, term()}.
resume_processes(GroupName, ScalingProcesses, Config) ->
Params = [{"AutoScalingGroupName", GroupName} | member_params("ScalingProcesses.member.", ScalingProcesses)],
case as_query(Config, "ResumeProcesses", Params, ?API_VERSION) of
{ok, Doc} ->
[RequestId] = xmerl_xpath:string(?RESUME_PROCESSES_ACTIVITY, Doc),
{ok, erlcloud_xml:get_text(RequestId)};
{error, Reason} ->
{error, Reason}
end.
%% --------------------------------------------------------------------
%% @doc Detach the given instances from the group using the default configuration
%% without decrementing the desired capacity of the group.
%% @end
%% --------------------------------------------------------------------
-spec detach_instances(list(string()),string()) -> aws_autoscaling_activity().
detach_instances(InstanceIds, GroupName) ->
detach_instances(InstanceIds, GroupName, erlcloud_aws:default_config()).
%% --------------------------------------------------------------------
%% @doc Detach the given instances from the group. The 3rd parameter can be:
%% 'false' to not decrement the desired capacity of the group
%% 'true' to decrement the desired capacity of the group
%% Config a supplied AWS configuration.
%% @end
%% --------------------------------------------------------------------
-spec detach_instances(list(string()),string(), boolean() | aws_config()) -> aws_autoscaling_activity().
detach_instances(InstanceIds, GroupName, ShouldDecrementDesiredCapacity) when is_boolean(ShouldDecrementDesiredCapacity) ->
detach_instances(InstanceIds, GroupName, ShouldDecrementDesiredCapacity, erlcloud_aws:default_config());
detach_instances(InstanceIds, GroupName, Config) ->
detach_instances(InstanceIds, GroupName, false, Config).
-spec detach_instances(list(string()),string(), boolean(), aws_config()) -> aws_autoscaling_activity().
detach_instances(InstanceIds, GroupName, ShouldDecrementDesiredCapacity, Config) ->
P = case ShouldDecrementDesiredCapacity of
true ->
[{"ShouldDecrementDesiredCapacity", "true"}, {"AutoScalingGroupName", GroupName} | member_params("InstanceIds.member.", InstanceIds)];
false ->
[{"ShouldDecrementDesiredCapacity", "false"}, {"AutoScalingGroupName", GroupName} | member_params("InstanceIds.member.", InstanceIds)]
end,
case as_query(Config, "DetachInstances", P, ?API_VERSION) of
{ok, Doc} ->
Activities = [extract_as_activity(A) || A <- xmerl_xpath:string(?DETACH_INSTANCES_ACTIVITY, Doc)],
{ok, Activities};
{error, Reason} ->
{error, Reason}
end.
%% given a list of member identifiers, return a list of
%% {key with prefix, member identifier} for use in autoscaling calls.
%% Example pair that could be returned in a list is
%% {"LaunchConfigurationNames.member.1", "my-launch-config}.
-spec member_params(string(), list(string())) -> list({string(), term()}).
member_params(Prefix, MemberIdentifiers) ->
MemberKeys = [Prefix ++ integer_to_list(I) || I <- lists:seq(1, length(MemberIdentifiers))],
[{K, V} || {K, V} <- lists:zip(MemberKeys, MemberIdentifiers)].
extract_config(C) ->
#aws_launch_config{
name = erlcloud_xml:get_text("LaunchConfigurationName", C),
image_id = erlcloud_xml:get_text("ImageId", C),
tenancy = erlcloud_xml:get_text("PlacementTenancy", C),
instance_type = erlcloud_xml:get_text("InstanceType", C)
}.
extract_as_activity(A) ->
#aws_autoscaling_activity{
id = get_text("ActivityId", A),
group_name = get_text("AutoScalingGroupName", A),
cause = get_text("Cause", A),
description = get_text("Description", A),
details = get_text("Details", A),
status_code = get_text("StatusCode", A),
status_msg = get_text("StatusMessage", A),
start_time = erlcloud_xml:get_time("StartTime", A),
end_time = erlcloud_xml:get_time("EndTime", A),
progress = erlcloud_xml:get_integer("Progress", A)
}.
get_text(Label, Doc) ->
erlcloud_xml:get_text(Label, Doc).
%% Based on erlcoud_ec2:ec2_query2()
%% @TODO: spec is too general with terms I think
-spec as_query(aws_config(), string(), list({string(), term()}), string()) -> {ok, term()} | {error, term()}.
as_query(Config, Action, Params, ApiVersion) ->
QParams = [{"Action", Action}, {"Version", ApiVersion}|Params],
erlcloud_aws:aws_request_xml4(post, Config#aws_config.as_host,
"/", QParams, "autoscaling", Config).