Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 63 additions & 3 deletions src/Aspire.Hosting/ContainerResourceBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public static class ContainerResourceBuilderExtensions
/// <returns>The <see cref="IResourceBuilder{T}"/> for chaining.</returns>
public static IResourceBuilder<ContainerResource> AddContainer(this IDistributedApplicationBuilder builder, [ResourceName] string name, string image)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(image);

return builder.AddContainer(name, image, "latest");
}

Expand All @@ -33,6 +37,11 @@ public static IResourceBuilder<ContainerResource> AddContainer(this IDistributed
/// <returns>The <see cref="IResourceBuilder{T}"/> for chaining.</returns>
public static IResourceBuilder<ContainerResource> AddContainer(this IDistributedApplicationBuilder builder, [ResourceName] string name, string image, string tag)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(image);
ArgumentNullException.ThrowIfNull(tag);

var container = new ContainerResource(name);
return builder.AddResource(container)
.WithImage(image, tag);
Expand All @@ -47,8 +56,11 @@ public static IResourceBuilder<ContainerResource> AddContainer(this IDistributed
/// <param name="target">The target path where the volume is mounted in the container.</param>
/// <param name="isReadOnly">A flag that indicates if the volume should be mounted as read-only.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithVolume<T>(this IResourceBuilder<T> builder, string name, string target, bool isReadOnly = false) where T : ContainerResource
public static IResourceBuilder<T> WithVolume<T>(this IResourceBuilder<T> builder, string? name, string target, bool isReadOnly = false) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(target);

var annotation = new ContainerMountAnnotation(name, target, ContainerMountType.Volume, isReadOnly);
return builder.WithAnnotation(annotation);
}
Expand All @@ -62,6 +74,9 @@ public static IResourceBuilder<T> WithVolume<T>(this IResourceBuilder<T> builder
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithVolume<T>(this IResourceBuilder<T> builder, string target) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(target);

var annotation = new ContainerMountAnnotation(null, target, ContainerMountType.Volume, false);
return builder.WithAnnotation(annotation);
}
Expand All @@ -77,6 +92,10 @@ public static IResourceBuilder<T> WithVolume<T>(this IResourceBuilder<T> builder
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithBindMount<T>(this IResourceBuilder<T> builder, string source, string target, bool isReadOnly = false) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(target);

var annotation = new ContainerMountAnnotation(Path.GetFullPath(source, builder.ApplicationBuilder.AppHostDirectory), target, ContainerMountType.BindMount, isReadOnly);
return builder.WithAnnotation(annotation);
}
Expand All @@ -90,6 +109,9 @@ public static IResourceBuilder<T> WithBindMount<T>(this IResourceBuilder<T> buil
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithEntrypoint<T>(this IResourceBuilder<T> builder, string entrypoint) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(entrypoint);

builder.Resource.Entrypoint = entrypoint;
return builder;
}
Expand All @@ -103,6 +125,9 @@ public static IResourceBuilder<T> WithEntrypoint<T>(this IResourceBuilder<T> bui
/// <returns></returns>
public static IResourceBuilder<T> WithImageTag<T>(this IResourceBuilder<T> builder, string tag) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(tag);

if (builder.Resource.Annotations.OfType<ContainerImageAnnotation>().LastOrDefault() is { } existingImageAnnotation)
{
existingImageAnnotation.Tag = tag;
Expand All @@ -119,8 +144,10 @@ public static IResourceBuilder<T> WithImageTag<T>(this IResourceBuilder<T> build
/// <param name="builder">Builder for the container resource.</param>
/// <param name="registry">Registry value.</param>
/// <returns></returns>
public static IResourceBuilder<T> WithImageRegistry<T>(this IResourceBuilder<T> builder, string registry) where T : ContainerResource
public static IResourceBuilder<T> WithImageRegistry<T>(this IResourceBuilder<T> builder, string? registry) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);

if (builder.Resource.Annotations.OfType<ContainerImageAnnotation>().LastOrDefault() is { } existingImageAnnotation)
{
existingImageAnnotation.Registry = registry;
Expand All @@ -140,6 +167,10 @@ public static IResourceBuilder<T> WithImageRegistry<T>(this IResourceBuilder<T>
/// <returns></returns>
public static IResourceBuilder<T> WithImage<T>(this IResourceBuilder<T> builder, string image, string tag = "latest") where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(image);
ArgumentNullException.ThrowIfNull(tag);

if (builder.Resource.Annotations.OfType<ContainerImageAnnotation>().LastOrDefault() is { } existingImageAnnotation)
{
existingImageAnnotation.Image = image;
Expand All @@ -162,6 +193,9 @@ public static IResourceBuilder<T> WithImage<T>(this IResourceBuilder<T> builder,
/// <returns></returns>
public static IResourceBuilder<T> WithImageSHA256<T>(this IResourceBuilder<T> builder, string sha256) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(sha256);

if (builder.Resource.Annotations.OfType<ContainerImageAnnotation>().LastOrDefault() is { } existingImageAnnotation)
{
existingImageAnnotation.SHA256 = sha256;
Expand All @@ -183,6 +217,8 @@ public static IResourceBuilder<T> WithImageSHA256<T>(this IResourceBuilder<T> bu
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuilder<T> builder, params string[] args) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithContainerRuntimeArgs(context => context.Args.AddRange(args));
}

Expand All @@ -198,6 +234,9 @@ public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuil
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuilder<T> builder, Action<ContainerRuntimeArgsCallbackContext> callback) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(callback);

return builder.WithContainerRuntimeArgs(context =>
{
callback(context);
Expand All @@ -217,6 +256,9 @@ public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuil
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuilder<T> builder, Func<ContainerRuntimeArgsCallbackContext, Task> callback) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(callback);

var annotation = new ContainerRuntimeArgsCallbackAnnotation(callback);
return builder.WithAnnotation(annotation);
}
Expand All @@ -238,6 +280,8 @@ public static IResourceBuilder<T> WithContainerRuntimeArgs<T>(this IResourceBuil
/// </example>
public static IResourceBuilder<T> WithLifetime<T>(this IResourceBuilder<T> builder, ContainerLifetime lifetime) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithAnnotation(new ContainerLifetimeAnnotation { Lifetime = lifetime }, ResourceAnnotationMutationBehavior.Replace);
}

Expand All @@ -253,6 +297,8 @@ private static IResourceBuilder<T> ThrowResourceIsNotContainer<T>(IResourceBuild
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> PublishAsContainer<T>(this IResourceBuilder<T> builder) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithManifestPublishingCallback(context => context.WriteContainerAsync(builder.Resource));
}

Expand Down Expand Up @@ -293,6 +339,7 @@ public static IResourceBuilder<T> PublishAsContainer<T>(this IResourceBuilder<T>
/// </example>
public static IResourceBuilder<T> WithDockerfile<T>(this IResourceBuilder<T> builder, string contextPath, string? dockerfilePath = null, string? stage = null) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(contextPath);

var fullyQualifiedContextPath = Path.GetFullPath(contextPath, builder.ApplicationBuilder.AppHostDirectory);
Expand All @@ -314,7 +361,7 @@ public static IResourceBuilder<T> WithDockerfile<T>(this IResourceBuilder<T> bui
var imageName = builder.GenerateImageName();
var annotation = new DockerfileBuildAnnotation(fullyQualifiedContextPath, fullyQualifiedDockerfilePath, stage);
return builder.WithAnnotation(annotation, ResourceAnnotationMutationBehavior.Replace)
.WithImageRegistry(null!)
.WithImageRegistry(registry: null)
.WithImage(imageName)
.WithImageTag("latest");
}
Expand Down Expand Up @@ -350,6 +397,10 @@ public static IResourceBuilder<T> WithDockerfile<T>(this IResourceBuilder<T> bui
/// </example>
public static IResourceBuilder<ContainerResource> AddDockerfile(this IDistributedApplicationBuilder builder, [ResourceName] string name, string contextPath, string? dockerfilePath = null, string? stage = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(contextPath);

return builder.AddContainer(name, "placeholder") // Image name will be replaced by WithDockerfile.
.WithDockerfile(contextPath, dockerfilePath, stage);
}
Expand All @@ -369,6 +420,9 @@ public static IResourceBuilder<ContainerResource> AddDockerfile(this IDistribute
/// <returns>The resource bulder for the container resource.</returns>
public static IResourceBuilder<T> WithContainerName<T>(this IResourceBuilder<T> builder, string name) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);

return builder.WithAnnotation(new ContainerNameAnnotation { Name = name }, ResourceAnnotationMutationBehavior.Replace);
}

Expand Down Expand Up @@ -402,6 +456,7 @@ public static IResourceBuilder<T> WithContainerName<T>(this IResourceBuilder<T>
/// </example>
public static IResourceBuilder<T> WithBuildArg<T>(this IResourceBuilder<T> builder, string name, object value) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(name);
ArgumentNullException.ThrowIfNull(value);

Expand Down Expand Up @@ -448,6 +503,10 @@ public static IResourceBuilder<T> WithBuildArg<T>(this IResourceBuilder<T> build
/// </example>
public static IResourceBuilder<T> WithBuildArg<T>(this IResourceBuilder<T> builder, string name, IResourceBuilder<ParameterResource> value) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(value);

if (value.Resource.Secret)
{
throw new InvalidOperationException("Cannot add secret parameter as a build argument. Use WithSecretBuildArg instead.");
Expand Down Expand Up @@ -487,6 +546,7 @@ public static IResourceBuilder<T> WithBuildArg<T>(this IResourceBuilder<T> build
/// </example>
public static IResourceBuilder<T> WithBuildSecret<T>(this IResourceBuilder<T> builder, string name, IResourceBuilder<ParameterResource> value) where T : ContainerResource
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrEmpty(name);
ArgumentNullException.ThrowIfNull(value);

Expand Down
4 changes: 4 additions & 0 deletions src/Aspire.Hosting/ContainerResourceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public static class ContainerResourceExtensions
/// <returns>A collection of container resources in the specified distributed application model.</returns>
public static IEnumerable<IResource> GetContainerResources(this DistributedApplicationModel model)
{
ArgumentNullException.ThrowIfNull(model);

foreach (var resource in model.Resources)
{
if (resource.Annotations.OfType<ContainerImageAnnotation>().Any())
Expand All @@ -33,6 +35,8 @@ public static IEnumerable<IResource> GetContainerResources(this DistributedAppli
/// <returns>true if the specified resource is a container resource; otherwise, false.</returns>
public static bool IsContainer(this IResource resource)
{
ArgumentNullException.ThrowIfNull(resource);

return resource.Annotations.OfType<ContainerImageAnnotation>().Any();
}
}
12 changes: 12 additions & 0 deletions src/Aspire.Hosting/ExecutableResourceBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public static class ExecutableResourceBuilderExtensions
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<ExecutableResource> AddExecutable(this IDistributedApplicationBuilder builder, [ResourceName] string name, string command, string workingDirectory, params string[]? args)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(command);
ArgumentNullException.ThrowIfNull(workingDirectory);

return AddExecutable(builder, name, command, workingDirectory, (object[]?)args);
}

Expand All @@ -37,6 +42,11 @@ public static IResourceBuilder<ExecutableResource> AddExecutable(this IDistribut
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<ExecutableResource> AddExecutable(this IDistributedApplicationBuilder builder, [ResourceName] string name, string command, string workingDirectory, params object[]? args)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(command);
ArgumentNullException.ThrowIfNull(workingDirectory);

workingDirectory = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, workingDirectory));

var executable = new ExecutableResource(name, command, workingDirectory);
Expand All @@ -61,6 +71,8 @@ public static IResourceBuilder<ExecutableResource> AddExecutable(this IDistribut
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> PublishAsDockerFile<T>(this IResourceBuilder<T> builder, IEnumerable<DockerBuildArg>? buildArgs = null) where T : ExecutableResource
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithManifestPublishingCallback(context => WriteExecutableAsDockerfileResourceAsync(context, builder.Resource, buildArgs));
}

Expand Down
2 changes: 2 additions & 0 deletions src/Aspire.Hosting/ExecutableResourceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public static class ExecutableResourceExtensions
/// <returns>An enumerable collection of executable resources.</returns>
public static IEnumerable<ExecutableResource> GetExecutableResources(this DistributedApplicationModel model)
{
ArgumentNullException.ThrowIfNull(model);

return model.Resources.OfType<ExecutableResource>();
}
}
6 changes: 6 additions & 0 deletions src/Aspire.Hosting/OtlpConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public static class OtlpConfigurationExtensions
/// <param name="environment">The host environment to check if the application is running in development mode.</param>
public static void AddOtlpEnvironment(IResource resource, IConfiguration configuration, IHostEnvironment environment)
{
ArgumentNullException.ThrowIfNull(resource);
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(environment);

// Configure OpenTelemetry in projects using environment variables.
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md

Expand Down Expand Up @@ -112,6 +116,8 @@ static void SetOtelEndpointAndProtocol(Dictionary<string, object> environmentVar
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<T> WithOtlpExporter<T>(this IResourceBuilder<T> builder) where T : IResourceWithEnvironment
{
ArgumentNullException.ThrowIfNull(builder);

AddOtlpEnvironment(builder.Resource, builder.ApplicationBuilder.Configuration, builder.ApplicationBuilder.Environment);
return builder;
}
Expand Down
Loading