Initial commit
This commit is contained in:
3
skills/iot-edge-module/assets/template-.dockerignore
Normal file
3
skills/iot-edge-module/assets/template-.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
||||
# Ignore .NET build outputs
|
||||
**/bin
|
||||
**/obj
|
||||
34
skills/iot-edge-module/assets/template-.gitignore
Normal file
34
skills/iot-edge-module/assets/template-.gitignore
Normal file
@@ -0,0 +1,34 @@
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
.vs
|
||||
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
33
skills/iot-edge-module/assets/template-Dockerfile.amd64
Normal file
33
skills/iot-edge-module/assets/template-Dockerfile.amd64
Normal file
@@ -0,0 +1,33 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS build-env
|
||||
ARG FEED_ACCESSTOKEN
|
||||
WORKDIR /app
|
||||
|
||||
RUN curl -L https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | sh
|
||||
|
||||
RUN mkdir src
|
||||
COPY {{MODULE_CSPROJ_PATH}}/*.csproj ./src/
|
||||
{{CONTRACTS_CSPROJ_COPY}}
|
||||
COPY Directory.Build.props .
|
||||
COPY .editorconfig .
|
||||
COPY nuget.config .
|
||||
|
||||
{{NUGET_CONFIG_SECTION}}
|
||||
RUN dotnet restore "./src/{{ModuleName}}.csproj"
|
||||
COPY src/ ./src/
|
||||
RUN dotnet publish "{{MODULE_PUBLISH_PATH}}/{{ModuleName}}.csproj" -c Release -o out
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:9.0-bookworm-slim
|
||||
WORKDIR /app
|
||||
COPY --from=build-env /app/out ./
|
||||
|
||||
ENV USER=moduleuser
|
||||
ENV PUID=2000
|
||||
ENV TPM_GID=3000
|
||||
|
||||
RUN useradd --uid $PUID --shell /bin/bash --create-home "$USER"
|
||||
RUN groupadd -f -g $TPM_GID aziottpm
|
||||
RUN usermod -a -G aziottpm $USER
|
||||
|
||||
USER $USER
|
||||
|
||||
ENTRYPOINT ["./{{ModuleName}}"]
|
||||
@@ -0,0 +1,38 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS build-env
|
||||
ARG FEED_ACCESSTOKEN
|
||||
WORKDIR /app
|
||||
|
||||
RUN curl -L https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | sh
|
||||
|
||||
RUN mkdir src
|
||||
COPY {{MODULE_CSPROJ_PATH}}/*.csproj ./src/
|
||||
{{CONTRACTS_CSPROJ_COPY}}
|
||||
COPY Directory.Build.props .
|
||||
COPY .editorconfig .
|
||||
COPY nuget.config .
|
||||
|
||||
{{NUGET_CONFIG_SECTION}}
|
||||
RUN dotnet restore "./src/{{ModuleName}}.csproj"
|
||||
COPY src/ ./src/
|
||||
RUN dotnet publish "{{MODULE_PUBLISH_PATH}}/{{ModuleName}}.csproj" -c Debug -o out
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime:9.0-bookworm-slim
|
||||
WORKDIR /app
|
||||
COPY --from=build-env /app/out ./
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends unzip procps && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -v latest -l ~/vsdbg
|
||||
|
||||
ENV USER=moduleuser
|
||||
ENV PUID=2000
|
||||
ENV TPM_GID=3000
|
||||
|
||||
RUN useradd --uid $PUID --shell /bin/bash --create-home "$USER"
|
||||
RUN groupadd -f -g $TPM_GID aziottpm
|
||||
RUN usermod -a -G aziottpm $USER
|
||||
|
||||
USER $USER
|
||||
|
||||
ENTRYPOINT ["./{{ModuleName}}"]
|
||||
10
skills/iot-edge-module/assets/template-GlobalUsings.cs
Normal file
10
skills/iot-edge-module/assets/template-GlobalUsings.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
global using Atc.Azure.IoTEdge.Extensions;
|
||||
global using Atc.Azure.IoTEdge.Factories;
|
||||
global using Atc.Azure.IoTEdge.TestMocks;
|
||||
global using Atc.Azure.IoTEdge.Wrappers;
|
||||
global using {{PROJECT_NAMESPACE}}.Modules.Contracts.Extensions;
|
||||
global using {{PROJECT_NAMESPACE}}.Modules.Contracts.{{ModuleName}};
|
||||
global using Microsoft.Azure.Devices.Client;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.Hosting;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace {{PROJECT_NAMESPACE}}.Modules.Contracts.Extensions;
|
||||
|
||||
public static class LoggingBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds systemd console logging with standardized timestamp format and log level configuration.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="ILoggingBuilder"/> to configure.</param>
|
||||
/// <returns>The <see cref="ILoggingBuilder"/> for chaining.</returns>
|
||||
public static ILoggingBuilder AddModuleConsoleLogging(this ILoggingBuilder builder)
|
||||
{
|
||||
builder.AddSystemdConsole(options =>
|
||||
{
|
||||
options.UseUtcTimestamp = true;
|
||||
options.TimestampFormat = " yyyy-MM-dd HH:mm:ss.fff zzz ";
|
||||
});
|
||||
|
||||
builder.SetMinimumLevel(LogLevel.Information);
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace {{PROJECT_NAMESPACE}}.Modules.Contracts.{{ModuleName}};
|
||||
|
||||
public static class {{ModuleName}}Constants
|
||||
{
|
||||
public const string ModuleId = "{{modulename}}";
|
||||
|
||||
//// TODO: Add direct method name constants here
|
||||
//// public const string DirectMethodExampleMethod = "ExampleMethod";
|
||||
}
|
||||
35
skills/iot-edge-module/assets/template-Program.cs
Normal file
35
skills/iot-edge-module/assets/template-Program.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace {{ModuleName}};
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
using var host = Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((hostContext, services) =>
|
||||
{
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
builder.AddModuleConsoleLogging();
|
||||
});
|
||||
|
||||
if (hostContext.IsStandaloneMode())
|
||||
{
|
||||
services.AddSingleton<IModuleClientWrapper, MockModuleClientWrapper>();
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddModuleClientWrapper(TransportSettingsFactory.BuildMqttTransportSettings());
|
||||
}
|
||||
|
||||
services.AddSingleton<IMethodResponseFactory, MethodResponseFactory>();
|
||||
|
||||
//// TODO: Add your service registrations here
|
||||
|
||||
services.AddHostedService<{{ModuleName}}Service>();
|
||||
})
|
||||
.UseConsoleLifetime()
|
||||
.Build();
|
||||
|
||||
await host.RunAsync();
|
||||
}
|
||||
}
|
||||
59
skills/iot-edge-module/assets/template-Service.cs
Normal file
59
skills/iot-edge-module/assets/template-Service.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
namespace {{ModuleName}};
|
||||
|
||||
/// <summary>
|
||||
/// The main {{ModuleName}}Service.
|
||||
/// </summary>
|
||||
public sealed partial class {{ModuleName}}Service : IHostedService
|
||||
{
|
||||
private readonly IHostApplicationLifetime hostApplication;
|
||||
private readonly IModuleClientWrapper moduleClient;
|
||||
|
||||
public {{ModuleName}}Service(
|
||||
ILogger<{{ModuleName}}Service> logger,
|
||||
IHostApplicationLifetime hostApplication,
|
||||
IModuleClientWrapper moduleClient)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.hostApplication = hostApplication;
|
||||
this.moduleClient = moduleClient;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
hostApplication.ApplicationStarted.Register(OnStarted);
|
||||
hostApplication.ApplicationStopping.Register(OnStopping);
|
||||
hostApplication.ApplicationStopped.Register(OnStopped);
|
||||
|
||||
moduleClient.SetConnectionStatusChangesHandler(LogConnectionStatusChange);
|
||||
|
||||
await moduleClient.OpenAsync(cancellationToken);
|
||||
|
||||
// TODO: Register direct method handlers here
|
||||
//// await moduleClient.SetMethodHandlerAsync("MethodName", HandleMethodAsync, string.Empty, cancellationToken);
|
||||
|
||||
LogModuleClientStarted({{ModuleName}}Constants.ModuleId);
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await moduleClient.CloseAsync(cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Cancellation is expected during shutdown — safe to ignore
|
||||
}
|
||||
|
||||
LogModuleClientStopped({{ModuleName}}Constants.ModuleId);
|
||||
}
|
||||
|
||||
private void OnStarted()
|
||||
=> LogModuleStarted({{ModuleName}}Constants.ModuleId);
|
||||
|
||||
private void OnStopping()
|
||||
=> LogModuleStopping({{ModuleName}}Constants.ModuleId);
|
||||
|
||||
private void OnStopped()
|
||||
=> LogModuleStopped({{ModuleName}}Constants.ModuleId);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace {{ModuleName}};
|
||||
|
||||
/// <summary>
|
||||
/// {{ModuleName}}Service LoggerMessages.
|
||||
/// </summary>
|
||||
public sealed partial class {{ModuleName}}Service
|
||||
{
|
||||
private readonly ILogger<{{ModuleName}}Service> logger;
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ModuleStarted,
|
||||
Level = LogLevel.Trace,
|
||||
Message = "Successfully started module '{ModuleName}'")]
|
||||
private partial void LogModuleStarted(string moduleName);
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ModuleStopping,
|
||||
Level = LogLevel.Trace,
|
||||
Message = "Stopping module '{ModuleName}'")]
|
||||
private partial void LogModuleStopping(string moduleName);
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ModuleStopped,
|
||||
Level = LogLevel.Trace,
|
||||
Message = "Successfully stopped module '{moduleName}'")]
|
||||
private partial void LogModuleStopped(string moduleName);
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ModuleClientStarted,
|
||||
Level = LogLevel.Trace,
|
||||
Message = "Successfully started moduleClient for module '{ModuleName}'")]
|
||||
private partial void LogModuleClientStarted(string moduleName);
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ModuleClientStopped,
|
||||
Level = LogLevel.Trace,
|
||||
Message = "Successfully stopped moduleClient for module '{ModuleName}'")]
|
||||
private partial void LogModuleClientStopped(string moduleName);
|
||||
|
||||
[LoggerMessage(
|
||||
EventId = Atc.Azure.IoTEdge.LoggingEventIdConstants.ConnectionStatusChange,
|
||||
Level = LogLevel.Debug,
|
||||
Message = "Connection status changed: Status={Status}, Reason={Reason}")]
|
||||
private partial void LogConnectionStatusChange(ConnectionStatus status, ConnectionStatusChangeReason reason);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"modulesContent": {
|
||||
"$edgeAgent": {
|
||||
"properties.desired": {
|
||||
"schemaVersion": "1.1",
|
||||
"modules": {},
|
||||
"runtime": {
|
||||
"type": "docker",
|
||||
"settings": {
|
||||
"minDockerVersion": "v1.25",
|
||||
"registryCredentials": {
|
||||
"registryName": {
|
||||
"username": "${ContainerRegistryUserName}",
|
||||
"password": "${ContainerRegistryPassword}",
|
||||
"address": "${ContainerRegistryLoginServer}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"systemModules": {
|
||||
"edgeAgent": {
|
||||
"imagePullPolicy": "on-create",
|
||||
"type": "docker",
|
||||
"env": {
|
||||
"storageFolder": {
|
||||
"value": "/aziot/storage/"
|
||||
},
|
||||
"UpstreamProtocol": {
|
||||
"value": "AMQPWS"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"image": "mcr.microsoft.com/azureiotedge-agent:1.5",
|
||||
"createOptions": {
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
"/etc/aziot/storage/:/aziot/storage/"
|
||||
],
|
||||
"LogConfig": {
|
||||
"Type": "json-file",
|
||||
"Config": {
|
||||
"max-size": "10m",
|
||||
"max-file": "10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"edgeHub": {
|
||||
"imagePullPolicy": "on-create",
|
||||
"type": "docker",
|
||||
"env": {
|
||||
"storageFolder": {
|
||||
"value": "/aziot/storage/"
|
||||
},
|
||||
"UpstreamProtocol": {
|
||||
"value": "AMQPWS"
|
||||
}
|
||||
},
|
||||
"status": "running",
|
||||
"restartPolicy": "always",
|
||||
"startupOrder": 0,
|
||||
"settings": {
|
||||
"image": "mcr.microsoft.com/azureiotedge-hub:1.5",
|
||||
"createOptions": {
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
"/etc/aziot/storage/:/aziot/storage/"
|
||||
],
|
||||
"LogConfig": {
|
||||
"Type": "json-file",
|
||||
"Config": {
|
||||
"max-size": "10m",
|
||||
"max-file": "10"
|
||||
}
|
||||
},
|
||||
"PortBindings": {
|
||||
"5671/tcp": [
|
||||
{
|
||||
"HostPort": "5671"
|
||||
}
|
||||
],
|
||||
"8883/tcp": [
|
||||
{
|
||||
"HostPort": "8883"
|
||||
}
|
||||
],
|
||||
"443/tcp": [
|
||||
{
|
||||
"HostPort": "443"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$edgeHub": {
|
||||
"properties.desired": {
|
||||
"schemaVersion": "1.1",
|
||||
"storeAndForwardConfiguration": {
|
||||
"timeToLiveSecs": 86400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
skills/iot-edge-module/assets/template-launchSettings.json
Normal file
13
skills/iot-edge-module/assets/template-launchSettings.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"profiles": {
|
||||
"{{ModuleName}}": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Standalone"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
skills/iot-edge-module/assets/template-module.json
Normal file
17
skills/iot-edge-module/assets/template-module.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema-version": "0.0.1",
|
||||
"description": "{{ModuleDescription}}",
|
||||
"image": {
|
||||
"repository": "{{CONTAINER_REGISTRY}}/{{modulename}}",
|
||||
"tag": {
|
||||
"version": "0.0.${BUILD_BUILDID}",
|
||||
"platforms": {
|
||||
"amd64": "./Dockerfile.amd64",
|
||||
"amd64.debug": "./Dockerfile.amd64.debug"
|
||||
}
|
||||
},
|
||||
"buildOptions": [],
|
||||
"contextPath": "../../../"
|
||||
},
|
||||
"language": "csharp"
|
||||
}
|
||||
32
skills/iot-edge-module/assets/template.csproj
Normal file
32
skills/iot-edge-module/assets/template.csproj
Normal file
@@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Atc" Version="2.0.562" />
|
||||
<PackageReference Include="Atc.Azure.IoTEdge" Version="1.0.177" />
|
||||
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.42.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.11" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
{{CONTRACTS_PROJECT_REFERENCE}}
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="$(AssemblyName).Tests" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user