Skip to content

Commit

Permalink
Merge pull request jellyfin#6902 from cvium/migrate_networkconfig
Browse files Browse the repository at this point in the history
Migrate network configuration safely
  • Loading branch information
crobibero authored Dec 11, 2021
2 parents fbc79cb + a87b878 commit 4d1b824
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 326 deletions.
2 changes: 1 addition & 1 deletion Emby.Dlna/Main/DlnaEntryPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public DlnaEntryPoint(
config);
Current = this;

var netConfig = config.GetConfiguration<NetworkConfiguration>("network");
var netConfig = config.GetConfiguration<NetworkConfiguration>(NetworkConfigurationStore.StoreKey);
_disabled = appHost.ListenWithHttps && netConfig.RequireHttps;

if (_disabled && _config.GetDlnaConfiguration().EnableServer)
Expand Down
18 changes: 0 additions & 18 deletions Emby.Server.Implementations/ApplicationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,22 +313,6 @@ public string SystemId
? Environment.MachineName
: ConfigurationManager.Configuration.ServerName;

/// <summary>
/// Temporary function to migration network settings out of system.xml and into network.xml.
/// TODO: remove at the point when a fixed migration path has been decided upon.
/// </summary>
private void MigrateNetworkConfiguration()
{
string path = Path.Combine(ConfigurationManager.CommonApplicationPaths.ConfigurationDirectoryPath, "network.xml");
if (!File.Exists(path))
{
var networkSettings = new NetworkConfiguration();
ClassMigrationHelper.CopyProperties(ConfigurationManager.Configuration, networkSettings);
_xmlSerializer.SerializeToFile(networkSettings, path);
Logger.LogDebug("Successfully migrated network settings.");
}
}

public string ExpandVirtualPath(string path)
{
var appPaths = ApplicationPaths;
Expand Down Expand Up @@ -513,8 +497,6 @@ public void Init(IServiceCollection serviceCollection)

ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());

// Have to migrate settings here as migration subsystem not yet initialised.
MigrateNetworkConfiguration();
NetManager = new NetworkManager(ConfigurationManager, LoggerFactory.CreateLogger<NetworkManager>());

// Initialize runtime stat collection
Expand Down
2 changes: 1 addition & 1 deletion Jellyfin.Api/Controllers/StartupController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public ActionResult SetRemoteAccess([FromBody, Required] StartupRemoteAccessDto
NetworkConfiguration settings = _config.GetNetworkConfiguration();
settings.EnableRemoteAccess = startupRemoteAccessDto.EnableRemoteAccess;
settings.EnableUPnP = startupRemoteAccessDto.EnableAutomaticPortMapping;
_config.SaveConfiguration("network", settings);
_config.SaveConfiguration(NetworkConfigurationStore.StoreKey, settings);
return NoContent();
}

Expand Down
71 changes: 0 additions & 71 deletions Jellyfin.Api/Helpers/ClassMigrationHelper.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ public IEnumerable<ConfigurationStore> GetConfigurations()
{
return new[]
{
new ConfigurationStore
{
Key = "network",
ConfigurationType = typeof(NetworkConfiguration)
}
new NetworkConfigurationStore()
};
}
}
Expand Down
24 changes: 24 additions & 0 deletions Jellyfin.Networking/Configuration/NetworkConfigurationStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using MediaBrowser.Common.Configuration;

namespace Jellyfin.Networking.Configuration
{
/// <summary>
/// A configuration that stores network related settings.
/// </summary>
public class NetworkConfigurationStore : ConfigurationStore
{
/// <summary>
/// The name of the configuration in the storage.
/// </summary>
public const string StoreKey = "network";

/// <summary>
/// Initializes a new instance of the <see cref="NetworkConfigurationStore"/> class.
/// </summary>
public NetworkConfigurationStore()
{
ConfigurationType = typeof(NetworkConfiguration);
Key = StoreKey;
}
}
}
2 changes: 1 addition & 1 deletion Jellyfin.Networking/Manager/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ private static string FormatIP6String(IPAddress address)

