-
Notifications
You must be signed in to change notification settings - Fork 110
Add PowerShell scripting support in Aspire AppHost #706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
3c0d25c
rebase main
fa49eaf
add tests
5783059
fix up directory.packages.props, oops
3a4fca9
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedAppl…
oising a71bec5
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunsp…
oising a0ffe83
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedAppl…
oising 73a2446
Merge branch 'main' into powershell
oising 8c18cde
address nits and completely restructure lifecycle management
194165b
conditionally use az cli in apphost sample; remove dead code
32ec6dc
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellScrip…
oising 8306f64
Merge branch 'main' into powershell
oising 0947edf
rebase main
8c039a7
add tests
bb34f88
fix up directory.packages.props, oops
a9d3252
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedAppl…
oising e68d7ce
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellRunsp…
oising 84529c6
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedAppl…
oising 35396da
address nits and completely restructure lifecycle management
9afd47b
conditionally use az cli in apphost sample; remove dead code
f4b6c05
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/PowerShellScrip…
oising cf0dfd4
address aaron's comments
45a2dec
fix git dumbness
dd67233
what
ee58e7e
drop some informational messages to debug level to reduce noise
6784a3f
Apply suggestions from code review
aaronpowell c656736
Merge branch 'main' into powershell
oising 1389a65
Update tests.yaml
oising d11ae45
Update src/CommunityToolkit.Aspire.Hosting.PowerShell/CommunityToolki…
aaronpowell a77e240
Merge branch 'main' into powershell
aaronpowell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
...munityToolkit.Aspire.PowerShell.AppHost/CommunityToolkit.Aspire.PowerShell.AppHost.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<Sdk Name="Aspire.AppHost.Sdk" Version="$(AspireAppHostSdkVersion)" /> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<IsAspireHost>true</IsAspireHost> | ||
<UserSecretsId>bc193f31-c9f7-4e3d-b70a-0dc39ec3047f</UserSecretsId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Aspire.Hosting" /> | ||
<PackageReference Include="Aspire.Hosting.AppHost" /> | ||
<PackageReference Include="Aspire.Hosting.Azure.Storage" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.PowerShell\CommunityToolkit.Aspire.Hosting.PowerShell.csproj" IsAspireProjectResource="false" /> | ||
</ItemGroup> | ||
|
||
</Project> |
39 changes: 39 additions & 0 deletions
39
examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Program.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using CommunityToolkit.Aspire.Hosting.PowerShell; | ||
|
||
var builder = DistributedApplication.CreateBuilder(args); | ||
|
||
var storage = builder.AddAzureStorage("storage").RunAsEmulator(); | ||
var blob = storage.AddBlobs("myblob"); | ||
|
||
var ps = builder.AddPowerShell("ps") | ||
.WithReference(blob) | ||
.WaitFor(storage); | ||
|
||
// uploads the script in scripts/ | ||
var script1 = ps.AddScript("script1", """ | ||
param($name) | ||
|
||
write-information "Hello, $name" | ||
|
||
# uncommenting this will hang the script if you don't attach the pwsh debugger | ||
# wait-debugger | ||
|
||
write-information "`$myblob is $myblob" | ||
|
||
az storage container create --connection-string $myblob -n demo | ||
az storage blob upload --connection-string $myblob -c demo --file ./scripts/script.ps1 | ||
|
||
write-information $pwd | ||
|
||
write-information "Blob uploaded" | ||
""").WithArgs("world"); | ||
|
||
// outputs "the sum of 2 and 3 is 5" | ||
var script2 = ps.AddScript("script2", """ | ||
& ./scripts/script.ps1 @args | ||
""") | ||
.WithArgs(2, 3) | ||
.WaitForCompletion(script1); | ||
|
||
builder.Build().Run(); | ||
|
29 changes: 29 additions & 0 deletions
29
...ples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Properties/launchSettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/launchsettings.json", | ||
"profiles": { | ||
"https": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "https://localhost:17118;http://localhost:15215", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development", | ||
"DOTNET_ENVIRONMENT": "Development", | ||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21165", | ||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22038" | ||
} | ||
}, | ||
"http": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "http://localhost:15215", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development", | ||
"DOTNET_ENVIRONMENT": "Development", | ||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19175", | ||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20201" | ||
} | ||
} | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/Scripts/script.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
param($a, $b) | ||
|
||
Write-Information "The sum of $a and $b is: $($a + $b)" |
9 changes: 9 additions & 0 deletions
9
examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost/appsettings.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning", | ||
"Aspire.Hosting.Dcp": "Warning" | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...munityToolkit.Aspire.Hosting.PowerShell/CommunityToolkit.Aspire.Hosting.PowerShell.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
aaronpowell marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<AdditionalPackageTags>powershell; pwsh; scripting; script; hosting</AdditionalPackageTags> | ||
<Description>Run powershell scripts in-process with your Aspire AppHost, injecting aspire resources and/or object instances as variables, using the command lines tools of your choice like azure cli, azd, or any other terminal tools.</Description> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Aspire.Hosting" /> | ||
<PackageReference Include="Microsoft.PowerShell.SDK" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<InternalsVisibleTo Include="CommunityToolkit.Aspire.Hosting.PowerShell.Tests" /> | ||
</ItemGroup> | ||
</Project> |
99 changes: 99 additions & 0 deletions
99
src/CommunityToolkit.Aspire.Hosting.PowerShell/DistributedApplicationBuilderExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
using Aspire.Hosting; | ||
using Aspire.Hosting.ApplicationModel; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
using System.Management.Automation; | ||
using System.Management.Automation.Runspaces; | ||
|
||
namespace CommunityToolkit.Aspire.Hosting.PowerShell; | ||
|
||
/// <summary> | ||
/// Extensions for the <see cref="IDistributedApplicationBuilder"/> to add PowerShell runspace pool resources. | ||
/// </summary> | ||
public static class DistributedApplicationBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Adds a PowerShell runspace pool resource to the distributed application. | ||
/// </summary> | ||
/// <param name="builder"></param> | ||
/// <param name="name"></param> | ||
/// <param name="languageMode"></param> | ||
/// <param name="minRunspaces"></param> | ||
/// <param name="maxRunspaces"></param> | ||
/// <returns></returns> | ||
/// <exception cref="ArgumentException"></exception> | ||
/// <exception cref="DistributedApplicationException"></exception> | ||
public static IResourceBuilder<PowerShellRunspacePoolResource> AddPowerShell( | ||
this IDistributedApplicationBuilder builder, | ||
[ResourceName] string name, | ||
PSLanguageMode languageMode = PSLanguageMode.ConstrainedLanguage, | ||
int minRunspaces = 1, | ||
int maxRunspaces = 5) | ||
{ | ||
if (string.IsNullOrWhiteSpace(name)) | ||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (builder.Resources.OfType<PowerShellRunspacePoolResource>().Any( | ||
rsp => rsp.Name == name)) | ||
{ | ||
throw new DistributedApplicationException("AddPowerShell failed", | ||
new InvalidOperationException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
"A PowerShell resource with the name '{0}' already exists.", name))); | ||
} | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
var pool = new PowerShellRunspacePoolResource(name, languageMode, minRunspaces, maxRunspaces); | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
builder.Eventing.Subscribe<AfterEndpointsAllocatedEvent>(async (e, ct) => | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
var pools = e.Model.Resources.OfType<PowerShellRunspacePoolResource>().ToList(); | ||
|
||
foreach (var poolResource in pools) | ||
{ | ||
Debug.Assert(poolResource is not null); | ||
|
||
var loggerService = e.Services.GetRequiredService<ResourceLoggerService>(); | ||
var notificationService = e.Services.GetRequiredService<ResourceNotificationService>(); | ||
|
||
var sessionState = InitialSessionState.CreateDefault(); | ||
|
||
foreach (var annotation in poolResource.Annotations) | ||
{ | ||
if (annotation is PowerShellVariableReferenceAnnotation<ConnectionStringReference> reference) | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
var connectionString = await reference.Value.Resource.GetConnectionStringAsync(ct); | ||
sessionState.Variables.Add( | ||
new SessionStateVariableEntry(reference.Name, connectionString, | ||
$"ConnectionString for {reference.Value.Resource.GetType().Name} '{reference.Name}'", | ||
ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope)); | ||
} | ||
} | ||
|
||
var poolName = poolResource.Name; | ||
var poolLogger = loggerService.GetLogger(poolName); | ||
|
||
_ = notificationService.WaitForDependenciesAsync(poolResource, ct) | ||
.ContinueWith( | ||
async _ => | ||
await poolResource.StartAsync(sessionState, notificationService, poolLogger, ct), | ||
oising marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ct); | ||
} | ||
}); | ||
|
||
return builder.AddResource(pool) | ||
.WithInitialState(new() | ||
{ | ||
ResourceType = "PowerShellRunspacePool", | ||
State = KnownResourceStates.NotStarted, | ||
Properties = [ | ||
|
||
new ("LanguageMode", pool.LanguageMode.ToString()), | ||
new ("MinRunspaces", pool.MinRunspaces.ToString()), | ||
new ("MaxRunspaces", pool.MaxRunspaces.ToString()) | ||
] | ||
}) | ||
.ExcludeFromManifest(); | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.