nicolas.dorier
7 years ago
13 changed files with 564 additions and 207 deletions
@ -0,0 +1,34 @@ |
|||
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00 |
|||
# Visual Studio 15 |
|||
VisualStudioVersion = 15.0.26124.0 |
|||
MinimumVisualStudioVersion = 15.0.26124.0 |
|||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "docker-compose-generator", "src/docker-compose-generator.csproj", "{0900AF35-48E8-46E2-85B3-BA3847EE0844}" |
|||
EndProject |
|||
Global |
|||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|||
Debug|Any CPU = Debug|Any CPU |
|||
Debug|x64 = Debug|x64 |
|||
Debug|x86 = Debug|x86 |
|||
Release|Any CPU = Release|Any CPU |
|||
Release|x64 = Release|x64 |
|||
Release|x86 = Release|x86 |
|||
EndGlobalSection |
|||
GlobalSection(SolutionProperties) = preSolution |
|||
HideSolutionNode = FALSE |
|||
EndGlobalSection |
|||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|x64.ActiveCfg = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|x64.Build.0 = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|x86.ActiveCfg = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Debug|x86.Build.0 = Debug|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|Any CPU.Build.0 = Release|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|x64.ActiveCfg = Release|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|x64.Build.0 = Release|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|x86.ActiveCfg = Release|Any CPU |
|||
{0900AF35-48E8-46E2-85B3-BA3847EE0844}.Release|x86.Build.0 = Release|Any CPU |
|||
EndGlobalSection |
|||
EndGlobal |
@ -0,0 +1,33 @@ |
|||
version: "3" |
|||
|
|||
services: |
|||
bitcoind: |
|||
restart: always |
|||
container_name: btcpayserver_bitcoind |
|||
image: nicolasdorier/docker-bitcoin:0.16.0 |
|||
environment: |
|||
BITCOIN_EXTRA_ARGS: | |
|||
rpcport=43782 |
|||
${NBITCOIN_NETWORK:-regtest}=1 |
|||
port=39388 |
|||
whitelist=0.0.0.0/0 |
|||
expose: |
|||
- "43782" |
|||
- "39388" |
|||
volumes: |
|||
- "bitcoin_datadir:/data" |
|||
nbxplorer: |
|||
environment: |
|||
BTCPAY_CHAINS: "btc" |
|||
NBXPLORER_BTCRPCURL: http://bitcoind:43782/ |
|||
NBXPLORER_BTCNODEENDPOINT: bitcoind:39388 |
|||
links: |
|||
- bitcoind |
|||
volumes: |
|||
- "bitcoin_datadir:/root/.bitcoin" |
|||
btcpayserver: |
|||
environment: |
|||
BTCPAY_CHAINS: "btc" |
|||
BTCPAY_BTCEXPLORERURL: http://nbxplorer:32838/ |
|||
volumes: |
|||
bitcoin_datadir: |
@ -0,0 +1,53 @@ |
|||
version: "3" |
|||
|
|||
services: |
|||
|
|||
btcpayserver: |
|||
restart: always |
|||
image: nicolasdorier/btcpayserver:1.0.1.53 |
|||
expose: |
|||
- "49392" |
|||
environment: |
|||
# BTCPay settings |
|||
BTCPAY_POSTGRES: User ID=postgres;Host=postgres;Port=5432;Database=btcpayserver${NBITCOIN_NETWORK:-regtest} |
|||
BTCPAY_NETWORK: ${NBITCOIN_NETWORK:-regtest} |
|||
BTCPAY_BIND: 0.0.0.0:49392 |
|||
BTCPAY_EXTERNALURL: https://${BTCPAY_HOST}/ |
|||
|
|||
# NGINX settings |
|||
VIRTUAL_NETWORK: nginx-proxy |
|||
VIRTUAL_PORT: 49392 |
|||
VIRTUAL_HOST: ${BTCPAY_HOST} |
|||
|
|||
# Let's encrypt settings |
|||
LETSENCRYPT_HOST: ${BTCPAY_HOST} |
|||
LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL:-yourname@example.com} |
|||
|
|||
links: |
|||
- nbxplorer |
|||
- postgres |
|||
volumes: |
|||
- "btcpay_datadir:/datadir" |
|||
- "nbxplorer_datadir:/root/.nbxplorer" |
|||
|
|||
nbxplorer: |
|||
restart: always |
|||
image: nicolasdorier/nbxplorer:1.0.1.23 |
|||
expose: |
|||
- "32838" |
|||
environment: |
|||
NBXPLORER_NETWORK: ${NBITCOIN_NETWORK:-regtest} |
|||
NBXPLORER_BIND: 0.0.0.0:32838 |
|||
volumes: |
|||
- "nbxplorer_datadir:/datadir" |
|||
|
|||
postgres: |
|||
restart: always |
|||
image: postgres:9.6.5 |
|||
volumes: |
|||
- "postgres_datadir:/var/lib/postgresql/data" |
|||
|
|||
volumes: |
|||
postgres_datadir: |
|||
btcpay_datadir: |
|||
nbxplorer_datadir: |
@ -0,0 +1,34 @@ |
|||
version: "3" |
|||
|
|||
services: |
|||
litecoind: |
|||
restart: always |
|||
container_name: btcpayserver_litecoind |
|||
image: nicolasdorier/docker-litecoin:0.14.2 |
|||
environment: |
|||
BITCOIN_EXTRA_ARGS: | |
|||
rpcport=43782 |
|||
${NBITCOIN_NETWORK:-regtest}=1 |
|||
port=39388 |
|||
whitelist=0.0.0.0/0 |
|||
expose: |
|||
- "43782" |
|||
- "39388" |
|||
volumes: |
|||
- "litecoin_datadir:/data" |
|||
nbxplorer: |
|||
environment: |
|||
BTCPAY_CHAINS: "ltc" |
|||
NBXPLORER_LTCRPCURL: http://litecoind:43782/ |
|||
NBXPLORER_LTCNODEENDPOINT: litecoind:39388 |
|||
links: |
|||
- litecoind |
|||
volumes: |
|||
- "litecoin_datadir:/root/.litecoin" |
|||
btcpayserver: |
|||
environment: |
|||
BTCPAY_LTCEXPLORERURL: http://nbxplorer:32838/ |
|||
BTCPAY_CHAINS: "ltc" |
|||
|
|||
volumes: |
|||
litecoin_datadir: |
@ -0,0 +1,55 @@ |
|||
version: "3" |
|||
|
|||
services: |
|||
nginx: |
|||
restart: always |
|||
image: nginx |
|||
container_name: nginx |
|||
ports: |
|||
- "80:80" |
|||
- "443:443" |
|||
volumes: |
|||
- "nginx_conf:/etc/nginx/conf.d" |
|||
- "nginx_vhost:/etc/nginx/vhost.d" |
|||
- "nginx_html:/usr/share/nginx/html" |
|||
- "nginx_certs:/etc/nginx/certs:ro" |
|||
links: |
|||
- btcpayserver |
|||
|
|||
nginx-gen: |
|||
restart: always |
|||
image: jwilder/docker-gen |
|||
container_name: nginx-gen |
|||
volumes: |
|||
- "/var/run/docker.sock:/tmp/docker.sock:ro" |
|||
- "./nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro" |
|||
- "nginx_conf:/etc/nginx/conf.d" |
|||
- "nginx_vhost:/etc/nginx/vhost.d" |
|||
- "nginx_html:/usr/share/nginx/html" |
|||
- "nginx_certs:/etc/nginx/certs:ro" |
|||
entrypoint: /usr/local/bin/docker-gen -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf |
|||
links: |
|||
- nginx |
|||
|
|||
letsencrypt-nginx-proxy-companion: |
|||
restart: always |
|||
image: jrcs/letsencrypt-nginx-proxy-companion |
|||
container_name: letsencrypt-nginx-proxy-companion |
|||
volumes: |
|||
- "/var/run/docker.sock:/var/run/docker.sock:ro" |
|||
- "nginx_conf:/etc/nginx/conf.d" |
|||
- "nginx_vhost:/etc/nginx/vhost.d" |
|||
- "nginx_html:/usr/share/nginx/html" |
|||
- "nginx_certs:/etc/nginx/certs:rw" |
|||
environment: |
|||
NGINX_DOCKER_GEN_CONTAINER: "nginx-gen" |
|||
NGINX_PROXY_CONTAINER: "nginx" |
|||
ACME_CA_URI: ${ACME_CA_URI:-https://acme-staging.api.letsencrypt.org/directory} |
|||
links: |
|||
- nginx |
|||
|
|||
volumes: |
|||
nginx_conf: |
|||
nginx_vhost: |
|||
nginx_html: |
|||
nginx_certs: |
@ -0,0 +1,132 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using YamlDotNet.RepresentationModel; |
|||
using YamlDotNet.Serialization; |
|||
using System.IO; |
|||
|
|||
namespace DockerGenerator |
|||
{ |
|||
public class DockerComposeDefinition |
|||
{ |
|||
string[] _Fragments; |
|||
private string _Name; |
|||
|
|||
public DockerComposeDefinition(string name, string[] fragments) |
|||
{ |
|||
_Fragments = fragments; |
|||
_Name = name; |
|||
} |
|||
|
|||
public string FragmentLocation |
|||
{ |
|||
get; set; |
|||
} |
|||
public string BuildOutputDirectory |
|||
{ |
|||
get; set; |
|||
} |
|||
|
|||
public string GetFilePath() |
|||
{ |
|||
return Path.Combine(BuildOutputDirectory, $"docker-compose.{_Name}.yml"); |
|||
} |
|||
public void Build() |
|||
{ |
|||
Console.WriteLine($"Generating {GetFilePath()}"); |
|||
var deserializer = new DeserializerBuilder().Build(); |
|||
var serializer = new SerializerBuilder().Build(); |
|||
|
|||
Console.WriteLine($"With fragments:"); |
|||
foreach(var fragment in _Fragments) |
|||
{ |
|||
Console.WriteLine($"\t{fragment}"); |
|||
} |
|||
var services = new List<KeyValuePair<YamlNode, YamlNode>>(); |
|||
var volumes = new List<KeyValuePair<YamlNode, YamlNode>>(); |
|||
|
|||
foreach(var doc in _Fragments.Select(f => ParseDocument(f))) |
|||
{ |
|||
if(doc.Children["services"] is YamlMappingNode fragmentServicesRoot) |
|||
{ |
|||
services.AddRange(fragmentServicesRoot.Children); |
|||
} |
|||
|
|||
if(doc.Children["volumes"] is YamlMappingNode fragmentVolumesRoot) |
|||
{ |
|||
volumes.AddRange(fragmentVolumesRoot.Children); |
|||
} |
|||
} |
|||
|
|||
|
|||
YamlMappingNode output = new YamlMappingNode(); |
|||
output.Add("version", new YamlScalarNode("3")); |
|||
output.Add("services", new YamlMappingNode(Merge(services))); |
|||
output.Add("volumes", new YamlMappingNode(volumes)); |
|||
var result = serializer.Serialize(output); |
|||
var outputFile = GetFilePath(); |
|||
File.WriteAllText(outputFile, result.Replace("''", "")); |
|||
Console.WriteLine($"Generated {outputFile}"); |
|||
Console.WriteLine(); |
|||
} |
|||
|
|||
private KeyValuePair<YamlNode, YamlNode>[] Merge(List<KeyValuePair<YamlNode, YamlNode>> services) |
|||
{ |
|||
return services |
|||
.GroupBy(s => s.Key.ToString(), s=> s.Value) |
|||
.Select(group => |
|||
(GroupName: group.Key, |
|||
MainNode: group.OfType<YamlMappingNode>().Single(n=> n.Children.ContainsKey("image")), |
|||
MergedNodes: group.OfType<YamlMappingNode>().Where(n => !n.Children.ContainsKey("image")))) |
|||
.Select(_ => |
|||
{ |
|||
foreach(var node in _.MergedNodes) |
|||
{ |
|||
foreach(var child in node) |
|||
{ |
|||
var childValue = child.Value; |
|||
if(!_.MainNode.Children.TryGetValue(child.Key, out var mainChildValue)) |
|||
{ |
|||
mainChildValue = child.Value; |
|||
_.MainNode.Add(child.Key, child.Value); |
|||
} |
|||
else if(childValue is YamlMappingNode childMapping && mainChildValue is YamlMappingNode mainChildMapping) |
|||
{ |
|||
foreach(var leaf in childMapping) |
|||
{ |
|||
if(mainChildMapping.Children.TryGetValue(leaf.Key, out var mainLeaf)) |
|||
{ |
|||
if(leaf.Value is YamlScalarNode leafScalar && mainLeaf is YamlScalarNode leafMainScalar) |
|||
{ |
|||
leafMainScalar.Value = leafMainScalar.Value + "," + leaf.Value; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
mainChildMapping.Add(leaf.Key, leaf.Value); |
|||
} |
|||
} |
|||
} |
|||
else if(childValue is YamlSequenceNode childSequence && mainChildValue is YamlSequenceNode mainSequence) |
|||
{ |
|||
foreach(var c in childSequence.Children) |
|||
{ |
|||
mainSequence.Add(c); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return new KeyValuePair<YamlNode, YamlNode>(_.GroupName, _.MainNode); |
|||
}).ToArray(); |
|||
} |
|||
|
|||
private YamlMappingNode ParseDocument(string fragment) |
|||
{ |
|||
var input = new StringReader(File.ReadAllText(Path.Combine(FragmentLocation, $"{fragment}.yml"))); |
|||
YamlStream stream = new YamlStream(); |
|||
stream.Load(input); |
|||
return (YamlMappingNode)stream.Documents[0].RootNode; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,45 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using YamlDotNet.Serialization; |
|||
|
|||
namespace DockerGenerator |
|||
{ |
|||
class Program |
|||
{ |
|||
static void Main(string[] args) |
|||
{ |
|||
new Program().Run(); |
|||
} |
|||
|
|||
private void Run() |
|||
{ |
|||
List<DockerComposeDefinition> defs = new List<DockerComposeDefinition>(); |
|||
var btc = new DockerComposeDefinition("btc", |
|||
new string[] { "nginx", "btcpayserver", "bitcoin" }); |
|||
defs.Add(btc); |
|||
defs.Add(new DockerComposeDefinition("btc-ltc", |
|||
new string[] { "nginx", "btcpayserver", "bitcoin", "litecoin" })); |
|||
|
|||
var fragmentLocation = FindLocation("docker-fragments"); |
|||
var productionLocation = FindLocation("Production"); |
|||
foreach(var def in defs) |
|||
{ |
|||
def.FragmentLocation = fragmentLocation; |
|||
def.BuildOutputDirectory = productionLocation; |
|||
def.Build(); |
|||
} |
|||
File.Copy(btc.GetFilePath(), Path.Combine(new FileInfo(btc.GetFilePath()).Directory.FullName, "docker-compose.yml"), true); |
|||
} |
|||
|
|||
private string FindLocation(string path) |
|||
{ |
|||
while(true) |
|||
{ |
|||
if(Directory.Exists(path)) |
|||
return path; |
|||
path = Path.Combine("..", path); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>netcoreapp2.0</TargetFramework> |
|||
<RootNamespace>DockerGenerator</RootNamespace> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.1" /> |
|||
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.2" /> |
|||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.13" /> |
|||
<PackageReference Include="YamlDotNet" Version="4.3.1" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1 @@ |
|||
cd .\docker-compose-generator; dotnet run -p .\src\docker-compose-generator.csproj; cd ..; |
Loading…
Reference in new issue