Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After upgrade to Ocelot 23.2, ocelot.global.json file no longer gets merged correctly #2084

Closed
silviuantochicommify opened this issue Jun 3, 2024 · 9 comments · Fixed by #2120
Assignees
Labels
bug Identified as a potential bug Configuration Ocelot feature: Configuration merged Issue has been merged to dev and is waiting for the next release

Comments

@silviuantochicommify
Copy link

silviuantochicommify commented Jun 3, 2024

Expected Behavior

Data inside ocelot.global.json file should be taken into account when creating the IInternalConfiguration

Actual Behavior

Defaults are being set, the data from the ocelot.global.json is completely ignored (we have a RequestIdKey set and a custom ServiceDiscoveryProvider)

Steps to Reproduce the Problem

  1. Create multiple json files inside a folder, each containing different routes
  2. Create ocelot.global.json file inside the same folder
  3. Use the Configuration.AddOcelot(string folder, IWebHostEnvironment env, MergeOcelotJson.ToMemory) overload
  4. At runtime, use the IInternalConfigurationRepository to get the Ocelot configuration.
  5. The data found in the InternalConfiguration object regarding global configuration contains default values, instead of the ones from the ocelot.global.json

Specifications

  • Version: 23.2.2 on .NET 8
  • Platform: Windows

After the upgrade to 23.2.2, the ocelot.global.json no longer gets interpreted when doing the merge, regardless if it's done InMemory or the old way, in the ocelot.json file. Since the deployment will be done in a Kubernetes cluster, we really want to use the InMemory option, but currently, it looks like there's an issue that was introduced with 23.2.2.

Just to make it clear, I've tested with 23.1.0 and everything is working as before, without any other changes to the code outside of removing the MergeOcelotJson from the Program.cs file to make it compile

I'm more than happy to give more details in case it's needed

@silviuantochicommify
Copy link
Author

silviuantochicommify commented Jun 3, 2024

Update: I've managed to make it work if I do this:

builder.Configuration.AddOcelot("GatewayConfiguration", builder.Environment, MergeOcelotJson.ToMemory, globalConfigFile: "GatewayConfiguration/ocelot.global.json");

It looks like the FileInfo instance created in the method GetMergedOcelotJson for the global config file (line 121) doesn't take into account the folder where the ocelot.*.json files are →


So the the current implementation will only work for root folder, since the file name is the same, but the full name is only the same if all the ocelot json files are in the root folder, making the if lower at lines 135-136 always returning false and never applying the configuration →
if (file.Name.Equals(globalFileInfo.Name, StringComparison.OrdinalIgnoreCase) &&
file.FullName.Equals(globalFileInfo.FullName, StringComparison.OrdinalIgnoreCase))

@raman-m
Copy link
Member

raman-m commented Jun 4, 2024

  1. At runtime, use the IInternalConfigurationRepository to get the Ocelot configuration.
  2. The data found in the InternalConfiguration object regarding global configuration contains default values, instead of the ones from the ocelot.global.json

I don't recommend to use IInternalConfigurationRepository object to read configuration which is already in DI:

Services.Configure<FileConfiguration>(configurationRoot);

So, use IOptions<FileConfiguration> object for constructor's injection.
For route config: use httpContext.Items.DownstreamRoute();

@raman-m
Copy link
Member

raman-m commented Jun 4, 2024

@silviuantochicommify commented on Jun 3:

It looks like the FileInfo instance created in the method GetMergedOcelotJson for the global config file (line 121) doesn't take into account the folder where the ocelot.*.json files are →

You are wrong! Look at the following lines 112-117:

var files = new DirectoryInfo(folder)
.EnumerateFiles()
.Where(fi => reg.IsMatch(fi.Name) &&
!fi.Name.Equals(environmentFileInfo.Name, StringComparison.OrdinalIgnoreCase) &&
!fi.FullName.Equals(environmentFileInfo.FullName, StringComparison.OrdinalIgnoreCase))
.ToArray();

The expression new DirectoryInfo(folder).EnumerateFiles() gets all files of the folder including the global one, ocelot.global.json! Just debug in runtime and you will see that is true. All files must be located at the same folder.

@raman-m
Copy link
Member

raman-m commented Jun 4, 2024

So the the current implementation will only work for root folder, since the file name is the same, but the full name is only the same if all the ocelot json files are in the root folder, making the if lower at lines 135-136 always returning false and never applying the configuration →

if (file.Name.Equals(globalFileInfo.Name, StringComparison.OrdinalIgnoreCase) &&
file.FullName.Equals(globalFileInfo.FullName, StringComparison.OrdinalIgnoreCase))

We will double check this! It can be an issue. I wonder if paths of FullName differ and the condition is false.

