Heavy WIP

This commit is contained in:
Cyberboss
2018-05-07 14:11:00 -04:00
parent 08ce48f4ee
commit f9ba711bc2
7 changed files with 168 additions and 13 deletions
@@ -1,4 +1,5 @@
using Tgstation.Server.Api.Rights;
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Rights;
namespace Tgstation.Server.Api.Models.Internal
{
@@ -12,24 +13,28 @@ namespace Tgstation.Server.Api.Models.Internal
/// If the BYOND web client can be used to connect to the game server
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetWebClient)]
public bool AllowWebClient { get; set; }
[Required]
public bool? AllowWebClient { get; set; }
/// <summary>
/// The <see cref="DreamDaemonSecurity"/> level of <see cref="DreamDaemon"/>
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetSecurity)]
public DreamDaemonSecurity SecurityLevel { get; set; }
[Required]
public DreamDaemonSecurity? SecurityLevel { get; set; }
/// <summary>
/// The first port <see cref="DreamDaemon"/> uses. This should be the publically advertised port
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetPorts)]
public ushort PrimaryPort { get; set; }
[Required]
public ushort? PrimaryPort { get; set; }
/// <summary>
/// The second port <see cref="DreamDaemon"/> uses
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetPorts)]
public ushort SecondaryPort { get; set; }
[Required]
public ushort? SecondaryPort { get; set; }
}
}
@@ -1,4 +1,5 @@
using Tgstation.Server.Api.Rights;
using System.ComponentModel.DataAnnotations;
using Tgstation.Server.Api.Rights;
namespace Tgstation.Server.Api.Models.Internal
{
@@ -11,18 +12,21 @@ namespace Tgstation.Server.Api.Models.Internal
/// If <see cref="DreamDaemon"/> starts when it's <see cref="Instance"/> starts
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SetAutoStart)]
public bool AutoStart { get; set; }
[Required]
public bool? AutoStart { get; set; }
/// <summary>
/// If the server is undergoing a soft reset. This may be automatically set by changes to other fields
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SoftRestart)]
public bool SoftRestart { get; set; }
[Required]
public bool? SoftRestart { get; set; }
/// <summary>
/// If the server is undergoing a soft shutdown
/// </summary>
[Permissions(ReadRight = DreamDaemonRights.ReadMetadata, WriteRight = DreamDaemonRights.SoftShutdown)]
public bool SoftShutdown { get; set; }
[Required]
public bool? SoftShutdown { get; set; }
}
}
@@ -41,6 +41,10 @@ namespace Tgstation.Server.Host.Components
/// </summary>
string AccessToken { get; }
DreamDaemonLaunchParameters LastLaunchParameters { get; }
Host.Models.CompileJob LastCompileJob { get; }
/// <summary>
/// Launch DreamDaemon
/// </summary>
@@ -0,0 +1,121 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Internal;
using Tgstation.Server.Api.Rights;
using Tgstation.Server.Host.Components;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Models;
using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Controllers
{
[Route("/" + nameof(DreamDaemon))]
public sealed class DreamDaemonController : ModelController<Api.Models.DreamDaemon>
{
/// <summary>
/// The <see cref="IJobManager"/> for the <see cref="DreamMakerController"/>
/// </summary>
readonly IJobManager jobManager;
/// <summary>
/// The <see cref="IInstanceManager"/> for the <see cref="DreamMakerController"/>
/// </summary>
readonly IInstanceManager instanceManager;
/// <summary>
/// Construct a <see cref="DreamDaemonController"/>
/// </summary>
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
public DreamDaemonController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory)
{
this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
}
/// <inheritdoc />
[TgsAuthorize(DreamDaemonRights.Start)]
public override async Task<IActionResult> Create([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
{
var instance = instanceManager.GetInstance(Instance);
if (instance.DreamDaemon.Running)
return StatusCode(HttpStatusCode.Gone);
var launchParams = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => new DreamDaemonLaunchParameters
{
AllowWebClient = x.DreamDaemonSettings.AllowWebClient,
PrimaryPort = x.DreamDaemonSettings.PrimaryPort,
SecondaryPort = x.DreamDaemonSettings.SecondaryPort,
SecurityLevel = x.DreamDaemonSettings.SecurityLevel
}).FirstAsync(cancellationToken).ConfigureAwait(false);
await jobManager.RegisterOperation(new Models.Job
{
Description = "Launch DreamDaemon",
CancelRight = (int)DreamDaemonRights.Shutdown,
CancelRightsType = RightsType.DreamDaemon,
Instance = Instance,
StartedBy = AuthenticationContext.User
}, (job, serviceProvider, innerCt) => instance.DreamDaemon.Launch(launchParams, innerCt), cancellationToken).ConfigureAwait(false);
return Ok();
}
/// <inheritdoc />
[TgsAuthorize(DreamDaemonRights.ReadMetadata | DreamDaemonRights.ReadRevision)]
public override async Task<IActionResult> Read(CancellationToken cancellationToken)
{
var dd = instanceManager.GetInstance(Instance).DreamDaemon;
var metadata = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadMetadata) != 0;
var revision = (AuthenticationContext.GetRight(RightsType.DreamDaemon) & (int)DreamDaemonRights.ReadRevision) != 0;
var settings = metadata ? await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false) : null;
Api.Models.DreamDaemon result = new Api.Models.DreamDaemon();
if(metadata)
{
result.AutoStart = settings.AutoStart;
result.CurrentPort = dd.CurrentPort;
result.CurrentSecurity = dd.CurrentSecurity;
result.PrimaryPort = dd.LastLaunchParameters.PrimaryPort;
result.AllowWebClient = dd.LastLaunchParameters.AllowWebClient;
result.Running = dd.Running;
result.SecondaryPort = dd.LastLaunchParameters.SecondaryPort;
result.SecurityLevel = dd.LastLaunchParameters.SecurityLevel;
result.SoftRestart = dd.SoftRebooting;
result.SoftShutdown = dd.SoftStopping;
};
if (revision)
result.CompileJob = dd.LastCompileJob.ToApi();
return Json(result);
}
/// <inheritdoc />
[TgsAuthorize(DreamDaemonRights.Shutdown)]
public override async Task<IActionResult> Delete([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
{
var instance = instanceManager.GetInstance(Instance);
if (!instance.DreamDaemon.Running)
return StatusCode(HttpStatusCode.Gone);
await instance.DreamDaemon.Terminate(false, cancellationToken).ConfigureAwait(false);
return Ok();
}
[TgsAuthorize(DreamDaemonRights.SetAutoStart | DreamDaemonRights.SetPorts | DreamDaemonRights.SetSecurity | DreamDaemonRights.SetWebClient | DreamDaemonRights.SoftRestart | DreamDaemonRights.SoftShutdown)]
public override async Task<IActionResult> Update([FromBody] Api.Models.DreamDaemon model, CancellationToken cancellationToken)
{
var current = await DatabaseContext.Instances.Where(x => x.Id == Instance.Id).Select(x => x.DreamDaemonSettings).FirstAsync(cancellationToken).ConfigureAwait(false);
var userRights = (DreamDaemonRights)AuthenticationContext.GetRight(RightsType.DreamDaemon)
if()
}
}
}
@@ -17,7 +17,7 @@ namespace Tgstation.Server.Host.Controllers
/// <summary>
/// Controller for managing the compiler
/// </summary>
[Route("/DreamMaker")]
[Route("/" + nameof(DreamMaker))]
public sealed class DreamMakerController : ModelController<Api.Models.DreamMaker>
{
/// <summary>
@@ -30,7 +30,7 @@ namespace Tgstation.Server.Host.Controllers
readonly IInstanceManager instanceManager;
/// <summary>
/// Construct a <see cref="HomeController"/>
/// Construct a <see cref="DreamMakerController"/>
/// </summary>
/// <param name="databaseContext">The <see cref="IDatabaseContext"/> for the <see cref="ApiController"/></param>
/// <param name="authenticationContextFactory">The <see cref="IAuthenticationContextFactory"/> for the <see cref="ApiController"/></param>
@@ -66,7 +66,8 @@ namespace Tgstation.Server.Host.Controllers
Description = "Compile active repository code",
StartedBy = AuthenticationContext.User,
CancelRightsType = RightsType.DreamMaker,
CancelRight = (int)DreamMakerRights.CancelCompile
CancelRight = (int)DreamMakerRights.CancelCompile,
Instance = Instance
};
await jobManager.RegisterOperation(job, (paramJob, serviceProvider, ct) => RunCompile(paramJob, serviceProvider, Instance, ct), cancellationToken).ConfigureAwait(false);
return Json(job);
@@ -14,7 +14,7 @@ namespace Tgstation.Server.Host.Controllers
/// <summary>
/// <see cref="ModelController{TModel}"/> for <see cref="Api.Models.Job"/>s
/// </summary>
[Route("/Job")]
[Route("/" + nameof(Job))]
public sealed class JobController : ModelController<Api.Models.Job>
{
/// <summary>
@@ -60,11 +60,23 @@ namespace Tgstation.Server.Host.Controllers
if (job == default(Job))
return NotFound();
if (job.CancelRight.HasValue && job.CancelRightsType.HasValue && (AuthenticationContext.GetRight(job.CancelRightsType.Value) & job.CancelRight.Value) == 0)
return Forbid();
if(job.StoppedAt != null)
return StatusCode(HttpStatusCode.Gone);
await jobManager.CancelJob(job, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
return Ok();
}
[TgsAuthorize]
public override async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
{
var job = await DatabaseContext.Jobs.Where(x => x.Id == id).Include(x => x.StartedBy).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (job == default(Job))
return NotFound();
return Json(job.ToApi());
}
}
}
@@ -43,6 +43,14 @@ namespace Tgstation.Server.Host.Controllers
[HttpGet]
public virtual Task<IActionResult> Read(CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
/// <summary>
/// Attempt to get a specific a <typeparamref name="TModel"/>
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the <see cref="IActionResult"/> of the operation</returns>
[HttpGet("/{0}")]
public virtual Task<IActionResult> GetId(long id, CancellationToken cancellationToken) => Task.FromResult((IActionResult)NotFound());
/// <summary>
/// Attempt to update a <paramref name="model"/>
/// </summary>