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

Adjust staging environment configuration #17

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
52 changes: 34 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,37 @@ Additionally, to test beatmap downloads, you may want to set up a local beatmap

For advanced testing purposes.

| Envvar name | Description | Mandatory? | Default value |
|:-----------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------:|:--------------|
| `DB_HOST` | Hostname under which the `osu-web` MySQL instance can be found. | ❌ No | `localhost` |
| `DB_PORT` | Port under which the `osu-web` MySQL instance can be found. | ❌ No | `3306` |
| `DB_USER` | Username to use when logging into the `osu-web` MySQL instance. | ❌ No | `root` |
| `DB_PASS` | Password to use when logging into the `osu-web` MySQL instance. | ❌ No | `""` |
| `DB_NAME` | Name of database to use on the indicated MySQL instance. | ❌ No | `osu` |
| `JWT_VALID_AUDIENCE` | The value of the `aud` claim to use when validating incoming JWTs. Should be set to the client ID assigned to osu! in the `osu-web` target deploy. | ✔️ Yes | None |
| `LOCAL_BEATMAP_STORAGE_PATH` | The path of a directory where the submitted beatmaps should reside. | ⚠️ In development config | None |
| `LEGACY_IO_DOMAIN` | The root domain to which legacy IO requests should be directed to. | ✔️ Yes | None |
| `SHARED_INTEROP_SECRET` | The interop secret used for legacy IO requests. Value should match same environment variable in target `osu-web` instance. | ✔️ Yes | None |
| `S3_ACCESS_KEY` | A valid Amazon S3 access key ID. | ⚠ In staging/production configs | None |
| `S3_SECRET_KEY` | The secret key corresponding to the `S3_ACCESS_KEY`. | ⚠ In staging/production configs | None |
| `S3_CENTRAL_BUCKET_NAME` | The name of the S3 bucket to use for storing beatmap packages and versioned files. | ⚠ In staging/production configs | None |
| `S3_BEATMAPS_BUCKET_NAME` | The name of the S3 bucket to use for storing .osu beatmap files. | ⚠ In staging/production configs | None |
| `SENTRY_DSN` | A valid Sentry DSN to use for logging application events. | ⚠ In staging/production configs | None |
| `DD_AGENT_HOST` | A hostname pointing to a Datadog agent instance to which metrics should be reported. | ⚠ In staging/production configs | None |

This project supports three environment setups.
The choice of the environment is steered by the `ASPNETCORE_ENVIRONMENT` environment variable.
Depending on environment, the configuration & config requirements change slightly.

- `ASPNETCORE_ENVIRONMENT=Development`:
- Developer exception pages & API docs (`/api-docs`) are enabled.
- Sentry & Datadog integrations are optional.
- `ASPNETCORE_ENVIRONMENT=Staging`:
- Developer exception pages & API docs are disabled.
- Sentry integration is mandatory.
- Datadog integration is optional.
- `ASPNETCORE_ENVIRONMENT=Production`:
- Developer exception pages & API docs are disabled.
- Sentry & Datadog integrations are mandatory.

| Envvar name | Description | Mandatory? | Default value |
|:------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------:|:---------------|
| `DB_HOST` | Hostname under which the `osu-web` MySQL instance can be found. | ❌ No | `localhost` |
| `DB_PORT` | Port under which the `osu-web` MySQL instance can be found. | ❌ No | `3306` |
| `DB_USER` | Username to use when logging into the `osu-web` MySQL instance. | ❌ No | `root` |
| `DB_PASS` | Password to use when logging into the `osu-web` MySQL instance. | ❌ No | `""` |
| `DB_NAME` | Name of database to use on the indicated MySQL instance. | ❌ No | `osu` |
| `JWT_VALID_AUDIENCE` | The value of the `aud` claim to use when validating incoming JWTs. Should be set to the client ID assigned to osu! in the `osu-web` target deploy. | ✔️ Yes | None |
| `BEATMAP_STORAGE_TYPE` | Which type of beatmap storage to use. Valid values are `local` and `s3`. | ✔️ Yes | None |
| `LOCAL_BEATMAP_STORAGE_PATH` | The path of a directory where the submitted beatmaps should reside. | ⚠️ If `BEATMAP_STORAGE_TYPE=local` | None |
| `S3_ACCESS_KEY` | A valid Amazon S3 access key ID. | ⚠ If `BEATMAP_STORAGE_TYPE=s3` | None |
| `S3_SECRET_KEY` | The secret key corresponding to the `S3_ACCESS_KEY`. | ⚠ If `BEATMAP_STORAGE_TYPE=s3` | None |
| `S3_CENTRAL_BUCKET_NAME` | The name of the S3 bucket to use for storing beatmap packages and versioned files. | ⚠ If `BEATMAP_STORAGE_TYPE=s3` | None |
| `S3_BEATMAPS_BUCKET_NAME` | The name of the S3 bucket to use for storing .osu beatmap files. | ⚠ If `BEATMAP_STORAGE_TYPE=s3` | None |
| `LEGACY_IO_DOMAIN` | The root domain to which legacy IO requests should be directed to. | ✔️ Yes | None |
| `SHARED_INTEROP_SECRET` | The interop secret used for legacy IO requests. Value should match same environment variable in target `osu-web` instance. | ✔️ Yes | None |
| `PURGE_BEATMAP_MIRROR_CACHES` | Whether to request that beatmap mirror caches should be purged when a beatmap is updated. Set to `0` to disable. Turning this off is useful in configurations where the beatmap mirror cache is the same directory as `LOCAL_BEATMAP_STORAGE_PATH`. | ❌ No | `1` |
| `SENTRY_DSN` | A valid Sentry DSN to use for logging application events. | ⚠ In staging & production environment | None |
| `DD_AGENT_HOST` | A hostname pointing to a Datadog agent instance to which metrics should be reported. | ⚠ In production environment | None |
27 changes: 27 additions & 0 deletions osu.Server.BeatmapSubmission/Configuration/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ public static class AppSettings
+ "The variable is used to authenticate clients using JWTs issued by osu-web. "
+ "Please set the value of this variable to the client ID assigned to osu! in the osu-web target deploy.");

