Skip to content

Commit

Permalink
[Cherry pick] Fix for Config File Path not found (#1693)
Browse files Browse the repository at this point in the history
- Cherry Picks #1681

---------

Co-authored-by: abhishekkumams <[email protected]>
  • Loading branch information
Aniruddh25 and abhishekkumams authored Sep 7, 2023
1 parent aa103b4 commit 69f4535
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 32 deletions.
2 changes: 1 addition & 1 deletion src/Cli/ConfigGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ public static bool TryStartEngineWithOptions(StartOptions options, FileSystemRun
return false;
}

loader.UpdateConfigFileName(runtimeConfigFile);
loader.UpdateConfigFilePath(runtimeConfigFile);

// Validates that config file has data and follows the correct json schema
// Replaces all the environment variables while deserializing when starting DAB.
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/ConfigMerger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static bool TryMergeConfigsIfAvailable(IFileSystem fileSystem, FileSystem
string baseConfigFile = FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME;
string environmentBasedConfigFile = loader.GetFileName(environmentValue, considerOverrides: false);

if (loader.DoesFileExistInCurrentDirectory(baseConfigFile) && !string.IsNullOrEmpty(environmentBasedConfigFile))
if (loader.DoesFileExistInDirectory(baseConfigFile) && !string.IsNullOrEmpty(environmentBasedConfigFile))
{
try
{
Expand Down
82 changes: 58 additions & 24 deletions src/Config/FileSystemRuntimeConfigLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ namespace Azure.DataApiBuilder.Config;
public class FileSystemRuntimeConfigLoader : RuntimeConfigLoader
{
// This stores either the default config name e.g. dab-config.json
// or user provided config file.
private string _baseConfigFileName;
// or user provided config file which could be a relative file path, absolute file path or simply the file name assumed to be in current directory.
private string _baseConfigFilePath;

private readonly IFileSystem _fileSystem;

Expand All @@ -45,19 +45,20 @@ public class FileSystemRuntimeConfigLoader : RuntimeConfigLoader
public const string DEFAULT_CONFIG_FILE_NAME = $"{CONFIGFILE_NAME}{CONFIG_EXTENSION}";

/// <summary>
/// Stores the config file name actually loaded by the engine.
/// Stores the config file actually loaded by the engine.
/// It could be the base config file (e.g. dab-config.json), any of its derivatives with
/// environment specific suffixes (e.g. dab-config.Development.json) or the user provided
/// config file name.
/// It could also be the config file provided by the user.
/// </summary>
public string ConfigFileName { get; internal set; }
public string ConfigFilePath { get; internal set; }

public FileSystemRuntimeConfigLoader(IFileSystem fileSystem, string baseConfigFileName = DEFAULT_CONFIG_FILE_NAME, string? connectionString = null)
public FileSystemRuntimeConfigLoader(IFileSystem fileSystem, string baseConfigFilePath = DEFAULT_CONFIG_FILE_NAME, string? connectionString = null)
: base(connectionString)
{
_fileSystem = fileSystem;
_baseConfigFileName = baseConfigFileName;
ConfigFileName = GetFileNameForEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), false);
_baseConfigFilePath = baseConfigFilePath;
ConfigFilePath = GetFinalConfigFilePath();
}

/// <summary>
Expand All @@ -75,6 +76,7 @@ public bool TryLoadConfig(
{
if (_fileSystem.File.Exists(path))
{
Console.WriteLine($"Loading config file from {path}.");
string json = _fileSystem.File.ReadAllText(path);
return TryParseConfig(json, out config, connectionString: _connectionString, replaceEnvVar: replaceEnvVar);
}
Expand All @@ -98,7 +100,7 @@ public bool TryLoadConfig(
/// <returns>True if the config was loaded, otherwise false.</returns>
public override bool TryLoadKnownConfig([NotNullWhen(true)] out RuntimeConfig? config, bool replaceEnvVar = false)
{
return TryLoadConfig(ConfigFileName, out config, replaceEnvVar);
return TryLoadConfig(ConfigFilePath, out config, replaceEnvVar);
}

/// <summary>
Expand Down Expand Up @@ -143,6 +145,29 @@ public string GetFileNameForEnvironment(string? aspnetEnvironment, bool consider
return configFileNameWithExtension;
}

/// <summary>
/// This method returns the final config file name that will be used by the runtime engine.
/// </summary>
private string GetFinalConfigFilePath()
{
if (!string.Equals(_baseConfigFilePath, DEFAULT_CONFIG_FILE_NAME))
{
// user provided config file is honoured.
return _baseConfigFilePath;
}

// ConfigFile not explicitly provided by user, so we need to get the config file name based on environment.
string configFilePath = GetFileNameForEnvironment(Environment.GetEnvironmentVariable(ASP_NET_CORE_ENVIRONMENT_VAR_NAME), false);

// If file for environment is not found, then the baseConfigFile is used as the final configFile for runtime engine.
if (string.IsNullOrWhiteSpace(configFilePath))
{
return _baseConfigFilePath;
}

return configFilePath;
}

/// <summary>
/// Generates the config file name and a corresponding overridden file name,
/// With precedence given to overridden file name, returns that name
Expand All @@ -154,31 +179,34 @@ public string GetFileNameForEnvironment(string? aspnetEnvironment, bool consider
/// <returns></returns>
public string GetFileName(string? environmentValue, bool considerOverrides)
{
string fileNameWithoutExtension = _fileSystem.Path.GetFileNameWithoutExtension(_baseConfigFileName);
string fileExtension = _fileSystem.Path.GetExtension(_baseConfigFileName);
string configFileName =
// If the baseConfigFilePath contains directory info, we need to ensure that it is not lost. for example: baseConfigFilePath = "config/dab-config.json"
// in this case, we need to get the directory name and the file name without extension and then combine them back. Else, we will lose the path
// and the file will be searched in the current directory.
string filePathWithoutExtension = _fileSystem.Path.Combine(_fileSystem.Path.GetDirectoryName(_baseConfigFilePath) ?? string.Empty, _fileSystem.Path.GetFileNameWithoutExtension(_baseConfigFilePath));
string fileExtension = _fileSystem.Path.GetExtension(_baseConfigFilePath);
string configFilePath =
!string.IsNullOrEmpty(environmentValue)
? $"{fileNameWithoutExtension}.{environmentValue}"
: $"{fileNameWithoutExtension}";
string configFileNameWithExtension = $"{configFileName}{fileExtension}";
string overriddenConfigFileNameWithExtension = GetOverriddenName(configFileName);
? $"{filePathWithoutExtension}.{environmentValue}"
: $"{filePathWithoutExtension}";
string configFileNameWithExtension = $"{configFilePath}{fileExtension}";
string overriddenConfigFileNameWithExtension = GetOverriddenName(configFilePath);

if (considerOverrides && DoesFileExistInCurrentDirectory(overriddenConfigFileNameWithExtension))
if (considerOverrides && DoesFileExistInDirectory(overriddenConfigFileNameWithExtension))
{
return overriddenConfigFileNameWithExtension;
}

if (DoesFileExistInCurrentDirectory(configFileNameWithExtension))
if (DoesFileExistInDirectory(configFileNameWithExtension))
{
return configFileNameWithExtension;
}

return string.Empty;
}

private static string GetOverriddenName(string fileName)
private static string GetOverriddenName(string filePath)
{
return $"{fileName}.overrides{CONFIG_EXTENSION}";
return $"{filePath}.overrides{CONFIG_EXTENSION}";
}

/// <summary>
Expand All @@ -190,10 +218,16 @@ public static string GetEnvironmentFileName(string fileName, string environmentV
return $"{fileName}.{environmentValue}{CONFIG_EXTENSION}";
}

public bool DoesFileExistInCurrentDirectory(string fileName)
/// <summary>
/// Checks if the file exists in the directory.
/// Works for both relative and absolute paths.
/// </summary>
/// <param name="filePath"></param>
/// <returns>True if file is found, else false.</returns>
public bool DoesFileExistInDirectory(string filePath)
{
string currentDir = _fileSystem.Directory.GetCurrentDirectory();
return _fileSystem.File.Exists(_fileSystem.Path.Combine(currentDir, fileName));
return _fileSystem.File.Exists(_fileSystem.Path.Combine(currentDir, filePath));
}

/// <summary>
Expand Down Expand Up @@ -256,9 +290,9 @@ public static string GetMergedFileNameForEnvironment(string fileName, string env
/// to be updated. This is commonly done when the CLI is starting up.
/// </summary>
/// <param name="fileName"></param>
public void UpdateConfigFileName(string fileName)
public void UpdateConfigFilePath(string filePath)
{
_baseConfigFileName = fileName;
ConfigFileName = fileName;
_baseConfigFilePath = filePath;
ConfigFilePath = filePath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void ValidateEasyAuthConfig()

// Since we added the config file to the filesystem above after the config loader was initialized
// in TestInitialize, we need to update the ConfigfileName, otherwise it will be an empty string.
_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);

try
{
Expand Down Expand Up @@ -75,7 +75,7 @@ public void ValidateJwtConfigParamsSet()
new MockFileData(config.ToJson())
);

_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);

try
{
Expand All @@ -96,7 +96,7 @@ public void ValidateAuthNSectionNotNecessary()
new MockFileData(config.ToJson())
);

_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);

try
{
Expand Down Expand Up @@ -125,7 +125,7 @@ public void ValidateFailureWithIncompleteJwtConfig()
new MockFileData(config.ToJson())
);

_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);

Assert.ThrowsException<NotSupportedException>(() =>
{
Expand Down Expand Up @@ -160,7 +160,7 @@ public void ValidateFailureWithUnneededEasyAuthConfig()
new MockFileData(config.ToJson())
);

_runtimeConfigLoader.UpdateConfigFileName(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);
_runtimeConfigLoader.UpdateConfigFilePath(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME);

Assert.ThrowsException<NotSupportedException>(() =>
{
Expand Down
66 changes: 66 additions & 0 deletions src/Service.Tests/Unittests/ConfigValidationUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -2016,6 +2017,71 @@ public void ValidateRuntimeBaseRouteSettings(
}
}

/// <summary>
/// This test checks that the final config used by runtime engine doesn't lose the directory information
/// if provided by the user.
/// It also validates that if config file is provided by the user, it will be used directly irrespective of
/// environment variable being set or not.
/// When user doesn't provide a config file, we check if environment variable is set and if it is, we use
/// the config file specified by the environment variable, else we use the default config file.
/// <param name="userProvidedConfigFilePath"></param>
/// <param name="environmentValue"></param>
/// <param name="useAbsolutePath"></param>
/// <param name="environmentFile"></param>
/// <param name="finalConfigFilePath"></param>
[DataTestMethod]
[DataRow("my-config.json", "", false, null, "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is not set")]
[DataRow("test-configs/my-config.json", "", false, null, "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is not set")]
[DataRow("my-config.json", "Test", false, "my-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set")]
[DataRow("test-configs/my-config.json", "Test", false, "test-configs/my-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set")]
[DataRow("my-config.json", "Test", false, "dab-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and environment file is present")]
[DataRow("test-configs/my-config.json", "Test", false, "test-configs/dab-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set and environment file is present")]
[DataRow("my-config.json", "", true, null, "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is not set and absolute path is provided")]
[DataRow("test-configs/my-config.json", "", true, null, "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is not set and absolute path is provided")]
[DataRow("my-config.json", "Test", true, "my-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and absolute path is provided")]
[DataRow("test-configs/my-config.json", "Test", true, "test-configs/my-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in different directory provided by user and environment variable is set and absolute path is provided")]
[DataRow("my-config.json", "Test", true, "dab-config.Test.json", "my-config.json", DisplayName = "Config file in the current directory provided by user and environment variable is set and environment file is present and absolute path is provided")]
[DataRow("test-configs/my-config.json", "Test", true, "test-configs/dab-config.Test.json", "test-configs/my-config.json", DisplayName = "Config file in the different directory provided by user and environment variable is set and environment file is present and absolute path is provided")]
[DataRow(null, "", false, null, "dab-config.json", DisplayName = "Config file not provided by user and environment variable is not set")]
[DataRow(null, "Test", false, "dab-config.Test.json", "dab-config.json", DisplayName = "Config file not provided by user and environment variable is set and environment file is present")]
[DataRow(null, "Test", false, null, "dab-config.json", DisplayName = "Config file not provided by user and environment variable is set and environment file is not present")]
public void TestCorrectConfigFileIsSelectedForRuntimeEngine(
string userProvidedConfigFilePath,
string environmentValue,
bool useAbsolutePath,
string environmentFile,
string finalConfigFilePath)
{
MockFileSystem fileSystem = new();
if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(userProvidedConfigFilePath)))
{
fileSystem.AddDirectory("test-configs");
}

if (useAbsolutePath)
{
userProvidedConfigFilePath = fileSystem.Path.GetFullPath(userProvidedConfigFilePath);
finalConfigFilePath = fileSystem.Path.GetFullPath(finalConfigFilePath);
}

if (environmentFile is not null)
{
fileSystem.AddEmptyFile(environmentFile);
}

FileSystemRuntimeConfigLoader runtimeConfigLoader;
if (userProvidedConfigFilePath is not null)
{
runtimeConfigLoader = new(fileSystem, userProvidedConfigFilePath);
}
else
{
runtimeConfigLoader = new(fileSystem);
}

Assert.AreEqual(finalConfigFilePath, runtimeConfigLoader.ConfigFilePath);
}

private static RuntimeConfigValidator InitializeRuntimeConfigValidator()
{
MockFileSystem fileSystem = new();
Expand Down
2 changes: 1 addition & 1 deletion src/Service/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, RuntimeC
_logger.LogError("Exiting the runtime engine...");
}

throw new ApplicationException($"Could not initialize the engine with the runtime config file: {fileSystemRuntimeConfigLoader.ConfigFileName}");
throw new ApplicationException($"Could not initialize the engine with the runtime config file: {fileSystemRuntimeConfigLoader.ConfigFilePath}");
}
}
else
Expand Down

0 comments on commit 69f4535

Please sign in to comment.