diff --git a/src/PIDMigrator/Program.cs b/src/PIDMigrator/Program.cs index 714baaae8031b957c5ce48b326aaf9d804fc8712..43cc77ff3149a6db8b31e84c4ec3b4b82291e4ca 100644 --- a/src/PIDMigrator/Program.cs +++ b/src/PIDMigrator/Program.cs @@ -1,25 +1,180 @@ using Coscine.Action.Utils; using Coscine.Configuration; using Coscine.Database.Models; +using Coscine.ProxyApi.Utils; -var configuration = new ConsulConfiguration(); +namespace PIDMigrator; -var projectModel = new ProjectModel(); -var resourceModel = new ResourceModel(); - -// PID Endpoints found inside EpicClient's definition (see Coscine.Action Library) -Console.WriteLine("Project PIDs"); -foreach (var project in projectModel.GetAll()) +public static class Program { - EpicUtil.UpdatePID(project.Id.ToString(), configuration); - Console.WriteLine($"Updated PID for Project {project.Id}"); -} + public static List<Guid> ProjectPIDs { get; set; } = new(); + public static List<Guid> ResourcePIDs { get; set; } = new(); + public static List<Guid> UnclassifiedPIDs { get; set; } = new(); + public static List<string> SkippedPIDs { get; set; } = new(); -Console.WriteLine("\nResource PIDs"); -foreach (var resource in resourceModel.GetAll()) -{ - EpicUtil.UpdatePID(resource.Id.ToString(), configuration); - Console.WriteLine($"Updated PID for Resource {resource.Id}"); -} + private static readonly ConsulConfiguration _configuration = new(); + private static bool _dummyMode = true; + + static void Main(string[] args) + { + _dummyMode = !(args.Length > 0 && args[0] == "--noDryRun"); + + // Console text output + Console.Write($"{new string('=', 80)}\n PID Migrator"); + if (_dummyMode) + { + Console.Write(" : DUMMY MODE"); + } + Console.WriteLine($"\n{new string('-', 80)}"); + + var epicClient = CreateEpicClient(_configuration); + + /*==============================================*/ + var hostUrl = "coscine.rwth-aachen.de"; + /*==============================================*/ + + Console.WriteLine($"- Searching for PIDs containing \"{hostUrl}\" ..."); + var pidMatches = epicClient.Search($"*{hostUrl}*"); // Define as wildcard with *<text>* + Console.WriteLine($"- Search yelded {pidMatches.Count()} results"); + + var projectModel = new ProjectModel(); + var resourceModel = new ResourceModel(); + + Console.WriteLine($"- Collecting Coscine data ..."); + var projects = projectModel.GetAll(); + var resources = resourceModel.GetAll(); + Console.WriteLine($"- Search yelded {projects.Count()} projects and {resources.Count()} resources."); + + Console.WriteLine(); + + // Sanity check the data + if (projects.Count() + resources.Count() > pidMatches.Count()) + { + Console.WriteLine("!! Failed sanity check... Since we're not deleting PIDs, it is not realistic, that we have more non-deleted projects and resources than PID matches."); + Console.WriteLine("Aborting..."); + return; + } + else + { + Console.WriteLine($"Iterating through {pidMatches.Count()} PIDs\n"); + foreach (var pidMatch in pidMatches) + { + if (Guid.TryParse(pidMatch.EpicPid, out var pid)) + { + Console.WriteLine($"┌ PID \"{pid}\""); + // Get it from the EpicClient + var epicClientPid = epicClient.Get(pid.ToString()); + if (!epicClientPid.Any(e => + { + var parsedData = e.ParsedData.ToString(); + if (parsedData is not null) + { + return parsedData.ToString().Contains("rwth-aachen.de/coscine/apps/pidresolve/?pid="); + } + return false; + })) + { + Console.WriteLine($"└ PID already up to date, or NOT a Coscine PID. Skipping.\n"); + continue; + } + + // Check if it's a project + var project = projectModel.GetByIdIncludingDeleted(pid); + if (project is not null) + { + MigratePid(pid, project.DisplayName, project.Deleted, "project"); + } + else + { + var resource = resourceModel.GetByIdIncludingDeleted(pid); + if (resource is not null) + { + MigratePid(pid, resource.DisplayName, resource.Deleted, "resource"); + } + else + { + Console.WriteLine($"├ Not a project nor a resource. Could be a deleted legacy resource."); + MigratePid(pid, "<UNKNOWN>", true, "unclassified"); + continue; + } + } + } + else + { + Console.WriteLine($"─ PID \"{pidMatch.EpicPid}\" is not a GUID, therefore is not relevant for Coscine. Continuing..."); + SkippedPIDs.Add(pidMatch.EpicPid); + continue; + } + } + + var activeProjectsNotMigrated = projects.ExceptBy(ProjectPIDs, p => p.Id); + var activeResourcesNotMigrated = resources.ExceptBy(ResourcePIDs, r => r.Id); + + Console.WriteLine($"\n{new string('-', 80)}"); + Console.WriteLine($" - Active Project that were NOT migrated: {activeProjectsNotMigrated.Count()}"); + activeProjectsNotMigrated.ToList().ForEach(p => Console.WriteLine($" - {p.Id}")); + Console.WriteLine($" - Active Resoures that were NOT migrated: {activeResourcesNotMigrated.Count()}"); + activeResourcesNotMigrated.ToList().ForEach(r => Console.WriteLine($" - {r.Id}")); + + Console.WriteLine(); + Console.WriteLine($" - Project PIDs migrated: {ProjectPIDs.Count()}"); + Console.WriteLine($" - Resource PIDs migrated: {ResourcePIDs.Count()}"); + Console.WriteLine($" - Unclassified PIDs migrated: {UnclassifiedPIDs.Count()}"); + Console.WriteLine($" - TOTAL PIDs MIGRATED: {ProjectPIDs.Count() + ResourcePIDs.Count() + UnclassifiedPIDs.Count()}/{pidMatches.Count()}"); + + Console.WriteLine("\nFinished."); + } + } + + public static EpicClient CreateEpicClient(ConsulConfiguration _configuration) + { + // default localhost + var _prefix = _configuration.GetString("coscine/global/epic/prefix"); + + var _epicClient = new EpicClient( + _configuration.GetString("coscine/global/epic/url"), + _prefix, + _configuration.GetString("coscine/global/epic/user"), + _configuration.GetString("coscine/global/epic/password") + ); + return _epicClient; + } + + public static void MigratePid(Guid pid, string displayName, bool isDeleted, string type) + { + Console.Write($"├ Is a "); + if (isDeleted) + { + Console.Write($"DELETED "); + } + Console.WriteLine($"{type} with display name \"{displayName}\""); + + if (!_dummyMode) + { + try + { + EpicUtil.UpdatePID(pid.ToString(), _configuration); + } + catch (Exception e) + { + Console.WriteLine($"└ Migration FAILED. {e.Message}"); + return; + } + } -Console.WriteLine("Finished."); \ No newline at end of file + if (type.ToLower().Equals("project")) + { + ProjectPIDs.Add(pid); + } + else if (type.ToLower().Equals("resource")) + { + ResourcePIDs.Add(pid); + } + else + { + UnclassifiedPIDs.Add(pid); + } + Console.WriteLine($"└ Successfully migrated and added to statistics."); + Console.WriteLine(); + } +} \ No newline at end of file