Configuration.cs
1 using ArgsUniform; 2 using CodexClient; 3 using DistTestCore; 4 5 namespace CodexNetDeployer 6 { 7 public class Configuration 8 { 9 public const int SecondsIn1Day = 24 * 60 * 60; 10 public const int TenMinutes = 10 * 60; 11 12 [Uniform("deploy-name", "nm", "DEPLOYNAME", false, "Name of the deployment. (optional)")] 13 public string DeploymentName { get; set; } = "unnamed"; 14 15 [Uniform("kube-config", "kc", "KUBECONFIG", false, "Path to Kubeconfig file. Use 'null' (default) to use local cluster.")] 16 public string KubeConfigFile { get; set; } = "null"; 17 18 [Uniform("kube-namespace", "kn", "KUBENAMESPACE", true, "Kubernetes namespace to be used for deployment.")] 19 public string KubeNamespace { get; set; } = string.Empty; 20 21 [Uniform("deploy-id", "di", "DEPLOYID", false, "ID of the deployment. (default) to current time)")] 22 public string DeployId { get; set; } = NameUtils.MakeDeployId(); 23 24 [Uniform("deploy-file", "df", "DEPLOYFILE", false, "Output deployment JSON file that will be written. Defaults to 'codex-deployment.json'.")] 25 public string DeployFile { get; set; } = "codex-deployment.json"; 26 27 [Uniform("codex-local-repo", "cr", "CODEXLOCALREPOPATH", false, "If set, instead of using the default Codex docker image, the local repository will be used to build an image. " + 28 "This requires the 'DOCKERUSERNAME' and 'DOCKERPASSWORD' environment variables to be set. (You can omit the password to use your system default, or use a docker access token as DOCKERPASSWORD.) You can set " + 29 "'DOCKERTAG' to define the image tag. If not set, one will be generated.")] 30 public string CodexLocalRepoPath { get; set; } = string.Empty; 31 32 [Uniform("nodes", "n", "NODES", true, "Number of Codex nodes to be created.")] 33 public int? NumberOfCodexNodes { get; set; } 34 35 [Uniform("validators", "v", "VALIDATORS", true, "Number of Codex nodes that will be validating.")] 36 public int? NumberOfValidators { get; set; } 37 38 [Uniform("storage-quota", "sq", "STORAGEQUOTA", true, "Storage quota in megabytes used by each Codex node.")] 39 public int? StorageQuota { get; set; } 40 41 [Uniform("log-level", "l", "LOGLEVEL", true, "Log level used by each Codex node. [Trace, Debug*, Info, Warn, Error]")] 42 public CodexLogLevel CodexLogLevel { get; set; } = CodexLogLevel.Debug; 43 44 [Uniform("log-level-libp2p", "lp2p", "LOGLEVELLIBP2P", true, "Log level for all libp2p topics. [Trace, Debug, Info, Warn*, Error]")] 45 public CodexLogLevel Libp2pLogLevel { get; set; } = CodexLogLevel.Warn; 46 47 [Uniform("log-level-discv5", "ldv5", "LOGLEVELDISCV5", true, "Log level for all discv5 topics. [Trace, Debug, Info, Warn*, Error]")] 48 public CodexLogLevel Discv5LogLevel { get; set; } = CodexLogLevel.Warn; 49 50 [Uniform("make-storage-available", "msa", "MAKESTORAGEAVAILABLE", true, "Is true, storage will be made available using the next configuration parameters.")] 51 public bool ShouldMakeStorageAvailable { get; set; } = false; 52 53 [Uniform("storage-sell", "ss", "STORAGESELL", false, "Number of megabytes of storage quota to make available for selling.")] 54 public int? StorageSell { get; set; } 55 56 [Uniform("test-tokens", "tt", "TESTTOKENS", false, "Initial amount of test-tokens minted for each Codex node.")] 57 public int InitialTestTokens { get; set; } 58 59 [Uniform("min-price", "mp", "MINPRICE", false, "Minimum price per byte per second in TSTWEI for the storage space for which contracts will be accepted.")] 60 public int MinPricePerBytePerSecond { get; set; } 61 62 [Uniform("max-collateral", "mc", "MAXCOLLATERAL", false, "Maximum collateral that will be placed for the total storage space.")] 63 public int MaxCollateral { get; set; } 64 65 [Uniform("max-duration", "md", "MAXDURATION", false, "Maximum duration in seconds for contracts which will be accepted.")] 66 public int MaxDuration { get; set; } 67 68 [Uniform("block-ttl", "bt", "BLOCKTTL", false, "Block timeout in seconds. Default is 24 hours.")] 69 public int BlockTTL { get; set; } = SecondsIn1Day; 70 71 [Uniform("block-mi", "bmi", "BLOCKMI", false, "Block maintenance interval in seconds. Default is 10 minutes.")] 72 public int BlockMI { get; set; } = TenMinutes; 73 74 [Uniform("block-mn", "bmn", "BLOCKMN", false, "Number of blocks maintained per interval. Default is 1000 blocks.")] 75 public int BlockMN { get; set; } = 1000; 76 77 [Uniform("metrics-endpoints", "me", "METRICSENDPOINTS", false, "[true, false]. Determines if metric endpoints will be enabled. Default is false.")] 78 public bool MetricsEndpoints { get; set; } = false; 79 80 [Uniform("metrics-scraper", "ms", "METRICSSCRAPER", false, "[true, false]. Determines if metrics scraper service will be deployed. (Required for certain tests.) Default is false.")] 81 public bool MetricsScraper { get; set; } = false; 82 83 [Uniform("teststype-podlabel", "ttpl", "TESTSTYPE-PODLABEL", false, "Each kubernetes pod will be created with a label 'teststype' with value 'continuous'. " + 84 "set this option to override the label value.")] 85 public string TestsTypePodLabel { get; set; } = "continuous-tests"; 86 87 [Uniform("check-connect", "cc", "CHECKCONNECT", false, "If true, deployer check ensure peer-connectivity between all deployed nodes after deployment. Default is false.")] 88 public bool CheckPeerConnection { get; set; } = false; 89 90 [Uniform("public-testnet", "ptn", "PUBLICTESTNET", false, "If true, deployment is created for public exposure. Default is false.")] 91 public bool IsPublicTestNet { get; set; } = false; 92 93 [Uniform("public-discports", "pdps", "PUBLICDISCPORTS", false, "Required if public-testnet is true. Comma-separated port numbers used for discovery. Number must match number of nodes.")] 94 public string PublicDiscPorts { get; set; } = string.Empty; 95 96 [Uniform("public-listenports", "plps", "PUBLICLISTENPORTS", false, "Required if public-testnet is true. Comma-separated port numbers used for listening. Number must match number of nodes.")] 97 public string PublicListenPorts { get; set; } = string.Empty; 98 99 [Uniform("public-gethdiscport", "pgdp", "PUBLICGETHDISCPORT", false, "Required if public-testnet is true. Single port number used for Geth's public discovery port.")] 100 public int PublicGethDiscPort { get; set; } 101 102 [Uniform("public-gethlistenport", "pglp", "PUBLICGETHLISTENPORT", false, "Required if public-testnet is true. Single port number used for Geth's public listen port.")] 103 public int PublicGethListenPort { get; set; } 104 105 [Uniform("discord-bot", "dbot", "DISCORDBOT", false, "If true, will deploy discord bot. Default is false.")] 106 public bool DeployDiscordBot { get; set; } = false; 107 108 [Uniform("dbot-token", "dbott", "DBOTTOKEN", false, "Required if discord-bot is true. Discord token used by bot.")] 109 public string DiscordBotToken { get; set; } = string.Empty; 110 111 [Uniform("dbot-servername", "dbotsn", "DBOTSERVERNAME", false, "Required if discord-bot is true. Name of the Discord server.")] 112 public string DiscordBotServerName { get; set; } = string.Empty; 113 114 [Uniform("dbot-adminrolename", "dbotarn", "DBOTADMINROLENAME", false, "Required if discord-bot is true. Name of the Discord role which will have access to admin features.")] 115 public string DiscordBotAdminRoleName { get; set; } = string.Empty; 116 117 [Uniform("dbot-adminchannelname", "dbotacn", "DBOTADMINCHANNELNAME", false, "Required if discord-bot is true. Name of the Discord channel in which admin commands are allowed.")] 118 public string DiscordBotAdminChannelName { get; set; } = string.Empty; 119 120 [Uniform("dbot-rewardchannelname", "dbotrcn", "DBOTREWARDCHANNELNAME", false, "Required if discord-bot is true. Name of the Discord channel in which reward updates are posted.")] 121 public string DiscordBotRewardChannelName { get; set; } = string.Empty; 122 123 [Uniform("dbot-datapath", "dbotdp", "DBOTDATAPATH", false, "Optional. Path in container where bot will save all data.")] 124 public string DiscordBotDataPath { get; set; } = string.Empty; 125 126 public List<string> Validate() 127 { 128 var errors = new List<string>(); 129 130 StringIsSet(nameof(KubeNamespace), KubeNamespace, errors); 131 StringIsSet(nameof(KubeConfigFile), KubeConfigFile, errors); 132 StringIsSet(nameof(TestsTypePodLabel), TestsTypePodLabel, errors); 133 134 if (NumberOfValidators > NumberOfCodexNodes) 135 { 136 errors.Add($"{nameof(NumberOfValidators)} ({NumberOfValidators}) may not be greater than {nameof(NumberOfCodexNodes)} ({NumberOfCodexNodes})."); 137 } 138 if (StorageSell.HasValue && StorageQuota.HasValue && StorageSell.Value >= StorageQuota.Value) 139 { 140 errors.Add("StorageSell cannot be greater than or equal to StorageQuota."); 141 } 142 143 if (ShouldMakeStorageAvailable) 144 { 145 IntIsOverZero(nameof(StorageSell), StorageSell, errors); 146 IntIsOverZero(nameof(InitialTestTokens), InitialTestTokens, errors); 147 IntIsOverZero(nameof(MinPricePerBytePerSecond), MinPricePerBytePerSecond, errors); 148 IntIsOverZero(nameof(MaxCollateral), MaxCollateral, errors); 149 IntIsOverZero(nameof(MaxDuration), MaxDuration, errors); 150 } 151 152 if (IsPublicTestNet) 153 { 154 if (NumberOfCodexNodes > 0) 155 { 156 if (PublicDiscPorts.Split(",").Length != NumberOfCodexNodes) errors.Add("Number of public discovery-ports provided does not match number of codex nodes."); 157 if (PublicListenPorts.Split(",").Length != NumberOfCodexNodes) errors.Add("Number of public listen-ports provided does not match number of codex nodes."); 158 } 159 if (PublicGethDiscPort == 0) errors.Add("Geth public discovery port is not set."); 160 if (PublicGethListenPort == 0) errors.Add("Geth public listen port is not set."); 161 } 162 163 if (DeployDiscordBot) 164 { 165 StringIsSet(nameof(DiscordBotToken), DiscordBotToken, errors); 166 StringIsSet(nameof(DiscordBotServerName), DiscordBotServerName, errors); 167 StringIsSet(nameof(DiscordBotAdminRoleName), DiscordBotAdminRoleName, errors); 168 StringIsSet(nameof(DiscordBotAdminChannelName), DiscordBotAdminChannelName, errors); 169 StringIsSet(nameof(DiscordBotRewardChannelName), DiscordBotRewardChannelName, errors); 170 } 171 172 return errors; 173 } 174 175 private static void IntIsOverZero(string variable, int? value, List<string> errors) 176 { 177 if (value == null || value.Value < 1) 178 { 179 errors.Add($"{variable} must be set and must be greater than 0."); 180 } 181 } 182 183 private static void StringIsSet(string variable, string value, List<string> errors) 184 { 185 if (string.IsNullOrWhiteSpace(value)) 186 { 187 errors.Add($"{variable} must be set."); 188 } 189 } 190 } 191 }