private void ConfigurationUpdated(object? sender, ConfigurationUpdateEventArgs evt)
{
if (evt.Key.Equals("network", StringComparison.Ordinal))
if (evt.Key.Equals(NetworkConfigurationStore.StoreKey, StringComparison.Ordinal))
{
UpdateSettings((NetworkConfiguration)evt.NewConfiguration);
}
Expand Down
60 changes: 53 additions & 7 deletions Jellyfin.Server/Migrations/MigrationRunner.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Emby.Server.Implementations;
using Emby.Server.Implementations.Serialization;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

Expand All @@ -11,6 +16,14 @@ namespace Jellyfin.Server.Migrations
/// </summary>
public sealed class MigrationRunner
{
/// <summary>
/// The list of known pre-startup migrations, in order of applicability.
/// </summary>
private static readonly Type[] _preStartupMigrationTypes =
{
typeof(PreStartupRoutines.CreateNetworkConfiguration)
};

/// <summary>
/// The list of known migrations, in order of applicability.
/// </summary>
Expand Down Expand Up @@ -41,17 +54,50 @@ public static void Run(CoreAppHost host, ILoggerFactory loggerFactory)
.Select(m => ActivatorUtilities.CreateInstance(host.ServiceProvider, m))
.OfType<IMigrationRoutine>()
.ToArray();

var migrationOptions = host.ConfigurationManager.GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey);
HandleStartupWizardCondition(migrations, migrationOptions, host.ConfigurationManager.Configuration.IsStartupWizardCompleted, logger);
PerformMigrations(migrations, migrationOptions, options => host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, options), logger);
}

/// <summary>
/// Run all needed pre-startup migrations.
/// </summary>
/// <param name="appPaths">Application paths.</param>
/// <param name="loggerFactory">Factory for making the logger.</param>
public static void RunPreStartup(ServerApplicationPaths appPaths, ILoggerFactory loggerFactory)
{
var logger = loggerFactory.CreateLogger<MigrationRunner>();
var migrations = _preStartupMigrationTypes
.Select(m => Activator.CreateInstance(m, appPaths, loggerFactory))
.OfType<IMigrationRoutine>()
.ToArray();

var xmlSerializer = new MyXmlSerializer();
var migrationConfigPath = Path.Join(appPaths.ConfigurationDirectoryPath, MigrationsListStore.StoreKey.ToLowerInvariant() + ".xml");
var migrationOptions = (MigrationOptions)xmlSerializer.DeserializeFromFile(typeof(MigrationOptions), migrationConfigPath)!;

if (!host.ConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0)
// We have to deserialize it manually since the configuration manager may overwrite it
var serverConfig = (ServerConfiguration)xmlSerializer.DeserializeFromFile(typeof(ServerConfiguration), appPaths.SystemConfigurationFilePath)!;
HandleStartupWizardCondition(migrations, migrationOptions, serverConfig.IsStartupWizardCompleted, logger);
PerformMigrations(migrations, migrationOptions, options => xmlSerializer.SerializeToFile(options, migrationConfigPath), logger);
}

private static void HandleStartupWizardCondition(IEnumerable<IMigrationRoutine> migrations, MigrationOptions migrationOptions, bool isStartWizardCompleted, ILogger logger)
{
if (isStartWizardCompleted || migrationOptions.Applied.Count != 0)
{
// If startup wizard is not finished, this is a fresh install.
// Don't run any migrations, just mark all of them as applied.
logger.LogInformation("Marking all known migrations as applied because this is a fresh install");
migrationOptions.Applied.AddRange(migrations.Where(m => !m.PerformOnNewInstall).Select(m => (m.Id, m.Name)));
host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
return;
}

// If startup wizard is not finished, this is a fresh install.
var onlyOldInstalls = migrations.Where(m => !m.PerformOnNewInstall).ToArray();
logger.LogInformation("Marking following migrations as applied because this is a fresh install: {@OnlyOldInstalls}", onlyOldInstalls.Select(m => m.Name));
migrationOptions.Applied.AddRange(onlyOldInstalls.Select(m => (m.Id, m.Name)));
}

private static void PerformMigrations(IMigrationRoutine[] migrations, MigrationOptions migrationOptions, Action<MigrationOptions> saveConfiguration, ILogger logger)
{
var appliedMigrationIds = migrationOptions.Applied.Select(m => m.Id).ToHashSet();

for (var i = 0; i < migrations.Length; i++)
Expand All @@ -78,7 +124,7 @@ public static void Run(CoreAppHost host, ILoggerFactory loggerFactory)
// Mark the migration as completed
logger.LogInformation("Migration '{Name}' applied successfully", migrationRoutine.Name);
migrationOptions.Applied.Add((migrationRoutine.Id, migrationRoutine.Name));
host.ConfigurationManager.SaveConfiguration(MigrationsListStore.StoreKey, migrationOptions);
saveConfiguration(migrationOptions);
logger.LogDebug("Migration '{Name}' marked as applied in configuration.", migrationRoutine.Name);
}
}
Expand Down
Loading

0 comments on commit 4d1b824

Please sign in to comment.