@raman-m raman-m added bug Identified as a potential bug needs validation Issue has not been replicated or verified yet Configuration Ocelot feature: Configuration labels Jun 4, 2024
@raman-m raman-m changed the title After upgrade to Ocelot 23.2, ocelot.global.json file no longer gets merged correctly After upgrade to Ocelot 23.2, ocelot.global.json file no longer gets merged correctly Jun 4, 2024
@silviuantochicommify
Copy link
Author

So the the current implementation will only work for root folder, since the file name is the same, but the full name is only the same if all the ocelot json files are in the root folder, making the if lower at lines 135-136 always returning false and never applying the configuration →

if (file.Name.Equals(globalFileInfo.Name, StringComparison.OrdinalIgnoreCase) &&
file.FullName.Equals(globalFileInfo.FullName, StringComparison.OrdinalIgnoreCase))

We will double check this! It can be an issue. I wonder if paths of FullName differ and the condition is false.

This is what I wanted to point out. Sorry if I didn't explain it properly initially.

I checked with a very simple console application and this is exactly the case. If you don't include the subfolder when creating the FileInfo, the Name property contains the same value, but FullName differs. I'm guessing that's why using the overload with the <subfolder>/ocelot.global.json works.

@raman-m
Copy link
Member

raman-m commented Jun 6, 2024

@silviuantochicommify
You have one day to submit a pull request with a hotfix to ensure its inclusion in version 23.3 (the current release). Otherwise, I will address the issue with a potential fix targeted for version 24.0 (the next upcoming release).

Initially, we need to create TDD tests that can replicate the issue in the current development version.

@silviuantochicommify
Copy link
Author

@silviuantochicommify
You have one day to submit a pull request with a hotfix to ensure its inclusion in version 23.3 (the current release). Otherwise, I will address the issue with a potential fix targeted for version 24.0 (the next upcoming release).

Initially, we need to create TDD tests that can replicate the issue in the current development version.

Hello @raman-m,

I'm taking some days off, so I won't be able to submit any PR. Best I can do is next week, on Monday.

Thanks

@raman-m raman-m added the Oct'24 October 2024 release label Jun 16, 2024
@raman-m raman-m added this to the Summer'24 milestone Jun 16, 2024
@raman-m raman-m modified the milestones: Summer'24, v23.3.x Hotfixes Jul 10, 2024
@raman-m
Copy link
Member

raman-m commented Jul 10, 2024

Silviu, will you be working during these days in July?
FYI, the issue has been added to the v23.3.x Hotfixes milestone.

@ben-bartholomew
Copy link
Contributor

I was running into this issue too so I jumped on it to get something in since it was simple. The defect here only mentions running into the problem with the global config file, but the environment and primary config default file paths are built the same way (and so would be incorrectly looked for outside the folder), so I applied the change to those also.

