diff --git a/docker/global.env b/docker/global.env
index d990f0bb46..75744ebcf2 100644
--- a/docker/global.env
+++ b/docker/global.env
@@ -1,8 +1,8 @@
ASPNETCORE_ENVIRONMENT=Production
-globalSettings:selfHosted=true
-globalSettings:baseServiceUri:vault=http://localhost
-globalSettings:baseServiceUri:api=http://localhost/api
-globalSettings:baseServiceUri:identity=http://localhost/identity
-globalSettings:baseServiceUri:internalIdentity=http://identity
-globalSettings:pushRelayBaseUri=https://push.bitwarden.com
-globalSettings:installation:identityUri=https://identity.bitwarden.com
+globalSettings__selfHosted=true
+globalSettings__baseServiceUri__vault=http://localhost
+globalSettings__baseServiceUri__api=http://localhost/api
+globalSettings__baseServiceUri__identity=http://localhost/identity
+globalSettings__baseServiceUri__internalIdentity=http://identity
+globalSettings__pushRelayBaseUri=https://push.bitwarden.com
+globalSettings__installation__identityUri=https://identity.bitwarden.com
diff --git a/src/Api/Dockerfile b/src/Api/Dockerfile
index 5ecf995163..2e77b62199 100644
--- a/src/Api/Dockerfile
+++ b/src/Api/Dockerfile
@@ -19,9 +19,19 @@ done
# Custom
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ cron \
+ && rm -rf /var/lib/apt/lists/*
+
WORKDIR /app
EXPOSE 80
-COPY obj/Docker/publish .
+COPY obj/Docker/publish/Api .
+
+COPY obj/Docker/publish/Jobs /jobs
+RUN mv /jobs/crontab /etc/cron.d/bitwarden-cron \
+ && chmod 0644 /etc/cron.d/bitwarden-cron \
+ && touch /var/log/cron.log
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
diff --git a/src/Api/build.ps1 b/src/Api/build.ps1
index 20bb292fb6..95dd649cb3 100644
--- a/src/Api/build.ps1
+++ b/src/Api/build.ps1
@@ -4,7 +4,8 @@ echo "`n# Building API"
echo "`nBuilding app"
echo ".NET Core version $(dotnet --version)"
-dotnet publish $dir\Api.csproj -f netcoreapp2.0 -c "Release" -o $dir\obj\Docker\publish
+dotnet publish $dir\Api.csproj -f netcoreapp2.0 -c "Release" -o $dir\obj\Docker\publish\Api
+dotnet publish $dir\..\Jobs\Jobs.csproj -f netcoreapp2.0 -c "Release" -o $dir\obj\Docker\publish\Jobs
echo "`nBuilding docker image"
docker --version
diff --git a/src/Api/entrypoint.sh b/src/Api/entrypoint.sh
index 78ec70fd2b..392f894225 100644
--- a/src/Api/entrypoint.sh
+++ b/src/Api/entrypoint.sh
@@ -1,3 +1,5 @@
#!/bin/sh
+env >> /etc/environment
+cron
dotnet /app/Api.dll
diff --git a/src/Jobs/Jobs.csproj b/src/Jobs/Jobs.csproj
index be69add01d..e9be561faa 100644
--- a/src/Jobs/Jobs.csproj
+++ b/src/Jobs/Jobs.csproj
@@ -8,6 +8,12 @@
bitwarden-Jobs
+
+
+ Always
+
+
+
diff --git a/src/Jobs/Program.cs b/src/Jobs/Program.cs
index 40df2b6ab1..098cdf4124 100644
--- a/src/Jobs/Program.cs
+++ b/src/Jobs/Program.cs
@@ -1,6 +1,9 @@
using Bit.Core.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
@@ -9,28 +12,31 @@ namespace Bit.Jobs
public class Program
{
private static ILicensingService _licensingService;
+ private static ILogger _logger;
public static void Main(string[] args)
{
+ var parameters = ParseParameters(args);
var host = new WebHostBuilder()
- .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseContentRoot(parameters.ContainsKey("d") ? parameters["d"] : Directory.GetCurrentDirectory())
.UseStartup()
.UseServer(new NoopServer())
.Build();
+ _logger = host.Services.GetRequiredService>();
_licensingService = host.Services.GetRequiredService();
- MainAsync(args).Wait();
+ MainAsync(parameters).Wait();
}
- private async static Task MainAsync(string[] args)
+ private async static Task MainAsync(IDictionary parameters)
{
- if(args.Length == 0)
+ if(!parameters.ContainsKey("j"))
{
return;
}
- switch(args[0])
+ switch(parameters["j"])
{
case "validate-licenses":
await _licensingService.ValidateOrganizationsAsync();
@@ -38,9 +44,28 @@ namespace Bit.Jobs
case "refresh-licenses":
// TODO
break;
+ case "hello":
+ _logger.LogInformation("Hello World!");
+ break;
default:
break;
}
}
+
+ private static IDictionary ParseParameters(string[] args)
+ {
+ var dict = new Dictionary();
+ for(var i = 0; i < args.Length; i = i + 2)
+ {
+ if(!args[i].StartsWith("-"))
+ {
+ continue;
+ }
+
+ dict.Add(args[i].Substring(1), args[i + 1]);
+ }
+
+ return dict;
+ }
}
}
diff --git a/src/Jobs/Startup.cs b/src/Jobs/Startup.cs
index b49189734d..c09eb7be36 100644
--- a/src/Jobs/Startup.cs
+++ b/src/Jobs/Startup.cs
@@ -6,6 +6,7 @@ using Bit.Core;
using Bit.Core.Utilities;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Builder;
+using Serilog.Events;
namespace Bit.Jobs
{
@@ -55,7 +56,10 @@ namespace Bit.Jobs
GlobalSettings globalSettings)
{
loggerFactory
- .AddSerilog(env, appLifetime, globalSettings)
+ .AddSerilog(env, appLifetime, globalSettings, (e) =>
+ {
+ return e.Level >= LogEventLevel.Information;
+ })
.AddConsole()
.AddDebug();
}
diff --git a/src/Jobs/crontab b/src/Jobs/crontab
new file mode 100644
index 0000000000..ba0c36b08f
--- /dev/null
+++ b/src/Jobs/crontab
@@ -0,0 +1,2 @@
+* * * * * root dotnet /jobs/Jobs.dll -d /jobs -j hello >> /var/log/cron.log 2>&1
+# An empty line is required at the end of this file for a valid cron file.
\ No newline at end of file
diff --git a/util/Setup/Program.cs b/util/Setup/Program.cs
index 58ae4ee6d4..3e423e59bf 100644
--- a/util/Setup/Program.cs
+++ b/util/Setup/Program.cs
@@ -261,26 +261,26 @@ server {{
using(var sw = File.CreateText("/bitwarden/docker/global.override.env"))
{
- sw.Write($@"globalSettings:baseServiceUri:vault={_url}
-globalSettings:baseServiceUri:api={_url}/api
-globalSettings:baseServiceUri:identity={_url}/identity
-globalSettings:sqlServer:connectionString={dbConnectionString}
-globalSettings:identityServer:certificatePassword={_identityCertPassword}
-globalSettings:attachment:baseDirectory={_outputDir}/core/attachments
-globalSettings:attachment:baseUrl={_url}/attachments
-globalSettings:dataProtection:directory={_outputDir}/core/aspnet-dataprotection
-globalSettings:logDirectory={_outputDir}/core/logs
-globalSettings:licenseDirectory={_outputDir}/core/licenses
-globalSettings:duo:aKey={Helpers.SecureRandomString(64, alpha: true, numeric: true)}
-globalSettings:installation:id={_installationId}
-globalSettings:installation:key={_installationKey}
-globalSettings:yubico:clientId=REPLACE
-globalSettings:yubico:key=REPLACE");
+ sw.Write($@"globalSettings__baseServiceUri__vault={_url}
+globalSettings__baseServiceUri__api={_url}/api
+globalSettings__baseServiceUri__identity={_url}/identity
+globalSettings__sqlServer__connectionString=""{dbConnectionString}""
+globalSettings__identityServer__certificatePassword={_identityCertPassword}
+globalSettings__attachment__baseDirectory={_outputDir}/core/attachments
+globalSettings__attachment__baseUrl={_url}/attachments
+globalSettings__dataProtection__directory={_outputDir}/core/aspnet-dataprotection
+globalSettings__logDirectory={_outputDir}/core/logs
+globalSettings__licenseDirectory={_outputDir}/core/licenses
+globalSettings__duo__aKey={Helpers.SecureRandomString(64, alpha: true, numeric: true)}
+globalSettings__installation__id={_installationId}
+globalSettings__installation__key={_installationKey}
+globalSettings__yubico__clientId=REPLACE
+globalSettings__yubico__key=REPLACE");
if(!_push)
{
sw.Write(@"
-globalSettings:pushRelayBaseUri=REPLACE");
+globalSettings__pushRelayBaseUri=REPLACE");
}
}