From 0aac39cde5c7fd02307c94f7dc28d8c858bbd2be Mon Sep 17 00:00:00 2001 From: David Fowler Date: Sun, 22 Sep 2024 08:07:17 -0700 Subject: [PATCH] Rename the dcp resource on restart - This change makes the old dcp resource as hidden and makes a new resource. The UI can be a bit jarring as items are removed and then added. Fixes #5803 --- .../CommandsConfigurationExtensions.cs | 8 ++-- src/Aspire.Hosting/Dcp/ApplicationExecutor.cs | 44 +++++++++---------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/Aspire.Hosting/ApplicationModel/CommandsConfigurationExtensions.cs b/src/Aspire.Hosting/ApplicationModel/CommandsConfigurationExtensions.cs index e2267008e2..b65958c2bd 100644 --- a/src/Aspire.Hosting/ApplicationModel/CommandsConfigurationExtensions.cs +++ b/src/Aspire.Hosting/ApplicationModel/CommandsConfigurationExtensions.cs @@ -21,7 +21,7 @@ internal static void AddLifeCycleCommands(this IResource resource) { var executor = context.ServiceProvider.GetRequiredService(); - await executor.StartResourceAsync(context.ResourceName, context.CancellationToken).ConfigureAwait(false); + await executor.StartResourceAsync(resource, context.ResourceName, context.CancellationToken).ConfigureAwait(false); return CommandResults.Success(); }, updateState: context => @@ -49,7 +49,7 @@ internal static void AddLifeCycleCommands(this IResource resource) { var executor = context.ServiceProvider.GetRequiredService(); - await executor.StopResourceAsync(context.ResourceName, context.CancellationToken).ConfigureAwait(false); + await executor.StopResourceAsync(resource, context.ResourceName, context.CancellationToken).ConfigureAwait(false); return CommandResults.Success(); }, updateState: context => @@ -77,8 +77,8 @@ internal static void AddLifeCycleCommands(this IResource resource) { var executor = context.ServiceProvider.GetRequiredService(); - await executor.StopResourceAsync(context.ResourceName, context.CancellationToken).ConfigureAwait(false); - await executor.StartResourceAsync(context.ResourceName, context.CancellationToken).ConfigureAwait(false); + await executor.StopResourceAsync(resource, context.ResourceName, context.CancellationToken).ConfigureAwait(false); + await executor.StartResourceAsync(resource, context.ResourceName, context.CancellationToken).ConfigureAwait(false); return CommandResults.Success(); }, updateState: context => diff --git a/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs b/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs index d0c9d863be..0d18bc3764 100644 --- a/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs +++ b/src/Aspire.Hosting/Dcp/ApplicationExecutor.cs @@ -403,6 +403,8 @@ private async Task ProcessResourceChange(WatchEventType watchEventType, T res { replicaAnnotation.Instances.TryRemove(resource.Metadata.Name, out _); } + + await notificationService.PublishUpdateAsync(appModelResource, resource.Metadata.Name, s => s with { State = "Hidden" }).ConfigureAwait(false); } else { @@ -411,6 +413,14 @@ private async Task ProcessResourceChange(WatchEventType watchEventType, T res _logger.LogTrace("Updating application model resource {ResourceName} with {ResourceKind} resource {ResourceName}", appModelResource.Name, resourceKind, resource.Metadata.Name); } + if (watchEventType == WatchEventType.Added) + { + if (appModelResource.TryGetLastAnnotation(out var replicaAnnotation)) + { + replicaAnnotation.Instances.TryAdd(resource.Metadata.Name, resource.Metadata.Name); + } + } + if (_hiddenResources.TryAdd(appModelResource, true)) { // Hide the application model resource because we have the DCP resource @@ -595,15 +605,6 @@ await notificationService.PublishUpdateAsync(appModelResource, cr.Metadata.Name, private CustomResourceSnapshot ToSnapshot(Container container, CustomResourceSnapshot previous) { - if (container.AppModelResourceName is not null && - _applicationModel.TryGetValue(container.AppModelResourceName, out var appModelResource)) - { - if (appModelResource.TryGetLastAnnotation(out var replicaAnnotation)) - { - replicaAnnotation.Instances.TryAdd(container.Metadata.Name, container.Metadata.Name); - } - } - var containerId = container.Status?.ContainerId; var urls = GetUrls(container); var volumes = GetVolumes(container); @@ -657,11 +658,6 @@ private CustomResourceSnapshot ToSnapshot(Executable executable, CustomResourceS _applicationModel.TryGetValue(executable.AppModelResourceName, out var appModelResource)) { projectPath = appModelResource is ProjectResource p ? p.GetProjectMetadata().ProjectPath : null; - - if (appModelResource.TryGetLastAnnotation(out var replicaAnnotation)) - { - replicaAnnotation.Instances.TryAdd(executable.Metadata.Name, executable.Metadata.Name); - } } var state = executable.AppModelInitialState is "Hidden" ? "Hidden" : executable.Status?.State; @@ -1983,9 +1979,9 @@ internal static V1Patch CreatePatch(T obj, Action change) where T : Custom return new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch); } - internal async Task StopResourceAsync(string resourceName, CancellationToken cancellationToken) + internal async Task StopResourceAsync(IResource resource, string resourceName, CancellationToken cancellationToken) { - var matchingResource = GetMatchingResource(resourceName); + var matchingResource = GetMatchingResource(resource, resourceName); V1Patch patch; switch (matchingResource.DcpResource) @@ -2007,10 +2003,10 @@ internal async Task StopResourceAsync(string resourceName, CancellationToken can } } - private AppResource GetMatchingResource(string resourceName) + private AppResource GetMatchingResource(IResource resource, string resourceName) { var matchingResource = _appResources - .Where(r => r.DcpResource is not Service) + .Where(r => r.ModelResource == resource) .SingleOrDefault(r => string.Equals(r.DcpResource.Metadata.Name, resourceName, StringComparisons.ResourceName)); if (matchingResource == null) { @@ -2020,17 +2016,17 @@ private AppResource GetMatchingResource(string resourceName) return matchingResource; } - internal async Task StartResourceAsync(string resourceName, CancellationToken cancellationToken) + internal async Task StartResourceAsync(IResource resource, string resourceName, CancellationToken cancellationToken) { - var matchingResource = GetMatchingResource(resourceName); + var matchingResource = GetMatchingResource(resource, resourceName); switch (matchingResource.DcpResource) { case Container c: - await StartExecutableOrContainerAsync(c).ConfigureAwait(false); + await StartExecutableOrContainerAsync(resource, c).ConfigureAwait(false); break; case Executable e: - await StartExecutableOrContainerAsync(e).ConfigureAwait(false); + await StartExecutableOrContainerAsync(resource, e).ConfigureAwait(false); break; case ExecutableReplicaSet rs: var replicas = matchingResource.ModelResource.GetReplicaCount(); @@ -2042,7 +2038,7 @@ internal async Task StartResourceAsync(string resourceName, CancellationToken ca throw new InvalidOperationException($"Unexpected resource type: {matchingResource.DcpResource.GetType().FullName}"); } - async Task StartExecutableOrContainerAsync(T resource) where T : CustomResource + async Task StartExecutableOrContainerAsync(IResource r, T resource) where T : CustomResource { var resourceName = resource.Metadata.Name; _logger.LogDebug("Starting {ResouceType} '{ResourceName}'.", typeof(T).Name, resourceName); @@ -2092,7 +2088,7 @@ await execution.ExecuteAsync(async (attemptCancellationToken) => } }, cancellationToken).ConfigureAwait(false); } - + resource.Metadata.Name = $"{r.Name}-{GetRandomNameSuffix()}"; await kubernetesService.CreateAsync(resource, cancellationToken).ConfigureAwait(false); } }