Skip to content
New issue

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

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

Already on GitHub? # to your account

[ADMINAPI-766] Retrieve ODS API Version from appsettings #94

Merged
merged 6 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
// See the LICENSE and NOTICES files in the project root for more information.

using System;
using System.Text.Json;
using System.Threading.Tasks;
using EdFi.Ods.AdminApi.Infrastructure.Api;
using NUnit.Framework;
using Shouldly;

Expand All @@ -15,51 +12,43 @@ namespace EdFi.Ods.AdminApi.Infrastructure.UnitTests.Api;
[TestFixture]
public class OdsSecurityVersionResolverTests
{
public static void ShouldReturnV3_5ForOdsV3() => new OdsSecurityVersionResolver(
new StubValidApi("3.2.0"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.ThreeThroughFive);
[Test]
public static void ShouldReturnV3_5ForOdsV53() => new OdsSecurityVersionResolver("5.3")
.DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.ThreeThroughFive);

public static void ShouldReturnV3_5ForOdsV51() => new OdsSecurityVersionResolver(
new StubValidApi("5.1"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.ThreeThroughFive);
[Test]
public static void ShouldReturnV3_5ForOdsV53Cqe() => new OdsSecurityVersionResolver("5.3-cqe")
.DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.FiveThreeCqe);

public static void ShouldReturnV3_5ForOdsV53() => new OdsSecurityVersionResolver(
new StubValidApi("5.3"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.ThreeThroughFive);
[Test]
public static void ShouldReturnV6ForOds6() => new OdsSecurityVersionResolver("6.0")
.DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.Six);

public static void ShouldReturnV6ForOds6() => new OdsSecurityVersionResolver(
new StubValidApi("6.0"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.Six);
[Test]
public static void ShouldReturnV6ForOdsGreaterThanV6() => new OdsSecurityVersionResolver("6.1")
.DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.Six);

public static void ShouldReturnV6ForOdsGreaterThanV6() => new OdsSecurityVersionResolver(
new StubValidApi("6.1"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.Six);

public static void ShouldReturnV6ForOdsMuchGreaterThanV6() => new OdsSecurityVersionResolver(
new StubValidApi("10.1"), "").DetermineSecurityModel().ShouldBe(EdFiOdsSecurityModelCompatibility.Six);

public static void ShouldThrowExceptionWhenValidApiReturnsNoVersion()
[Test]
public static void ShouldThrowExceptionForOdsV3()
{
Should.Throw<Exception>(
() => new OdsSecurityVersionResolver(new StubValidApi(null), "").DetermineSecurityModel());
Should.Throw<Exception>(() => new OdsSecurityVersionResolver("3.2.0").DetermineSecurityModel());
}

public static void ShouldThrowMatchingExceptionWhenValidationFails()
[Test]
public static void ShouldThrowExceptionForOdsV51()
{
Should.Throw<JsonException>(
() => new OdsSecurityVersionResolver(new StubInvalidApi(), "").DetermineSecurityModel());
Should.Throw<Exception>(() => new OdsSecurityVersionResolver("5.1").DetermineSecurityModel());
}

private class StubValidApi : IOdsApiValidator
[Test]
public static void ShouldThrowExceptionForOdsMuchGreaterThanV6()
{
private readonly Version _version;

public StubValidApi(string version)
{
_version = version == null ? null : new Version(version);
}
public Task<OdsApiValidatorResult> Validate(string apiServerUrl)
=> Task.FromResult(new OdsApiValidatorResult { IsValidOdsApi = true, Version = _version, });
Should.Throw<Exception>(() => new OdsSecurityVersionResolver("10.1").DetermineSecurityModel());
}

private class StubInvalidApi : IOdsApiValidator
[Test]
public static void ShouldThrowExceptionWhenValidApiReturnsNoVersion()
{
public Task<OdsApiValidatorResult> Validate(string apiServerUrl)
=> Task.FromResult(new OdsApiValidatorResult { IsValidOdsApi = false, Exception = new JsonException(), });
Should.Throw<Exception>(() => new OdsSecurityVersionResolver(string.Empty).DetermineSecurityModel());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ API_MODE=SharedInstance
ODS_VIRTUAL_NAME=api
ADMIN_API_VIRTUAL_NAME=adminapi
LOGS_FOLDER=/tmp/logs
ODS_API_VERSION=6.1

# For Authentication
AUTHORITY=http://localhost/${ADMIN_API_VIRTUAL_NAME}
Expand All @@ -14,8 +15,7 @@ POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
PGBOUNCER_LISTEN_PORT=6432

# The following needs to be set to specify the ODS API endpoint for Admin API to internally connect.
# If user chooses direct connection between ODS API and Admin API within docker network, then set the api internal url as follows
API_INTERNAL_URL=http://${ODS_VIRTUAL_NAME}
# For Supported ODS API Version
ODS_API_VERSION=${ODS_API_VERSION}

ADMIN_API_HEALTHCHECK_TEST="curl -f http://${ADMIN_API_VIRTUAL_NAME}/health"
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.

using EdFi.Ods.AdminApi.Infrastructure.Api;
using System.Runtime.CompilerServices;
using log4net;

namespace EdFi.Ods.AdminApi.Infrastructure;
Expand All @@ -17,21 +17,11 @@ public class OdsSecurityVersionResolver : IOdsSecurityModelVersionResolver
{
private readonly ILog _log;
private readonly Lazy<EdFiOdsSecurityModelCompatibility> _modelVersion;
private readonly IOdsApiValidator _apiValidator;
private readonly string _apiServerUrl;
private readonly string _odsApiVersion;

// In ODS/API version 5.3 there is a special branch/tag that provides
// additional security functionality, which was originally developed for
// ODS/API 6.1. In general, the Admin and Security databases still look like
// ODS/API 5.3, but we need to know that it is in fact "CQE" so that we can
// handle the "ReadChanges" action properly.
private readonly bool _using53Cqe;

public OdsSecurityVersionResolver(IOdsApiValidator apiValidator, string apiServerUrl, bool using53Cqe = false)
public OdsSecurityVersionResolver(string odsApiVersion)
{
_apiValidator = apiValidator;
_apiServerUrl = apiServerUrl;
_using53Cqe = using53Cqe;
_odsApiVersion = odsApiVersion;
_log = LogManager.GetLogger(typeof(OdsSecurityVersionResolver));
_modelVersion = new Lazy<EdFiOdsSecurityModelCompatibility>(InitializeModelVersion);
}
Expand All @@ -40,24 +30,21 @@ public OdsSecurityVersionResolver(IOdsApiValidator apiValidator, string apiServe

private EdFiOdsSecurityModelCompatibility InitializeModelVersion()
{
var validationResult = _apiValidator.Validate(_apiServerUrl).GetAwaiter().GetResult();

if (!validationResult.IsValidOdsApi || validationResult.Version == null)
try
{
_log.Error("Unable to determine security model from ODS API Response");
throw validationResult.Exception ?? new Exception("No version reported from the Ed-Fi API");
return _odsApiVersion switch
{
"5.3" => EdFiOdsSecurityModelCompatibility.ThreeThroughFive,
"5.3-cqe" => EdFiOdsSecurityModelCompatibility.FiveThreeCqe,
"6.0" or "6.1" => EdFiOdsSecurityModelCompatibility.Six,
_ => throw new SwitchExpressionException()
};
}

if (_using53Cqe)
catch (SwitchExpressionException)
{
return EdFiOdsSecurityModelCompatibility.FiveThreeCqe;
_log.Error("OdsApiVersion not configured. Valid values are 5.3, 5.3-cqe, 6.0 and 6.1");
throw new Exception("OdsApiVersion not configured. Valid values are 5.3, 5.3-cqe, 6.0 and 6.1");
}

var serverVersion = validationResult.Version;

return serverVersion.Major < 6
? EdFiOdsSecurityModelCompatibility.ThreeThroughFive
: EdFiOdsSecurityModelCompatibility.Six;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,8 @@ public static void AddServices(this WebApplicationBuilder webApplicationBuilder)
//Add service to identify ODS Version
webApplicationBuilder.Services.AddSingleton<IOdsSecurityModelVersionResolver>(sp =>
{
var apiServerUrl = webApplicationBuilder.Configuration.GetValue<string>("AppSettings:ProductionApiUrl");
var using53Cqe = webApplicationBuilder.Configuration.GetValue<bool>("AppSettings:Using53Cqe");

var validator = sp.GetRequiredService<IOdsApiValidator>();
return new OdsSecurityVersionResolver(validator, apiServerUrl, using53Cqe);
var odsApiVersion = webApplicationBuilder.Configuration.GetValue<string>("AppSettings:OdsApiVersion");
return new OdsSecurityVersionResolver(odsApiVersion);
});

// Add services to the container.
Expand Down
5 changes: 2 additions & 3 deletions Application/EdFi.Ods.AdminApi/appsettings.Docker.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"AppSettings": {
"DatabaseEngine": "PostgreSQL",
"ProductionApiUrl": "$API_INTERNAL_URL",
"ApiExternalUrl": "$API_EXTERNAL_URL",
"ApiStartupType": "$API_MODE",
"PathBase": "$ADMIN_API_VIRTUAL_NAME"
"PathBase": "$ADMIN_API_VIRTUAL_NAME",
"OdsApiVersion": "$ODS_API_VERSION"
},
"Authentication": {
"Authority": "$AUTHORITY",
Expand Down
2 changes: 1 addition & 1 deletion Application/EdFi.Ods.AdminApi/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ProductionApiUrl": "http://localhost:54746",
"ApiStartupType": "SharedInstance",
"PathBase": "",
"Using53Cqe": false
"OdsApiVersion": "6.1"
},
"Authentication": {
"Authority": "",
Expand Down
6 changes: 3 additions & 3 deletions Application/EdFi.Ods.AdminApi/env.example.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
API_MODE=<API Mode Eg. SharedInstance, YearSpecific, DistrictSpecific>
ODS_VIRTUAL_NAME=<virtual name for the ods endpoint>
ADMIN_API_VIRTUAL_NAME=<virtual name for the Admin API endpoint>
ODS_API_VERSION=<Version number of ODS API eg. 5.3, 5.3-cqe, 6.0, 6.1>

# For Authentication
AUTHORITY=<Authentication Authority Appsetting Eg. https://localhost:443>
Expand All @@ -15,6 +16,5 @@ ADMIN_POSTGRES_HOST=<DNS or IP Address of the Postgres Server, i.e. sql.somedns.
ODS_POSTGRES_HOST=<DNS or IP Address of the Postgres Server, i.e. sql.somedns.org Eg. 172.25.32.1
ODS_WAIT_POSTGRES_HOSTS=<DNS or IP Address of the different ODS Postgres Servers, i.e. sql.somedns.org Eg. 172.25.32.1

# The following needs to be set to specify the ODS API endpoint for Admin API to internally connect.
# If user chooses direct connection between ODS API and Admin API within docker network, then set the api internal url as follows
API_INTERNAL_URL = http://${ODS_VIRTUAL_NAME}
# For Supported ODS API Version
ODS_API_VERSION=${ODS_API_VERSION}
2 changes: 1 addition & 1 deletion Docker/Compose/pgsql/compose-build-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ services:
ISSUER_URL: ${ISSUER_URL}
SIGNING_KEY: ${SIGNING_KEY}
ADMIN_API_VIRTUAL_NAME: ${ADMIN_API_VIRTUAL_NAME:-adminapi}
API_INTERNAL_URL: ${API_INTERNAL_URL}
ODS_API_VERSION: ${ODS_API_VERSION}
depends_on:
- db-admin
restart: always
Expand Down
2 changes: 1 addition & 1 deletion Docker/Compose/pgsql/compose-build-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ services:
ISSUER_URL: ${ISSUER_URL}
SIGNING_KEY: ${SIGNING_KEY}
ADMIN_API_VIRTUAL_NAME: ${ADMIN_API_VIRTUAL_NAME:-adminapi}
API_INTERNAL_URL: ${API_INTERNAL_URL}
ODS_API_VERSION: ${ODS_API_VERSION}
depends_on:
- pb-admin
restart: always
Expand Down
7 changes: 3 additions & 4 deletions Docker/Compose/pgsql/env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
API_MODE=SharedInstance
ADMIN_API_VIRTUAL_NAME=adminapi
ODS_VIRTUAL_NAME=webapi
ODS_API_VERSION=6.1

# For Authentication
AUTHORITY=http://localhost/${ADMIN_API_VIRTUAL_NAME}
Expand All @@ -20,6 +20,5 @@ ADMIN_API_HEALTHCHECK_TEST="curl -f http://${ADMIN_API_VIRTUAL_NAME}/health"
# ADMIN_API_HEALTHCHECK_TEST=/bin/true
# To add a custom health check, consult the documentation at https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck

# The following needs to be set to specify the ODS API endpoint for Admin API to internally connect.
# If user chooses direct connection between ODS API and Admin API within docker network, then set the api internal url as follows
API_INTERNAL_URL=http://${ODS_VIRTUAL_NAME}
# FOr Supported ODS API Version
ODS_API_VERSION=${ODS_API_VERSION}
5 changes: 2 additions & 3 deletions Docker/Settings/mssql/appsettings.template.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"AppSettings": {
"DatabaseEngine": "SqlServer",
"ProductionApiUrl": "$API_INTERNAL_URL",
"ApiExternalUrl": "$API_EXTERNAL_URL",
"ApiStartupType": "$API_MODE",
"PathBase": "$ADMIN_API_VIRTUAL_NAME"
"PathBase": "$ADMIN_API_VIRTUAL_NAME",
"OdsApiVersion": "$ODS_API_VERSION"
},
"Authentication": {
"Authority": "$AUTHORITY",
Expand Down
8 changes: 3 additions & 5 deletions Docker/Settings/mssql/env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
API_MODE=<API Mode Eg. SharedInstance, YearSpecific, DistrictSpecific>

ODS_VIRTUAL_NAME=<virtual name for the ods endpoint>
ADMIN_API_VIRTUAL_NAME=<virtual name for the Admin API endpoint>
ODS_API_VERSION=<Version number of ODS API eg. 5.3, 5.3-cqe, 6.0, 6.1>

# For Authentication
AUTHORITY=<Authentication Authority Appsetting Eg. https://localhost:443>
Expand All @@ -21,6 +20,5 @@ ADMIN_API_HEALTHCHECK_TEST="curl -f http://${ADMIN_API_VIRTUAL_NAME}/health"
# ADMIN_API_HEALTHCHECK_TEST=/bin/true
# To add a custom health check, consult the documentation at https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck

# The following needs to be set to specify the ODS API endpoint for Admin API to internally connect.
# If user chooses direct connection between ODS API and Admin API within docker network, then set the api internal url as follows
API_INTERNAL_URL = http://${ODS_VIRTUAL_NAME}
# For Supported ODS API Version
ODS_API_VERSION=${ODS_API_VERSION}
5 changes: 2 additions & 3 deletions Docker/Settings/pgsql/appsettings.template.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
{
"AppSettings": {
"DatabaseEngine": "PostgreSQL",
"ProductionApiUrl": "$API_INTERNAL_URL",
"ApiExternalUrl": "$API_EXTERNAL_URL",
"ApiStartupType": "$API_MODE",
"PathBase": "$ADMIN_API_VIRTUAL_NAME"
"PathBase": "$ADMIN_API_VIRTUAL_NAME",
"OdsApiVersion": "$ODS_API_VERSION"
},
"Authentication": {
"Authority": "$AUTHORITY",
Expand Down
7 changes: 3 additions & 4 deletions Docker/Settings/pgsql/env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
API_MODE=<API Mode Eg. SharedInstance, YearSpecific, DistrictSpecific>
ODS_VIRTUAL_NAME=<virtual name for the ods endpoint>
ADMIN_API_VIRTUAL_NAME=<virtual name for the Admin API endpoint>
ODS_API_VERSION=<Version number of ODS API eg. 5.3, 5.3-cqe, 6.0, 6.1>

# For Authentication
AUTHORITY=<Authentication Authority Appsetting Eg. https://localhost:443>
Expand All @@ -15,6 +15,5 @@ ADMIN_POSTGRES_HOST=<DNS or IP Address of the Postgres Server, i.e. sql.somedns.
ODS_POSTGRES_HOST=<DNS or IP Address of the Postgres Server, i.e. sql.somedns.org Eg. 172.25.32.1
ODS_WAIT_POSTGRES_HOSTS=<DNS or IP Address of the different ODS Postgres Servers, i.e. sql.somedns.org Eg. 172.25.32.1

# The following needs to be set to specify the ODS API endpoint for Admin API to internally connect.
# If user chooses direct connection between ODS API and Admin API within docker network, then set the api internal url as follows
API_INTERNAL_URL = http://${ODS_VIRTUAL_NAME}
# For Supported ODS API Version
ODS_API_VERSION=${ODS_API_VERSION}
17 changes: 9 additions & 8 deletions Installer.AdminApi/Install-AdminApi.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function Install-EdFiOdsAdminApi {
ToolsPath = "C:/temp/tools"
DbConnectionInfo = $dbConnectionInfo
OdsDatabaseName = "EdFi_Ods_Sandbox"
OdsApiUrl = "http://example-web-api.com/WebApi"
OdsApiVersion = "6.1"
}
PS c:\> Install-EdFiOdsAdminApi @parameters

Expand All @@ -60,7 +60,7 @@ function Install-EdFiOdsAdminApi {
.EXAMPLE
PS c:\> $parameters = @{
ToolsPath = "C:/temp/tools"
OdsApiUrl = "http://example-web-api.com/WebApi"
OdsApiVersion = "6.1"
AdminDbConnectionInfo = @{
Engine="SqlServer"
Server="edfi-auth.my-sql-server.example"
Expand Down Expand Up @@ -112,7 +112,7 @@ function Install-EdFiOdsAdminApi {
PS c:\> $parameters = @{
ToolsPath = "C:/temp/tools"
DbConnectionInfo = $dbConnectionInfo
OdsApiUrl = "http://example-web-api.com/WebApi"
OdsApiVersion = "6.1"
AdminApiFeatures = @{
ApiMode="yearspecific"
}
Expand Down Expand Up @@ -165,10 +165,11 @@ function Install-EdFiOdsAdminApi {
[string]
$CertThumbprint,

# Full URL to the Ed-Fi ODS / API version endpoint.
[string]
# ODS / API version. Valid values are 5.3, 5.3-cqe, 6.0, 6.1. Default: "6.1"
[Parameter(Mandatory=$true)]
$OdsApiUrl,
[ValidateSet('5.3', '5.3-cqe', '6.0', '6.1')]
[string]
$OdsApiVersion,

# Install Credentials: User
[string]
Expand Down Expand Up @@ -271,7 +272,7 @@ function Install-EdFiOdsAdminApi {
WebSitePort = $WebsitePort
CertThumbprint = $CertThumbprint
WebApplicationName = $WebApplicationName
OdsApiUrl = $OdsApiUrl
OdsApiVersion = $OdsApiVersion
DatabaseInstallCredentials = @{
DatabaseUser = $InstallCredentialsUser
DatabasePassword = $InstallCredentialsPassword
Expand Down Expand Up @@ -961,7 +962,7 @@ function Invoke-TransformAppSettings {
Invoke-Task -Name ($MyInvocation.MyCommand.Name) -Task {
$settingsFile = Join-Path $Config.WebConfigLocation "appsettings.json"
$settings = Get-Content $settingsFile | ConvertFrom-Json | ConvertTo-Hashtable
$settings.AppSettings.ProductionApiUrl = $Config.OdsApiUrl
$settings.AppSettings.OdsApiVersion = $Config.OdsApiVersion
$settings.AppSettings.DatabaseEngine = $config.engine

if ($Config.AdminApiFeatures) {
Expand Down
Loading