diff --git a/docs/features/kubernetes.rst b/docs/features/kubernetes.rst index 11fbd71d..be23845b 100644 --- a/docs/features/kubernetes.rst +++ b/docs/features/kubernetes.rst @@ -75,3 +75,21 @@ The polling interval is in milliseconds and tells Ocelot how often to call kuber Please note there are tradeoffs here. If you poll kubernetes it is possible Ocelot will not know if a service is down depending on your polling interval and you might get more errors than if you get the latest services per request. This really depends on how volatile your services are. I doubt it will matter for most people and polling may give a tiny performance improvement over calling kubernetes per request. There is no way for Ocelot to work these out for you. + +If your downstream service resides in a different namespace you can override the global setting at the ReRoute level by specifying a ServiceNamespace + + +.. code-block:: json + +{ + "ReRoutes": [ + { + "DownstreamPathTemplate": "/api/values", + "DownstreamScheme": "http", + "UpstreamPathTemplate": "/values", + "ServiceName": "downstreamservice", + "ServiceNamespace": "downstream-namespace", + "UpstreamHttpMethod": [ "Get" ] + } + ] +} diff --git a/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs b/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs index cdf422b8..8cffa882 100644 --- a/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs +++ b/src/Ocelot.Provider.Consul/ConsulProviderFactory.cs @@ -6,13 +6,13 @@ public static class ConsulProviderFactory { - public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) => + public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) => { var factory = provider.GetService(); var consulFactory = provider.GetService(); - var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Host, config.Port, name, config.Token); + var consulRegistryConfiguration = new ConsulRegistryConfiguration(config.Host, config.Port, reRoute.ServiceName, config.Token); var consulServiceDiscoveryProvider = new Consul(consulRegistryConfiguration, factory, consulFactory); diff --git a/src/Ocelot.Provider.Eureka/EurekaProviderFactory.cs b/src/Ocelot.Provider.Eureka/EurekaProviderFactory.cs index 9fdea310..d9bba179 100644 --- a/src/Ocelot.Provider.Eureka/EurekaProviderFactory.cs +++ b/src/Ocelot.Provider.Eureka/EurekaProviderFactory.cs @@ -6,13 +6,13 @@ public static class EurekaProviderFactory { - public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) => + public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) => { var client = provider.GetService(); if (config.Type?.ToLower() == "eureka" && client != null) { - return new Eureka(name, client); + return new Eureka(reRoute.ServiceName, client); } return null; diff --git a/src/Ocelot.Provider.Kubernetes/KubeProvider.cs b/src/Ocelot.Provider.Kubernetes/KubeProvider.cs index b790c147..3083fb32 100644 --- a/src/Ocelot.Provider.Kubernetes/KubeProvider.cs +++ b/src/Ocelot.Provider.Kubernetes/KubeProvider.cs @@ -24,8 +24,7 @@ namespace Ocelot.Provider.Kubernetes public async Task> Get() { - var service = await kubeApi.ServicesV1() - .Get(kubeRegistryConfiguration.KeyOfServiceInK8s, kubeRegistryConfiguration.KubeNamespace); + var service = await kubeApi.ServicesV1().Get(kubeRegistryConfiguration.KeyOfServiceInK8s, kubeRegistryConfiguration.KubeNamespace); var services = new List(); if (IsValid(service)) { diff --git a/src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs b/src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs index c33839c6..f12d0ebc 100644 --- a/src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs +++ b/src/Ocelot.Provider.Kubernetes/KubernetesProviderFactory.cs @@ -3,24 +3,25 @@ using Microsoft.Extensions.DependencyInjection; using Ocelot.Logging; using Ocelot.ServiceDiscovery; using System; +using Ocelot.Configuration; namespace Ocelot.Provider.Kubernetes { public static class KubernetesProviderFactory { - public static ServiceDiscoveryFinderDelegate Get = (provider, config, name) => + public static ServiceDiscoveryFinderDelegate Get = (provider, config, reRoute) => { var factory = provider.GetService(); - return GetkubeProvider(provider, config, name, factory); + return GetkubeProvider(provider, config, reRoute, factory); }; - private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, string name, IOcelotLoggerFactory factory) + private static ServiceDiscovery.Providers.IServiceDiscoveryProvider GetkubeProvider(IServiceProvider provider, Configuration.ServiceProviderConfiguration config, DownstreamReRoute reRoute, IOcelotLoggerFactory factory) { var kubeClient = provider.GetService(); var k8sRegistryConfiguration = new KubeRegistryConfiguration() { - KeyOfServiceInK8s = name, - KubeNamespace = config.Namespace, + KeyOfServiceInK8s = reRoute.ServiceName, + KubeNamespace = string.IsNullOrEmpty(reRoute.ServiceNamespace) ? config.Namespace : reRoute.ServiceNamespace }; var k8sServiceDiscoveryProvider = new Kube(k8sRegistryConfiguration, factory, kubeClient); diff --git a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs index 42ad17db..2d7e9207 100644 --- a/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs +++ b/src/Ocelot/Configuration/Builder/DownstreamReRouteBuilder.cs @@ -30,6 +30,7 @@ namespace Ocelot.Configuration.Builder private RateLimitOptions _rateLimitOptions; private bool _useServiceDiscovery; private string _serviceName; + private string _serviceNamespace; private List _upstreamHeaderFindAndReplace; private List _downstreamHeaderFindAndReplace; private readonly List _downstreamAddresses; @@ -185,6 +186,12 @@ namespace Ocelot.Configuration.Builder _serviceName = serviceName; return this; } + + public DownstreamReRouteBuilder WithServiceNamespace(string serviceNamespace) + { + _serviceNamespace = serviceNamespace; + return this; + } public DownstreamReRouteBuilder WithUpstreamHeaderFindAndReplace(List upstreamHeaderFindAndReplace) { @@ -243,6 +250,7 @@ namespace Ocelot.Configuration.Builder _downstreamHeaderFindAndReplace, _downstreamAddresses, _serviceName, + _serviceNamespace, _httpHandlerOptions, _useServiceDiscovery, _enableRateLimiting, diff --git a/src/Ocelot/Configuration/Creator/ReRoutesCreator.cs b/src/Ocelot/Configuration/Creator/ReRoutesCreator.cs index c6171521..52b81985 100644 --- a/src/Ocelot/Configuration/Creator/ReRoutesCreator.cs +++ b/src/Ocelot/Configuration/Creator/ReRoutesCreator.cs @@ -126,6 +126,7 @@ namespace Ocelot.Configuration.Creator .WithRateLimitOptions(rateLimitOption) .WithHttpHandlerOptions(httpHandlerOptions) .WithServiceName(fileReRoute.ServiceName) + .WithServiceNamespace(fileReRoute.ServiceNamespace) .WithUseServiceDiscovery(fileReRouteOptions.UseServiceDiscovery) .WithUpstreamHeaderFindAndReplace(hAndRs.Upstream) .WithDownstreamHeaderFindAndReplace(hAndRs.Downstream) diff --git a/src/Ocelot/Configuration/DownstreamReRoute.cs b/src/Ocelot/Configuration/DownstreamReRoute.cs index b332b622..cf421285 100644 --- a/src/Ocelot/Configuration/DownstreamReRoute.cs +++ b/src/Ocelot/Configuration/DownstreamReRoute.cs @@ -13,6 +13,7 @@ namespace Ocelot.Configuration List downstreamHeadersFindAndReplace, List downstreamAddresses, string serviceName, + string serviceNamespace, HttpHandlerOptions httpHandlerOptions, bool useServiceDiscovery, bool enableEndpointEndpointRateLimiting, @@ -47,6 +48,7 @@ namespace Ocelot.Configuration DownstreamHeadersFindAndReplace = downstreamHeadersFindAndReplace ?? new List(); DownstreamAddresses = downstreamAddresses ?? new List(); ServiceName = serviceName; + ServiceNamespace = serviceNamespace; HttpHandlerOptions = httpHandlerOptions; UseServiceDiscovery = useServiceDiscovery; EnableEndpointEndpointRateLimiting = enableEndpointEndpointRateLimiting; @@ -76,6 +78,7 @@ namespace Ocelot.Configuration public List DownstreamHeadersFindAndReplace { get; } public List DownstreamAddresses { get; } public string ServiceName { get; } + public string ServiceNamespace { get; } public HttpHandlerOptions HttpHandlerOptions { get; } public bool UseServiceDiscovery { get; } public bool EnableEndpointEndpointRateLimiting { get; } diff --git a/src/Ocelot/Configuration/File/FileReRoute.cs b/src/Ocelot/Configuration/File/FileReRoute.cs index c87bf435..bad0e2af 100644 --- a/src/Ocelot/Configuration/File/FileReRoute.cs +++ b/src/Ocelot/Configuration/File/FileReRoute.cs @@ -38,6 +38,7 @@ namespace Ocelot.Configuration.File public FileCacheOptions FileCacheOptions { get; set; } public bool ReRouteIsCaseSensitive { get; set; } public string ServiceName { get; set; } + public string ServiceNamespace { get; set; } public string DownstreamScheme { get; set; } public FileQoSOptions QoSOptions { get; set; } public FileLoadBalancerOptions LoadBalancerOptions { get; set; } diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryFinderDelegate.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryFinderDelegate.cs index 848b0eef..a3cf8460 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryFinderDelegate.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryFinderDelegate.cs @@ -4,5 +4,5 @@ namespace Ocelot.ServiceDiscovery using Providers; using System; - public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, string key); + public delegate IServiceDiscoveryProvider ServiceDiscoveryFinderDelegate(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamReRoute reRoute); } diff --git a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs index b7f6ef4e..1863a206 100644 --- a/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs +++ b/src/Ocelot/ServiceDiscovery/ServiceDiscoveryProviderFactory.cs @@ -27,7 +27,7 @@ namespace Ocelot.ServiceDiscovery { if (reRoute.UseServiceDiscovery) { - return GetServiceDiscoveryProvider(serviceConfig, reRoute.ServiceName); + return GetServiceDiscoveryProvider(serviceConfig, reRoute); } var services = new List(); @@ -42,17 +42,17 @@ namespace Ocelot.ServiceDiscovery return new OkResponse(new ConfigurationServiceProvider(services)); } - private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, string key) + private Response GetServiceDiscoveryProvider(ServiceProviderConfiguration config, DownstreamReRoute reRoute) { if (config.Type?.ToLower() == "servicefabric") { - var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, key); + var sfConfig = new ServiceFabricConfiguration(config.Host, config.Port, reRoute.ServiceName); return new OkResponse(new ServiceFabricServiceDiscoveryProvider(sfConfig)); } if (_delegates != null) { - var provider = _delegates?.Invoke(_provider, config, key); + var provider = _delegates?.Invoke(_provider, config, reRoute); if (provider.GetType().Name.ToLower() == config.Type.ToLower()) { diff --git a/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs b/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs index 3aeb0751..5d4939d2 100644 --- a/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Consul/ProviderFactoryTests.cs @@ -1,4 +1,6 @@ -namespace Ocelot.UnitTests.Consul +using Ocelot.Configuration.Builder; + +namespace Ocelot.UnitTests.Consul { using Microsoft.Extensions.DependencyInjection; using Moq; @@ -29,7 +31,11 @@ [Fact] public void should_return_ConsulServiceDiscoveryProvider() { - var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("", "", 1, "", "", 1), ""); + var reRoute = new DownstreamReRouteBuilder() + .WithServiceName("") + .Build(); + + var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("", "", 1, "", "", 1), reRoute); provider.ShouldBeOfType(); } @@ -37,7 +43,12 @@ public void should_return_PollingConsulServiceDiscoveryProvider() { var stopsPollerFromPolling = 10000; - var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("pollconsul", "", 1, "", "", stopsPollerFromPolling), ""); + + var reRoute = new DownstreamReRouteBuilder() + .WithServiceName("") + .Build(); + + var provider = ConsulProviderFactory.Get(_provider, new ServiceProviderConfiguration("pollconsul", "", 1, "", "", stopsPollerFromPolling), reRoute); provider.ShouldBeOfType(); } } diff --git a/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs b/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs index 2dea63cb..04e40db4 100644 --- a/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs +++ b/test/Ocelot.UnitTests/Eureka/EurekaProviderFactoryTests.cs @@ -27,7 +27,10 @@ var services = new ServiceCollection(); services.AddSingleton(client.Object); var sp = services.BuildServiceProvider(); - var provider = EurekaProviderFactory.Get(sp, config, null); + var reRoute = new DownstreamReRouteBuilder() + .WithServiceName("") + .Build(); + var provider = EurekaProviderFactory.Get(sp, config, reRoute); provider.ShouldBeOfType(); } }