using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Amazon.Common.DotNetCli.Tools;
using Amazon.Common.DotNetCli.Tools.Options;
using Amazon.Lambda.Model;
using ThirdParty.Json.LitJson;
namespace Amazon.Lambda.Tools.Commands
{
///
/// Get the current configuration for a deployed function
///
public class GetFunctionConfigCommand : LambdaBaseCommand
{
public const string COMMAND_NAME = "get-function-config";
public const string COMMAND_DESCRIPTION = "Command to get the current runtime configuration for a Lambda function";
public const string COMMAND_ARGUMENTS = " The name of the function to get the configuration for";
public static readonly IList GetConfigCommandOptions = BuildLineOptions(new List
{
LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME
});
public string FunctionName { get; set; }
public GetFunctionConfigCommand(IToolLogger logger, string workingDirectory, string[] args)
: base(logger, workingDirectory, GetConfigCommandOptions, args)
{
}
///
/// Parse the CommandOptions into the Properties on the command.
///
///
protected override void ParseCommandArguments(CommandOptions values)
{
base.ParseCommandArguments(values);
if (values.Arguments.Count > 0)
{
this.FunctionName = values.Arguments[0];
}
Tuple tuple;
if ((tuple = values.FindCommandOption(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME.Switch)) != null)
this.FunctionName = tuple.Item2.StringValue;
}
protected override async Task PerformActionAsync()
{
GetFunctionConfigurationResponse response;
var functionName = this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, true);
try
{
response = await this.LambdaClient.GetFunctionConfigurationAsync(functionName);
}
catch (Exception e)
{
throw new LambdaToolsException("Error getting configuration for Lambda function: " + e.Message, LambdaToolsException.LambdaErrorCode.LambdaGetConfiguration, e);
}
const int PAD_SIZE = 30;
this.Logger.WriteLine("Name:".PadRight(PAD_SIZE) + response.FunctionName);
this.Logger.WriteLine("Arn:".PadRight(PAD_SIZE) + response.FunctionArn);
if(!string.IsNullOrEmpty(response.Description))
this.Logger.WriteLine("Description:".PadRight(PAD_SIZE) + response.Description);
this.Logger.WriteLine("Package Type:".PadRight(PAD_SIZE) + response.PackageType);
if (response.PackageType == PackageType.Image)
{
if(response.ImageConfigResponse?.ImageConfig?.Command?.Count > 0)
this.Logger.WriteLine("Image Command:".PadRight(PAD_SIZE) + FormatAsJsonStringArray(response.ImageConfigResponse?.ImageConfig?.Command));
if (response.ImageConfigResponse?.ImageConfig?.EntryPoint?.Count > 0)
this.Logger.WriteLine("Image EntryPoint:".PadRight(PAD_SIZE) + FormatAsJsonStringArray(response.ImageConfigResponse?.ImageConfig?.EntryPoint));
if (!string.IsNullOrEmpty(response.ImageConfigResponse?.ImageConfig?.WorkingDirectory))
this.Logger.WriteLine("Image WorkingDirectory:".PadRight(PAD_SIZE) + response.ImageConfigResponse?.ImageConfig?.WorkingDirectory);
}
else
{
this.Logger.WriteLine("Runtime:".PadRight(PAD_SIZE) + response.Runtime);
this.Logger.WriteLine("Function Handler:".PadRight(PAD_SIZE) + response.Handler);
}
this.Logger.WriteLine("Last Modified:".PadRight(PAD_SIZE) + response.LastModified);
this.Logger.WriteLine("Memory Size:".PadRight(PAD_SIZE) + response.MemorySize);
if(response.EphemeralStorage != null)
{
this.Logger.WriteLine("Ephemeral Storage Size:".PadRight(PAD_SIZE) + response.EphemeralStorage.Size);
}
this.Logger.WriteLine("Role:".PadRight(PAD_SIZE) + response.Role);
this.Logger.WriteLine("Timeout:".PadRight(PAD_SIZE) + response.Timeout);
this.Logger.WriteLine("Version:".PadRight(PAD_SIZE) + response.Version);
this.Logger.WriteLine("State:".PadRight(PAD_SIZE) + response.State);
if(!string.IsNullOrEmpty(response.StateReason))
this.Logger.WriteLine("State Reason:".PadRight(PAD_SIZE) + response.StateReason);
this.Logger.WriteLine("Last Update Status:".PadRight(PAD_SIZE) + response.LastUpdateStatus);
if (!string.IsNullOrEmpty(response.LastUpdateStatusReason))
this.Logger.WriteLine("Last Update Status Reason:".PadRight(PAD_SIZE) + response.LastUpdateStatusReason);
if (!string.IsNullOrEmpty(response.KMSKeyArn))
this.Logger.WriteLine("KMS Key ARN:".PadRight(PAD_SIZE) + response.KMSKeyArn);
else
this.Logger.WriteLine("KMS Key ARN:".PadRight(PAD_SIZE) + "(default) aws/lambda");
if(!string.IsNullOrEmpty(response.DeadLetterConfig?.TargetArn))
{
this.Logger.WriteLine("Dead Letter Target:".PadRight(PAD_SIZE) + response.DeadLetterConfig.TargetArn);
}
if (response.Environment?.Variables?.Count > 0)
{
StringBuilder sb = new StringBuilder();
foreach(var kvp in response.Environment.Variables)
{
if (sb.Length > 0)
sb.Append(";");
sb.Append($"{kvp.Key}={kvp.Value}");
}
this.Logger.WriteLine("Environment Vars:".PadRight(PAD_SIZE) + sb);
}
if (response.VpcConfig != null && !string.IsNullOrEmpty(response.VpcConfig.VpcId))
{
this.Logger.WriteLine("VPC Config");
this.Logger.WriteLine(" VPC: ".PadRight(22) + response.VpcConfig.VpcId);
this.Logger.WriteLine(" Security Groups: ".PadRight(22) + string.Join(",", response.VpcConfig?.SecurityGroupIds));
this.Logger.WriteLine(" Subnets: ".PadRight(22) + string.Join(",", response.VpcConfig?.SubnetIds));
}
var urlConfig = await GetFunctionUrlConfigAsync(functionName);
if(urlConfig != null)
{
this.Logger.WriteLine("Function Url Config");
this.Logger.WriteLine(" Url: ".PadRight(PAD_SIZE) + urlConfig.FunctionUrl);
this.Logger.WriteLine(" Auth: ".PadRight(PAD_SIZE) + urlConfig.AuthType.Value);
}
return true;
}
private async Task GetFunctionUrlConfigAsync(string functionName)
{
try
{
var urlConfig = (await this.LambdaClient.GetFunctionUrlConfigAsync(new GetFunctionUrlConfigRequest { FunctionName = functionName }));
return urlConfig;
}
catch (AmazonLambdaException ex) when (ex.StatusCode == HttpStatusCode.NotFound || ex.StatusCode == HttpStatusCode.Unauthorized)
{
return null;
}
catch (Exception e)
{
throw new LambdaToolsException("Error getting configuration url config for Lambda function: " + e.Message, LambdaToolsException.LambdaErrorCode.LambdaGetConfiguration, e);
}
}
private static string FormatAsJsonStringArray(IList items)
{
if (items.Count == 0)
return null;
var sb = new StringBuilder();
sb.Append("[");
foreach(var token in items)
{
if(sb.Length > 1)
{
sb.Append(", ");
}
sb.Append("\"" + token + "\"");
}
sb.Append("]");
return sb.ToString();
}
protected override void SaveConfigFile(JsonData data)
{
data.SetIfNotNull(LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME.ConfigFileKey, this.GetStringValueOrDefault(this.FunctionName, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_NAME, false));
}
}
}