2023-06-26 11:58:41 +00:00
using ArgsUniform ;
2023-09-20 10:02:32 +00:00
using CodexPlugin ;
2024-02-22 13:41:07 +00:00
using DistTestCore ;
2023-06-22 08:17:12 +00:00
namespace CodexNetDeployer
2023-06-22 07:51:25 +00:00
{
public class Configuration
{
2023-06-29 14:03:45 +00:00
public const int SecondsIn1Day = 24 * 60 * 60 ;
2023-08-23 06:29:16 +00:00
public const int TenMinutes = 10 * 60 ;
2023-06-29 14:03:45 +00:00
2023-10-23 08:19:52 +00:00
[Uniform("deploy-name", "nm", "DEPLOYNAME", false, "Name of the deployment. (optional)")]
public string DeploymentName { get ; set ; } = "unnamed" ;
2023-06-27 06:29:39 +00:00
[Uniform("kube-config", "kc", "KUBECONFIG", false, "Path to Kubeconfig file. Use 'null' (default) to use local cluster.")]
public string KubeConfigFile { get ; set ; } = "null" ;
2023-06-26 11:58:41 +00:00
[Uniform("kube-namespace", "kn", "KUBENAMESPACE", true, "Kubernetes namespace to be used for deployment.")]
public string KubeNamespace { get ; set ; } = string . Empty ;
2024-02-22 13:41:07 +00:00
[Uniform("deploy-id", "di", "DEPLOYID", false, "ID of the deployment. (default) to current time)")]
public string DeployId { get ; set ; } = NameUtils . MakeDeployId ( ) ;
2023-06-26 11:58:41 +00:00
2023-10-05 06:46:59 +00:00
[Uniform("deploy-file", "df", "DEPLOYFILE", false, "Output deployment JSON file that will be written. Defaults to 'codex-deployment.json'.")]
public string DeployFile { get ; set ; } = "codex-deployment.json" ;
2023-09-28 09:31:09 +00:00
[ 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. " +
2023-09-28 10:22:35 +00:00
"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 " +
"'DOCKERTAG' to define the image tag. If not set, one will be generated." ) ]
2023-09-28 09:31:09 +00:00
public string CodexLocalRepoPath { get ; set ; } = string . Empty ;
2023-06-26 11:58:41 +00:00
[Uniform("nodes", "n", "NODES", true, "Number of Codex nodes to be created.")]
public int? NumberOfCodexNodes { get ; set ; }
[Uniform("validators", "v", "VALIDATORS", true, "Number of Codex nodes that will be validating.")]
public int? NumberOfValidators { get ; set ; }
2023-06-29 09:05:58 +00:00
[Uniform("storage-quota", "sq", "STORAGEQUOTA", true, "Storage quota in megabytes used by each Codex node.")]
2023-06-26 11:58:41 +00:00
public int? StorageQuota { get ; set ; }
2023-06-22 07:51:25 +00:00
2023-06-26 11:58:41 +00:00
[Uniform("log-level", "l", "LOGLEVEL", true, "Log level used by each Codex node. [Trace, Debug*, Info, Warn, Error] ")]
2023-06-27 06:29:39 +00:00
public CodexLogLevel CodexLogLevel { get ; set ; } = CodexLogLevel . Debug ;
2023-10-08 05:29:55 +00:00
[Uniform("log-level-libp2p", "lp2p", "LOGLEVELLIBP2P", true, "Log level for all libp2p topics. [Trace, Debug, Info, Warn*, Error] ")]
public CodexLogLevel Libp2pLogLevel { get ; set ; } = CodexLogLevel . Warn ;
[Uniform("log-level-discv5", "ldv5", "LOGLEVELDISCV5", true, "Log level for all discv5 topics. [Trace, Debug, Info, Warn*, Error] ")]
public CodexLogLevel Discv5LogLevel { get ; set ; } = CodexLogLevel . Warn ;
2023-06-26 11:58:41 +00:00
2023-10-23 10:52:47 +00:00
[Uniform("make-storage-available", "msa", "MAKESTORAGEAVAILABLE", true, "Is true, storage will be made available using the next configuration parameters.")]
public bool ShouldMakeStorageAvailable { get ; set ; } = false ;
[Uniform("storage-sell", "ss", "STORAGESELL", false, "Number of megabytes of storage quota to make available for selling.")]
public int? StorageSell { get ; set ; }
[Uniform("test-tokens", "tt", "TESTTOKENS", false, "Initial amount of test-tokens minted for each Codex node.")]
public int InitialTestTokens { get ; set ; }
2023-06-28 06:48:46 +00:00
2023-10-23 10:52:47 +00:00
[Uniform("min-price", "mp", "MINPRICE", false, "Minimum price for the storage space for which contracts will be accepted.")]
2023-06-28 06:48:46 +00:00
public int MinPrice { get ; set ; }
2023-10-23 10:52:47 +00:00
[Uniform("max-collateral", "mc", "MAXCOLLATERAL", false, "Maximum collateral that will be placed for the total storage space.")]
2023-06-28 06:48:46 +00:00
public int MaxCollateral { get ; set ; }
2023-10-23 10:52:47 +00:00
[Uniform("max-duration", "md", "MAXDURATION", false, "Maximum duration in seconds for contracts which will be accepted.")]
2023-06-28 06:48:46 +00:00
public int MaxDuration { get ; set ; }
2023-06-29 14:03:45 +00:00
[Uniform("block-ttl", "bt", "BLOCKTTL", false, "Block timeout in seconds. Default is 24 hours.")]
public int BlockTTL { get ; set ; } = SecondsIn1Day ;
2023-07-11 08:59:41 +00:00
2023-08-23 06:29:16 +00:00
[Uniform("block-mi", "bmi", "BLOCKMI", false, "Block maintenance interval in seconds. Default is 10 minutes.")]
public int BlockMI { get ; set ; } = TenMinutes ;
[Uniform("block-mn", "bmn", "BLOCKMN", false, "Number of blocks maintained per interval. Default is 1000 blocks.")]
public int BlockMN { get ; set ; } = 1000 ;
2023-10-23 08:57:59 +00:00
[Uniform("metrics-endpoints", "me", "METRICSENDPOINTS", false, "[true, false] . Determines if metric endpoints will be enabled . Default is false . ")]
public bool MetricsEndpoints { get ; set ; } = false ;
[Uniform("metrics-scraper", "ms", "METRICSSCRAPER", false, "[true, false] . Determines if metrics scraper service will be deployed . ( Required for certain tests . ) Default is false . ")]
public bool MetricsScraper { get ; set ; } = false ;
2023-08-07 13:51:44 +00:00
[ Uniform ( "teststype-podlabel" , "ttpl" , "TESTSTYPE-PODLABEL" , false , "Each kubernetes pod will be created with a label 'teststype' with value 'continuous'. " +
"set this option to override the label value." ) ]
2023-08-10 12:31:08 +00:00
public string TestsTypePodLabel { get ; set ; } = "continuous-tests" ;
2023-08-24 09:32:32 +00:00
2023-09-20 10:55:09 +00:00
[Uniform("check-connect", "cc", "CHECKCONNECT", false, "If true, deployer check ensure peer-connectivity between all deployed nodes after deployment. Default is false.")]
2023-08-24 09:32:32 +00:00
public bool CheckPeerConnection { get ; set ; } = false ;
2023-09-28 09:31:09 +00:00
2023-10-23 10:43:50 +00:00
[Uniform("public-testnet", "ptn", "PUBLICTESTNET", false, "If true, deployment is created for public exposure. Default is false.")]
public bool IsPublicTestNet { get ; set ; } = false ;
[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.")]
public string PublicDiscPorts { get ; set ; } = string . Empty ;
[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.")]
public string PublicListenPorts { get ; set ; } = string . Empty ;
2023-10-23 11:19:57 +00:00
[Uniform("public-gethdiscport", "pgdp", "PUBLICGETHDISCPORT", false, "Required if public-testnet is true. Single port number used for Geth's public discovery port.")]
public int PublicGethDiscPort { get ; set ; }
2023-10-27 06:33:07 +00:00
[Uniform("public-gethlistenport", "pglp", "PUBLICGETHLISTENPORT", false, "Required if public-testnet is true. Single port number used for Geth's public listen port.")]
public int PublicGethListenPort { get ; set ; }
2023-10-24 08:29:07 +00:00
[Uniform("discord-bot", "dbot", "DISCORDBOT", false, "If true, will deploy discord bot. Default is false.")]
public bool DeployDiscordBot { get ; set ; } = false ;
[Uniform("dbot-token", "dbott", "DBOTTOKEN", false, "Required if discord-bot is true. Discord token used by bot.")]
public string DiscordBotToken { get ; set ; } = string . Empty ;
[Uniform("dbot-servername", "dbotsn", "DBOTSERVERNAME", false, "Required if discord-bot is true. Name of the Discord server.")]
public string DiscordBotServerName { get ; set ; } = string . Empty ;
[Uniform("dbot-adminrolename", "dbotarn", "DBOTADMINROLENAME", false, "Required if discord-bot is true. Name of the Discord role which will have access to admin features.")]
public string DiscordBotAdminRoleName { get ; set ; } = string . Empty ;
2023-10-25 08:38:21 +00:00
[Uniform("dbot-adminchannelname", "dbotacn", "DBOTADMINCHANNELNAME", false, "Required if discord-bot is true. Name of the Discord channel in which admin commands are allowed.")]
public string DiscordBotAdminChannelName { get ; set ; } = string . Empty ;
2024-02-19 08:11:36 +00:00
[Uniform("dbot-rewardchannelname", "dbotrcn", "DBOTREWARDCHANNELNAME", false, "Required if discord-bot is true. Name of the Discord channel in which reward updates are posted.")]
public string DiscordBotRewardChannelName { get ; set ; } = string . Empty ;
2023-10-25 08:38:21 +00:00
2023-10-25 09:53:33 +00:00
[Uniform("dbot-datapath", "dbotdp", "DBOTDATAPATH", false, "Optional. Path in container where bot will save all data.")]
public string DiscordBotDataPath { get ; set ; } = string . Empty ;
2023-09-28 10:22:35 +00:00
public List < string > Validate ( )
2023-06-22 07:51:25 +00:00
{
var errors = new List < string > ( ) ;
2023-09-28 09:31:09 +00:00
StringIsSet ( nameof ( KubeNamespace ) , KubeNamespace , errors ) ;
StringIsSet ( nameof ( KubeConfigFile ) , KubeConfigFile , errors ) ;
StringIsSet ( nameof ( TestsTypePodLabel ) , TestsTypePodLabel , errors ) ;
2023-06-22 13:58:18 +00:00
if ( NumberOfValidators > NumberOfCodexNodes )
{
errors . Add ( $"{nameof(NumberOfValidators)} ({NumberOfValidators}) may not be greater than {nameof(NumberOfCodexNodes)} ({NumberOfCodexNodes})." ) ;
}
2023-06-29 09:05:58 +00:00
if ( StorageSell . HasValue & & StorageQuota . HasValue & & StorageSell . Value > = StorageQuota . Value )
{
errors . Add ( "StorageSell cannot be greater than or equal to StorageQuota." ) ;
}
2023-06-22 13:58:18 +00:00
2023-10-23 11:36:20 +00:00
if ( ShouldMakeStorageAvailable )
{
IntIsOverZero ( nameof ( StorageSell ) , StorageSell , errors ) ;
IntIsOverZero ( nameof ( InitialTestTokens ) , InitialTestTokens , errors ) ;
IntIsOverZero ( nameof ( MinPrice ) , MinPrice , errors ) ;
IntIsOverZero ( nameof ( MaxCollateral ) , MaxCollateral , errors ) ;
IntIsOverZero ( nameof ( MaxDuration ) , MaxDuration , errors ) ;
}
2023-10-23 10:43:50 +00:00
if ( IsPublicTestNet )
{
2023-12-11 07:30:05 +00:00
if ( NumberOfCodexNodes > 0 )
{
if ( PublicDiscPorts . Split ( "," ) . Length ! = NumberOfCodexNodes ) errors . Add ( "Number of public discovery-ports provided does not match number of codex nodes." ) ;
if ( PublicListenPorts . Split ( "," ) . Length ! = NumberOfCodexNodes ) errors . Add ( "Number of public listen-ports provided does not match number of codex nodes." ) ;
}
2023-10-23 11:19:57 +00:00
if ( PublicGethDiscPort = = 0 ) errors . Add ( "Geth public discovery port is not set." ) ;
2023-10-27 06:33:07 +00:00
if ( PublicGethListenPort = = 0 ) errors . Add ( "Geth public listen port is not set." ) ;
2023-10-23 10:43:50 +00:00
}
2023-10-25 08:38:21 +00:00
if ( DeployDiscordBot )
{
StringIsSet ( nameof ( DiscordBotToken ) , DiscordBotToken , errors ) ;
StringIsSet ( nameof ( DiscordBotServerName ) , DiscordBotServerName , errors ) ;
StringIsSet ( nameof ( DiscordBotAdminRoleName ) , DiscordBotAdminRoleName , errors ) ;
StringIsSet ( nameof ( DiscordBotAdminChannelName ) , DiscordBotAdminChannelName , errors ) ;
2024-02-19 08:11:36 +00:00
StringIsSet ( nameof ( DiscordBotRewardChannelName ) , DiscordBotRewardChannelName , errors ) ;
2023-10-25 08:38:21 +00:00
}
2023-06-22 07:51:25 +00:00
return errors ;
}
private static void IntIsOverZero ( string variable , int? value , List < string > errors )
{
if ( value = = null | | value . Value < 1 )
{
2023-06-27 06:29:39 +00:00
errors . Add ( $"{variable} must be set and must be greater than 0." ) ;
2023-06-22 07:51:25 +00:00
}
}
private static void StringIsSet ( string variable , string value , List < string > errors )
{
if ( string . IsNullOrWhiteSpace ( value ) )
{
2023-06-27 06:29:39 +00:00
errors . Add ( $"{variable} must be set." ) ;
2023-06-22 07:51:25 +00:00
}
}
}
}