Example #1
0
        private static void AugmentEntity(CommandAuditEntity entity, Provider provider, ICommand command, ICommandResult commandResult)
        {
            var timestamp = DateTime.UtcNow;

            entity.Provider = provider.Id;
            entity.Command  = command.GetType().Name;
            entity.Project ??= command.ProjectId?.ToString();
            entity.Created ??= timestamp;

            if (commandResult != null)
            {
                entity.Status = commandResult.RuntimeStatus;

                if (commandResult.RuntimeStatus.IsFinal())
                {
                    entity.Sent ??= timestamp;
                    entity.Processed ??= timestamp;

                    if (commandResult.RuntimeStatus == CommandRuntimeStatus.Failed)
                    {
                        // the command ran into an error - trace the error in our audit log
                        entity.Errors = commandResult.Errors.Select(err => err.Message).ToArray();
                    }
                }
                else if (commandResult.RuntimeStatus.IsActive())
                {
                    // the provider returned an active state
                    // so we could set the sent state and
                    // tace the timeout returned by the provider

                    entity.Sent ??= timestamp;
                    entity.Timeout ??= timestamp + commandResult.Timeout;
                }
            }
        }
Example #2
0
    internal static string GetResultPath(this CommandAuditEntity commandAuditEntity)
    {
        if (commandAuditEntity is null)
        {
            throw new ArgumentNullException(nameof(commandAuditEntity));
        }

        return($"{ToPathSegmentSafe(commandAuditEntity.OrganizationId)}/{ToPathSegmentSafe(commandAuditEntity.ProjectId)}/{commandAuditEntity.CommandId}.{RESULT_QUALIFIER}.json");
    }
Example #3
0
        public static async Task RunActivity(
            [ActivityTrigger] IDurableActivityContext functionContext,
            [Table("AuditCommands")] CloudTable commandTable,
            ILogger log)
        {
            if (functionContext is null)
            {
                throw new ArgumentNullException(nameof(functionContext));
            }

            if (commandTable is null)
            {
                throw new ArgumentNullException(nameof(commandTable));
            }

            var(instanceId, provider, command, commandResult) =
                functionContext.GetInput <(string, Provider, ICommand, ICommandResult)>();

            try
            {
                var entity = new CommandAuditEntity()
                {
                    InstanceId = instanceId,
                    CommandId  = command.CommandId.ToString()
                };

                var entityResult = await commandTable
                                   .ExecuteAsync(TableOperation.Retrieve <CommandAuditEntity>(entity.TableEntity.PartitionKey, entity.TableEntity.RowKey))
                                   .ConfigureAwait(false);

                entity = entityResult.HttpStatusCode == (int)HttpStatusCode.OK
                    ? (CommandAuditEntity)entityResult.Result
                    : entity;

                AugmentEntity(entity, provider, command, commandResult);

                await commandTable
                .ExecuteAsync(TableOperation.InsertOrReplace(entity))
                .ConfigureAwait(false);
            }
            catch (Exception exc)
            {
                log.LogWarning(exc, $"Failed to audit command {command?.GetType().Name ?? "UNKNOWN"} ({command?.CommandId ?? Guid.Empty}) for provider {provider?.Id ?? "UNKNOWN"}");
            }
        }
        private static async Task WriteAuditTableAsync(IBinder binder, string prefix, ICommand command, ICommandResult commandResult, string providerId)
        {
            var entity = new CommandAuditEntity(command, providerId);

            var auditTable = await binder
                             .BindAsync <CloudTable>(new TableAttribute($"{prefix}Audit"))
                             .ConfigureAwait(false);

            var entityResult = await auditTable
                               .ExecuteAsync(TableOperation.Retrieve <CommandAuditEntity>(entity.TableEntity.PartitionKey, entity.TableEntity.RowKey))
                               .ConfigureAwait(false);

            if (entityResult.HttpStatusCode == (int)HttpStatusCode.OK)
            {
                entity = (entityResult.Result as CommandAuditEntity) ?? entity;
            }

            await auditTable
            .ExecuteAsync(TableOperation.InsertOrReplace(entity.Augment(command, commandResult)))
            .ConfigureAwait(false);
        }
Example #5
0
    public async Task <CommandAuditEntity> GetAsync(Guid organizationId, Guid commandId, bool includeJsonDumps = false)
    {
        var tableClient = await tableClientInstance
                          .EnsureTableAsync()
                          .ConfigureAwait(false);

        CommandAuditEntity entity = null;

        try
        {
            var response = await tableClient
                           .GetEntityAsync <CommandAuditEntity>(organizationId.ToString(), commandId.ToString())
                           .ConfigureAwait(false);

            entity = response.Value;
        }
        catch (RequestFailedException ex) when(ex.Status == 404)
        {
            // doesn't exist
            return(null);
        }

        if (entity is not null && includeJsonDumps)
        {
            var blobContainerClient = await blobContainerClientInstance
                                      .EnsureContainerAsync()
                                      .ConfigureAwait(false);

            await Task.WhenAll(

                ReadBlobAsync(blobContainerClient, entity.GetCommandPath())
                .ContinueWith(t => entity.CommandJson = t.Result, TaskContinuationOptions.OnlyOnRanToCompletion),

                ReadBlobAsync(blobContainerClient, entity.GetResultPath())
                .ContinueWith(t => entity.ResultJson = t.Result, TaskContinuationOptions.OnlyOnRanToCompletion)

                ).ConfigureAwait(false);
        }

        return(entity);
        private async Task WriteTableAsync(ICommand command, ICommandResult commandResult, string providerId)
        {
            var entity = new CommandAuditEntity(command, providerId);

            var auditTable = await GetAuditTableAsync()
                             .ConfigureAwait(false);

            var entityResult = await auditTable
                               .ExecuteAsync(TableOperation.Retrieve <CommandAuditEntity>(entity.PartitionKey, entity.RowKey))
                               .ConfigureAwait(false);

            if (entityResult.HttpStatusCode == (int)HttpStatusCode.OK)
            {
                entity = entityResult.Result as CommandAuditEntity ?? entity;
            }

            if (commandResult != null && !entity.RuntimeStatus.IsFinal())
            {
                entity.Created = GetTableStorageMinDate(entity.Created, commandResult.CreatedTime);
                entity.Updated = GetTableStorageMaxDate(entity.Updated, commandResult.LastUpdatedTime);

                entity.RuntimeStatus = commandResult.RuntimeStatus;
                entity.CustomStatus  = commandResult.CustomStatus ?? string.Empty;

                if (entity.RuntimeStatus.IsFinal())
                {
                    entity.Errors = string.Join(Environment.NewLine, commandResult.Errors.Select(error => $"[{error.Severity}] {error.Message}"));
                }

                if (!string.IsNullOrEmpty(entity.Provider))
                {
                    entity.Timeout ??= entity.Created?.Add(commandResult.Timeout);
                }
            }

            await auditTable
            .ExecuteAsync(TableOperation.InsertOrReplace(entity))
            .ConfigureAwait(false);