Ejemplo n.º 1
0
        private async Task AttemptDeleteRepair(
            ContentTypeDefinition contentTypeDefinition,
            IContentItemVersion contentItemVersion,
            ValidateAndRepairResult result,
            ValidationFailure failure)
        {
            var deleteGraphSyncer = _serviceProvider.GetRequiredService <IDeleteGraphSyncer>();

            try
            {
                await deleteGraphSyncer.DeleteIfAllowed(failure.ContentItem, contentItemVersion, SyncOperation.Delete);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Repair of deleted {ContentItem} failed.", failure.ContentItem);
            }

            (bool validated, string?validationFailureReason) =
                await ValidateDeletedContentItem(failure.ContentItem, contentTypeDefinition, contentItemVersion);

            if (validated)
            {
                _logger.LogInformation("Repair was successful on deleted {ContentType} {ContentItemId} in {CurrentGraph}.",
                                       failure.ContentItem.ContentType,
                                       failure.ContentItem.ContentItemId,
                                       GraphDescription(_currentGraph !));
                result.Repaired.Add(new ValidatedContentItem(failure.ContentItem, ValidateType.Delete));
            }
            else
            {
                string message = $"Repair was unsuccessful.{Environment.NewLine}{{ValidationFailureReason}}.";
                _logger.LogWarning(message, validationFailureReason);
                result.RepairFailures.Add(new RepairFailure(failure.ContentItem, validationFailureReason !, ValidateType.Delete));
            }
        }
Ejemplo n.º 2
0
        private async Task AttemptRepair(
            IEnumerable <ValidationFailure> syncValidationFailures,
            ContentTypeDefinition contentTypeDefinition,
            IContentItemVersion contentItemVersion,
            ValidateAndRepairResult result)
        {
            _logger.LogWarning(
                "Content items of type {ContentTypeDefinitionName} failed validation ({ValidationFailures}). Attempting to repair them.",
                contentTypeDefinition.Name,
                string.Join(", ", syncValidationFailures.Select(f => f.ContentItem.ToString())));

            foreach (var failure in syncValidationFailures)
            {
                if (failure.Type == ValidateType.Merge)
                {
                    await AttemptMergeRepair(contentTypeDefinition, contentItemVersion, result, failure);
                }
                else
                {
                    await AttemptDeleteRepair(contentTypeDefinition, contentItemVersion, result, failure);
                }
            }
        }
Ejemplo n.º 3
0
        private async Task AttemptMergeRepair(
            ContentTypeDefinition contentTypeDefinition,
            IContentItemVersion contentItemVersion,
            ValidateAndRepairResult result,
            ValidationFailure failure)
        {
            var mergeGraphSyncer             = _serviceProvider.GetRequiredService <IMergeGraphSyncer>();
            IGraphReplicaSet graphReplicaSet = _currentGraph !.GetReplicaSetLimitedToThisGraph();

            try
            {
                await mergeGraphSyncer.SyncToGraphReplicaSetIfAllowed(graphReplicaSet, failure.ContentItem, _contentManager);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Repair of {ContentItem} in {GraphReplicaSet} failed.",
                                   failure.ContentItem, graphReplicaSet);
            }

            (bool validated, string?validationFailureReason) =
                await ValidateContentItem(failure.ContentItem, contentTypeDefinition, contentItemVersion);

            if (validated)
            {
                _logger.LogInformation("Repair was successful on {ContentType} {ContentItemId} in {CurrentGraph}.",
                                       failure.ContentItem.ContentType,
                                       failure.ContentItem.ContentItemId,
                                       GraphDescription(_currentGraph !));
                result.Repaired.Add(new ValidatedContentItem(failure.ContentItem));
            }
            else
            {
                string message = $"Repair was unsuccessful.{Environment.NewLine}{{ValidationFailureReason}}.";
                _logger.LogWarning(message, validationFailureReason);
                result.RepairFailures.Add(new RepairFailure(failure.ContentItem, validationFailureReason !));
            }
        }
