add service dependency detection

This commit is contained in:
Chris Cheetham 2020-03-25 21:55:41 -04:00
Родитель 01e6ab7326
Коммит 90278e0dd6
8 изменённых файлов: 175 добавлений и 26 удалений

Просмотреть файл

@ -49,7 +49,7 @@ namespace Steeltoe.Tooling.Controllers
/// <returns>The project.</returns>
protected Deployment GetDeployment()
{
return new DeploymentBuilder().BuildDeployment(Context.WorkingDirectory);
return new DeploymentBuilder(Context).BuildDeployment();
}
}
}

Просмотреть файл

@ -21,17 +21,27 @@ namespace Steeltoe.Tooling.Models
/// </summary>
public class DeploymentBuilder
{
private readonly Context _context;
/// <summary>
/// Create a DocumentBuilder for the specified directory.
/// </summary>
public DeploymentBuilder(Context context)
{
_context = context;
}
/// <summary>
/// Returns a deployment for the specified directory.
/// </summary>
/// <returns>deployment model</returns>
public Deployment BuildDeployment(string directory)
public Deployment BuildDeployment()
{
var name = Path.GetFileName(directory);
var name = Path.GetFileName(_context.WorkingDirectory);
var deployment = new Deployment
{
Name = name,
Project = new ProjectBuilder().BuildProject(Path.Join(directory, $"{name}.csproj"))
Project = new ProjectBuilder(_context, Path.Join(_context.WorkingDirectory, $"{name}.csproj")).BuildProject()
};
return deployment;
}

Просмотреть файл

@ -33,6 +33,7 @@ namespace Steeltoe.Tooling.Models
}
private string _name;
/// <summary>
/// Project file path.
/// </summary>
@ -45,6 +46,12 @@ namespace Steeltoe.Tooling.Models
[YamlMember(Alias = "framework")]
public string Framework { get; set; }
/// <summary>
/// Docker image.
/// </summary>
[YamlMember(Alias = "image")]
public string Image { get; set; }
/// <summary>
/// Network ports.
/// </summary>
@ -55,6 +62,6 @@ namespace Steeltoe.Tooling.Models
/// Project service dependencies to be deployed.
/// </summary>
[YamlMember(Alias = "services")]
public List<Service> Services { get; }
public List<Service> Services { get; set; }
}
}

Просмотреть файл

