Cake build script calling AWS.ElasticBeanstalk DescribeEnvironments() throwing MissingMethodException

224 Views Asked by At

This is a very specific error, I have spent the last several days investigating it but have hit a dead end.

A task in my cake build script is trying to check if the elastic beanstalk environment is ready. We have been using this addin (https://github.com/mathieukempe/Cake.AWS.ElasticBeanstalk) I forked the repo to add the DescribeEnvironments() implementation. The addin code works if I run it directly in a console app. However when I run it from the cake build script it throws System.MissingMethodException: Method not found: 'System.String Amazon.Runtime.Internal.Util.StringUtils.FromDateTimeToISO8601(System.DateTime)' and unfortunately I think I am the only person on the internet having this problem.

Below is the task my cake script is running:

Task("CheckEBEnvironment")
.Does((context) => {
    var settings = CreateElasticBeanstalkSettings();
    if (context.ApplicationVersionReady(settings, ebApplication, ebEnvironment, ebVersion)) {
        Information("Environment ready.");
        isReady = true;
    } else {
        Information("Environment not ready...");
    } 
});

and below is the addin code:

[CakeAliasCategory("AWS")]
[CakeNamespaceImport("Amazon")]
[CakeNamespaceImport("Amazon.ElasticBeanstalk")]
public static class ElasticBeanstalkAliases
{
    private static IElasticBeanstalkManager CreateManager(this ICakeContext context)
    {
        return new ElasticBeanstalkManager(context.Environment, context.Log);
    }

    // ...

    [CakeMethodAlias]
    [CakeAliasCategory("ElasticBeanstalk")]
    public static bool ApplicationVersionReady(this ICakeContext context, ElasticBeanstalkSettings settings, string applicationName, string environmentName, string versionLabel)
    {
        var manager = context.CreateManager();
        return manager.ApplicationVersionReady(settings, applicationName, environmentName, versionLabel);
    }
}

Here is the implementation:

public class ElasticBeanstalkManager : IElasticBeanstalkManager
{
    private readonly ICakeEnvironment _Environment;
    private readonly ICakeLog _Log;

    /// <summary>
    /// If the manager should output progrtess events to the cake log
    /// </summary>
    public bool LogProgress { get; set; }

    public ElasticBeanstalkManager(ICakeEnvironment environment, ICakeLog log)
    {
        if (environment == null)
        {
            throw new ArgumentNullException("environment");
        }
        if (log == null)
        {
            throw new ArgumentNullException("log");
        }

        _Environment = environment;
        _Log = log;

        this.LogProgress = true;
    }

    //Request
    private AmazonElasticBeanstalkClient GetClient(ElasticBeanstalkSettings settings)
    {
        if (settings == null)
        {
            throw new ArgumentNullException("settings");
        }

        if (settings.Region == null)
        {
            throw new ArgumentNullException("settings.Region");
        }

        if (settings.Credentials == null)
        {
            if (String.IsNullOrEmpty(settings.AccessKey))
            {
                throw new ArgumentNullException("settings.AccessKey");
            }
            if (String.IsNullOrEmpty(settings.SecretKey))
            {
                throw new ArgumentNullException("settings.SecretKey");
            }

            return new AmazonElasticBeanstalkClient(settings.AccessKey, settings.SecretKey, settings.Region);
        }
        else
        {
            return new AmazonElasticBeanstalkClient(settings.Credentials, settings.Region);
        }
    }

    public bool ApplicationVersionReady(ElasticBeanstalkSettings settings, string applicationName, string environmentName, string versionLabel)
    {
        if (string.IsNullOrEmpty(applicationName))
        {
            throw new ArgumentNullException(nameof(applicationName));
        }

        if (string.IsNullOrEmpty(environmentName))
        {
            throw new ArgumentNullException(nameof(environmentName));
        }

        if (string.IsNullOrEmpty(versionLabel))
        {
            throw new ArgumentNullException(nameof(versionLabel));
        }

        var client = GetClient(settings);
        var status = client.DescribeEnvironmentsAsync(new DescribeEnvironmentsRequest
        {
            ApplicationName = applicationName,
            EnvironmentNames = new List<string>(new[] {environmentName}),
            VersionLabel = versionLabel,
            IncludeDeleted = false,
        }).Result.Environments[0].Status.Value;

        return status == "Ready";
    }
}

Here is the entire exception message:

System.AggregateException: One or more errors occurred. ---> System.MissingMethodException: Method not found: 'System.String Amazon.Runtime.Internal.Util.StringUtils.FromDateTimeToISO8601(System.DateTime)'. at Amazon.ElasticBeanstalk.Model.Internal.MarshallTransformations.DescribeEnvironmentsRequestMarshaller.Marshall(DescribeEnvironmentsRequest publicRequest) at Amazon.Runtime.Internal.Marshaller.PreInvoke(IExecutionContext executionContext) at Amazon.Runtime.Internal.Marshaller.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.CallbackHandler.d__91.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.ErrorCallbackHandler.<InvokeAsync>d__51.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.MetricsHandler.d__11.MoveNext() --- End of inner exception stack trace --- at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) at Cake.AWS.ElasticBeanstalk.ElasticBeanstalkManager.ApplicationVersionReady(ElasticBeanstalkSettings settings, String applicationName, String environmentName, String versionLabel) at Submission#0.<>b__0_11(ICakeContext context) ---> (Inner Exception #0) System.MissingMethodException: Method not found: 'System.String Amazon.Runtime.Internal.Util.StringUtils.FromDateTimeToISO8601(System.DateTime)'. at Amazon.ElasticBeanstalk.Model.Internal.MarshallTransformations.DescribeEnvironmentsRequestMarshaller.Marshall(DescribeEnvironmentsRequest publicRequest) at Amazon.Runtime.Internal.Marshaller.PreInvoke(IExecutionContext executionContext) at Amazon.Runtime.Internal.Marshaller.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.CallbackHandler.d__91.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.ErrorCallbackHandler.<InvokeAsync>d__51.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.MetricsHandler.d__1`1.MoveNext()<---

My guess is that the cake context is somewhere setting a date time on the request which is in a formate that Amazon can't handle. If anyone has any ideas or has come accross a similar issue I would be very grateful.

2

There are 2 best solutions below

0
On BEST ANSWER

I figured out the issue. I was using two addins the first is Cake.AWS.S3 the second is Cake.AWS.ElasticBeanstalk and since the S3 addin was defined first when cake needed to reference the AWSSDK.Core.dll it would use the .dll the S3 addin provided which happened to be an older version than the ElasticBeanstalk addin was expecting, resulting in it calling a method that doesn't exist.

If I simply define the Cake.AWS.ElasticBeanstalk addin first it works. I may submit a pull request to upgrade S3 addin's AWSSDK.Core.dll

1
On

My guess is, that you are missing some dependencies.

As the error states, the method Amazon.Runtime.Internal.Util.StringUtils.FromDateTimeToISO8601(System.DateTime) can not be found. Looking at the Cake addin you mentioned, on nuget.org it shows that it has some dependencies to the AWSSDK.Core and AWSSDK.ElasticBeanstalk packages. And on the github project of the first one you can see, that this is where the method is implemented.

So I guess that you don't specify those dependencies when building your forked addin and therefor the error occurs. If you build a nuget package, add those packages as dependencies (the same way the original addin does).