From a3dcd6241959fad446f90accd6b0bc52755e20bc Mon Sep 17 00:00:00 2001 From: Phillip Hoff Date: Wed, 21 Jul 2021 15:30:04 -0700 Subject: [PATCH] Sketch Node.js service "building". --- src/Microsoft.Tye.Core/ApplicationFactory.cs | 12 +++++++ .../ConfigModel/ConfigNode.cs | 16 +++++++++ .../ConfigModel/ConfigService.cs | 1 + src/Microsoft.Tye.Core/NodeServiceBuilder.cs | 21 ++++++++++++ .../Serialization/ConfigServiceParser.cs | 33 +++++++++++++++++++ src/tye/ApplicationBuilderExtensions.cs | 29 ++++++++++++++++ 6 files changed, 112 insertions(+) create mode 100644 src/Microsoft.Tye.Core/ConfigModel/ConfigNode.cs create mode 100644 src/Microsoft.Tye.Core/NodeServiceBuilder.cs diff --git a/src/Microsoft.Tye.Core/ApplicationFactory.cs b/src/Microsoft.Tye.Core/ApplicationFactory.cs index b20aa3ea..7d9cdccd 100644 --- a/src/Microsoft.Tye.Core/ApplicationFactory.cs +++ b/src/Microsoft.Tye.Core/ApplicationFactory.cs @@ -337,6 +337,18 @@ namespace Microsoft.Tye var external = new ExternalServiceBuilder(configService.Name, ServiceSource.Configuration); service = external; } + else if (configService.Node != null) + { + string packagePath = Path.GetFullPath(Path.Combine(config.Source.Directory!.FullName, configService.Node.Package)); + + var node = new NodeServiceBuilder(configService.Name, packagePath, ServiceSource.Configuration) + { + Replicas = configService.Replicas ?? 1, + Script = configService.Node.Script + }; + + service = node; + } else { throw new CommandException("Unable to determine service type."); diff --git a/src/Microsoft.Tye.Core/ConfigModel/ConfigNode.cs b/src/Microsoft.Tye.Core/ConfigModel/ConfigNode.cs new file mode 100644 index 00000000..886d1972 --- /dev/null +++ b/src/Microsoft.Tye.Core/ConfigModel/ConfigNode.cs @@ -0,0 +1,16 @@ +// 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.ComponentModel.DataAnnotations; + +namespace Microsoft.Tye.ConfigModel +{ + public class ConfigNode + { + [Required] + public string Package { get; set; } = default!; + + public string? Script { get; set; } = default!; + } +} diff --git a/src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs b/src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs index a131f937..4450380b 100644 --- a/src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs +++ b/src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs @@ -46,5 +46,6 @@ namespace Microsoft.Tye.ConfigModel public string? Version { get; set; } public string? Architecture { get; set; } public string? CloneDirectory { get; internal set; } + public ConfigNode? Node { get; set; } } } diff --git a/src/Microsoft.Tye.Core/NodeServiceBuilder.cs b/src/Microsoft.Tye.Core/NodeServiceBuilder.cs new file mode 100644 index 00000000..61415792 --- /dev/null +++ b/src/Microsoft.Tye.Core/NodeServiceBuilder.cs @@ -0,0 +1,21 @@ +// 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 +{ + public class NodeServiceBuilder : LaunchedServiceBuilder + { + public NodeServiceBuilder(string name, string packagePath, ServiceSource source) + : base(name, source) + { + PackagePath = packagePath; + } + + public string PackagePath { get; set; } + + public string? Script { get; set; } + } +} diff --git a/src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs b/src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs index 014bce75..086fd7c1 100644 --- a/src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs +++ b/src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs @@ -165,6 +165,10 @@ namespace Tye.Serialization case "cloneDirectory": service.CloneDirectory = YamlParser.GetScalarValue(key, child.Value); break; + case "node": + service.Node = new ConfigNode(); + HandleNode((YamlMappingNode)child.Value, service.Node); + break; default: throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key)); } @@ -235,6 +239,35 @@ namespace Tye.Serialization } } + private static void HandleNode(YamlSequenceNode yamlSequenceNode, ConfigNode node) + { + foreach (var child in yamlSequenceNode.Children) + { + YamlParser.ThrowIfNotYamlMapping(child); + HandleNode((YamlMappingNode)child, node); + } + } + + private static void HandleNode(YamlMappingNode yamlMappingNode, ConfigNode node) + { + foreach (var child in yamlMappingNode.Children) + { + var key = YamlParser.GetScalarValue(child.Key); + + switch (key) + { + case "package": + node.Package = YamlParser.GetScalarValue("package", child.Value); + break; + case "script": + node.Script = YamlParser.GetScalarValue("script", child.Value); + break; + default: + throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key)); + } + } + } + private static void HandleServiceProbe(YamlMappingNode yamlMappingNode, ConfigProbe probe) { foreach (var child in yamlMappingNode.Children) diff --git a/src/tye/ApplicationBuilderExtensions.cs b/src/tye/ApplicationBuilderExtensions.cs index 1012e669..36ea7925 100644 --- a/src/tye/ApplicationBuilderExtensions.cs +++ b/src/tye/ApplicationBuilderExtensions.cs @@ -152,6 +152,35 @@ namespace Microsoft.Tye liveness = null; readiness = null; } + else if (service is NodeServiceBuilder node) + { + string executablePath = "node"; + string? workingDirectory = Path.GetDirectoryName(node.PackagePath); + + var input = new StringReader(File.ReadAllText(node.PackagePath)); + + var yaml = new YamlDotNet.RepresentationModel.YamlStream(); + + yaml.Load(input); + + var mapping = (YamlDotNet.RepresentationModel.YamlMappingNode)yaml.Documents[0].RootNode; + + var mainNode = (YamlDotNet.RepresentationModel.YamlScalarNode)mapping.Children[new YamlDotNet.RepresentationModel.YamlScalarNode("main")]; + + var main = mainNode.Value; + + string args = $"{main}"; + + runInfo = new ExecutableRunInfo(executablePath, workingDirectory, args); + replicas = node.Replicas; + liveness = null; + readiness = null; + + foreach (var entry in node.EnvironmentVariables) + { + env.Add(entry.ToHostingEnvironmentVariable()); + } + } else { throw new InvalidOperationException($"Cannot figure out how to run service '{service.Name}'.");