public override Task ProcessAsync(ExtensionContext context, ExtensionConfiguration config) { // If we're getting called then the user configured dapr in their tye.yaml. // We don't have any of our own config. if (context.Operation == ExtensionContext.OperationKind.LocalRun) { // default placement port number var daprPlacementImage = "daprio/dapr"; var daprPlacementContainerPort = 50005; var daprPlacementPort = NextPortFinder.GetNextPort(); var isCustomPlacementPortDefined = false; // see if a placement port number has been defined if (config.Data.TryGetValue("placement-port", out var obj) && obj?.ToString() is string && int.TryParse(obj.ToString(), out var customPlacementPort)) { context.Output.WriteDebugLine($"Using Dapr placement service host port {customPlacementPort} from 'placement-port'"); daprPlacementPort = customPlacementPort; isCustomPlacementPortDefined = true; } // see if a placement image has been defined if (config.Data.TryGetValue("placement-image", out obj) && obj?.ToString() is string customPlacementImage) { context.Output.WriteDebugLine($"Using Dapr placement service image {customPlacementImage} from 'placement-image'"); daprPlacementImage = customPlacementImage; } // see if a placement container port has been defined if (config.Data.TryGetValue("placement-container-port", out obj) && obj?.ToString() is string && int.TryParse(obj.ToString(), out var customPlacementContainerPort)) { context.Output.WriteDebugLine($"Using Dapr placement service container port {customPlacementContainerPort} from 'placement-container-port'"); daprPlacementContainerPort = customPlacementContainerPort; } // We can only skip injecting a Dapr placement container if a 'placement-port' has been defined and 'exclude-placement-container=true' if (!(isCustomPlacementPortDefined && config.Data.TryGetValue("exclude-placement-container", out obj) && obj?.ToString() is string excludePlacementContainer && excludePlacementContainer == "true")) { if (!isCustomPlacementPortDefined) { context.Output.WriteDebugLine("A 'placement-port' has not been defined. So the 'exclude-placement-container' will default to 'false'."); } context.Output.WriteDebugLine("Injecting Dapr placement service..."); var daprPlacement = new ContainerServiceBuilder("placement", daprPlacementImage) { Args = "./placement", Bindings = { new BindingBuilder() { Port = daprPlacementPort, ContainerPort = daprPlacementContainerPort, Protocol = "http" } } }; context.Application.Services.Add(daprPlacement); } else { context.Output.WriteDebugLine("Skipping injecting Dapr placement service because 'exclude-placement-container=true'."); } // For local run, enumerate all projects, and add services for each dapr proxy. var projects = context.Application.Services.OfType <ProjectServiceBuilder>().ToList(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.FirstOrDefault(b => b.Protocol == "http"); if (httpBinding == null) { continue; } // See https://github.com/dotnet/tye/issues/260 // // Currently the pub-sub pattern does not work when you have multiple replicas. Each // daprd instance expects that it has a single application to talk to. So if you're using // pub-sub this means that you'll won't get some messages. // // We have no way to know if an app is using pub-sub or not, so just block it. if (project.Replicas > 1) { throw new CommandException("Dapr support does not support multiple replicas yet for development."); } var daprExecutablePath = GetDaprExecutablePath(); var proxy = new ExecutableServiceBuilder($"{project.Name}-dapr", daprExecutablePath) { WorkingDirectory = context.Application.Source.DirectoryName, // These environment variables are replaced with environment variables // defined for this service. Args = $"-app-id {project.Name} -app-port %APP_PORT% -dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT% --placement-host-address localhost:{daprPlacementPort}", }; // When running locally `-config` specifies a filename, not a configuration name. By convention // we'll assume the filename and config name are the same. if (config.Data.TryGetValue("config", out obj) && obj?.ToString() is string daprConfig) { var configFile = Path.Combine(context.Application.Source.DirectoryName !, "components", $"{daprConfig}.yaml"); if (File.Exists(configFile)) { proxy.Args += $" -config \"{configFile}\""; } else { context.Output.WriteAlwaysLine($"Could not find dapr config '{configFile}'. Skipping..."); } } if (config.Data.TryGetValue("log-level", out obj) && obj?.ToString() is string logLevel) { proxy.Args += $" -log-level {logLevel}"; } if (config.Data.TryGetValue("components-path", out obj) && obj?.ToString() is string componentsPath) { proxy.Args += $" -components-path {componentsPath}"; } // Add dapr proxy as a service available to everyone. proxy.Dependencies.UnionWith(context.Application.Services.Select(s => s.Name)); foreach (var s in context.Application.Services) { s.Dependencies.Add(proxy.Name); } context.Application.Services.Add(proxy); // Listen for grpc on an auto-assigned port var grpc = new BindingBuilder() { Name = "grpc", Protocol = "https", }; proxy.Bindings.Add(grpc); // Listen for http on an auto-assigned port var http = new BindingBuilder() { Name = "http", Protocol = "http", }; proxy.Bindings.Add(http); // Listen for metrics on an auto-assigned port var metrics = new BindingBuilder() { Name = "metrics", Protocol = "http", }; proxy.Bindings.Add(metrics); // Set APP_PORT based on the project's assigned port for http var appPort = new EnvironmentVariableBuilder("APP_PORT") { Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name) { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(appPort); // Set DAPR_GRPC_PORT based on this service's assigned port var daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprGrpcPort); // Add another copy of this envvar to the project. daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprGrpcPort); // Set DAPR_HTTP_PORT based on this service's assigned port var daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprHttpPort); // Add another copy of this envvar to the project. daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprHttpPort); // Set METRICS_PORT to a random port var metricsPort = new EnvironmentVariableBuilder("METRICS_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "metrics") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(metricsPort); } }
public override Task ProcessAsync(ExtensionContext context, ExtensionConfiguration config) { // If we're getting called then the user configured dapr in their tye.yaml. // We don't have any of our own config. if (context.Operation == ExtensionContext.OperationKind.LocalRun) { // For local run, enumerate all projects, and add services for each dapr proxy. var projects = context.Application.Services.OfType <ProjectServiceBuilder>().ToList(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.Where(b => b.Protocol == "http").FirstOrDefault(); if (httpBinding == null) { continue; } // See https://github.com/dotnet/tye/issues/260 // // Currently the pub-sub pattern does not work when you have multiple replicas. Each // daprd instance expects that it has a single application to talk to. So if you're using // pub-sub this means that you'll won't get some messages. // // We have no way to know if an app is using pub-sub or not, so just block it. if (project.Replicas > 1) { throw new CommandException("Dapr support does not support multiple replicas yet for development."); } var proxy = new ExecutableServiceBuilder($"{project.Name}-dapr", "daprd") { WorkingDirectory = context.Application.Source.DirectoryName, // These environment variables are replaced with environment variables // defined for this service. Args = $"-app-id {project.Name} -app-port %APP_PORT% -dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT% --placement-address localhost:50005", }; context.Application.Services.Add(proxy); // Listen for grpc on an auto-assigned port var grpc = new BindingBuilder() { Name = "grpc", Protocol = "https", }; proxy.Bindings.Add(grpc); // Listen for http on an auto-assigned port var http = new BindingBuilder() { Name = "http", Protocol = "http", }; proxy.Bindings.Add(http); // Listen for metrics on an auto-assigned port var metrics = new BindingBuilder() { Name = "metrics", Protocol = "http", }; proxy.Bindings.Add(metrics); // Set APP_PORT based on the project's assigned port for http var appPort = new EnvironmentVariableBuilder("APP_PORT") { Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name) { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(appPort); // Set DAPR_GRPC_PORT based on this service's assigned port var daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprGrpcPort); // Add another copy of this envvar to the project. daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprGrpcPort); // Set DAPR_Http_PORT based on this service's assigned port var daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprHttpPort); // Set METRICS_PORT to a random port var metricsPort = new EnvironmentVariableBuilder("METRICS_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "metrics") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(metricsPort); } } else { // In deployment, enumerate all projects and add anotations to each one. var projects = context.Application.Services.OfType <ProjectServiceBuilder>(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.Where(b => b.Protocol == "http").FirstOrDefault(); if (httpBinding == null) { continue; } if (project.ManifestInfo?.Deployment is DeploymentManifestInfo deployment) { deployment.Annotations.Add("dapr.io/enabled", "true"); deployment.Annotations.Add("dapr.io/id", project.Name); deployment.Annotations.Add("dapr.io/port", (httpBinding.Port ?? 80).ToString(CultureInfo.InvariantCulture)); } } } return(Task.CompletedTask); }
public override async Task ProcessAsync(ExtensionContext context, ExtensionConfiguration config) { // If we're getting called then the user configured dapr in their tye.yaml. // We don't have any of our own config. var extensionConfiguration = DaprExtensionConfigurationReader.ReadConfiguration(config.Data); if (context.Operation == ExtensionContext.OperationKind.LocalRun) { await VerifyDaprInitialized(context); // 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(); foreach (var project in services) { DaprExtensionServiceConfiguration?serviceConfiguration = null; extensionConfiguration?.Services.TryGetValue(project.Name, out serviceConfiguration); if (serviceConfiguration?.Enabled != null && serviceConfiguration.Enabled.Value == false) { context.Output.WriteDebugLine($"Dapr has been disabled for service {project.Name}."); continue; } var httpBinding = project.Bindings.FirstOrDefault(b => b.Protocol == "http"); if (httpBinding == null && project.Bindings.Count == 1 && project.Bindings[0].Protocol == null) { // Assume the only untyped binding is HTTP... httpBinding = project.Bindings[0]; } if (httpBinding == null && (serviceConfiguration?.Enabled == null || !serviceConfiguration.Enabled.Value)) { context.Output.WriteDebugLine($"Dapr has been disabled for unbound service {project.Name}."); continue; } // See https://github.com/dotnet/tye/issues/260 // // Currently the pub-sub pattern does not work when you have multiple replicas. Each // daprd instance expects that it has a single application to talk to. So if you're using // pub-sub this means that you'll won't get some messages. // // We have no way to know if an app is using pub-sub or not, so just block it. if (project.Replicas > 1) { throw new CommandException("Dapr support does not support multiple replicas yet for development."); } var daprExecutablePath = GetDaprExecutablePath(); string appId = serviceConfiguration?.AppId ?? project.Name; var proxy = new ExecutableServiceBuilder($"{project.Name}-dapr", daprExecutablePath, ServiceSource.Extension) { WorkingDirectory = context.Application.Source.DirectoryName, // These environment variables are replaced with environment variables // defined for this service. Args = $"run --app-id {appId} --dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT%", }; if (httpBinding != null) { proxy.Args += $" --app-port %APP_PORT%"; } var appMaxConcurrency = serviceConfiguration?.AppMaxConcurrency ?? extensionConfiguration?.AppMaxConcurrency; if (appMaxConcurrency != null) { proxy.Args += $" --app-max-concurrency {appMaxConcurrency}"; } var appProtocol = serviceConfiguration?.AppProtocol ?? extensionConfiguration?.AppProtocol; if (appProtocol != null) { proxy.Args += $" --app-protocol {appProtocol}"; } var appSsl = serviceConfiguration?.AppSsl ?? extensionConfiguration?.AppSsl; if (appSsl == true) { proxy.Args += " --app-ssl"; } var daprPlacementPort = serviceConfiguration?.PlacementPort ?? extensionConfiguration?.PlacementPort; if (daprPlacementPort.HasValue) { context.Output.WriteDebugLine($"Using Dapr placement service host port {daprPlacementPort.Value} from 'placement-port' for service {project.Name}."); proxy.Args += $" --placement-host-address localhost:{daprPlacementPort.Value}"; } string?componentsPath = serviceConfiguration?.ComponentsPath ?? extensionConfiguration?.ComponentsPath; if (componentsPath != null) { proxy.Args += $" --components-path {componentsPath}"; } string?daprConfig = serviceConfiguration?.Config ?? extensionConfiguration?.Config; // When running locally `-config` specifies a filename, not a configuration name. By convention // we'll assume the filename and config name are the same. if (daprConfig != null) { string configDirectory = componentsPath ?? Path.Combine(context.Application.Source.DirectoryName !, "components"); var configFile = Path.Combine(configDirectory, $"{daprConfig}.yaml"); if (File.Exists(configFile)) { proxy.Args += $" --config \"{configFile}\""; } else { context.Output.WriteAlwaysLine($"Could not find dapr config '{configFile}'. Skipping..."); } } int?httpMaxRequestSize = serviceConfiguration?.HttpMaxRequestSize ?? extensionConfiguration?.HttpMaxRequestSize; if (httpMaxRequestSize != null) { proxy.Args += $" --dapr-http-max-request-size {httpMaxRequestSize}"; } if ((serviceConfiguration?.EnableProfiling ?? extensionConfiguration?.EnableProfiling) == true) { proxy.Args += " --enable-profiling"; } string?logLevel = serviceConfiguration?.LogLevel ?? extensionConfiguration?.LogLevel; if (logLevel != null) { proxy.Args += $" --log-level {logLevel}"; } // Add dapr proxy as a service available to everyone. proxy.Dependencies.UnionWith(context.Application.Services.Select(s => s.Name)); foreach (var s in context.Application.Services) { s.Dependencies.Add(proxy.Name); } context.Application.Services.Add(proxy); // Listen for grpc on an auto-assigned port var grpc = new BindingBuilder() { Name = "grpc", Protocol = "https", Port = serviceConfiguration?.GrpcPort }; proxy.Bindings.Add(grpc); // Listen for http on an auto-assigned port var http = new BindingBuilder() { Name = "http", Protocol = "http", Port = serviceConfiguration?.HttpPort }; proxy.Bindings.Add(http); // Listen for metrics on an auto-assigned port var metrics = new BindingBuilder() { Name = "metrics", Protocol = "http", Port = serviceConfiguration?.MetricsPort }; proxy.Bindings.Add(metrics); if (httpBinding != null) { // Set APP_PORT based on the project's assigned port for http var appPort = new EnvironmentVariableBuilder("APP_PORT") { Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name) { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(appPort); } // Set DAPR_GRPC_PORT based on this service's assigned port var daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprGrpcPort); // Add another copy of this envvar to the project. daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprGrpcPort); // Set DAPR_HTTP_PORT based on this service's assigned port var daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprHttpPort); // Add another copy of this envvar to the project. daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprHttpPort); // Set METRICS_PORT to a random port var metricsPort = new EnvironmentVariableBuilder("METRICS_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "metrics") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(metricsPort); // TODO: Do we add a means of dynamically using the profile port? if (serviceConfiguration?.ProfilePort != null) { proxy.Args += $" --profile-port %PROFILE_PORT%"; var profile = new BindingBuilder() { Name = "profile", Protocol = "http", Port = serviceConfiguration.ProfilePort }; proxy.Bindings.Add(profile); var profilePort = new EnvironmentVariableBuilder("PROFILE_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "profile") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(profilePort); } } } else { // In deployment, enumerate all projects and add anotations to each one. var projects = context.Application.Services.OfType <ProjectServiceBuilder>(); foreach (var project in projects) { DaprExtensionServiceConfiguration?serviceConfiguration = null; extensionConfiguration?.Services.TryGetValue(project.Name, out serviceConfiguration); // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.FirstOrDefault(b => b.Protocol == "http"); if (httpBinding == null) { continue; } if (!(project.ManifestInfo?.Deployment is { } deployment)) { continue; } string appId = serviceConfiguration?.AppId ?? project.Name; deployment.Annotations.Add("dapr.io/enabled", "true"); deployment.Annotations.Add("dapr.io/app-id", appId); deployment.Annotations.Add("dapr.io/app-port", (httpBinding.Port ?? 80).ToString(CultureInfo.InvariantCulture)); string?daprConfig = serviceConfiguration?.Config ?? extensionConfiguration?.Config; if (daprConfig != null) { deployment.Annotations.TryAdd("dapr.io/config", daprConfig); } string?logLevel = serviceConfiguration?.LogLevel ?? extensionConfiguration?.LogLevel; if (logLevel != null) { deployment.Annotations.TryAdd("dapr.io/log-level", logLevel); } } } }
public override Task ProcessAsync(ExtensionContext context, ExtensionConfiguration config) { // If we're getting called then the user configured dapr in their tye.yaml. // We don't have any of our own config. if (context.Operation == ExtensionContext.OperationKind.LocalRun) { // For local run, enumerate all projects, and add services for each dapr proxy. var projects = context.Application.Services.OfType <ProjectServiceBuilder>().ToList(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.Where(b => b.Protocol == "http").FirstOrDefault(); if (httpBinding == null) { continue; } var proxy = new ExecutableServiceBuilder($"{project.Name}-dapr", "daprd") { WorkingDirectory = context.Application.Source.DirectoryName, // These environment variables are replaced with environment variables // defined for this service. Args = $"-app-id {project.Name} -app-port %APP_PORT% -dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT% -log-level %LOG_LEVEL% -config %CONFIG% --placement-address localhost:50005", }; context.Application.Services.Add(proxy); // Listen for grpc on an auto-assigned port var grpc = new BindingBuilder() { AutoAssignPort = true, Name = "grpc", Protocol = "https", }; proxy.Bindings.Add(grpc); // Listen for http on an auto-assigned port var http = new BindingBuilder() { AutoAssignPort = true, Name = "http", Protocol = "http", }; proxy.Bindings.Add(http); // Listen for metrics on an auto-assigned port var metrics = new BindingBuilder() { AutoAssignPort = true, Name = "metrics", Protocol = "http", }; proxy.Bindings.Add(metrics); // Set APP_PORT based on the project's assigned port for http var appPort = new EnvironmentVariableBuilder("APP_PORT") { Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name) { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(appPort); // Set DAPR_GRPC_PORT based on this service's assigned port var daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprGrpcPort); // Add another copy of this envvar to the project. daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprGrpcPort); // Set DAPR_Http_PORT based on this service's assigned port var daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprHttpPort); // Set METRICS_PORT to a random port var metricsPort = new EnvironmentVariableBuilder("METRICS_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "metrics") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(metricsPort); } } else { // In deployment, enumerate all projects and add anotations to each one. var projects = context.Application.Services.OfType <ProjectServiceBuilder>(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.Where(b => b.Protocol == "http").FirstOrDefault(); if (httpBinding == null) { continue; } if (project.ManifestInfo?.Deployment is DeploymentManifestInfo deployment) { deployment.Annotations.Add("dapr.io/enabled", "true"); deployment.Annotations.Add("dapr.io/id", project.Name); deployment.Annotations.Add("dapr.io/port", (httpBinding.Port ?? 80).ToString(CultureInfo.InvariantCulture)); if (config.Data.TryGetValue("config", out var daprConfig) && daprConfig is object) { deployment.Annotations.TryAdd("dapr.io/config", daprConfig !.ToString() ?? string.Empty); } if (config.Data.TryGetValue("log-level", out var logLevel) && logLevel is object) { deployment.Annotations.TryAdd("dapr.io/log-level", logLevel !.ToString() ?? string.Empty); } } } } return(Task.CompletedTask); }
public override Task ProcessAsync(ExtensionContext context, ExtensionConfiguration config) { // If we're getting called then the user configured dapr in their tye.yaml. // We don't have any of our own config. if (context.Operation == ExtensionContext.OperationKind.LocalRun) { // For local run, enumerate all projects, and add services for each dapr proxy. var projects = context.Application.Services.OfType <ProjectServiceBuilder>().ToList(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.FirstOrDefault(b => b.Protocol == "http"); if (httpBinding == null) { continue; } // See https://github.com/dotnet/tye/issues/260 // // Currently the pub-sub pattern does not work when you have multiple replicas. Each // daprd instance expects that it has a single application to talk to. So if you're using // pub-sub this means that you'll won't get some messages. // // We have no way to know if an app is using pub-sub or not, so just block it. if (project.Replicas > 1) { throw new CommandException("Dapr support does not support multiple replicas yet for development."); } var daprExecutablePath = GetDaprExecutablePath(); var proxy = new ExecutableServiceBuilder($"{project.Name}-dapr", daprExecutablePath) { WorkingDirectory = context.Application.Source.DirectoryName, // These environment variables are replaced with environment variables // defined for this service. Args = $"-app-id {project.Name} -app-port %APP_PORT% -dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT% --placement-address localhost:50005", }; // When running locally `-config` specifies a filename, not a configuration name. By convention // we'll assume the filename and config name are the same. if (config.Data.TryGetValue("config", out var obj) && obj?.ToString() is string daprConfig) { var configFile = Path.Combine(context.Application.Source.DirectoryName !, "components", $"{daprConfig}.yaml"); if (File.Exists(configFile)) { proxy.Args += $" -config \"{configFile}\""; } else { context.Output.WriteAlwaysLine($"Could not find dapr config '{configFile}'. Skipping..."); } } if (config.Data.TryGetValue("log-level", out obj) && obj?.ToString() is string logLevel) { proxy.Args += $" -log-level {logLevel}"; } if (config.Data.TryGetValue("components-path", out obj) && obj?.ToString() is string componentsPath) { proxy.Args += $" -components-path {componentsPath}"; } // Add dapr proxy as a service available to everyone. proxy.Dependencies.UnionWith(context.Application.Services.Select(s => s.Name)); foreach (var s in context.Application.Services) { s.Dependencies.Add(proxy.Name); } context.Application.Services.Add(proxy); // Listen for grpc on an auto-assigned port var grpc = new BindingBuilder() { Name = "grpc", Protocol = "https", }; proxy.Bindings.Add(grpc); // Listen for http on an auto-assigned port var http = new BindingBuilder() { Name = "http", Protocol = "http", }; proxy.Bindings.Add(http); // Listen for metrics on an auto-assigned port var metrics = new BindingBuilder() { Name = "metrics", Protocol = "http", }; proxy.Bindings.Add(metrics); // Set APP_PORT based on the project's assigned port for http var appPort = new EnvironmentVariableBuilder("APP_PORT") { Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name) { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(appPort); // Set DAPR_GRPC_PORT based on this service's assigned port var daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprGrpcPort); // Add another copy of this envvar to the project. daprGrpcPort = new EnvironmentVariableBuilder("DAPR_GRPC_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "grpc") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprGrpcPort); // Set DAPR_HTTP_PORT based on this service's assigned port var daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(daprHttpPort); // Add another copy of this envvar to the project. daprHttpPort = new EnvironmentVariableBuilder("DAPR_HTTP_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "http") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; project.EnvironmentVariables.Add(daprHttpPort); // Set METRICS_PORT to a random port var metricsPort = new EnvironmentVariableBuilder("METRICS_PORT") { Source = new EnvironmentVariableSourceBuilder(proxy.Name, binding: "metrics") { Kind = EnvironmentVariableSourceBuilder.SourceKind.Port, }, }; proxy.EnvironmentVariables.Add(metricsPort); } } else { // In deployment, enumerate all projects and add anotations to each one. var projects = context.Application.Services.OfType <ProjectServiceBuilder>(); foreach (var project in projects) { // Dapr requires http. If this project isn't listening to HTTP then it's not daprized. var httpBinding = project.Bindings.FirstOrDefault(b => b.Protocol == "http"); if (httpBinding == null) { continue; } if (!(project.ManifestInfo?.Deployment is { } deployment)) { continue; } deployment.Annotations.Add("dapr.io/enabled", "true"); deployment.Annotations.Add("dapr.io/id", project.Name); deployment.Annotations.Add("dapr.io/port", (httpBinding.Port ?? 80).ToString(CultureInfo.InvariantCulture)); if (config.Data.TryGetValue("config", out var obj) && obj?.ToString() is string daprConfig) { deployment.Annotations.TryAdd("dapr.io/config", daprConfig); } if (config.Data.TryGetValue("log-level", out obj) && obj?.ToString() is string logLevel) { deployment.Annotations.TryAdd("dapr.io/log-level", logLevel); } } } return(Task.CompletedTask); }