@raman-m raman-m added accepted Bug or feature would be accepted as a PR or is being worked on and removed needs validation Issue has not been replicated or verified yet labels Jul 12, 2024
raman-m added a commit to ben-bartholomew/Ocelot that referenced this issue Jul 16, 2024
raman-m added a commit that referenced this issue Jul 16, 2024
…roviding the `folder` argument of `AddOcelot` (#2120)

* Adding unit test first

* Fixing default global config file not being found in folder

* Adding PR trait to test

* Backing out whitespace changes

* Code review by @raman-m

* Create Configuration feature folder and move test classes

* Adjust namespace and review what we have

* Acceptance tests for #2084 user scenario

---------

Co-authored-by: Raman Maksimchuk <[email protected]>
@raman-m raman-m added merged Issue has been merged to dev and is waiting for the next release and removed accepted Bug or feature would be accepted as a PR or is being worked on labels Jul 16, 2024
@raman-m raman-m removed the Oct'24 October 2024 release label Aug 12, 2024
raman-m added a commit that referenced this issue Oct 3, 2024
…Blue Olympic Balumbes release

* #2084 Apply default config file paths in `GetMergedOcelotJson` when providing the `folder` argument of `AddOcelot` (#2120)

* Adding unit test first

* Fixing default global config file not being found in folder

* Adding PR trait to test

* Backing out whitespace changes

* Code review by @raman-m

* Create Configuration feature folder and move test classes

* Adjust namespace and review what we have

* Acceptance tests for #2084 user scenario

---------

Co-authored-by: Raman Maksimchuk <[email protected]>

* Bump Steeltoe.Discovery.Eureka from 3.2.5 to 3.2.8 in /src/Ocelot.Provider.Eureka (#2122)

* Bump Steeltoe.Discovery.Eureka in /src/Ocelot.Provider.Eureka

Bumps [Steeltoe.Discovery.Eureka](https://github.com/SteeltoeOSS/Steeltoe) from 3.2.5 to 3.2.8.
- [Release notes](https://github.com/SteeltoeOSS/Steeltoe/releases)
- [Changelog](https://github.com/SteeltoeOSS/Steeltoe/blob/main/Steeltoe.Release.ruleset)
- [Commits](SteeltoeOSS/Steeltoe@3.2.5...3.2.8)

---
updated-dependencies:
- dependency-name: Steeltoe.Discovery.Eureka
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>

* Bump Steeltoe.Discovery.ClientCore from 3.2.5 to 3.2.8

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Raman Maksimchuk <[email protected]>

* #2110 Review load balancing and independent fetching the list of services in `Kube` provider (#2111)

* Move the creation of the services list from the class field to the method, to prevent modification list from different threads

* Early return after data checking

* Add unit test for concurrent get list of services

* Add logging for invalid service configuration error in RoundRobin load balancer

* Code review by @raman-m

* Workaround for mistakes made during acceptance testing of load balancing versus service discovery, where tests designed for parallel requests were mistakenly executed sequentially. This resulted in load balancers being loaded by sequential `HttpClient` calls, which was a significant oversight.

* Let's DRY StickySessionsTests

* Add acceptance tests, but...
RoundRobin is not actually RoundRobin 😁 -> 😆

* Independent static indexing iterators per route via service names

* Stabilize `CookieStickySessions` load balancer.
Review tests after refactoring of `RoundRobin` load balancer

* Refactor Lease operation for load balancing.
Review LeastConnection load balancer

* Leasing mechanism in Round Robin load balancer

* Acceptance tests, final version

* Apply Retry pattern for K8s endpoint integration

* Fix IDE warnings and messages

* Follow suggestions and fix issues from code review by @ggnaegi

* Bump KubeClient from 2.4.10 to 2.5.8

* Fix warnings

* Final version of `Retry` pattern

---------

Co-authored-by: Raman Maksimchuk <[email protected]>

* Downgrade the Warning to Information on missing `Content-Length` header in `MultiplexingMiddleware` (#2146)

* fix: downgrade the warning to information on missing content-length header

* chore: add route name to logs

* test: fixing multiplexing middleware tests

* Code review by @raman-m

---------

Co-authored-by: Paul Roy <[email protected]>
Co-authored-by: Raman Maksimchuk <[email protected]>

* Correct the broken link to the GraphQL sample's `README.md` (#2149)

Signed-off-by: Emmanuel Ferdman <[email protected]>
Co-authored-by: Raman Maksimchuk <[email protected]>

* #2116 Escaping unsafe pattern values of `Regex` constructor ​​derived from URL query parameter values containing special `Regex` chars (#2150)

* regex escape handling for url templates

* refactored regex method to lamda version

* Quick code review by @raman-m

* added acceptance test for url regex bug

* moved acceptance test to routing tests

* Convert to theory: define 2 test cases

---------

Co-authored-by: Raman Maksimchuk <[email protected]>

* #2119 Review load balancing (2nd round) and redesign `DefaultConsulServiceBuilder` with `ConsulProviderFactory` refactoring to make it thread safe and friendly (#2151)

* Review tests

* History of Service Discovery testing: add traits

* LoadBalancer traits

* #2119 Steps to Reproduce

* Reuse service handlers of `ConcurrentSteps`

* Reuse service counters of `ConcurrentSteps`

* Add LoadBalancer namespace and move classes

* Move `Lease`

* Move `LeaseEventArgs`

* Analyze load balancers aka `ILoadBalancerAnalyzer` interface objects

* Prefer using named local methods as delegates over anonymous methods for awesome call stack, ensuring the delegate's typed result matches the typed balancer's creator. Additionally, employ an IServiceProvider workaround.

* Review load balancing. Assert service & leasing counters as concurrent step. Final version of acceptance test.

* Fixed naming violation for asynchronous methods: `Lease` -> `LeaseAsync`

* Fix ugly reflection issue of dymanic detection in favor of static type property

* Propagate the `ConsulRegistryConfiguration` object through `HttpContext` in the scoped version of the default service builder, utilizing the injected `IHttpContextAccessor` object.
Update `ConsulProviderFactory`.
Update docs.
Update tests.

* Add tests from clean experiment

* Final review of the tests

* Review `IHttpContextAccessor` logic.
Convert anonymous delegates to named ones in placeholders processing

* Tried to enhance more, but failed

---------

Signed-off-by: dependabot[bot] <[email protected]>
Signed-off-by: Emmanuel Ferdman <[email protected]>
Co-authored-by: Ben Bartholomew <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Roman <[email protected]>
Co-authored-by: Paul Roy <[email protected]>
Co-authored-by: Paul Roy <[email protected]>
Co-authored-by: Emmanuel Ferdman <[email protected]>
Co-authored-by: Finn <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Identified as a potential bug Configuration Ocelot feature: Configuration merged Issue has been merged to dev and is waiting for the next release
Projects
None yet
3 participants