@ -28,9 +28,13 @@ namespace Steeltoe.Tooling.Models
public class ProjectBuilder
{
private static readonly ILogger Logger = Logging.LoggerFactory.CreateLogger<ProjectBuilder>();
private static readonly List<Protocol> DefaultProtocols = new List<Protocol>();
private Context _context;
private readonly string _projectFile;
private readonly string _launchSettingsFile;
private XmlDocument _projectDoc;
static ProjectBuilder()
{
DefaultProtocols.Add(new Protocol("http", 8080));
@ -41,39 +45,59 @@ namespace Steeltoe.Tooling.Models
/// </summary>
public string ProjectFile { get; set; }
/// <summary>
/// Create a ProjectBuilder for the specified project file.
/// </summary>
public ProjectBuilder(Context context, string projectFile)
{
_context = context;
_projectFile = projectFile;
_launchSettingsFile = Path.Join(Path.GetDirectoryName(projectFile), "Properties", "launchSettings.json");
}
/// <summary>
/// Returns a Project representation of the ProjectFile.
/// </summary>
/// <returns>project model</returns>
public Project BuildProject(string projectFile)
public Project BuildProject()
{
Logger.LogDebug($"loading project file: {projectFile}");
if (!File.Exists(projectFile))
Logger.LogDebug($"loading project file: {_projectFile}");
if (!File.Exists(_projectFile))
{
throw new ToolingException($"project file not found: {projectFile}");
throw new ToolingException($"project file not found: {_projectFile}");
}
_projectDoc = new XmlDocument();
_projectDoc.Load(_projectFile);
var project = new Project
{
Name = Path.GetFileNameWithoutExtension(projectFile),
File = Path.GetFileName(projectFile),
Framework = GetFramework(projectFile),
Protocols = GetProtocols(projectFile)
Name = Path.GetFileNameWithoutExtension(_projectFile),
File = Path.GetFileName(_projectFile)
};
project.Framework = GetFramework();
if (_context.Registry.Images.TryGetValue(project.Framework, out var image))
{
project.Image = image;
}
else
{
throw new ToolingException($"no image for framework: {project.Framework}");
}
project.Protocols = GetProtocols();
project.Services = GetServices();
return project;
}
private string GetFramework(string projectFile)
private string GetFramework()
{
XmlDocument projectDoc = new XmlDocument();
projectDoc.Load(projectFile);
XmlNodeList nodes = projectDoc.SelectNodes("/Project/PropertyGroup/TargetFramework");
XmlNodeList nodes = _projectDoc.SelectNodes("/Project/PropertyGroup/TargetFramework");
if (nodes.Count > 0)
{
return nodes[0].InnerText;
}
nodes = projectDoc.SelectNodes("/Project/PropertyGroup/TargetFrameworks");
nodes = _projectDoc.SelectNodes("/Project/PropertyGroup/TargetFrameworks");
if (nodes.Count > 0)
{
return nodes[0].InnerText.Split(';')[0];
@ -82,18 +106,16 @@ namespace Steeltoe.Tooling.Models
throw new ToolingException("could not determine framework");
}
private List<Protocol> GetProtocols(string projectFile)
private List<Protocol> GetProtocols()
{
var launchSettingsPath =
Path.Join(Path.GetDirectoryName(projectFile), "Properties", "launchSettings.json");
if (!File.Exists(launchSettingsPath))
if (!File.Exists(_launchSettingsFile))
{
return DefaultProtocols;
}
Logger.LogDebug($"loading launch settings: {launchSettingsPath}");
Logger.LogDebug($"loading launch settings: {_launchSettingsFile}");
var yaml = new YamlStream();
using (var reader = new StreamReader(launchSettingsPath))
using (var reader = new StreamReader(_launchSettingsFile))
{
yaml.Load(reader);
}
@ -101,7 +123,7 @@ namespace Steeltoe.Tooling.Models
var root = (YamlMappingNode) yaml.Documents[0].RootNode;
var profiles = (YamlMappingNode) root.Children[new YamlScalarNode("profiles")];
var profile =
(YamlMappingNode) profiles.Children[new YamlScalarNode(Path.GetFileNameWithoutExtension(projectFile))];
(YamlMappingNode) profiles.Children[new YamlScalarNode(Path.GetFileNameWithoutExtension(_projectFile))];
if (!profile.Children.ContainsKey(new YamlScalarNode("applicationUrl")))
{
return DefaultProtocols;
@ -118,5 +140,64 @@ namespace Steeltoe.Tooling.Models
protocols.Sort();
return protocols;
}
private List<Service> GetServices()
{
List<Service> services = new List<Service>();
Dictionary<string, string> serviceNugets = new Dictionary<string, string>();
serviceNugets["Pivotal.GemFire"] = "gemfire";
serviceNugets["Microsoft.EntityFrameworkCore.SqlServer"] = "mssql";
serviceNugets["MySql.Data"] = "mysql";
serviceNugets["Pomelo.EntityFrameworkCore.MySql"] = "mysql";
serviceNugets["Npgsql"] = "pgsql";
serviceNugets["Npgsql.EntityFrameworkCore.PostgreSQL"] = "pgsql";
serviceNugets["RabbitMQ.Client"] = "rabbitmq";
serviceNugets["Microsoft.Extensions.Caching.StackExchangeRedis"] = "redis";
foreach (var serviceNuget in serviceNugets.Keys)
{
var xpath = $"/Project/ItemGroup/PackageReference[@Include='{serviceNuget}']";
if (_projectDoc.SelectNodes(xpath).Count == 0)
{
xpath = $"/Project/ItemGroup/Reference[@Include='{serviceNuget}']";
if (_projectDoc.SelectNodes(xpath).Count == 0)
{
continue;
}
}
var serviceName = serviceNugets[serviceNuget];
var service = new Service()
{
Name = serviceName,
Type = serviceName
};
if (_context.Registry.Images.TryGetValue(service.Name, out var image))
{
service.Image = image;
}
else
{
throw new ToolingException($"no image for service: {service.Name}");
}
if (_context.Registry.Ports.TryGetValue(service.Name, out var port))
{
service.Port = port;
}
else
{
throw new ToolingException($"no port for service: {service.Name}");
}
services.Add(service);
}
if (services.Count == 0)
{
return null;
}
return services;
}
}
}

Просмотреть файл

@ -16,7 +16,39 @@ using YamlDotNet.Serialization;
namespace Steeltoe.Tooling.Models
{
/// <summary>
/// A model of a project service dependency.
/// </summary>
public class Service
{
/// <summary>
/// Service name.
/// </summary>
[YamlMember(Alias = "name")]
public string Name
{
get => _name;
set => _name = value.ToLower();
}
private string _name;
/// <summary>
/// Service type.
/// </summary>
[YamlMember(Alias = "type")]
public string Type { get; set; }
/// <summary>
/// Service port.
/// </summary>
[YamlMember(Alias = "port")]
public int Port { get; set; }
/// <summary>
/// Docker image.
/// </summary>
[YamlMember(Alias = "image")]
public string Image { get; set; }
}
}

Просмотреть файл

@ -20,6 +20,11 @@ namespace Steeltoe.Tooling
/// </summary>
public Dictionary<string, string> Images { get; private set; }
/// <summary>
/// Service ports.
/// </summary>
public Dictionary<string, int> Ports { get; private set; }
/// <summary>
/// Load the registry from the specified directory.
/// </summary>
@ -32,6 +37,10 @@ namespace Steeltoe.Tooling
{
Images = deserializer.Deserialize<Dictionary<string, string>>(reader);
}
using (var reader = new StreamReader(Path.Join(directory, "ports.yml")))
{
Ports = deserializer.Deserialize<Dictionary<string, int>>(reader);
}
}
}
}

Просмотреть файл

@ -1,2 +1,7 @@
mssql: steeltoeoss/mssql-amd64-linux
mysql: steeltoeoss/mysql:5.7
pgsql: steeltoeoss/postgresql:10.8
rabbitmq: steeltoeoss/rabbitmq:3.7
redis: steeltoeoss/redis-amd64-linux:4.0.11
netcoreapp2.1: mcr.microsoft.com/dotnet/core/sdk:2.1
netcoreapp3.1: mcr.microsoft.com/dotnet/core/sdk:3.1

Просмотреть файл

@ -0,0 +1,5 @@
mssql: 1433
mysql: 3306
pgsql: 5432
rabbitmq: 5672
redis: 5672