Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Add support for Dapr + Function apps #1612

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,5 @@ MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

.idea/
4 changes: 1 addition & 3 deletions src/Microsoft.Tye.Core/AzureFunctionServiceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@

namespace Microsoft.Tye
{
public class AzureFunctionServiceBuilder : ServiceBuilder
public class AzureFunctionServiceBuilder : LaunchedServiceBuilder
{
public AzureFunctionServiceBuilder(string name, string path, ServiceSource source)
: base(name, source)
{
FunctionPath = path;
}

public int Replicas { get; set; } = 1;
public string? Args { get; set; }
public string FunctionPath { get; }
public string? FuncExecutablePath { get; set; }
public string? ProjectFile { get; set; }
public string? AzureFunctionsVersion { get; set; }
public List<EnvironmentVariableBuilder> EnvironmentVariables { get; } = new List<EnvironmentVariableBuilder>();
}
}
3 changes: 2 additions & 1 deletion src/Microsoft.Tye.Extensions/Dapr/DaprExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public override async Task ProcessAsync(ExtensionContext context, ExtensionConfi
// For local run, enumerate all projects, and add services for each dapr proxy.
var projects = context.Application.Services.OfType<ProjectServiceBuilder>().Cast<LaunchedServiceBuilder>();
var executables = context.Application.Services.OfType<ExecutableServiceBuilder>().Cast<LaunchedServiceBuilder>();
var services = projects.Concat(executables).ToList();
var functions = context.Application.Services.OfType<AzureFunctionServiceBuilder>().Cast<LaunchedServiceBuilder>();
var services = projects.Concat(executables).Concat(functions).ToList();

foreach (var project in services)
{
Expand Down
4 changes: 3 additions & 1 deletion test/E2ETest/Microsoft.Tye.E2ETests.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
Expand All @@ -15,6 +15,7 @@
The Microsoft.Build.Locator package takes care of dynamically loading these assemblies
at runtime. We don't need/want to ship them, just to have them as references.
-->

<PackageReference Include="Microsoft.Build" Version="17.3.2" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
Expand All @@ -29,6 +30,7 @@
</ItemGroup>

<ItemGroup>

<Content Include="testassets\**\*" CopyToOutputDirectory="PreserveNewest" />
<Compile Remove="testassets\**\*" />
<None Remove="testassets\generate\apps-with-ingress.1.18.yaml" />
Expand Down
4 changes: 4 additions & 0 deletions test/E2ETest/TyeGenerateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ public async Task Generate_DaprApplication()
}
}





[ConditionalFact]
[SkipIfDockerNotRunning]
public async Task Generate_ConnectionStringDependency()
Expand Down
40 changes: 37 additions & 3 deletions test/E2ETest/TyeRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ public async Task FrontendBackendRunTest()
});
}

[Fact(Skip = "Need to figure out how to install func before running")]
//[Fact(Skip = "Need to figure out how to install func before running")]
[Fact]
public async Task FrontendBackendAzureFunctionTest()
{
// Install to directory
using var tmp = TempDirectory.Create();
await ProcessUtil.RunAsync("npm", "install azure-functions-core-tools@3`", workingDirectory: tmp.DirectoryPath);
//await ProcessUtil.RunAsync("npm", "install azure-functions-core-tools@3`", workingDirectory: tmp.DirectoryPath);
using var projectDirectory = CopyTestProjectDirectory("azure-functions");

var content = @$"
Expand All @@ -97,7 +98,6 @@ public async Task FrontendBackendAzureFunctionTest()
services:
- name: backend
azureFunction: backend/
pathToFunc: {tmp.DirectoryPath}/node_modules/azure-functions-core-tools/bin/func.dll
- name: frontend
project: frontend/frontend.csproj";

Expand Down Expand Up @@ -126,6 +126,40 @@ public async Task FrontendBackendAzureFunctionTest()
Assert.True(frontendResponse.IsSuccessStatusCode);
});
}
[Fact]
public async Task DaprAzureFunctionTest()
{
using var projectDirectory = CopyTestProjectDirectory("dapr-function-app");

var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
var outputContext = new OutputContext(_sink, Verbosity.Debug);
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);

await application.ProcessExtensionsAsync(new HostOptions(), outputContext, ExtensionContext.OperationKind.LocalRun);
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
AllowAutoRedirect = false
};

var client = new HttpClient(new RetryHandler(handler));

await RunHostingApplication(application, new HostOptions(), async (app, uri) =>
{
//The backend calls the Function app via Dapr InvokeMethod. So test that that func has a sidecar, and being proxied.
var backendUri = await GetServiceUrl(client, uri, "dapr-test-project");

//Wait for the services to start
await Task.Delay(10000);

var backendResponse = await client.GetAsync(backendUri);

Assert.True(backendResponse.IsSuccessStatusCode);

var responseContent = await backendResponse.Content.ReadAsStringAsync();
Assert.Contains("Welcome to Azure Functions!", responseContent);
});
}

[ConditionalTheory]
[SkipIfDockerNotRunning]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<TargetFramework>net7.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.2.0" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 25.0.1706.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dapr-function-app", "function/dapr-function-app.csproj", "{0979B3EB-D56F-4402-A858-AB19B6D9B902}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dapr", "dapr\dapr.csproj", "{8336F6C8-57F3-4D80-B4AF-CFE0A9DA446E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0979B3EB-D56F-4402-A858-AB19B6D9B902}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0979B3EB-D56F-4402-A858-AB19B6D9B902}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0979B3EB-D56F-4402-A858-AB19B6D9B902}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0979B3EB-D56F-4402-A858-AB19B6D9B902}.Release|Any CPU.Build.0 = Release|Any CPU
{8336F6C8-57F3-4D80-B4AF-CFE0A9DA446E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8336F6C8-57F3-4D80-B4AF-CFE0A9DA446E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8336F6C8-57F3-4D80-B4AF-CFE0A9DA446E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8336F6C8-57F3-4D80-B4AF-CFE0A9DA446E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B9930E6C-6675-4B5A-8D01-5BEEABAF024D}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace dapr
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:64181",
"sslPort": 44315
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dapr": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Dapr.Client;

namespace dapr
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
var functionAppId = "dapr-function-app";
var methodName = "api/HttpTrigger1";


var daprClient = new DaprClientBuilder().Build();
var daprRequest = daprClient.CreateInvokeMethodRequest(HttpMethod.Post, functionAppId, methodName);

var response = await daprClient.InvokeMethodWithResponseAsync(daprRequest);

await context.Response.WriteAsync(await response.Content.ReadAsStringAsync());
});
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapr.Client" Version="1.11.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace dapr_function_app
{
public class HttpTrigger1
{
private readonly ILogger _logger;

public HttpTrigger1(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<HttpTrigger1>();
}

[Function("HttpTrigger1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");

var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

response.WriteString("Welcome to Azure Functions!");

return response;
}


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

internal class Program
{
private static void Main(string[] args)
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(config =>
{
config.Services.AddLogging();
})
.Build();


host.Run();
}
}
Loading