diff --git a/src/Tgstation.Server.Api/Models/Instance.cs b/src/Tgstation.Server.Api/Models/Instance.cs
index 66e5238161..01e41bbca7 100644
--- a/src/Tgstation.Server.Api/Models/Instance.cs
+++ b/src/Tgstation.Server.Api/Models/Instance.cs
@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
using Tgstation.Server.Api.Rights;
namespace Tgstation.Server.Api.Models
@@ -48,6 +49,13 @@ namespace Tgstation.Server.Api.Models
[Permissions(WriteRight = InstanceManagerRights.SetAutoUpdate)]
public int? AutoUpdateInterval { get; set; }
+ ///
+ /// The representing a change of
+ ///
+ [Permissions(DenyWrite = true)]
+ [NotMapped]
+ public Job MoveJob { get; set; }
+
///
public Instance CloneMetadata() => new Instance
{
diff --git a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
index 7d0a3c4ace..f8997edce3 100644
--- a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
+++ b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
@@ -47,6 +47,10 @@ namespace Tgstation.Server.Api.Rights
///
/// User can change
///
- SetAutoUpdate = 256
+ SetAutoUpdate = 256,
+ ///
+ /// User can cancel move operations
+ ///
+ CancelMove = 512,
}
}
diff --git a/src/Tgstation.Server.Host/Components/InstanceManager.cs b/src/Tgstation.Server.Host/Components/InstanceManager.cs
index 44099741d7..323fa7568a 100644
--- a/src/Tgstation.Server.Host/Components/InstanceManager.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceManager.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
@@ -40,6 +41,11 @@ namespace Tgstation.Server.Host.Components
///
readonly IApplication application;
+ ///
+ /// The for the
+ ///
+ readonly ILogger logger;
+
///
/// Map of s to respective s
///
@@ -56,12 +62,14 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of
- public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application)
+ /// The value of
+ public InstanceManager(IInstanceFactory instanceFactory, IIOManager ioManager, IDatabaseContextFactory databaseContextFactory, IApplication application, ILogger logger)
{
this.instanceFactory = instanceFactory ?? throw new ArgumentNullException(nameof(instanceFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.application = application ?? throw new ArgumentNullException(nameof(application));
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
instances = new Dictionary();
interopConsumers = new Dictionary();
@@ -93,24 +101,11 @@ namespace Tgstation.Server.Host.Components
if (newPath == null)
throw new ArgumentNullException(nameof(newPath));
if (instance.Online.Value)
- await OfflineInstance(instance, cancellationToken).ConfigureAwait(false);
- Task instanceOnlineTask = null;
- try
- {
- var oldPath = instance.Path;
- await ioManager.CopyDirectory(oldPath, newPath, null, cancellationToken).ConfigureAwait(false);
- instance.Path = ioManager.ResolvePath(newPath);
- instanceOnlineTask = OnlineInstance(instance, default);
- await ioManager.DeleteDirectory(oldPath, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- if (instance.Online.Value)
- if (instanceOnlineTask == null)
- await OnlineInstance(instance, default).ConfigureAwait(false);
- else
- await instanceOnlineTask.ConfigureAwait(false);
- }
+ throw new InvalidOperationException("Cannot move an online instance!");
+ var oldPath = instance.Path;
+ await ioManager.CopyDirectory(oldPath, newPath, null, cancellationToken).ConfigureAwait(false);
+ instance.Path = ioManager.ResolvePath(newPath);
+ await ioManager.DeleteDirectory(oldPath, cancellationToken).ConfigureAwait(false);
}
///
@@ -118,6 +113,7 @@ namespace Tgstation.Server.Host.Components
{
if (metadata == null)
throw new ArgumentNullException(nameof(metadata));
+ logger.LogInformation("Offlining instance ID {0}", metadata.Id);
IInstance instance;
lock (this)
{
@@ -140,6 +136,7 @@ namespace Tgstation.Server.Host.Components
{
if (metadata == null)
throw new ArgumentNullException(nameof(metadata));
+ logger.LogInformation("Onlining instance ID {0} ({1}) at {2}", metadata.Id, metadata.Name, metadata.Path);
var instance = instanceFactory.CreateInstance(metadata, this);
try
{
diff --git a/src/Tgstation.Server.Host/Controllers/ByondController.cs b/src/Tgstation.Server.Host/Controllers/ByondController.cs
index 5d731e6060..a70c5d80a8 100644
--- a/src/Tgstation.Server.Host/Controllers/ByondController.cs
+++ b/src/Tgstation.Server.Host/Controllers/ByondController.cs
@@ -78,7 +78,7 @@ namespace Tgstation.Server.Host.Controllers
var byondManager = instanceManager.GetInstance(Instance).ByondManager;
//remove cruff fields
- var installingVersion = new Version(model.Version.Major, model.Version.Major);
+ var installingVersion = new Version(model.Version.Major, model.Version.Minor);
var result = new Api.Models.Byond();
diff --git a/src/Tgstation.Server.Host/Controllers/InstanceController.cs b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
index 40225f90dc..aab876e91b 100644
--- a/src/Tgstation.Server.Host/Controllers/InstanceController.cs
+++ b/src/Tgstation.Server.Host/Controllers/InstanceController.cs
@@ -272,27 +272,58 @@ namespace Tgstation.Server.Host.Controllers
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
+ var oldAutoStart = originalModel.DreamDaemonSettings.AutoStart;
try
{
if (originalOnline && model.Online.Value == false)
await instanceManager.OfflineInstance(originalModel, cancellationToken).ConfigureAwait(false);
else if (!originalOnline && model.Online.Value == true)
+ {
+ //force autostart false here because we don't want any long running jobs right now
+ //remember to document this
+ originalModel.DreamDaemonSettings.AutoStart = false;
await instanceManager.OnlineInstance(originalModel, cancellationToken).ConfigureAwait(false);
+ }
}
catch (Exception e)
{
logger.LogError("Error changing instance online state! Exception: {0}", e);
originalModel.Online = originalOnline;
+ originalModel.DreamDaemonSettings.AutoStart = oldAutoStart;
if (originalModelPath != null)
originalModel.Path = originalModelPath;
await DatabaseContext.Save(default).ConfigureAwait(false);
throw;
}
+ var api = originalModel.ToApi();
if (originalModelPath != null)
- await ioManager.MoveDirectory(originalModelPath, model.Path, cancellationToken).ConfigureAwait(false);
+ {
+ var job = new Models.Job
+ {
+ Description = "Move instance location",
+ Instance = Instance,
+ CancelRightsType = RightsType.InstanceManager,
+ CancelRight = (int)InstanceManagerRights.CancelMove,
+ StartedBy = AuthenticationContext.User
+ };
- return Json(originalModel.ToApi());
+ await jobManager.RegisterOperation(job, async (paramJob, serviceProvider, ct) => {
+ try
+ {
+ await instanceManager.MoveInstance(Instance, originalModel.Path, ct).ConfigureAwait(false);
+ }
+ catch
+ {
+ originalModel.Path = originalModelPath;
+ await DatabaseContext.Save(default).ConfigureAwait(false);
+ throw;
+ }
+ }, cancellationToken).ConfigureAwait(false);
+ api.MoveJob = job.ToApi();
+ }
+
+ return Json(api);
}
///
diff --git a/src/Tgstation.Server.Host/Controllers/JobController.cs b/src/Tgstation.Server.Host/Controllers/JobController.cs
index a8d2a20739..79bb25cc15 100644
--- a/src/Tgstation.Server.Host/Controllers/JobController.cs
+++ b/src/Tgstation.Server.Host/Controllers/JobController.cs
@@ -37,18 +37,12 @@ namespace Tgstation.Server.Host.Controllers
[TgsAuthorize]
public override async Task List(CancellationToken cancellationToken)
{
- IQueryable query = DatabaseContext.Jobs;
- if (Instance != null)
+ //you KNOW this will need pagination eventually right?
+ var jobs = await DatabaseContext.Jobs.Where(x => x.Instance.Id == Instance.Id).OrderByDescending(x => x.StartedAt).Select(x => new Api.Models.Job
{
- if (AuthenticationContext.InstanceUser?.AnyRights != true)
- return Forbid();
- query = query.Where(x => x.Instance.Id == Instance.Id);
- }
- else
- query = query.Where(x => x.Instance == null);
-
- var jobs = await query.Where(x => x.StoppedAt == null).ToListAsync(cancellationToken).ConfigureAwait(false);
- return Json(jobs.Select(x => x.ToApi()));
+ Id = x.Id
+ }).ToListAsync(cancellationToken).ConfigureAwait(false);
+ return Json(jobs);
}
///
@@ -60,12 +54,12 @@ namespace Tgstation.Server.Host.Controllers
if (job == default(Job))
return NotFound();
+ if (job.StoppedAt != null)
+ return StatusCode((int)HttpStatusCode.Gone);
+
if (job.CancelRight.HasValue && job.CancelRightsType.HasValue && (AuthenticationContext.GetRight(job.CancelRightsType.Value) & job.CancelRight.Value) == 0)
return Forbid();
- if(job.StoppedAt != null)
- return StatusCode((int)HttpStatusCode.Gone);
-
await jobManager.CancelJob(job, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
return Ok();
}
diff --git a/src/Tgstation.Server.Host/Core/JobManager.cs b/src/Tgstation.Server.Host/Core/JobManager.cs
index c99672c654..c72590d5c9 100644
--- a/src/Tgstation.Server.Host/Core/JobManager.cs
+++ b/src/Tgstation.Server.Host/Core/JobManager.cs
@@ -172,6 +172,8 @@ namespace Tgstation.Server.Host.Core
var databaseContext = scope.ServiceProvider.GetRequiredService();
job = new Job { Id = job.Id };
databaseContext.Jobs.Attach(job);
+ user = new User { Id = user.Id };
+ databaseContext.Users.Attach(user);
job.CancelledBy = user;
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
}