Ejemplo n.º 4
0
        private async Task <IValidateAndRepairResults> ValidateGraphImpl(
            ValidationScope validationScope,
            params string[] graphReplicaSetNames)
        {
            IEnumerable <ContentTypeDefinition> syncableContentTypeDefinitions = _contentDefinitionManager
                                                                                 .ListTypeDefinitions()
                                                                                 .Where(x => x.Parts.Any(p => p.Name == nameof(GraphSyncPart)));

            DateTime timestamp = DateTime.UtcNow;

            IEnumerable <string> graphReplicaSetNamesToValidate = graphReplicaSetNames.Any()
                ? graphReplicaSetNames
                : _graphClusterLowLevel.GraphReplicaSetNames;

            DateTime validateFrom = await GetValidateFromTime(validationScope);

            var results = new ValidateAndRepairResults(validateFrom);

            //todo: we could optimise to only get content items from the oc database once for each replica set,
            // rather than for each instance
            foreach (string graphReplicaSetName in graphReplicaSetNamesToValidate)
            {
                IGraphReplicaSetLowLevel graphReplicaSetLowLevel = _graphClusterLowLevel.GetGraphReplicaSetLowLevel(graphReplicaSetName);
                IContentItemVersion      contentItemVersion      = _contentItemVersionFactory.Get(graphReplicaSetName);

                foreach (IGraph graph in graphReplicaSetLowLevel.GraphInstances)
                {
                    ValidateAndRepairResult result = results.AddNewValidateAndRepairResult(
                        graphReplicaSetName,
                        graph.Instance,
                        graph.Endpoint.Name,
                        graph.GraphName,
                        graph.DefaultGraph);

                    // make current graph available for when parts/fields call back into ValidateContentItem
                    // seems a little messy, and will make concurrent validation a pita,
                    // but stops part/field syncers needing low level graph access
                    _currentGraph = graph;

                    foreach (ContentTypeDefinition contentTypeDefinition in syncableContentTypeDefinitions)
                    {
                        List <ValidationFailure> syncFailures = await ValidateContentItemsOfContentType(
                            contentItemVersion,
                            contentTypeDefinition,
                            validateFrom,
                            result,
                            validationScope);

                        if (syncFailures.Any())
                        {
                            await AttemptRepair(syncFailures, contentTypeDefinition, contentItemVersion, result);
                        }
                    }
                }
            }

            if (results.AnyRepairFailures)
            {
                return(results);
            }

            _logger.LogInformation("Woohoo: graph passed validation or was successfully repaired at {Time}.",
                                   timestamp.ToString("O"));

            _session.Save(new AuditSyncLog(timestamp));
            await _session.CommitAsync();

            return(results);
        }
Ejemplo n.º 5
0
        private async Task <List <ValidationFailure> > ValidateContentItemsOfContentType(
            IContentItemVersion contentItemVersion,
            ContentTypeDefinition contentTypeDefinition,
            DateTime lastSynced,
            ValidateAndRepairResult result,
            ValidationScope scope)
        {
            List <ValidationFailure> syncFailures = new List <ValidationFailure>();

            (bool?latest, bool?published) = contentItemVersion.ContentItemIndexFilterTerms;

            //todo: do we want to batch up content items of type?
            IEnumerable <ContentItem> contentTypeContentItems = await _contentItemsService
                                                                .Get(contentTypeDefinition.Name, lastSynced, latest : latest, published : published);

            IEnumerable <ContentItem> deletedContentTypeContentItems = await _contentItemsService
                                                                       .GetDeleted(contentTypeDefinition.Name, lastSynced);

            if (!contentTypeContentItems.Any() && !deletedContentTypeContentItems.Any())
            {
                _logger.LogDebug("No {ContentType} content items found that require validation.", contentTypeDefinition.Name);
                return(syncFailures);
            }

            foreach (ContentItem contentItem in contentTypeContentItems)
            {
                (bool validated, string?validationFailureReason) =
                    await ValidateContentItem(contentItem, contentTypeDefinition, contentItemVersion);

                if (validated)
                {
                    _logger.LogInformation("Sync validation passed for {ContentType} {ContentItemId} in {CurrentGraph}.",
                                           contentItem.ContentType,
                                           contentItem.ContentItemId,
                                           GraphDescription(_currentGraph !));
                    result.Validated.Add(new ValidatedContentItem(contentItem));
                }
                else
                {
                    string message = $"Sync validation failed in {{CurrentGraph}}.{Environment.NewLine}{{ValidationFailureReason}}.";
                    _logger.LogWarning(message, GraphDescription(_currentGraph !), validationFailureReason);
                    ValidationFailure validationFailure = new ValidationFailure(contentItem, validationFailureReason !);
                    syncFailures.Add(validationFailure);
                    result.ValidationFailures.Add(validationFailure);
                }
            }

            if (scope == ValidationScope.ModifiedSinceLastValidation)
            {
                foreach (ContentItem contentItem in deletedContentTypeContentItems)
                {
                    (bool validated, string?validationFailureReason) =
                        await ValidateDeletedContentItem(contentItem, contentTypeDefinition, contentItemVersion);

                    if (validated)
                    {
                        _logger.LogInformation(
                            "Sync validation passed for deleted {ContentType} {ContentItemId} in {CurrentGraph}.",
                            contentItem.ContentType,
                            contentItem.ContentItemId,
                            GraphDescription(_currentGraph !));
                        result.Validated.Add(new ValidatedContentItem(contentItem, ValidateType.Delete));
                    }
                    else
                    {
                        string message =
                            $"Sync validation failed in {{CurrentGraph}}.{Environment.NewLine}{{validationFailureReason}}.";
                        _logger.LogWarning(message, GraphDescription(_currentGraph !), validationFailureReason);
                        ValidationFailure validationFailure = new ValidationFailure(contentItem,
                                                                                    validationFailureReason !, ValidateType.Delete);
                        syncFailures.Add(validationFailure);
                        result.ValidationFailures.Add(validationFailure);
                    }
                }
            }

            return(syncFailures);
        }