11
11
suffixDir = base : i : "${ base } ${ optionalString ( i != 0 ) "-${ toString i } " } " ;
12
12
nullOrStr = types . nullOr types . str ;
13
13
funcToOr = t : types . either t ( types . functionTo t ) ;
14
+
15
+ newTopology = i : {
16
+ localRoots = map ( g : {
17
+ accessPoints = map ( e : builtins . removeAttrs e [ "valency" ] ) g . accessPoints ;
18
+ advertise = g . advertise or false ;
19
+ valency = g . valency or ( length g . accessPoints ) ;
20
+ } ) ( cfg . producers ++ ( cfg . instanceProducers i ) ) ;
21
+ publicRoots = map ( g : {
22
+ accessPoints = map ( e : builtins . removeAttrs e [ "valency" ] ) g . accessPoints ;
23
+ advertise = g . advertise or false ;
24
+ } ) ( cfg . publicProducers ++ ( cfg . instancePublicProducers i ) ) ;
25
+ } // optionalAttrs ( cfg . usePeersFromLedgerAfterSlot != null ) {
26
+ useLedgerAfterSlot = cfg . usePeersFromLedgerAfterSlot ;
27
+ } ;
28
+
29
+ oldTopology = i : {
30
+ Producers = concatMap ( g : map ( a : {
31
+ addr = a . address ;
32
+ inherit ( a ) port ;
33
+ valency = a . valency or 1 ;
34
+ } ) g . accessPoints ) (
35
+ cfg . producers ++ ( cfg . instanceProducers i ) ++ cfg . publicProducers ++ ( cfg . instancePublicProducers i )
36
+ ) ;
37
+ } ;
38
+
39
+ selectTopology = i :
40
+ if cfg . topology != null
41
+ then cfg . topology
42
+ else toFile "topology.yaml" ( toJSON ( if ( cfg . useNewTopology ) then newTopology i else oldTopology i ) ) ;
43
+
44
+ topology = i :
45
+ if cfg . useSystemdReload
46
+ then "/etc/cardano-node/topology-${ toString i } .yaml"
47
+ else selectTopology i ;
48
+
14
49
mkScript = cfg :
15
50
let baseConfig =
16
51
recursiveUpdate
49
84
instanceConfig = recursiveUpdate ( baseInstanceConfig i ) ( cfg . extraNodeInstanceConfig i ) ;
50
85
nodeConfigFile = if ( cfg . nodeConfigFile != null ) then cfg . nodeConfigFile
51
86
else toFile "config-${ toString cfg . nodeId } -${ toString i } .json" ( toJSON instanceConfig ) ;
52
- newTopology = {
53
- localRoots = map ( g : {
54
- accessPoints = map ( e : builtins . removeAttrs e [ "valency" ] ) g . accessPoints ;
55
- advertise = g . advertise or false ;
56
- valency = g . valency or ( length g . accessPoints ) ;
57
- } ) ( cfg . producers ++ ( cfg . instanceProducers i ) ) ;
58
- publicRoots = map ( g : {
59
- accessPoints = map ( e : builtins . removeAttrs e [ "valency" ] ) g . accessPoints ;
60
- advertise = g . advertise or false ;
61
- } ) ( cfg . publicProducers ++ ( cfg . instancePublicProducers i ) ) ;
62
- } // optionalAttrs ( cfg . usePeersFromLedgerAfterSlot != null ) {
63
- useLedgerAfterSlot = cfg . usePeersFromLedgerAfterSlot ;
64
- } ;
65
- oldTopology = {
66
- Producers = concatMap ( g : map ( a : {
67
- addr = a . address ;
68
- inherit ( a ) port ;
69
- valency = a . valency or 1 ;
70
- } ) g . accessPoints ) (
71
- cfg . producers ++ ( cfg . instanceProducers i ) ++ cfg . publicProducers ++ ( cfg . instancePublicProducers i )
72
- ) ;
73
- } ;
74
- topology = if cfg . topology != null then cfg . topology else toFile "topology.yaml" ( toJSON (
75
- if ( cfg . useNewTopology ) then newTopology
76
- else oldTopology
77
- ) ) ;
78
87
consensusParams = {
79
88
RealPBFT = [
80
89
"${ lib . optionalString ( cfg . signingKey != null )
108
117
"${ cfg . executable } run"
109
118
"--config ${ nodeConfigFile } "
110
119
"--database-path ${ instanceDbPath } "
111
- "--topology ${ topology } "
120
+ "--topology ${ topology i } "
112
121
] ++ lib . optionals ( ! cfg . systemdSocketActivation ) ( [
113
122
"--host-addr ${ cfg . hostAddr } "
114
123
"--port ${ if ( cfg . shareIpv4port || cfg . shareIpv6port ) then toString cfg . port else toString ( cfg . port + i ) } "
143
152
(the blockchain protocols running cardano).
144
153
'' ;
145
154
} ;
155
+
146
156
instances = mkOption {
147
157
type = types . int ;
148
158
default = 1 ;
@@ -511,6 +521,21 @@ in {
511
521
'' ;
512
522
} ;
513
523
524
+ useSystemdReload = mkOption {
525
+ type = types . bool ;
526
+ default = false ;
527
+ description = ''
528
+ If set, systemd will reload cardano-node service units instead of restarting them
529
+ if only the topology file has changed and p2p is in use.
530
+
531
+ Cardano-node topology files will be stored in /etc as:
532
+ /etc/cardano-node/topology-'' ${toString i}.yaml
533
+
534
+ Enabling this option will also allow direct topology edits for tests when a full
535
+ service re-deployment is not desired.
536
+ '' ;
537
+ } ;
538
+
514
539
nodeConfig = mkOption {
515
540
type = types . attrs // {
516
541
merge = loc : foldl' ( res : def : recursiveUpdate res def . value ) { } ;
@@ -642,6 +667,10 @@ in {
642
667
isSystemUser = true ;
643
668
} ;
644
669
670
+ environment . etc = mkIf cfg . useSystemdReload ( foldl'
671
+ ( acc : i : recursiveUpdate acc { "cardano-node/topology-${ toString i } .yaml" . source = selectTopology i ; } ) { }
672
+ ( range 0 ( cfg . instances - 1 ) ) ) ;
673
+
645
674
## TODO: use http://hackage.haskell.org/package/systemd for:
646
675
## 1. only declaring success after we perform meaningful init (local state recovery)
647
676
## 2. heartbeat & watchdog functionality
@@ -655,10 +684,12 @@ in {
655
684
wants = [ "network-online.target" ] ;
656
685
wantedBy = [ "multi-user.target" ] ;
657
686
partOf = mkIf ( cfg . instances > 1 ) [ "cardano-node.service" ] ;
687
+ reloadTriggers = mkIf ( cfg . useSystemdReload && cfg . useNewTopology ) [ ( selectTopology i ) ] ;
658
688
script = mkScript cfg i ;
659
689
serviceConfig = {
660
690
User = "cardano-node" ;
661
691
Group = "cardano-node" ;
692
+ ExecReload = mkIf ( cfg . useSystemdReload && cfg . useNewTopology ) "${ pkgs . coreutils } /bin/kill -HUP $MAINPID" ;
662
693
Restart = "always" ;
663
694
RuntimeDirectory = lib . mkIf ( ! cfg . systemdSocketActivation )
664
695
( lib . removePrefix runDirBase ( runtimeDir i ) ) ;
0 commit comments