diff --git a/.gitignore b/.gitignore index 00f3bfd..ca3fc1d 100644 --- a/.gitignore +++ b/.gitignore @@ -295,3 +295,4 @@ BTCPayServer/wwwroot/bundles/* Production/.env .env .vscode/ +/docker-compose.generated.yml diff --git a/docker-compose-generator/Dockerfile b/docker-compose-generator/Dockerfile index ee3eefa..20517d3 100644 --- a/docker-compose-generator/Dockerfile +++ b/docker-compose-generator/Dockerfile @@ -13,6 +13,8 @@ RUN mkdir /datadir ENV APP_DATADIR=/datadir VOLUME /datadir +ENV INSIDE_CONTAINER=1 + COPY --from=builder "/app" . COPY docker-fragments docker-fragments diff --git a/docker-compose-generator/src/CryptoDefinition.cs b/docker-compose-generator/src/CryptoDefinition.cs new file mode 100644 index 0000000..7994dd1 --- /dev/null +++ b/docker-compose-generator/src/CryptoDefinition.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DockerGenerator +{ + public class CryptoDefinition + { + public string Crypto + { + get; + private set; + } + public string CryptoFragment + { + get; + private set; + } + public string CLightningFragment + { + get; + private set; + } + + public static CryptoDefinition[] GetDefinitions() + { + return new[] + { + new CryptoDefinition() + { + Crypto = "ltc", + CryptoFragment = "litecoin", + CLightningFragment = "litecoin-clightning", + }, + new CryptoDefinition() + { + Crypto = "btc", + CryptoFragment = "bitcoin", + CLightningFragment = "bitcoin-clightning", + }, + }; + } + } +} diff --git a/docker-compose-generator/src/DockerComposition.cs b/docker-compose-generator/src/DockerComposition.cs new file mode 100644 index 0000000..b4df35b --- /dev/null +++ b/docker-compose-generator/src/DockerComposition.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DockerGenerator +{ + public class DockerComposition + { + public HashSet SelectedCryptos + { + get; + set; + } + public string SelectedProxy + { + get; + set; + } + public string SelectedLN + { + get; + set; + } + + public static DockerComposition FromEnvironmentVariables() + { + DockerComposition composition = new DockerComposition(); + composition.SelectedCryptos = new HashSet(); + for(int i = 1; i < 10; i++) + { + var selectedCrypto = Environment.GetEnvironmentVariable("BTCPAYGEN_CRYPTO" + i); + if(string.IsNullOrEmpty(selectedCrypto)) + break; + composition.SelectedCryptos.Add(selectedCrypto.ToLowerInvariant()); + } + composition.SelectedProxy = (Environment.GetEnvironmentVariable("BTCPAYGEN_REVERSEPROXY") ?? "").ToLowerInvariant(); + composition.SelectedLN = (Environment.GetEnvironmentVariable("BTCPAYGEN_LIGHTNING") ?? "").ToLowerInvariant(); + return composition; + } + } +} diff --git a/docker-compose-generator/src/Program.cs b/docker-compose-generator/src/Program.cs index 299b663..9c0e159 100644 --- a/docker-compose-generator/src/Program.cs +++ b/docker-compose-generator/src/Program.cs @@ -8,108 +8,99 @@ namespace DockerGenerator { class Program { + static void Main(string[] args) { - new Program().Run(); + var root = Environment.GetEnvironmentVariable("INSIDE_CONTAINER") == "1" ? FindRoot("app") + : Path.GetFullPath(Path.Combine(FindRoot("docker-compose-generator"), "..")); + + if(args.Any(a => a == "pregen")) + { + var productionLocation = Path.GetFullPath(Path.Combine(root, "Production")); + var testLocation = Path.GetFullPath(Path.Combine(root, "Production-NoReverseProxy")); + + foreach(var proxy in new[] { "nginx", "no-reverseproxy" }) + { + foreach(var lightning in new[] { "clightning", "" }) + { + foreach(var btc in new[] { "btc", "" }) + { + foreach(var ltc in new[] { "ltc", "" }) + { + if(btc == "" && ltc == "") + continue; + string name = $"{btc}-{ltc}-{lightning}".Replace("--", "-"); + if(name.EndsWith("-")) + name = name.Substring(0, name.Length - 1); + if(name.StartsWith("-")) + name = name.Substring(1, name.Length - 1); + var composition = new DockerComposition(); + composition.SelectedCryptos = new HashSet(); + composition.SelectedCryptos.Add(btc); + composition.SelectedCryptos.Add(ltc); + composition.SelectedLN = lightning; + composition.SelectedProxy = proxy; + new Program().Run(composition, name, proxy == "nginx" ? productionLocation : testLocation); + } + } + } + } + } + else + { + var composition = DockerComposition.FromEnvironmentVariables(); + Console.WriteLine("Crypto: " + string.Join(", ", composition.SelectedCryptos.ToArray())); + Console.WriteLine("Lightning: " + composition.SelectedLN); + Console.WriteLine("ReverseProxy: " + composition.SelectedProxy); + new Program().Run(composition, "generated", root); + } } - private void Run() + private void Run(DockerComposition composition, string name, string output) { - var fragmentLocation = FindLocation("docker-fragments"); - var productionLocation = FindLocation("Production"); - var testLocation = FindLocation("Production-NoReverseProxy"); + var fragmentLocation = Environment.GetEnvironmentVariable("INSIDE_CONTAINER") == "1" ? "app" : "docker-compose-generator"; + fragmentLocation = FindRoot(fragmentLocation); + fragmentLocation = Path.GetFullPath(Path.Combine(fragmentLocation, "docker-fragments")); - HashSet processed = new HashSet(); - foreach(var permutation in ItemCombinations(new[] { "btc", "ltc", "clightning" }.ToList())) + var fragments = new List(); + if(composition.SelectedProxy == "nginx") { - if(permutation.Count == 1 && permutation.First() == "clightning") - continue; - permutation.Sort(); - if(permutation.Remove("clightning")) - permutation.Add("clightning"); // ensure clightning at the end - string id = string.Join('-', permutation); - if(!processed.Add(id)) - continue; - - var fragments = new List(); fragments.Add("nginx"); - fragments.Add("btcpayserver"); - - if(permutation.Contains("ltc")) - { - fragments.Add("litecoin"); - if(permutation.Contains("clightning")) - fragments.Add("litecoin-clightning"); - } - if(permutation.Contains("btc")) - { - fragments.Add("bitcoin"); - if(permutation.Contains("clightning")) - fragments.Add("bitcoin-clightning"); - } - - var def = new DockerComposeDefinition(id, fragments); - def.FragmentLocation = fragmentLocation; - def.BuildOutputDirectory = productionLocation; - def.Build(); - - - def.Fragments.Remove("nginx"); - def.Fragments.Add("btcpayserver-noreverseproxy"); - def.BuildOutputDirectory = testLocation; - def.Build(); } - } - - /// - /// Method to create lists containing possible combinations of an input list of items. This is - /// basically copied from code by user "jaolho" on this thread: - /// http://stackoverflow.com/questions/7802822/all-possible-combinations-of-a-list-of-values - /// - /// type of the items on the input list - /// list of items - /// minimum number of items wanted in the generated combinations, - /// if zero the empty combination is included, - /// default is one - /// maximum number of items wanted in the generated combinations, - /// default is no maximum limit - /// list of lists for possible combinations of the input items - public static List> ItemCombinations(List inputList, int minimumItems = 1, - int maximumItems = int.MaxValue) - { - int nonEmptyCombinations = (int)Math.Pow(2, inputList.Count) - 1; - List> listOfLists = new List>(nonEmptyCombinations + 1); - - if(minimumItems == 0) // Optimize default case - listOfLists.Add(new List()); - - for(int i = 1; i <= nonEmptyCombinations; i++) + else { - List thisCombination = new List(inputList.Count); - for(int j = 0; j < inputList.Count; j++) - { - if((i >> j & 1) == 1) - thisCombination.Add(inputList[j]); - } + fragments.Add("btcpayserver-noreverseproxy"); + } + fragments.Add("btcpayserver"); + foreach(var crypto in CryptoDefinition.GetDefinitions()) + { + if(!composition.SelectedCryptos.Contains(crypto.Crypto)) + continue; - if(thisCombination.Count >= minimumItems && thisCombination.Count <= maximumItems) - listOfLists.Add(thisCombination); + fragments.Add(crypto.CryptoFragment); + if(composition.SelectedLN == "clightning" && crypto.CLightningFragment != null) + { + fragments.Add(crypto.CLightningFragment); + } } - return listOfLists; + var def = new DockerComposeDefinition(name, fragments); + def.FragmentLocation = fragmentLocation; + def.BuildOutputDirectory = output; + def.Build(); } - private string FindLocation(string path) + private static string FindRoot(string rootDirectory) { - string directory = path; + string directory = Directory.GetCurrentDirectory(); int i = 0; while(true) { if(i > 10) - throw new DirectoryNotFoundException(directory); - if(Directory.Exists(path)) - return path; - path = Path.Combine("..", path); + throw new DirectoryNotFoundException(rootDirectory); + if(directory.EndsWith(rootDirectory)) + return directory; + directory = Path.GetFullPath(Path.Combine(directory, "..")); i++; } } diff --git a/docker-compose-generator/src/Properties/launchSettings.json b/docker-compose-generator/src/Properties/launchSettings.json new file mode 100644 index 0000000..114251a --- /dev/null +++ b/docker-compose-generator/src/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "profiles": { + "docker-compose-generator": { + "commandName": "Project", + "commandLineArgs": "pregen", + "environmentVariables": { + "BTCPAYGEN_LIGHTNING": "clightning", + "BTCPAYGEN_CRYPTO2": "ltc", + "BTCPAYGEN_CRYPTO1": "btc", + "BTCPAYGEN_REVERSEPROXY": "nginx" + } + } + } +} \ No newline at end of file diff --git a/generate-docker-compose.ps1 b/generate-docker-compose.ps1 index 1b2422c..0fb05d7 100644 --- a/generate-docker-compose.ps1 +++ b/generate-docker-compose.ps1 @@ -1,4 +1,4 @@ # This script will run docker-compose-generator in a container to generate the yml files docker build -t btcpayserver/docker-compose-generator "$(Get-Location)\docker-compose-generator" -docker run -v "$(Get-Location)\Production:/app/Production" -v "$(Get-Location)\Production-NoReverseProxy:/app/Production-NoReverseProxy" --rm btcpayserver/docker-compose-generator \ No newline at end of file +docker run -v "$(Get-Location)\Production:/app/Production" -v "$(Get-Location)\Production-NoReverseProxy:/app/Production-NoReverseProxy" --rm btcpayserver/docker-compose-generator pregen \ No newline at end of file diff --git a/generate-docker-compose.sh b/generate-docker-compose.sh index 47afeb6..434fc80 100755 --- a/generate-docker-compose.sh +++ b/generate-docker-compose.sh @@ -2,4 +2,4 @@ # This script will run docker-compose-generator in a container to generate the yml files docker build -t btcpayserver/docker-compose-generator "$(pwd)/docker-compose-generator" -docker run -v "$(pwd)/Production:/app/Production" -v "$(pwd)/Production-NoReverseProxy:/app/Production-NoReverseProxy" --rm btcpayserver/docker-compose-generator \ No newline at end of file +docker run -v "$(pwd)/Production:/app/Production" -v "$(pwd)/Production-NoReverseProxy:/app/Production-NoReverseProxy" --rm btcpayserver/docker-compose-generator pregen \ No newline at end of file