Browse Source

Support Dapr "standalone" applications (#1194)

* Try inverting default placement service behavior.

* Eliminate placement service management.

* Remove references to placement service options.

* Try to determine Dapr status.

* Update formatting.

* Sketch service-based override of Dapr configuration.

* Move types to separate files.

* Fix formatting.
pull/1203/head
Phillip Hoff 5 years ago
committed by GitHub
parent
commit
bbf5475806
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/Microsoft.Tye.Core/Serialization/ConfigExtensionsParser.cs
  2. 26
      src/Microsoft.Tye.Core/Serialization/YamlParser.cs
  3. 57
      src/Microsoft.Tye.Extensions/Dapr/DaprExtension.cs
  4. 24
      src/Microsoft.Tye.Extensions/Dapr/DaprExtensionConfiguration.cs
  5. 58
      src/Microsoft.Tye.Extensions/Dapr/DaprExtensionConfigurationReader.cs

8
src/Microsoft.Tye.Core/Serialization/ConfigExtensionsParser.cs

@ -16,13 +16,7 @@ namespace Tye.Serialization
switch (child.NodeType)
{
case YamlNodeType.Mapping:
var extensionDictionary = new Dictionary<string, object>();
foreach (var mapping in (YamlMappingNode)child)
{
var key = YamlParser.GetScalarValue(mapping.Key);
extensionDictionary[key] = YamlParser.GetScalarValue(key, mapping.Value)!;
}
var extensionDictionary = YamlParser.GetDictionary(child);
extensions.Add(extensionDictionary);
break;
default:

26
src/Microsoft.Tye.Core/Serialization/YamlParser.cs

@ -77,6 +77,32 @@ namespace Tye.Serialization
return app;
}
public static Dictionary<string, object> GetDictionary(YamlNode node)
{
if (node.NodeType != YamlNodeType.Mapping)
{
throw new TyeYamlException(node.Start,
CoreStrings.FormatUnexpectedType(YamlNodeType.Mapping.ToString(), node.NodeType.ToString()));
}
var dictionary = new Dictionary<string, object>();
foreach (var mapping in (YamlMappingNode)node)
{
var key = YamlParser.GetScalarValue(mapping.Key);
dictionary[key] = mapping.Value.NodeType switch
{
YamlNodeType.Scalar => YamlParser.GetScalarValue(key, mapping.Value)!,
YamlNodeType.Mapping => YamlParser.GetDictionary(mapping.Value),
_ => throw new TyeYamlException(mapping.Value.Start,
CoreStrings.FormatUnexpectedType(YamlNodeType.Mapping.ToString(), mapping.Value.NodeType.ToString()))
};
}
return dictionary;
}
public static string GetScalarValue(YamlNode node)
{
if (node.NodeType != YamlNodeType.Scalar)

57
src/Microsoft.Tye.Extensions/Dapr/DaprExtension.cs

@ -23,14 +23,7 @@ namespace Microsoft.Tye.Extensions.Dapr
{
await VerifyDaprInitialized(context);
int? daprPlacementPort = null;
// 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;
}
var extensionConfiguration = DaprExtensionConfigurationReader.ReadConfiguration(config.Data);
// For local run, enumerate all projects, and add services for each dapr proxy.
var projects = context.Application.Services.OfType<ProjectServiceBuilder>().Cast<LaunchedServiceBuilder>();
@ -39,10 +32,25 @@ namespace Microsoft.Tye.Extensions.Dapr
foreach (var project in services)
{
// Dapr requires http. If this project isn't listening to HTTP then it's not daprized.
extensionConfiguration.Services.TryGetValue(project.Name, out DaprExtensionServiceConfiguration? 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)
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;
}
@ -66,17 +74,25 @@ namespace Microsoft.Tye.Extensions.Dapr
// These environment variables are replaced with environment variables
// defined for this service.
Args = $"run --app-id {project.Name} --app-port %APP_PORT% --dapr-grpc-port %DAPR_GRPC_PORT% --dapr-http-port %DAPR_HTTP_PORT% --metrics-port %METRICS_PORT%",
Args = $"run --app-id {project.Name} --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 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}";
}
// 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)
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))
@ -132,15 +148,18 @@ namespace Microsoft.Tye.Extensions.Dapr
};
proxy.Bindings.Add(metrics);
// Set APP_PORT based on the project's assigned port for http
var appPort = new EnvironmentVariableBuilder("APP_PORT")
if (httpBinding != null)
{
Source = new EnvironmentVariableSourceBuilder(project.Name, binding: httpBinding.Name)
// Set APP_PORT based on the project's assigned port for http
var appPort = new EnvironmentVariableBuilder("APP_PORT")
{
Kind = EnvironmentVariableSourceBuilder.SourceKind.Port,
},
};
proxy.EnvironmentVariables.Add(appPort);
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")

24
src/Microsoft.Tye.Extensions/Dapr/DaprExtensionConfiguration.cs

@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
namespace Microsoft.Tye.Extensions.Dapr
{
internal abstract class DaprExtensionCommonConfiguration
{
public int? PlacementPort { get; set; }
}
internal sealed class DaprExtensionServiceConfiguration : DaprExtensionCommonConfiguration
{
public bool? Enabled { get; set; }
}
internal sealed class DaprExtensionConfiguration : DaprExtensionCommonConfiguration
{
public IReadOnlyDictionary<string, DaprExtensionServiceConfiguration> Services { get; set; }
= new Dictionary<string, DaprExtensionServiceConfiguration>();
}
}

58
src/Microsoft.Tye.Extensions/Dapr/DaprExtensionConfigurationReader.cs

@ -0,0 +1,58 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
namespace Microsoft.Tye.Extensions.Dapr
{
internal static class DaprExtensionConfigurationReader
{
public static DaprExtensionConfiguration ReadConfiguration(IDictionary<string, object> rawConfiguration)
{
var configuration = new DaprExtensionConfiguration();
ReadCommonConfiguration(rawConfiguration, configuration);
if (rawConfiguration.TryGetValue("services", out var servicesObject) && servicesObject is Dictionary<string, object> rawServicesConfiguration)
{
var services = new Dictionary<string, DaprExtensionServiceConfiguration>();
foreach (var kvp in rawServicesConfiguration)
{
if (kvp.Value is Dictionary<string, object> rawServiceConfiguration)
{
var serviceConfiguration = new DaprExtensionServiceConfiguration();
ReadServiceConfiguration(rawServiceConfiguration, serviceConfiguration);
services.Add(kvp.Key, serviceConfiguration);
}
}
configuration.Services = services;
}
return configuration;
}
private static void ReadServiceConfiguration(IDictionary<string, object> rawConfiguration, DaprExtensionServiceConfiguration serviceConfiguration)
{
ReadCommonConfiguration(rawConfiguration, serviceConfiguration);
if (rawConfiguration.TryGetValue("enabled", out var obj) && obj is string && Boolean.TryParse(obj.ToString(), out var enabled))
{
serviceConfiguration.Enabled = enabled;
}
}
private static void ReadCommonConfiguration(IDictionary<string, object> rawConfiguration, DaprExtensionCommonConfiguration commonConfiguration)
{
if (rawConfiguration.TryGetValue("placement-port", out var obj) && obj?.ToString() is string && int.TryParse(obj.ToString(), out var customPlacementPort))
{
commonConfiguration.PlacementPort = customPlacementPort;
}
}
}
}
Loading…
Cancel
Save