public static StorageType StorageType
{
get
{
string? value = Environment.GetEnvironmentVariable("STORAGE_TYPE");

if (!Enum.TryParse(value, true, out StorageType storageType) || !Enum.IsDefined(storageType))
{
throw new InvalidOperationException($"STORAGE_TYPE environment variable not set to a valid value (`{value}`). "
+ "The variable is used to choose the implementation of beatmap storage used. "
+ "Valid values are:\n"
+ "- `local` (requires setting `LOCAL_BEATMAP_STORAGE_PATH`),\n"
+ "- `s3` (requires setting `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_CENTRAL_BUCKET_NAME`, `S3_BEATMAPS_BUCKET_NAME`)");
}

return storageType;
}
}

public static string LocalBeatmapStoragePath =>
Environment.GetEnvironmentVariable("LOCAL_BEATMAP_STORAGE_PATH")
?? throw new InvalidOperationException("LOCAL_BEATMAP_STORAGE_PATH environment variable not set. "
Expand Down Expand Up @@ -46,8 +65,16 @@ public static class AppSettings
?? throw new InvalidOperationException("S3_BEATMAPS_BUCKET_NAME environment variable not set. "
+ "Please set the value of this variable to the name of the bucket to be used for storing .osu beatmap files on S3.");

public static bool PurgeBeatmapMirrorCaches => Environment.GetEnvironmentVariable("PURGE_BEATMAP_MIRROR_CACHES") != "0";

public static string? SentryDsn => Environment.GetEnvironmentVariable("SENTRY_DSN");

public static string? DatadogAgentHost => Environment.GetEnvironmentVariable("DD_AGENT_HOST");
}

public enum StorageType
{
Local,
S3,
}
}
41 changes: 30 additions & 11 deletions osu.Server.BeatmapSubmission/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ public static void Main(string[] args)
{
case "Development":
{
builder.Services.AddTransient<IBeatmapStorage, LocalBeatmapStorage>();
builder.Services.AddTransient<BeatmapPackagePatcher>();
builder.Services.AddHttpClient();
builder.Services.AddTransient<ILegacyIO, LegacyIO>();
builder.Services.AddTransient<IMirrorService, NoOpMirrorService>();
builder.Services.AddSwaggerGen(c =>
{
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, Assembly.GetExecutingAssembly().GetName().Name + ".xml"));
Expand All @@ -60,14 +55,18 @@ public static void Main(string[] args)
}

case "Staging":
case "Production":
{
builder.Services.AddSingleton<IBeatmapStorage, S3BeatmapStorage>();
builder.Services.AddTransient<BeatmapPackagePatcher>();
builder.Services.AddHttpClient();
builder.Services.AddTransient<ILegacyIO, LegacyIO>();
builder.Services.AddTransient<IMirrorService, MirrorService>();
if (AppSettings.SentryDsn == null)
{
throw new InvalidOperationException("SENTRY_DSN environment variable not set. "
+ "Please set the value of this variable to a valid Sentry DSN to use for logging events.");
}

break;
}

case "Production":
{
if (AppSettings.SentryDsn == null)
{
throw new InvalidOperationException("SENTRY_DSN environment variable not set. "
Expand All @@ -84,6 +83,26 @@ public static void Main(string[] args)
}
}

builder.Services.AddTransient<BeatmapPackagePatcher>();
builder.Services.AddHttpClient();
builder.Services.AddTransient<ILegacyIO, LegacyIO>();

switch (AppSettings.StorageType)
{
case StorageType.Local:
builder.Services.AddTransient<IBeatmapStorage, LocalBeatmapStorage>();
break;

case StorageType.S3:
builder.Services.AddSingleton<IBeatmapStorage, S3BeatmapStorage>();
break;
}

if (AppSettings.PurgeBeatmapMirrorCaches)
builder.Services.AddTransient<IMirrorService, MirrorService>();
else
builder.Services.AddTransient<IMirrorService, NoOpMirrorService>();

builder.Services.AddRateLimiter(options =>
{
options.RejectionStatusCode = (int)HttpStatusCode.TooManyRequests;
Expand Down
Loading