11import { Command , InvalidArgumentError } from "commander" ;
2-
2+ import { ARTIFACT_DEFAULTS } from "../constants/artifact-defaults.ts" ;
33import {
44 ALGORITHM ,
55 type Algorithm ,
@@ -55,11 +55,13 @@ type BootstrapDependencies = {
5555
5656const DEFAULT_VALIDATOR_COUNT = 4 ;
5757const DEFAULT_STATIC_NODE_PORT = 30_303 ;
58- const DEFAULT_STATIC_NODE_SERVICE_NAME = "besu-node" ;
59- const DEFAULT_STATIC_NODE_POD_PREFIX = "besu-node-validator" ;
60- const DEFAULT_GENESIS_CONFIGMAP_NAME = "besu-genesis" ;
61- const DEFAULT_STATIC_NODES_CONFIGMAP_NAME = "besu-static-nodes" ;
62- const DEFAULT_FAUCET_ARTIFACT_PREFIX = "besu-faucet" ;
58+ const {
59+ staticNodeServiceName : DEFAULT_STATIC_NODE_SERVICE_NAME ,
60+ staticNodePodPrefix : DEFAULT_STATIC_NODE_POD_PREFIX ,
61+ genesisConfigMapName : DEFAULT_GENESIS_CONFIGMAP_NAME ,
62+ staticNodesConfigMapName : DEFAULT_STATIC_NODES_CONFIGMAP_NAME ,
63+ faucetArtifactPrefix : DEFAULT_FAUCET_ARTIFACT_PREFIX ,
64+ } = ARTIFACT_DEFAULTS ;
6365const OUTPUT_CHOICES : OutputType [ ] = [ "screen" , "file" , "kubernetes" ] ;
6466const LEADING_DOT_REGEX = / ^ \. / u;
6567const UNCOMPRESSED_PUBLIC_KEY_PREFIX = "04" ;
@@ -139,6 +141,81 @@ const normalizeStaticNodeNamespace = (
139141 return trimmed . length === 0 ? undefined : trimmed ;
140142} ;
141143
144+ type TextOptionKey =
145+ | "staticNodeDomain"
146+ | "staticNodeNamespace"
147+ | "staticNodeServiceName"
148+ | "staticNodePodPrefix"
149+ | "genesisConfigmapName"
150+ | "staticNodesConfigmapName"
151+ | "faucetArtifactPrefix" ;
152+
153+ type TextOptionDescriptor < T extends TextOptionKey > = {
154+ key : T ;
155+ flag : string ;
156+ description : string ;
157+ parser ?: ( value : string ) => CliOptions [ T ] ;
158+ sanitize ?: ( value : NonNullable < CliOptions [ T ] > ) => CliOptions [ T ] | undefined ;
159+ } ;
160+
161+ const TEXT_OPTION_DESCRIPTORS : TextOptionDescriptor < TextOptionKey > [ ] = [
162+ {
163+ key : "staticNodeDomain" ,
164+ flag : "--static-node-domain <domain>" ,
165+ description :
166+ "DNS suffix appended to validator peer hostnames for static-nodes entries." ,
167+ parser : stripSurroundingQuotes ,
168+ sanitize : ( value ) => normalizeStaticNodeDomain ( value ) ?? undefined ,
169+ } ,
170+ {
171+ key : "staticNodeNamespace" ,
172+ flag : "--static-node-namespace <name>" ,
173+ description :
174+ "Namespace segment inserted between service name and domain for static-nodes entries." ,
175+ parser : stripSurroundingQuotes ,
176+ sanitize : ( value ) => normalizeStaticNodeNamespace ( value ) ?? undefined ,
177+ } ,
178+ {
179+ key : "staticNodeServiceName" ,
180+ flag : "--static-node-service-name <name>" ,
181+ description :
182+ "Headless Service name used when constructing static-nodes hostnames." ,
183+ parser : stripSurroundingQuotes ,
184+ sanitize : ( value ) => stripSurroundingQuotes ( value ) ,
185+ } ,
186+ {
187+ key : "staticNodePodPrefix" ,
188+ flag : "--static-node-pod-prefix <prefix>" ,
189+ description :
190+ "StatefulSet prefix used when constructing validator pod hostnames." ,
191+ parser : stripSurroundingQuotes ,
192+ sanitize : ( value ) => stripSurroundingQuotes ( value ) ,
193+ } ,
194+ {
195+ key : "genesisConfigmapName" ,
196+ flag : "--genesis-configmap-name <name>" ,
197+ description :
198+ "ConfigMap name that stores the generated genesis.json payload." ,
199+ parser : stripSurroundingQuotes ,
200+ sanitize : ( value ) => stripSurroundingQuotes ( value ) ,
201+ } ,
202+ {
203+ key : "staticNodesConfigmapName" ,
204+ flag : "--static-nodes-configmap-name <name>" ,
205+ description :
206+ "ConfigMap name that stores the generated static-nodes.json payload." ,
207+ parser : stripSurroundingQuotes ,
208+ sanitize : ( value ) => stripSurroundingQuotes ( value ) ,
209+ } ,
210+ {
211+ key : "faucetArtifactPrefix" ,
212+ flag : "--faucet-artifact-prefix <prefix>" ,
213+ description : "Prefix applied to faucet ConfigMaps and Secrets." ,
214+ parser : stripSurroundingQuotes ,
215+ sanitize : ( value ) => stripSurroundingQuotes ( value ) ,
216+ } ,
217+ ] ;
218+
142219const deriveNodeId = ( publicKey : string ) : string => {
143220 const trimmed = publicKey . startsWith ( "0x" ) ? publicKey . slice ( 2 ) : publicKey ;
144221 if (
@@ -368,6 +445,16 @@ const createCliCommand = (
368445 "Generate node identities, configure consensus, and emit a Besu genesis."
369446 ) ;
370447
448+ const identityParser = < T > ( value : T ) : T => value ;
449+ for ( const descriptor of TEXT_OPTION_DESCRIPTORS ) {
450+ const parser = descriptor . parser ?? identityParser ;
451+ generate . option (
452+ descriptor . flag ,
453+ descriptor . description ,
454+ parser as ( value : string ) => unknown
455+ ) ;
456+ }
457+
371458 generate
372459 . option (
373460 "-v, --validators <count>" ,
@@ -393,16 +480,6 @@ const createCliCommand = (
393480 } ,
394481 "screen"
395482 )
396- . option (
397- "--static-node-domain <domain>" ,
398- "DNS suffix appended to validator peer hostnames for static-nodes entries." ,
399- ( value : string ) => stripSurroundingQuotes ( value )
400- )
401- . option (
402- "--static-node-namespace <name>" ,
403- "Namespace segment inserted between service name and domain for static-nodes entries." ,
404- ( value : string ) => stripSurroundingQuotes ( value )
405- )
406483 . option (
407484 "--static-node-port <number>" ,
408485 "P2P port used for static-nodes enode URIs." ,
@@ -416,31 +493,6 @@ const createCliCommand = (
416493 parseNonNegativeInteger ( value , "Static node discovery port" ) ,
417494 DEFAULT_STATIC_NODE_PORT
418495 )
419- . option (
420- "--static-node-service-name <name>" ,
421- "Headless Service name used when constructing static-nodes hostnames." ,
422- ( value : string ) => stripSurroundingQuotes ( value )
423- )
424- . option (
425- "--static-node-pod-prefix <prefix>" ,
426- "StatefulSet prefix used when constructing validator pod hostnames." ,
427- ( value : string ) => stripSurroundingQuotes ( value )
428- )
429- . option (
430- "--genesis-configmap-name <name>" ,
431- "ConfigMap name that stores the generated genesis.json payload." ,
432- ( value : string ) => stripSurroundingQuotes ( value )
433- )
434- . option (
435- "--static-nodes-configmap-name <name>" ,
436- "ConfigMap name that stores the generated static-nodes.json payload." ,
437- ( value : string ) => stripSurroundingQuotes ( value )
438- )
439- . option (
440- "--faucet-artifact-prefix <prefix>" ,
441- "Prefix applied to faucet ConfigMaps and Secrets." ,
442- ( value : string ) => stripSurroundingQuotes ( value )
443- )
444496 . option (
445497 "--consensus <algorithm>" ,
446498 `Consensus algorithm (${ Object . values ( ALGORITHM ) . join ( ", " ) } ). (default: ${
@@ -502,14 +554,6 @@ const createCliCommand = (
502554 cmd . getOptionValueSource ( "validators" ) === "default"
503555 ? undefined
504556 : options . validators ,
505- staticNodeDomain :
506- cmd . getOptionValueSource ( "staticNodeDomain" ) === "default"
507- ? undefined
508- : options . staticNodeDomain ,
509- staticNodeNamespace :
510- cmd . getOptionValueSource ( "staticNodeNamespace" ) === "default"
511- ? undefined
512- : options . staticNodeNamespace ,
513557 staticNodePort :
514558 cmd . getOptionValueSource ( "staticNodePort" ) === "default"
515559 ? undefined
@@ -518,64 +562,41 @@ const createCliCommand = (
518562 cmd . getOptionValueSource ( "staticNodeDiscoveryPort" ) === "default"
519563 ? undefined
520564 : options . staticNodeDiscoveryPort ,
521- staticNodeServiceName :
522- cmd . getOptionValueSource ( "staticNodeServiceName" ) === "default"
523- ? undefined
524- : options . staticNodeServiceName ,
525- staticNodePodPrefix :
526- cmd . getOptionValueSource ( "staticNodePodPrefix" ) === "default"
527- ? undefined
528- : options . staticNodePodPrefix ,
529- genesisConfigmapName :
530- cmd . getOptionValueSource ( "genesisConfigmapName" ) === "default"
531- ? undefined
532- : options . genesisConfigmapName ,
533- staticNodesConfigmapName :
534- cmd . getOptionValueSource ( "staticNodesConfigmapName" ) === "default"
535- ? undefined
536- : options . staticNodesConfigmapName ,
537- faucetArtifactPrefix :
538- cmd . getOptionValueSource ( "faucetArtifactPrefix" ) === "default"
539- ? undefined
540- : options . faucetArtifactPrefix ,
541565 } ;
542566
567+ for ( const { key } of TEXT_OPTION_DESCRIPTORS ) {
568+ if ( cmd . getOptionValueSource ( key ) === "default" ) {
569+ normalizedOptions [ key ] = undefined ;
570+ }
571+ }
572+
543573 const sanitizedOptions : CliOptions = {
544574 ...normalizedOptions ,
545575 allocations :
546576 normalizedOptions . allocations === undefined
547577 ? undefined
548578 : stripSurroundingQuotes ( normalizedOptions . allocations ) ,
549- staticNodeDomain : normalizeStaticNodeDomain (
550- normalizedOptions . staticNodeDomain
551- ) ,
552- staticNodeNamespace : normalizeStaticNodeNamespace (
553- normalizedOptions . staticNodeNamespace
554- ) ,
555- staticNodeServiceName :
556- normalizedOptions . staticNodeServiceName === undefined
557- ? undefined
558- : stripSurroundingQuotes ( normalizedOptions . staticNodeServiceName ) ,
559- staticNodePodPrefix :
560- normalizedOptions . staticNodePodPrefix === undefined
561- ? undefined
562- : stripSurroundingQuotes ( normalizedOptions . staticNodePodPrefix ) ,
563- genesisConfigmapName :
564- normalizedOptions . genesisConfigmapName === undefined
565- ? undefined
566- : stripSurroundingQuotes ( normalizedOptions . genesisConfigmapName ) ,
567- staticNodesConfigmapName :
568- normalizedOptions . staticNodesConfigmapName === undefined
569- ? undefined
570- : stripSurroundingQuotes (
571- normalizedOptions . staticNodesConfigmapName
572- ) ,
573- faucetArtifactPrefix :
574- normalizedOptions . faucetArtifactPrefix === undefined
575- ? undefined
576- : stripSurroundingQuotes ( normalizedOptions . faucetArtifactPrefix ) ,
577579 } ;
578580
581+ for ( const { key, sanitize } of TEXT_OPTION_DESCRIPTORS ) {
582+ const currentValue = normalizedOptions [ key ] ;
583+ if ( currentValue === undefined ) {
584+ sanitizedOptions [ key ] = undefined ;
585+ continue ;
586+ }
587+
588+ if ( ! sanitize ) {
589+ sanitizedOptions [ key ] = currentValue ;
590+ continue ;
591+ }
592+
593+ const sanitizedValue = sanitize (
594+ currentValue as NonNullable < CliOptions [ typeof key ] >
595+ ) ;
596+ sanitizedOptions [ key ] = ( sanitizedValue ??
597+ undefined ) as CliOptions [ typeof key ] ;
598+ }
599+
579600 await runBootstrap ( sanitizedOptions , deps ) ;
580601 } ) ;
581602
0 commit comments