示例#1
0
        private async Task LoadApplicationDataAsync(Dictionary <string, string> data, ApplicationWrapper application, CancellationToken cancellationToken)
        {
            IEnumerable <ServiceWrapper> services;

            try
            {
                services = await _serviceFabricCaller.GetServiceListAsync(application.ApplicationName, cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                _logger.LogError(ex,
                                 $"Could not get service list for application {application.ApplicationName}, skipping application.");
                return;
            }

            var appId     = application.ApplicationName.ToString().Replace("fabric:/", string.Empty);
            var appPrefix =
                $"Fabric{ConfigurationPath.KeyDelimiter}Applications{ConfigurationPath.KeyDelimiter}{appId}{ConfigurationPath.KeyDelimiter}";

            data[$"{appPrefix}Id"]          = appId;
            data[$"{appPrefix}Name"]        = application.ApplicationName.ToString();
            data[$"{appPrefix}TypeName"]    = application.ApplicationTypeName;
            data[$"{appPrefix}TypeVersion"] = application.ApplicationTypeVersion;
            foreach (var parameter in application.ApplicationParameters)
            {
                var paramPrefix =
                    $"{appPrefix}Parameters{ConfigurationPath.KeyDelimiter}{parameter.Key}{ConfigurationPath.KeyDelimiter}";
                data[$"{paramPrefix}Name"]  = parameter.Key;
                data[$"{paramPrefix}Value"] = parameter.Value;
            }

            foreach (var service in services)
            {
                await LoadServiceDataAsync(data, application, appPrefix, service, cancellationToken);
            }
        }
示例#2
0
        /// <inheritdoc/>
        public async Task <(IReadOnlyList <RouteConfig> Routes, IReadOnlyList <ClusterConfig> Clusters)> DiscoverAsync(CancellationToken cancellation)
        {
            // Take a snapshot of current options and use that consistently for this execution.
            var options = _optionsMonitor.CurrentValue;

            _serviceFabricCaller.CleanUpExpired();

            var discoveredBackends = new Dictionary <string, ClusterConfig>(StringComparer.Ordinal);
            var discoveredRoutes   = new List <RouteConfig>();
            IEnumerable <ApplicationWrapper> applications;

            try
            {
                applications = await _serviceFabricCaller.GetApplicationListAsync(cancellation);
            }
            catch (OperationCanceledException) when(cancellation.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                // The serviceFabricCaller does their best effort to use LKG information, nothing we can do at this point
                Log.GettingApplicationFailed(_logger, ex);
                applications = Enumerable.Empty <ApplicationWrapper>();
            }

            foreach (var application in applications)
            {
                IEnumerable <ServiceWrapper> services;

                try
                {
                    services = await _serviceFabricCaller.GetServiceListAsync(application.ApplicationName, cancellation);
                }
                catch (OperationCanceledException) when(cancellation.IsCancellationRequested)
                {
                    throw;
                }
                catch (Exception ex) // TODO: davidni: not fatal?
                {
                    Log.GettingServiceFailed(_logger, application.ApplicationName, ex);
                    continue;
                }

                foreach (var service in services)
                {
                    try
                    {
                        var serviceExtensionLabels = await _serviceFabricExtensionConfigProvider.GetExtensionLabelsAsync(application, service, cancellation);

                        // If this service wants to use us as the proxy
                        if (serviceExtensionLabels.GetValueOrDefault("YARP.Enable", null) != "true")
                        {
                            // Skip this service
                            continue;
                        }

                        var destinations = await DiscoverDestinationsAsync(options, service, serviceExtensionLabels, cancellation);

                        var cluster = LabelsParser.BuildCluster(service.ServiceName, serviceExtensionLabels, destinations);
                        var clusterValidationErrors = await _configValidator.ValidateClusterAsync(cluster);

                        if (clusterValidationErrors.Count > 0)
                        {
                            throw new ConfigException($"Skipping cluster id '{cluster.ClusterId} due to validation errors.", new AggregateException(clusterValidationErrors));
                        }

                        if (!discoveredBackends.TryAdd(cluster.ClusterId, cluster))
                        {
                            throw new ConfigException($"Duplicated cluster id '{cluster.ClusterId}'. Skipping repeated definition, service '{service.ServiceName}'");
                        }

                        var routes = LabelsParser.BuildRoutes(service.ServiceName, serviceExtensionLabels);
                        var routeValidationErrors = new List <Exception>();
                        foreach (var route in routes)
                        {
                            routeValidationErrors.AddRange(await _configValidator.ValidateRouteAsync(route));
                        }

                        if (routeValidationErrors.Count > 0)
                        {
                            // Don't add ANY routes if even a single one is bad. Trying to add partial routes
                            // could lead to unexpected results (e.g. a typo in the configuration of higher-priority route
                            // could lead to a lower-priority route being selected for requests it should not be handling).
                            throw new ConfigException($"Skipping ALL routes for cluster id '{cluster.ClusterId} due to validation errors.", new AggregateException(routeValidationErrors));
                        }

                        discoveredRoutes.AddRange(routes);

                        ReportServiceHealth(options, service.ServiceName, HealthState.Ok, $"Successfully built cluster '{cluster.ClusterId}' with {routes.Count} routes.");
                    }
                    catch (ConfigException ex)
                    {
                        // User error
                        Log.InvalidServiceConfig(_logger, service.ServiceName, ex);

                        // TODO: emit Error health report once we are able to detect config issues *during* (as opposed to *after*) a target service upgrade.
                        // Proactive Error health report would trigger a rollback of the target service as desired. However, an Error report after rhe fact
                        // will NOT cause a rollback and will prevent the target service from performing subsequent monitored upgrades to mitigate, making things worse.
                        ReportServiceHealth(options, service.ServiceName, HealthState.Warning, $"Could not load service configuration: {ex.Message}.");
                    }
                    catch (Exception ex) // TODO: davidni: not fatal?
                    {
                        // Not user's problem
                        Log.ErrorLoadingServiceConfig(_logger, service.ServiceName, ex);
                    }
                }
            }

            Log.ServiceDiscovered(_logger, discoveredBackends.Count, discoveredRoutes.Count);
            return(discoveredRoutes, discoveredBackends.Values.ToList());
        }