@@ -20,18 +20,18 @@ import {SoloError, IllegalArgumentError, MissingArgumentError} from './errors.js
20
20
import * as yaml from 'yaml' ;
21
21
import dot from 'dot-object' ;
22
22
import * as semver from 'semver' ;
23
- import type { SemVer } from 'semver' ;
24
23
import { readFile , writeFile } from 'fs/promises' ;
25
24
26
25
import { Flags as flags } from '../commands/flags.js' ;
27
26
import { Templates } from './templates.js' ;
28
27
import * as constants from './constants.js' ;
29
28
import { type ConfigManager } from './config_manager.js' ;
30
29
import * as helpers from './helpers.js' ;
31
- import { getNodeAccountMap , parseIpAddressToUint8Array } from './helpers.js' ;
30
+ import { getNodeAccountMap } from './helpers.js' ;
31
+ import type { SemVer } from 'semver' ;
32
32
import type { SoloLogger } from './logging.js' ;
33
- import type { NodeAlias , NodeAliases } from '../types/aliases.js' ;
34
- import { type GenesisNetworkDataConstructor } from './models/genesisNetworkDataConstructor.js' ;
33
+ import type { AnyObject , NodeAlias , NodeAliases , Path } from '../types/aliases.js' ;
34
+ import type { GenesisNetworkDataConstructor } from './models/genesisNetworkDataConstructor.js' ;
35
35
36
36
const consensusSidecars = [
37
37
'recordStreamUploader' ,
@@ -46,10 +46,10 @@ export class ProfileManager {
46
46
private readonly configManager : ConfigManager ;
47
47
private readonly cacheDir : string ;
48
48
49
- private profiles : Map < string , object > ;
49
+ private profiles : Map < string , AnyObject > ;
50
50
private profileFile : string | undefined ;
51
51
52
- constructor ( logger : SoloLogger , configManager : ConfigManager , cacheDir : string = constants . SOLO_VALUES_DIR ) {
52
+ constructor ( logger : SoloLogger , configManager : ConfigManager , cacheDir = constants . SOLO_VALUES_DIR ) {
53
53
if ( ! logger ) throw new MissingArgumentError ( 'An instance of core/SoloLogger is required' ) ;
54
54
if ( ! configManager ) throw new MissingArgumentError ( 'An instance of core/ConfigManager is required' ) ;
55
55
@@ -62,7 +62,15 @@ export class ProfileManager {
62
62
this . cacheDir = cacheDir ;
63
63
}
64
64
65
- loadProfiles ( forceReload = false ) : Map < string , object > {
65
+ /**
66
+ * Load profiles from a profile file and populate the profiles map.
67
+ *
68
+ * @param [forceReload = false] - forces the profiles map to override even if it exists.
69
+ * @returns reference to the populated profiles map.
70
+ *
71
+ * @throws {IllegalArgumentError } if the profile file is not found.
72
+ */
73
+ loadProfiles ( forceReload = false ) : Map < string , AnyObject > {
66
74
const profileFile = this . configManager . getFlag < string > ( flags . profileFile ) ;
67
75
if ( ! profileFile ) throw new MissingArgumentError ( 'profileFile is required' ) ;
68
76
@@ -76,7 +84,7 @@ export class ProfileManager {
76
84
// load profile file
77
85
this . profiles = new Map ( ) ;
78
86
const yamlData = fs . readFileSync ( profileFile , 'utf8' ) ;
79
- const profileItems = yaml . parse ( yamlData ) as Record < string , object > ;
87
+ const profileItems = yaml . parse ( yamlData ) as Record < string , AnyObject > ;
80
88
81
89
// add profiles
82
90
for ( const key in profileItems ) {
@@ -89,15 +97,25 @@ export class ProfileManager {
89
97
return this . profiles ;
90
98
}
91
99
92
- getProfile ( profileName : string ) : object {
100
+ /**
101
+ * Get profile from the profiles map, loads them on demand if they are not loaded already.
102
+ *
103
+ * @param profileName - profile name (key in the map).
104
+ * @returns the profile.
105
+ *
106
+ * @throws {IllegalArgumentError } if profiles can't be loaded or the profile name is not found in the map.
107
+ */
108
+ getProfile ( profileName : string ) : AnyObject {
93
109
if ( ! profileName ) throw new MissingArgumentError ( 'profileName is required' ) ;
94
110
if ( ! this . profiles || this . profiles . size <= 0 ) {
95
111
this . loadProfiles ( ) ;
96
112
}
97
113
98
- if ( ! this . profiles || ! this . profiles . has ( profileName ) )
114
+ if ( ! this . profiles || ! this . profiles . has ( profileName ) ) {
99
115
throw new IllegalArgumentError ( `Profile does not exists with name: ${ profileName } ` ) ;
100
- return this . profiles . get ( profileName ) as object ;
116
+ }
117
+
118
+ return this . profiles . get ( profileName ) as AnyObject ;
101
119
}
102
120
103
121
/**
@@ -107,7 +125,7 @@ export class ProfileManager {
107
125
* @param yamlRoot - root of the YAML object
108
126
* @returns
109
127
*/
110
- _setValue ( itemPath : string , value : any , yamlRoot : object ) : object {
128
+ _setValue ( itemPath : string , value : any , yamlRoot : AnyObject ) : AnyObject {
111
129
// find the location where to set the value in the YAML
112
130
const itemPathParts : string [ ] = itemPath . split ( '.' ) ;
113
131
let parent = yamlRoot ;
@@ -116,7 +134,7 @@ export class ProfileManager {
116
134
for ( let itemPathPart of itemPathParts ) {
117
135
if ( helpers . isNumeric ( itemPathPart ) ) {
118
136
// @ts -ignore
119
- itemPathPart = Number . parseInt ( itemPathPart ) ; // numeric path part can only be array index i.e. an integer
137
+ itemPathPart = Number . parseInt ( itemPathPart ) ; // numeric path part can only be array index i.e., an integer
120
138
if ( ! Array . isArray ( parent [ prevItemPath ] ) ) {
121
139
parent [ prevItemPath ] = [ ] ;
122
140
}
@@ -145,12 +163,12 @@ export class ProfileManager {
145
163
146
164
/**
147
165
* Set items for the chart
148
- * @param itemPath - item path in the yaml , if empty then root of the yaml object will be used
166
+ * @param itemPath - item path in the YAML , if empty then root of the YAML object will be used
149
167
* @param items - the element object
150
- * @param yamlRoot - root of the yaml object to update
168
+ * @param yamlRoot - root of the YAML object to update
151
169
* @private
152
170
*/
153
- _setChartItems ( itemPath : string , items : any , yamlRoot : object ) {
171
+ _setChartItems ( itemPath : string , items : any , yamlRoot : AnyObject ) {
154
172
if ( ! items ) return ;
155
173
156
174
const dotItems = dot . dot ( items ) ;
@@ -172,11 +190,11 @@ export class ProfileManager {
172
190
}
173
191
174
192
resourcesForConsensusPod (
175
- profile : any ,
193
+ profile : AnyObject ,
176
194
nodeAliases : NodeAliases ,
177
- yamlRoot : object ,
195
+ yamlRoot : AnyObject ,
178
196
genesisNetworkData ?: GenesisNetworkDataConstructor ,
179
- ) : object {
197
+ ) : AnyObject {
180
198
if ( ! profile ) throw new MissingArgumentError ( 'profile is required' ) ;
181
199
182
200
const accountMap = getNodeAccountMap ( nodeAliases ) ;
@@ -266,26 +284,26 @@ export class ProfileManager {
266
284
return yamlRoot ;
267
285
}
268
286
269
- resourcesForHaProxyPod ( profile : any , yamlRoot : object ) {
287
+ private resourcesForHaProxyPod ( profile : AnyObject , yamlRoot : AnyObject ) {
270
288
if ( ! profile ) throw new MissingArgumentError ( 'profile is required' ) ;
271
289
if ( ! profile . haproxy ) return ; // use chart defaults
272
290
273
291
return this . _setChartItems ( 'defaults.haproxy' , profile . haproxy , yamlRoot ) ;
274
292
}
275
293
276
- resourcesForEnvoyProxyPod ( profile : any , yamlRoot : object ) {
294
+ private resourcesForEnvoyProxyPod ( profile : AnyObject , yamlRoot : AnyObject ) {
277
295
if ( ! profile ) throw new MissingArgumentError ( 'profile is required' ) ;
278
296
if ( ! profile . envoyProxy ) return ; // use chart defaults
279
297
return this . _setChartItems ( 'defaults.envoyProxy' , profile . envoyProxy , yamlRoot ) ;
280
298
}
281
299
282
- resourcesForHederaExplorerPod ( profile : any , yamlRoot : object ) {
300
+ private resourcesForHederaExplorerPod ( profile : AnyObject , yamlRoot : AnyObject ) {
283
301
if ( ! profile ) throw new MissingArgumentError ( 'profile is required' ) ;
284
302
if ( ! profile . explorer ) return ;
285
303
return this . _setChartItems ( '' , profile . explorer , yamlRoot ) ;
286
304
}
287
305
288
- resourcesForMinioTenantPod ( profile : any , yamlRoot : object ) {
306
+ private resourcesForMinioTenantPod ( profile : AnyObject , yamlRoot : AnyObject ) {
289
307
if ( ! profile ) throw new MissingArgumentError ( 'profile is required' ) ;
290
308
// @ts -ignore
291
309
if ( ! profile . minio || ! profile . minio . tenant ) return ; // use chart defaults
@@ -306,11 +324,11 @@ export class ProfileManager {
306
324
307
325
/**
308
326
* Prepare a values file for Solo Helm chart
309
- * @param profileName resource profile name
310
- * @param genesisNetworkData
327
+ * @param profileName - resource profile name
328
+ * @param genesisNetworkData - reference to the constructor
311
329
* @returns return the full path to the values file
312
330
*/
313
- prepareValuesForSoloChart ( profileName : string , genesisNetworkData ?: GenesisNetworkDataConstructor ) {
331
+ public async prepareValuesForSoloChart ( profileName : string , genesisNetworkData ?: GenesisNetworkDataConstructor ) {
314
332
if ( ! profileName ) throw new MissingArgumentError ( 'profileName is required' ) ;
315
333
const profile = this . getProfile ( profileName ) ;
316
334
@@ -324,20 +342,11 @@ export class ProfileManager {
324
342
this . resourcesForEnvoyProxyPod ( profile , yamlRoot ) ;
325
343
this . resourcesForMinioTenantPod ( profile , yamlRoot ) ;
326
344
327
- // write the YAML
328
345
const cachedValuesFile = path . join ( this . cacheDir , `solo-${ profileName } .yaml` ) ;
329
- return new Promise < string > ( ( resolve , reject ) => {
330
- fs . writeFile ( cachedValuesFile , yaml . stringify ( yamlRoot ) , err => {
331
- if ( err ) {
332
- reject ( err ) ;
333
- }
334
-
335
- resolve ( cachedValuesFile ) ;
336
- } ) ;
337
- } ) ;
346
+ return this . writeToYaml ( cachedValuesFile , yamlRoot ) ;
338
347
}
339
348
340
- async bumpHederaConfigVersion ( applicationPropertiesPath : string ) {
349
+ private async bumpHederaConfigVersion ( applicationPropertiesPath : string ) {
341
350
const lines = ( await readFile ( applicationPropertiesPath , 'utf-8' ) ) . split ( '\n' ) ;
342
351
343
352
for ( const line of lines ) {
@@ -351,62 +360,59 @@ export class ProfileManager {
351
360
await writeFile ( applicationPropertiesPath , lines . join ( '\n' ) ) ;
352
361
}
353
362
354
- async prepareValuesForNodeAdd ( configTxtPath : string , applicationPropertiesPath : string ) {
363
+ public async prepareValuesForNodeAdd ( configTxtPath : string , applicationPropertiesPath : string ) {
355
364
const yamlRoot = { } ;
356
365
this . _setFileContentsAsValue ( 'hedera.configMaps.configTxt' , configTxtPath , yamlRoot ) ;
357
366
await this . bumpHederaConfigVersion ( applicationPropertiesPath ) ;
358
367
this . _setFileContentsAsValue ( 'hedera.configMaps.applicationProperties' , applicationPropertiesPath , yamlRoot ) ;
359
368
360
- // write the yaml
361
369
const cachedValuesFile = path . join ( this . cacheDir , 'solo-node-add.yaml' ) ;
362
- return new Promise < string > ( ( resolve , reject ) => {
363
- fs . writeFile ( cachedValuesFile , yaml . stringify ( yamlRoot ) , err => {
364
- if ( err ) {
365
- reject ( err ) ;
366
- }
370
+ return this . writeToYaml ( cachedValuesFile , yamlRoot ) ;
371
+ }
367
372
368
- resolve ( cachedValuesFile ) ;
369
- } ) ;
370
- } ) ;
373
+ public setValueForGenesisNetwork ( path : string ) {
374
+ const yamlRoot = { } ;
375
+
376
+ this . _setFileContentsAsValue ( 'hedera.configMaps.genesisNetworkJson' , path , yamlRoot ) ;
371
377
}
372
378
373
379
/**
374
380
* Prepare a values file for rpc-relay Helm chart
375
381
* @param profileName - resource profile name
376
382
* @returns return the full path to the values file
377
383
*/
378
- prepareValuesForRpcRelayChart ( profileName : string ) {
384
+ public async prepareValuesForRpcRelayChart ( profileName : string ) {
379
385
if ( ! profileName ) throw new MissingArgumentError ( 'profileName is required' ) ;
380
- const profile = this . getProfile ( profileName ) as any ;
386
+ const profile = this . getProfile ( profileName ) as AnyObject ;
381
387
if ( ! profile . rpcRelay ) return Promise . resolve ( ) ; // use chart defaults
382
388
383
389
// generate the YAML
384
390
const yamlRoot = { } ;
385
391
this . _setChartItems ( '' , profile . rpcRelay , yamlRoot ) ;
386
392
387
- // write the YAML
388
393
const cachedValuesFile = path . join ( this . cacheDir , `rpcRelay-${ profileName } .yaml` ) ;
389
- return new Promise < string > ( ( resolve , reject ) => {
390
- fs . writeFile ( cachedValuesFile , yaml . stringify ( yamlRoot ) , err => {
391
- if ( err ) {
392
- reject ( err ) ;
393
- }
394
-
395
- resolve ( cachedValuesFile ) ;
396
- } ) ;
397
- } ) ;
394
+ return this . writeToYaml ( cachedValuesFile , yamlRoot ) ;
398
395
}
399
396
400
- prepareValuesHederaExplorerChart ( profileName : string ) {
397
+ public async prepareValuesHederaExplorerChart ( profileName : string ) {
401
398
if ( ! profileName ) throw new MissingArgumentError ( 'profileName is required' ) ;
402
- const profile = this . getProfile ( profileName ) as any ;
399
+ const profile = this . getProfile ( profileName ) as AnyObject ;
403
400
// generate the YAML
404
401
const yamlRoot = { } ;
405
402
this . resourcesForHederaExplorerPod ( profile , yamlRoot ) ;
406
403
407
- // write the YAML
408
404
const cachedValuesFile = path . join ( this . cacheDir , `explorer-${ profileName } .yaml` ) ;
409
- return new Promise < string > ( ( resolve , reject ) => {
405
+ return this . writeToYaml ( cachedValuesFile , yamlRoot ) ;
406
+ }
407
+
408
+ /**
409
+ * Writes the YAML to file.
410
+ *
411
+ * @param cachedValuesFile - the target file to write the YAML root to.
412
+ * @param yamlRoot - object to turn into YAML and write to file.
413
+ */
414
+ private async writeToYaml ( cachedValuesFile : Path , yamlRoot : AnyObject ) {
415
+ return await new Promise < string > ( ( resolve , reject ) => {
410
416
fs . writeFile ( cachedValuesFile , yaml . stringify ( yamlRoot ) , err => {
411
417
if ( err ) {
412
418
reject ( err ) ;
@@ -422,9 +428,9 @@ export class ProfileManager {
422
428
* @param profileName - resource profile name
423
429
* @returns the full path to the values file
424
430
*/
425
- prepareValuesForMirrorNodeChart ( profileName : string ) {
431
+ public async prepareValuesForMirrorNodeChart ( profileName : string ) {
426
432
if ( ! profileName ) throw new MissingArgumentError ( 'profileName is required' ) ;
427
- const profile = this . getProfile ( profileName ) as any ;
433
+ const profile = this . getProfile ( profileName ) as AnyObject ;
428
434
if ( ! profile . mirror ) return Promise . resolve ( ) ; // use chart defaults
429
435
430
436
// generate the YAML
@@ -443,26 +449,17 @@ export class ProfileManager {
443
449
this . _setChartItems ( 'grpc' , profile . mirror . grpc , yamlRoot ) ;
444
450
this . _setChartItems ( 'monitor' , profile . mirror . monitor , yamlRoot ) ;
445
451
446
- // write the YAML
447
452
const cachedValuesFile = path . join ( this . cacheDir , `mirror-${ profileName } .yaml` ) ;
448
- return new Promise < string > ( ( resolve , reject ) => {
449
- fs . writeFile ( cachedValuesFile , yaml . stringify ( yamlRoot ) , err => {
450
- if ( err ) {
451
- reject ( err ) ;
452
- }
453
-
454
- resolve ( cachedValuesFile ) ;
455
- } ) ;
456
- } ) ;
453
+ return this . writeToYaml ( cachedValuesFile , yamlRoot ) ;
457
454
}
458
455
459
456
/**
460
- * Writes the contents of a file as a value for the given nested item path in the yaml object
461
- * @param itemPath - nested item path in the yaml object to store the file contents
462
- * @param valueFilePath - path to the file whose contents will be stored in the yaml object
463
- * @param yamlRoot - root of the yaml object
457
+ * Writes the contents of a file as a value for the given nested item path in the YAML object
458
+ * @param itemPath - nested item path in the YAML object to store the file contents
459
+ * @param valueFilePath - path to the file whose contents will be stored in the YAML object
460
+ * @param yamlRoot - root of the YAML object
464
461
*/
465
- private _setFileContentsAsValue ( itemPath : string , valueFilePath : string , yamlRoot : object ) {
462
+ private _setFileContentsAsValue ( itemPath : string , valueFilePath : string , yamlRoot : AnyObject ) {
466
463
const fileContents = fs . readFileSync ( valueFilePath , 'utf8' ) ;
467
464
this . _setValue ( itemPath , fileContents , yamlRoot ) ;
468
465
}
@@ -548,7 +545,7 @@ export class ProfileManager {
548
545
fs . writeFileSync ( configFilePath , configLines . join ( '\n' ) ) ;
549
546
550
547
return configFilePath ;
551
- } catch ( e : Error | any ) {
548
+ } catch ( e : Error | unknown ) {
552
549
throw new SoloError ( 'failed to generate config.txt' , e ) ;
553
550
}
554
551
}
0 commit comments