public async Task ApplyConfigurationsAsync_OneClusterOneDestinationOneRoute_Works()
        {
            // Arrange
            const string TestAddress = "https://localhost:123/";

            var cluster = new Cluster
            {
                Destinations = {
                    { "d1", new Destination { Address = TestAddress } }
                }
            };
            var route = new ParsedRoute
            {
                RouteId = "route1",
                ClusterId = "cluster1",
            };

            var dynamicConfigRoot = new DynamicConfigRoot
            {
                Clusters = new Dictionary<string, Cluster> { { "cluster1", cluster }  },
                Routes = new[] { route },
            };
            Mock<IDynamicConfigBuilder>()
                .Setup(d => d.BuildConfigAsync(It.IsAny<CancellationToken>()))
                .ReturnsAsync(dynamicConfigRoot);

            var proxyManager = Create<ReverseProxyConfigManager>();

            // Act
            await proxyManager.ApplyConfigurationsAsync(CancellationToken.None);

            // Assert

            var actualClusters = _clusterManager.GetItems();
            Assert.Single(actualClusters);
            Assert.Equal("cluster1", actualClusters[0].ClusterId);
            Assert.NotNull(actualClusters[0].DestinationManager);
            Assert.NotNull(actualClusters[0].Config.Value);

            var actualDestinations = actualClusters[0].DestinationManager.GetItems();
            Assert.Single(actualDestinations);
            Assert.Equal("d1", actualDestinations[0].DestinationId);
            Assert.NotNull(actualDestinations[0].Config);
            Assert.Equal(TestAddress, actualDestinations[0].Config.Address);

            var actualRoutes = _routeManager.GetItems();
            Assert.Single(actualRoutes);
            Assert.Equal("route1", actualRoutes[0].RouteId);
            Assert.NotNull(actualRoutes[0].Config.Value);
            Assert.Same(actualClusters[0], actualRoutes[0].Config.Value.Cluster);
        }
예제 #2
0
        private void CreateEndpoints()
        {
            var routes    = _routeManager.GetItems();
            var endpoints = new List <Endpoint>(routes.Count);

            foreach (var existingRoute in routes)
            {
                // Only rebuild the endpoint for modified routes or clusters.
                var endpoint = existingRoute.CachedEndpoint;
                if (endpoint == null)
                {
                    endpoint = _proxyEndpointFactory.CreateEndpoint(existingRoute.Config, _conventions);
                    existingRoute.CachedEndpoint = endpoint;
                }
                endpoints.Add(endpoint);
            }

            UpdateEndpoints(endpoints);
        }
        public async Task ApplyConfigurationsAsync_OneBackendOneEndpointOneRoute_Works()
        {
            // Arrange
            const string TestAddress = "https://localhost:123/";

            var backend = new Backend
            {
                Endpoints =
                {
                    { "ep1", new BackendEndpoint {
                          Address = TestAddress
                      } }
                }
            };
            var route = new ParsedRoute
            {
                RouteId   = "route1",
                BackendId = "backend1",
            };

            var dynamicConfigRoot = new DynamicConfigRoot
            {
                Backends = new Dictionary <string, Backend> {
                    { "backend1", backend }
                },
                Routes = new[] { route },
            };

            Mock <IDynamicConfigBuilder>()
            .Setup(d => d.BuildConfigAsync(It.IsAny <IConfigErrorReporter>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(Result.Success(dynamicConfigRoot));

            var errorReporter = new TestConfigErrorReporter();
            var proxyManager  = Create <ReverseProxyConfigManager>();

            // Act
            var result = await proxyManager.ApplyConfigurationsAsync(errorReporter, CancellationToken.None);

            // Assert
            Assert.True(result);

            var actualBackends = _backendManager.GetItems();

            Assert.Single(actualBackends);
            Assert.Equal("backend1", actualBackends[0].BackendId);
            Assert.NotNull(actualBackends[0].EndpointManager);
            Assert.NotNull(actualBackends[0].Config.Value);

            var actualEndpoints = actualBackends[0].EndpointManager.GetItems();

            Assert.Single(actualEndpoints);
            Assert.Equal("ep1", actualEndpoints[0].EndpointId);
            Assert.NotNull(actualEndpoints[0].Config.Value);
            Assert.Equal(TestAddress, actualEndpoints[0].Config.Value.Address);

            var actualRoutes = _routeManager.GetItems();

            Assert.Single(actualRoutes);
            Assert.Equal("route1", actualRoutes[0].RouteId);
            Assert.NotNull(actualRoutes[0].Config.Value);
            Assert.Same(actualBackends[0], actualRoutes[0].Config.Value.BackendOrNull);
        }
예제 #4
0
        private void UpdateRuntimeRoutes(DynamicConfigRoot config)
        {
            var desiredRoutes = new HashSet <string>(StringComparer.Ordinal);
            var changed       = false;

            foreach (var configRoute in config.Routes)
            {
                desiredRoutes.Add(configRoute.RouteId);

                // Note that this can be null, and that is fine. The resulting route may match
                // but would then fail to route, which is exactly what we were instructed to do in this case
                // since no valid backend was specified.
                var backendOrNull = _backendManager.TryGetItem(configRoute.BackendId);

                _routeManager.GetOrCreateItem(
                    itemId: configRoute.RouteId,
                    setupAction: route =>
                {
                    var currentRouteConfig = route.Config.Value;
                    if (currentRouteConfig == null ||
                        currentRouteConfig.HasConfigChanged(configRoute, backendOrNull))
                    {
                        // Config changed, so update runtime route
                        changed = true;
                        if (currentRouteConfig == null)
                        {
                            _logger.LogDebug("Route {routeId} has been added.", configRoute.RouteId);
                        }
                        else
                        {
                            _logger.LogDebug("Route {routeId} has changed.", configRoute.RouteId);
                        }

                        var newConfig      = _routeEndpointBuilder.Build(configRoute, backendOrNull, route);
                        route.Config.Value = newConfig;
                    }
                });
            }

            foreach (var existingRoute in _routeManager.GetItems())
            {
                if (!desiredRoutes.Contains(existingRoute.RouteId))
                {
                    // NOTE 1: This is safe to do within the `foreach` loop
                    // because `IRouteManager.GetItems` returns a copy of the list of routes.
                    //
                    // NOTE 2: Removing the route from `IRouteManager` is safe and existing
                    // ASP .NET Core endpoints will continue to work with their existing behavior since
                    // their copy of `RouteConfig` is immutable and remains operational in whichever state is was in.
                    _logger.LogDebug("Route {routeId} has been removed.", existingRoute.RouteId);
                    _routeManager.TryRemoveItem(existingRoute.RouteId);
                    changed = true;
                }
            }

            if (changed)
            {
                var aspNetCoreEndpoints = new List <AspNetCore.Http.Endpoint>();
                foreach (var existingRoute in _routeManager.GetItems())
                {
                    var runtimeConfig = existingRoute.Config.Value;
                    if (runtimeConfig?.AspNetCoreEndpoints != null)
                    {
                        aspNetCoreEndpoints.AddRange(runtimeConfig.AspNetCoreEndpoints);
                    }
                }

                // This is where the new routes take effect!
                _dynamicEndpointDataSource.Update(aspNetCoreEndpoints);
            }
        }