diff --git a/.github/workflows/check-mainnet-config.yml b/.github/workflows/check-mainnet-config.yml index 338a622c050..98b6bcdc037 100644 --- a/.github/workflows/check-mainnet-config.yml +++ b/.github/workflows/check-mainnet-config.yml @@ -42,7 +42,9 @@ jobs: 'mainnet-byron-genesis.json' 'mainnet-checkpoints.json' 'mainnet-config-bp.json' + 'mainnet-config-bp-legacy.json' 'mainnet-config.json' + 'mainnet-config-legacy.json' 'mainnet-peer-snapshot.json' 'mainnet-shelley-genesis.json' 'mainnet-topology.json' diff --git a/.github/workflows/release-ghcr.yaml b/.github/workflows/release-ghcr.yaml index 365e706b2ac..1ddd4690344 100644 --- a/.github/workflows/release-ghcr.yaml +++ b/.github/workflows/release-ghcr.yaml @@ -85,6 +85,16 @@ jobs: skopeo copy docker-archive:./result-api docker://ghcr.io/intersectmbo/cardano-submit-api:$GITHUB_REF_NAME echo "::endgroup::" + - name: Uploading intersectmbo/cardano-tracer + run: | + echo "::group::Downloading from cache" + nix build --accept-flake-config --print-out-paths --builders "" --max-jobs 0 --out-link ./result-tracer ${{ steps.flake-metadata.outputs.LOCKED_URL }}#dockerImage/tracer + echo "::endgroup::" + + echo "::group::Uploading to registry" + skopeo copy docker-archive:./result-tracer docker://ghcr.io/intersectmbo/cardano-tracer:$GITHUB_REF_NAME + echo "::endgroup::" + - name: Obtaining latest release tag id: latest-tag run: | @@ -110,3 +120,7 @@ jobs: echo "::group::Tagging latest for intersectmbo/cardano-submit-api" skopeo copy docker-archive:./result-api docker://ghcr.io/intersectmbo/cardano-submit-api:latest echo "::endgroup::" + + echo "::group::Tagging latest for intersectmbo/cardano-tracer" + skopeo copy docker-archive:./result-tracer docker://ghcr.io/intersectmbo/cardano-tracer:latest + echo "::endgroup::" diff --git a/Makefile b/Makefile index 7e7b31bc9d0..a2cb3546c6e 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ cli node: cabal --ghc-options="+RTS -qn8 -A32M -RTS" build cardano-$@ trace-documentation: - cabal run -- exe:cardano-node trace-documentation --config 'configuration/cardano/mainnet-config-new-tracing.yaml' --output-file 'doc/new-tracing/tracers_doc_generated.md' + cabal run -- exe:cardano-node trace-documentation --config 'configuration/cardano/mainnet-config.yaml' --output-file 'doc/new-tracing/tracers_doc_generated.md' ### ### Workbench @@ -83,7 +83,7 @@ $(eval $(call define_profile_targets, $(LOCAL_PROFILES))) $(eval $(call define_profile_targets_nomadcloud,$(CLOUD_PROFILES))) # Dynamic local/supervisor profile targets. -playground-%: +playground-%: nix-shell -A 'workbench-shell' --max-jobs 8 --cores 0 --show-trace --argstr profileName $*-${ERA} --argstr backendName supervisor ### diff --git a/cardano-node/test/Test/Cardano/Tracing/NewTracing/Consistency.hs b/cardano-node/test/Test/Cardano/Tracing/NewTracing/Consistency.hs index 7ff1d998edd..9ce11415100 100644 --- a/cardano-node/test/Test/Cardano/Tracing/NewTracing/Consistency.hs +++ b/cardano-node/test/Test/Cardano/Tracing/NewTracing/Consistency.hs @@ -25,7 +25,7 @@ tests = do [ ( [] -- This file name should reference the current standard config with new tracing , configSubdir - , "mainnet-config-new-tracing.json" + , "mainnet-config.json" ) , ( [] diff --git a/configuration/cardano/mainnet-config-bp-legacy.json b/configuration/cardano/mainnet-config-bp-legacy.json new file mode 100644 index 00000000000..c9ffc51d2fc --- /dev/null +++ b/configuration/cardano/mainnet-config-bp-legacy.json @@ -0,0 +1,117 @@ +{ + "AlonzoGenesisFile": "mainnet-alonzo-genesis.json", + "AlonzoGenesisHash": "7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874", + "ByronGenesisFile": "mainnet-byron-genesis.json", + "ByronGenesisHash": "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb", + "CheckpointsFile": "mainnet-checkpoints.json", + "CheckpointsFileHash": "3e6dee5bae7acc6d870187e72674b37c929be8c66e62a552cf6a876b1af31ade", + "ConsensusMode": "PraosMode", + "ConwayGenesisFile": "mainnet-conway-genesis.json", + "ConwayGenesisHash": "15a199f895e461ec0ffc6dd4e4028af28a492ab4e806d39cb674c88f7643ef62", + "EnableP2P": true, + "LastKnownBlockVersion-Alt": 0, + "LastKnownBlockVersion-Major": 3, + "LastKnownBlockVersion-Minor": 0, + "LedgerDB": { + "Backend": "V2InMemory", + "NumOfDiskSnapshots": 2, + "QueryBatchSize": 100000, + "SnapshotInterval": 4320 + }, + "MaxKnownMajorProtocolVersion": 2, + "MinNodeVersion": "10.4.0", + "PeerSharing": false, + "Protocol": "Cardano", + "RequiresNetworkMagic": "RequiresNoMagic", + "ShelleyGenesisFile": "mainnet-shelley-genesis.json", + "ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81", + "TargetNumberOfKnownPeers": 100, + "TargetNumberOfRootPeers": 100, + "TraceAcceptPolicy": true, + "TraceBlockFetchClient": false, + "TraceBlockFetchDecisions": false, + "TraceBlockFetchProtocol": false, + "TraceBlockFetchProtocolSerialised": false, + "TraceBlockFetchServer": false, + "TraceChainDb": true, + "TraceChainSyncBlockServer": false, + "TraceChainSyncClient": false, + "TraceChainSyncHeaderServer": false, + "TraceChainSyncProtocol": false, + "TraceConnectionManager": true, + "TraceDNSResolver": true, + "TraceDNSSubscription": true, + "TraceDiffusionInitialization": true, + "TraceErrorPolicy": true, + "TraceForge": true, + "TraceHandshake": true, + "TraceInboundGovernor": true, + "TraceIpSubscription": true, + "TraceLedgerPeers": true, + "TraceLocalChainSyncProtocol": false, + "TraceLocalConnectionManager": true, + "TraceLocalErrorPolicy": true, + "TraceLocalHandshake": true, + "TraceLocalRootPeers": true, + "TraceLocalTxSubmissionProtocol": false, + "TraceLocalTxSubmissionServer": false, + "TraceMempool": false, + "TraceMux": false, + "TracePeerSelection": true, + "TracePeerSelectionActions": true, + "TracePublicRootPeers": true, + "TraceServer": true, + "TraceTxInbound": false, + "TraceTxOutbound": false, + "TraceTxSubmissionProtocol": false, + "TracingVerbosity": "NormalVerbosity", + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + "UseTraceDispatcher": false, + "defaultBackends": [ + "KatipBK" + ], + "defaultScribes": [ + [ + "StdoutSK", + "stdout" + ] + ], + "hasEKG": 12788, + "hasPrometheus": [ + "127.0.0.1", + 12798 + ], + "minSeverity": "Info", + "options": { + "mapBackends": { + "cardano.node.metrics": [ + "EKGViewBK" + ], + "cardano.node.resources": [ + "EKGViewBK" + ] + }, + "mapSubtrace": { + "cardano.node.metrics": { + "subtrace": "Neutral" + } + } + }, + "rotation": { + "rpKeepFilesNum": 10, + "rpLogLimitBytes": 5000000, + "rpMaxAgeHours": 24 + }, + "setupBackends": [ + "KatipBK" + ], + "setupScribes": [ + { + "scFormat": "ScText", + "scKind": "StdoutSK", + "scName": "stdout", + "scRotation": null + } + ] +} diff --git a/configuration/cardano/mainnet-config-bp.json b/configuration/cardano/mainnet-config-bp.json index c9ffc51d2fc..dcbdcd1aff7 100644 --- a/configuration/cardano/mainnet-config-bp.json +++ b/configuration/cardano/mainnet-config-bp.json @@ -27,91 +27,120 @@ "ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81", "TargetNumberOfKnownPeers": 100, "TargetNumberOfRootPeers": 100, - "TraceAcceptPolicy": true, - "TraceBlockFetchClient": false, - "TraceBlockFetchDecisions": false, - "TraceBlockFetchProtocol": false, - "TraceBlockFetchProtocolSerialised": false, - "TraceBlockFetchServer": false, - "TraceChainDb": true, - "TraceChainSyncBlockServer": false, - "TraceChainSyncClient": false, - "TraceChainSyncHeaderServer": false, - "TraceChainSyncProtocol": false, - "TraceConnectionManager": true, - "TraceDNSResolver": true, - "TraceDNSSubscription": true, - "TraceDiffusionInitialization": true, - "TraceErrorPolicy": true, - "TraceForge": true, - "TraceHandshake": true, - "TraceInboundGovernor": true, - "TraceIpSubscription": true, - "TraceLedgerPeers": true, - "TraceLocalChainSyncProtocol": false, - "TraceLocalConnectionManager": true, - "TraceLocalErrorPolicy": true, - "TraceLocalHandshake": true, - "TraceLocalRootPeers": true, - "TraceLocalTxSubmissionProtocol": false, - "TraceLocalTxSubmissionServer": false, - "TraceMempool": false, - "TraceMux": false, - "TracePeerSelection": true, - "TracePeerSelectionActions": true, - "TracePublicRootPeers": true, - "TraceServer": true, - "TraceTxInbound": false, - "TraceTxOutbound": false, - "TraceTxSubmissionProtocol": false, - "TracingVerbosity": "NormalVerbosity", - "TurnOnLogMetrics": true, - "TurnOnLogging": true, - "UseTraceDispatcher": false, - "defaultBackends": [ - "KatipBK" - ], - "defaultScribes": [ - [ - "StdoutSK", - "stdout" - ] - ], - "hasEKG": 12788, - "hasPrometheus": [ - "127.0.0.1", - 12798 - ], - "minSeverity": "Info", - "options": { - "mapBackends": { - "cardano.node.metrics": [ - "EKGViewBK" + "TraceOptionForwarder": { + "connQueueSize": 64, + "disconnQueueSize": 128, + "maxReconnectDelay": 30 + }, + "TraceOptionMetricsPrefix": "cardano.node.metrics.", + "TraceOptionPeerFrequency": 2000, + "TraceOptionResourceFrequency": 1000, + "TraceOptions": { + "": { + "backends": [ + "EKGBackend", + "Forwarder", + "PrometheusSimple suffix 127.0.0.1 12798", + "Stdout HumanFormatColoured" ], - "cardano.node.resources": [ - "EKGViewBK" - ] - }, - "mapSubtrace": { - "cardano.node.metrics": { - "subtrace": "Neutral" - } + "detail": "DNormal", + "severity": "Notice" + }, + "BlockFetch.Client.CompletedBlockFetch": { + "maxFrequency": 2.0 + }, + "BlockFetch.Decision": { + "severity": "Silence" + }, + "ChainDB": { + "severity": "Info" + }, + "ChainDB.AddBlockEvent.AddBlockValidation": { + "severity": "Silence" + }, + "ChainDB.AddBlockEvent.AddBlockValidation.ValidCandidate": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToQueue": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToVolatileDB": { + "maxFrequency": 2.0 + }, + "ChainDB.CopyToImmutableDBEvent.CopiedBlockToImmutableDB": { + "maxFrequency": 2.0 + }, + "ChainDB.LedgerEvent.Forker": { + "severity": "Silence" + }, + "ChainSync.Client": { + "severity": "Warning" + }, + "Forge.Loop": { + "severity": "Info" + }, + "Forge.StateInfo": { + "severity": "Info" + }, + "Mempool": { + "severity": "Silence" + }, + "Mempool.AttemptAdd": { + "severity": "Silence" + }, + "Mempool.LedgerFound": { + "severity": "Silence" + }, + "Mempool.LedgerNotFound": { + "severity": "Silence" + }, + "Mempool.SyncNotNeeded": { + "severity": "Silence" + }, + "Net.ConnectionManager.Remote": { + "severity": "Info" + }, + "Net.ConnectionManager.Remote.ConnectionManagerCounters": { + "severity": "Silence" + }, + "Net.ErrorPolicy": { + "severity": "Info" + }, + "Net.ErrorPolicy.Local": { + "severity": "Info" + }, + "Net.InboundGovernor": { + "severity": "Warning" + }, + "Net.InboundGovernor.Remote": { + "severity": "Info" + }, + "Net.Mux.Remote": { + "severity": "Info" + }, + "Net.PeerSelection": { + "severity": "Silence" + }, + "Net.Subscription.DNS": { + "severity": "Info" + }, + "Net.Subscription.IP": { + "severity": "Info" + }, + "Resources": { + "severity": "Silence" + }, + "Startup.DiffusionInit": { + "severity": "Info" } }, - "rotation": { - "rpKeepFilesNum": 10, - "rpLogLimitBytes": 5000000, - "rpMaxAgeHours": 24 - }, - "setupBackends": [ - "KatipBK" - ], - "setupScribes": [ - { - "scFormat": "ScText", - "scKind": "StdoutSK", - "scName": "stdout", - "scRotation": null - } - ] + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + "UseTraceDispatcher": true, + "defaultBackends": [], + "defaultScribes": [], + "minSeverity": "Critical", + "options": {}, + "setupBackends": [], + "setupScribes": [] } diff --git a/configuration/cardano/mainnet-config-legacy.json b/configuration/cardano/mainnet-config-legacy.json new file mode 100644 index 00000000000..c863b9c07bc --- /dev/null +++ b/configuration/cardano/mainnet-config-legacy.json @@ -0,0 +1,115 @@ +{ + "AlonzoGenesisFile": "mainnet-alonzo-genesis.json", + "AlonzoGenesisHash": "7e94a15f55d1e82d10f09203fa1d40f8eede58fd8066542cf6566008068ed874", + "ByronGenesisFile": "mainnet-byron-genesis.json", + "ByronGenesisHash": "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb", + "CheckpointsFile": "mainnet-checkpoints.json", + "CheckpointsFileHash": "3e6dee5bae7acc6d870187e72674b37c929be8c66e62a552cf6a876b1af31ade", + "ConsensusMode": "PraosMode", + "ConwayGenesisFile": "mainnet-conway-genesis.json", + "ConwayGenesisHash": "15a199f895e461ec0ffc6dd4e4028af28a492ab4e806d39cb674c88f7643ef62", + "EnableP2P": true, + "LastKnownBlockVersion-Alt": 0, + "LastKnownBlockVersion-Major": 3, + "LastKnownBlockVersion-Minor": 0, + "LedgerDB": { + "Backend": "V2InMemory", + "NumOfDiskSnapshots": 2, + "QueryBatchSize": 100000, + "SnapshotInterval": 4320 + }, + "MaxKnownMajorProtocolVersion": 2, + "MinNodeVersion": "10.4.0", + "PeerSharing": true, + "Protocol": "Cardano", + "RequiresNetworkMagic": "RequiresNoMagic", + "ShelleyGenesisFile": "mainnet-shelley-genesis.json", + "ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81", + "TraceAcceptPolicy": true, + "TraceBlockFetchClient": false, + "TraceBlockFetchDecisions": false, + "TraceBlockFetchProtocol": false, + "TraceBlockFetchProtocolSerialised": false, + "TraceBlockFetchServer": false, + "TraceChainDb": true, + "TraceChainSyncBlockServer": false, + "TraceChainSyncClient": false, + "TraceChainSyncHeaderServer": false, + "TraceChainSyncProtocol": false, + "TraceConnectionManager": true, + "TraceDNSResolver": true, + "TraceDNSSubscription": true, + "TraceDiffusionInitialization": true, + "TraceErrorPolicy": true, + "TraceForge": true, + "TraceHandshake": true, + "TraceInboundGovernor": true, + "TraceIpSubscription": true, + "TraceLedgerPeers": true, + "TraceLocalChainSyncProtocol": false, + "TraceLocalConnectionManager": true, + "TraceLocalErrorPolicy": true, + "TraceLocalHandshake": true, + "TraceLocalRootPeers": true, + "TraceLocalTxSubmissionProtocol": false, + "TraceLocalTxSubmissionServer": false, + "TraceMempool": false, + "TraceMux": false, + "TracePeerSelection": true, + "TracePeerSelectionActions": true, + "TracePublicRootPeers": true, + "TraceServer": true, + "TraceTxInbound": false, + "TraceTxOutbound": false, + "TraceTxSubmissionProtocol": false, + "TracingVerbosity": "NormalVerbosity", + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + "UseTraceDispatcher": false, + "defaultBackends": [ + "KatipBK" + ], + "defaultScribes": [ + [ + "StdoutSK", + "stdout" + ] + ], + "hasEKG": 12788, + "hasPrometheus": [ + "127.0.0.1", + 12798 + ], + "minSeverity": "Info", + "options": { + "mapBackends": { + "cardano.node.metrics": [ + "EKGViewBK" + ], + "cardano.node.resources": [ + "EKGViewBK" + ] + }, + "mapSubtrace": { + "cardano.node.metrics": { + "subtrace": "Neutral" + } + } + }, + "rotation": { + "rpKeepFilesNum": 10, + "rpLogLimitBytes": 5000000, + "rpMaxAgeHours": 24 + }, + "setupBackends": [ + "KatipBK" + ], + "setupScribes": [ + { + "scFormat": "ScText", + "scKind": "StdoutSK", + "scName": "stdout", + "scRotation": null + } + ] +} diff --git a/configuration/cardano/mainnet-config.json b/configuration/cardano/mainnet-config.json index c863b9c07bc..eeb676748ab 100644 --- a/configuration/cardano/mainnet-config.json +++ b/configuration/cardano/mainnet-config.json @@ -25,91 +25,120 @@ "RequiresNetworkMagic": "RequiresNoMagic", "ShelleyGenesisFile": "mainnet-shelley-genesis.json", "ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81", - "TraceAcceptPolicy": true, - "TraceBlockFetchClient": false, - "TraceBlockFetchDecisions": false, - "TraceBlockFetchProtocol": false, - "TraceBlockFetchProtocolSerialised": false, - "TraceBlockFetchServer": false, - "TraceChainDb": true, - "TraceChainSyncBlockServer": false, - "TraceChainSyncClient": false, - "TraceChainSyncHeaderServer": false, - "TraceChainSyncProtocol": false, - "TraceConnectionManager": true, - "TraceDNSResolver": true, - "TraceDNSSubscription": true, - "TraceDiffusionInitialization": true, - "TraceErrorPolicy": true, - "TraceForge": true, - "TraceHandshake": true, - "TraceInboundGovernor": true, - "TraceIpSubscription": true, - "TraceLedgerPeers": true, - "TraceLocalChainSyncProtocol": false, - "TraceLocalConnectionManager": true, - "TraceLocalErrorPolicy": true, - "TraceLocalHandshake": true, - "TraceLocalRootPeers": true, - "TraceLocalTxSubmissionProtocol": false, - "TraceLocalTxSubmissionServer": false, - "TraceMempool": false, - "TraceMux": false, - "TracePeerSelection": true, - "TracePeerSelectionActions": true, - "TracePublicRootPeers": true, - "TraceServer": true, - "TraceTxInbound": false, - "TraceTxOutbound": false, - "TraceTxSubmissionProtocol": false, - "TracingVerbosity": "NormalVerbosity", - "TurnOnLogMetrics": true, - "TurnOnLogging": true, - "UseTraceDispatcher": false, - "defaultBackends": [ - "KatipBK" - ], - "defaultScribes": [ - [ - "StdoutSK", - "stdout" - ] - ], - "hasEKG": 12788, - "hasPrometheus": [ - "127.0.0.1", - 12798 - ], - "minSeverity": "Info", - "options": { - "mapBackends": { - "cardano.node.metrics": [ - "EKGViewBK" + "TraceOptionForwarder": { + "connQueueSize": 64, + "disconnQueueSize": 128, + "maxReconnectDelay": 30 + }, + "TraceOptionMetricsPrefix": "cardano.node.metrics.", + "TraceOptionPeerFrequency": 2000, + "TraceOptionResourceFrequency": 1000, + "TraceOptions": { + "": { + "backends": [ + "EKGBackend", + "Forwarder", + "PrometheusSimple suffix 127.0.0.1 12798", + "Stdout HumanFormatColoured" ], - "cardano.node.resources": [ - "EKGViewBK" - ] - }, - "mapSubtrace": { - "cardano.node.metrics": { - "subtrace": "Neutral" - } + "detail": "DNormal", + "severity": "Notice" + }, + "BlockFetch.Client.CompletedBlockFetch": { + "maxFrequency": 2.0 + }, + "BlockFetch.Decision": { + "severity": "Silence" + }, + "ChainDB": { + "severity": "Info" + }, + "ChainDB.AddBlockEvent.AddBlockValidation": { + "severity": "Silence" + }, + "ChainDB.AddBlockEvent.AddBlockValidation.ValidCandidate": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToQueue": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToVolatileDB": { + "maxFrequency": 2.0 + }, + "ChainDB.CopyToImmutableDBEvent.CopiedBlockToImmutableDB": { + "maxFrequency": 2.0 + }, + "ChainDB.LedgerEvent.Forker": { + "severity": "Silence" + }, + "ChainSync.Client": { + "severity": "Warning" + }, + "Forge.Loop": { + "severity": "Info" + }, + "Forge.StateInfo": { + "severity": "Info" + }, + "Mempool": { + "severity": "Silence" + }, + "Mempool.AttemptAdd": { + "severity": "Silence" + }, + "Mempool.LedgerFound": { + "severity": "Silence" + }, + "Mempool.LedgerNotFound": { + "severity": "Silence" + }, + "Mempool.SyncNotNeeded": { + "severity": "Silence" + }, + "Net.ConnectionManager.Remote": { + "severity": "Info" + }, + "Net.ConnectionManager.Remote.ConnectionManagerCounters": { + "severity": "Silence" + }, + "Net.ErrorPolicy": { + "severity": "Info" + }, + "Net.ErrorPolicy.Local": { + "severity": "Info" + }, + "Net.InboundGovernor": { + "severity": "Warning" + }, + "Net.InboundGovernor.Remote": { + "severity": "Info" + }, + "Net.Mux.Remote": { + "severity": "Info" + }, + "Net.PeerSelection": { + "severity": "Silence" + }, + "Net.Subscription.DNS": { + "severity": "Info" + }, + "Net.Subscription.IP": { + "severity": "Info" + }, + "Resources": { + "severity": "Silence" + }, + "Startup.DiffusionInit": { + "severity": "Info" } }, - "rotation": { - "rpKeepFilesNum": 10, - "rpLogLimitBytes": 5000000, - "rpMaxAgeHours": 24 - }, - "setupBackends": [ - "KatipBK" - ], - "setupScribes": [ - { - "scFormat": "ScText", - "scKind": "StdoutSK", - "scName": "stdout", - "scRotation": null - } - ] + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + "UseTraceDispatcher": true, + "defaultBackends": [], + "defaultScribes": [], + "minSeverity": "Critical", + "options": {}, + "setupBackends": [], + "setupScribes": [] } diff --git a/configuration/cardano/mainnet-config.yaml b/configuration/cardano/mainnet-config.yaml index c3e53a72c29..fbe47081c56 100644 --- a/configuration/cardano/mainnet-config.yaml +++ b/configuration/cardano/mainnet-config.yaml @@ -83,7 +83,6 @@ LedgerDB: # `V1LMDB`. Backend: V2InMemory - ##### Version Information ##### MinNodeVersion: 10.4.0 @@ -98,231 +97,185 @@ TurnOnLogging: True # be directed to the logs or monitoring backends. TurnOnLogMetrics: True -# Use legacy tracing -UseTraceDispatcher: False - -# Global logging severity filter. Messages must have at least this severity to -# pass. Typical values would be Warning, Notice, Info or Debug. -minSeverity: Info - -# Log items can be rendered with more or less verbose detail. -# Verbosity ranges from MinimalVerbosity, NormalVerbosity to MaximalVerbosity -TracingVerbosity: NormalVerbosity - -# The system supports a number of backends for logging and monitoring. -# This setting lists the backends that will be available to use in the -# configuration below. The logging backend is called Katip. -setupBackends: - - KatipBK - -# This specifies the default backends that trace output is sent to if it -# is not specifically configured to be sent to other backends. -defaultBackends: - - KatipBK - -# EKG is a simple metrics monitoring system. Uncomment the following to enable -# this backend and listen on the given local port and point your web browser to -# http://localhost:12788/ -hasEKG: 12788 - -# The Prometheus monitoring system exports EKG metrics. Uncomment the following -# to listen on the given port. Output is provided on -# http://localhost:12789/metrics -# hasPrometheus: -# - "127.0.0.1" -# - 12789 - -# To enable the legacy 'TraceForwarder' backend, uncomment the following setting. Log -# items are then forwarded based on an entry in 'mapBackends' to a separate -# process running a 'TraceAcceptor'. -# Example using UNIX pipes: -# traceForwardTo: -# tag: RemotePipe -# contents: "logs/pipe" -# -# Example using Windows named pipes: -# traceForwardTo: -# tag: RemotePipe -# contents: "\\\\.\\pipe\\acceptor" -# -# Example using network socket: -# traceForwardTo: -# tag: RemoteSocket -# contents: -# - "127.0.0.1" -# - "2997" - - -# For the Katip logging backend we must set up outputs (called scribes) -# The available types of scribe are: -# FileSK for files -# StdoutSK/StderrSK for stdout/stderr -# JournalSK for systemd's journal system -# DevNullSK ignores all output -# The scribe output format can be ScText or ScJson. Log rotation settings can -# be specified in the defaults below or overridden on a per-scribe basis here. -setupScribes: - - scKind: StdoutSK - scName: stdout - scFormat: ScText - scRotation: null - -# For the Katip logging backend this specifies the default scribes that trace -# output is sent to if it is not configured to be sent to other scribes. -defaultScribes: - - - StdoutSK - - stdout - -# The default file rotation settings for katip scribes, unless overridden -# in the setupScribes above for specific scribes. -rotation: - rpLogLimitBytes: 5000000 - rpKeepFilesNum: 10 - rpMaxAgeHours: 24 - -##### Coarse grained logging control ##### - -# Trace output from whole subsystems can be enabled/disabled using the following -# settings. This provides fairly coarse grained control, but it is relatively -# efficient at filtering out unwanted trace output. - -TraceAcceptPolicy: True - -# Trace BlockFetch client. -TraceBlockFetchClient: False - -# Trace BlockFetch decisions made by the BlockFetch client. -TraceBlockFetchDecisions: False - -# Trace BlockFetch protocol messages. -TraceBlockFetchProtocol: False - -# Serialised Trace BlockFetch protocol messages. -TraceBlockFetchProtocolSerialised: False - -# Trace BlockFetch server. -TraceBlockFetchServer: False - -# Trace BlockchainTime. -# TraceBlockchainTime: False - -# Verbose tracer of ChainDB -TraceChainDb: True - -# Trace ChainSync client. -TraceChainSyncClient: False - -# Trace ChainSync server (blocks). -TraceChainSyncBlockServer: False - -# Trace ChainSync server (headers). -TraceChainSyncHeaderServer: False - -# Trace ChainSync protocol messages. -TraceChainSyncProtocol: False - -TraceConnectionManager: True +# Use the modern tracing system instead of the legacy tracing system. +UseTraceDispatcher: True -# Trace DNS Resolver messages. -TraceDNSResolver: True +# Match the metrics prefix of the legacy tracing system to minimize breaking +# changes. +TraceOptionMetricsPrefix: "cardano.node.metrics." -# Trace DNS Subscription messages. -TraceDNSSubscription: True +# Optional node name. Defaults to hostname if left unset. Ideally this is +# set in downstream code where the node's name is known. +# TraceOptionNodeName: -TraceDiffusionInitialization: True +# The frequency of peer messages. +TraceOptionPeerFrequency: 2000 -# Trace error policy resolution. -TraceErrorPolicy: True +# The frequency of resource messages. +TraceOptionResourceFrequency: 1000 -# Trace local error policy resolution. -TraceLocalErrorPolicy: True - -# Trace block forging. -TraceForge: True - -# Trace Handshake protocol messages. -TraceHandshake: True - -# Trace IP Subscription messages. -TraceIpSubscription: True - -TraceLedgerPeers: True - -TraceLocalRootPeers: True - -TraceInboundGovernor: True - -TracePeerSelection: True - -TracePeerSelectionActions: True - -TracePublicRootPeers: True - -TraceServer: True - - -# Trace local ChainSync protocol messages. -TraceLocalChainSyncProtocol: False - -# Trace local connection manager messages. -TraceLocalConnectionManager: True - -# Trace local Handshake protocol messages. -TraceLocalHandshake: True - -# Trace local TxSubmission protocol messages. -TraceLocalTxSubmissionProtocol: False - -# Trace local TxSubmission server. -TraceLocalTxSubmissionServer: False - -# Trace mempool. -TraceMempool: False - -# Trace Mux Events. -TraceMux: False - -# Trace TxSubmission server (inbound transactions). -TraceTxInbound: False +# Queue size control: +# In case of a missing forwarding service consumer, trace messages will be +# buffered. This mitigates short forwarding interruptions, or delays at +# startup time. +# +# The queue capacity should thus correlate to the expected log lines per +# second given a particular tracing configuration to avoid unnecessarily +# increasing memory footprint. +# +# The maxReconnectDelay config option specifies the maximum delay in seconds +# between (re-)connection attempts of a forwarder. +TraceOptionForwarder: + connQueueSize: 64 + disconnQueueSize: 128 + maxReconnectDelay: 30 + +# Tracing options for node +TraceOptions: + # The default tracer configuration + '': + backends: + # None, any combination, or all of the following backends can be + # enabled, where `EKGBackend` forwards EKG resource status to + # cardano-tracer, `Forwarder` forwards message traces and + # `PrometheusSimple` serves cardano-node metrics directly from + # cardano-node and defaults to use of the same port as in the legacy + # tracing system. + - EKGBackend + - Forwarder + - PrometheusSimple suffix 127.0.0.1 12798 + + # Only one of the following can be enabled, which determines for format + # of node logging to stdout. + - Stdout HumanFormatColoured + # - Stdout HumanFormatUncoloured + # - Stdout MachineFormat + + # Each tracer can specify the level of details for printing messages. + # Options include `DMinimal`, `DNormal`, `DDetailed`, and `DMaximum`. If + # no implementation is given, `DNormal` is chosen. + detail: DNormal + + # The severity levels, ranging from the least severe (`Debug`) to the + # most severe (`Emergency`), provide a framework for ignoring messages + # with severity levels below a globally configured severity cutoff. + # + # The full list of severities are: + # `Debug`, `Info`, `Notice`, `Warning`, `Error`, `Critical`, `Alert` and + # `Emergency`. + # + # To enhance severity filtering, there is also the option of `Silence` + # which allows for the unconditional silencing of a specific trace, + # essentially representing the deactivation of tracers -- a semantic + # continuation of the functionality in the legacy system. + severity: Notice + + # The following tracer configurations are configured to closely match the + # default logging seen in the legacy cardano-node tracing system. + BlockFetch.Client.CompletedBlockFetch: + # A frequency limit for the number of messages per second may also be + # provided for any tracer. + maxFrequency: 2.0 + + BlockFetch.Decision: + severity: Silence + + ChainDB: + severity: Info + + ChainDB.AddBlockEvent.AddBlockValidation: + severity: Silence + + ChainDB.AddBlockEvent.AddBlockValidation.ValidCandidate: + maxFrequency: 2.0 + + ChainDB.AddBlockEvent.AddedBlockToQueue: + maxFrequency: 2.0 + + ChainDB.AddBlockEvent.AddedBlockToVolatileDB: + maxFrequency: 2.0 + + ChainDB.CopyToImmutableDBEvent.CopiedBlockToImmutableDB: + maxFrequency: 2.0 + + ChainSync.Client: + severity: Warning + + Forge.Loop: + severity: Info + + Forge.StateInfo: + severity: Info + + Mempool: + severity: Silence + + Net.ConnectionManager.Remote: + severity: Info + + Net.ConnectionManager.Remote.ConnectionManagerCounters: + severity: Silence + + Net.ErrorPolicy: + severity: Info + + Net.ErrorPolicy.Local: + severity: Info + + Net.InboundGovernor: + severity: Warning + + Net.InboundGovernor.Remote: + severity: Info + + Net.Mux.Remote: + severity: Info + + Net.PeerSelection: + severity: Silence + + Net.Subscription.DNS: + severity: Info + + Net.Subscription.IP: + severity: Info -# Trace TxSubmission client (outbound transactions). -TraceTxOutbound: False + Resources: + severity: Silence -# Trace TxSubmission protocol messages. -TraceTxSubmissionProtocol: False + Startup.DiffusionInit: + severity: Info -##### Fine grained logging control ##### + # The following messages are UTxO-HD specific. Silencing these tracers aims + # at having comparable log line rates in messages per second on both the + # UTxO-HD and earlier non-UTxO-HD nodes. The additional high granularity + # mempool silences are not redundant in the case that the top level Mempool + # severity is switched away from silence. + ChainDB.LedgerEvent.Forker: + severity: Silence -# It is also possible to have more fine grained control over filtering of -# trace output, and to match and route trace output to particular backends. -# This is less efficient than the coarse trace filters above but provides -# much more precise control. + Mempool.AttemptAdd: + severity: Silence -options: + Mempool.LedgerFound: + severity: Silence - # This routes metrics matching specific names to particular backends. - # This overrides the 'defaultBackends' listed above. And note that it is - # an override and not an extension so anything matched here will not - # go to the default backend, only to the explicitly listed backends. - mapBackends: - cardano.node.metrics: - - EKGViewBK + Mempool.LedgerNotFound: + severity: Silence - cardano.node.resources: - - EKGViewBK + Mempool.SyncNotNeeded: + severity: Silence - # # redirects traced values to a specific scribe which is identified by its - # # type and its name, separated by "::": - # mapScribes: - # cardano.node.metrics: - # - "FileSK::logs/mainnet.log" - mapSubtrace: - cardano.node.metrics: - subtrace: Neutral +# Required by the legacy tracing system, this key is still required for +# cardano-node to start. +minSeverity: Critical -hasPrometheus: - - 127.0.0.1 - - 12798 +# Required by some legacy tests which may otherwise fail to start. +defaultBackends: [] +defaultScribes: [] +options: {} +setupBackends: [] +setupScribes: [] # Set or unset the mempool capacity override in number of bytes. # diff --git a/configuration/cardano/testnet-template-config.json b/configuration/cardano/testnet-template-config.json index f5c1dcc7555..2ef1b3df5b4 100644 --- a/configuration/cardano/testnet-template-config.json +++ b/configuration/cardano/testnet-template-config.json @@ -1,10 +1,13 @@ { - "ByronGenesisFile": "byron-genesis.json", - "ShelleyGenesisFile": "shelley-genesis.json", "AlonzoGenesisFile": "alonzo-genesis.json", - "ConwayGenesisFile": "conway-genesis.json", "ApplicationName": "cardano-sl", "ApplicationVersion": 0, + "ByronGenesisFile": "byron-genesis.json", + "ConsensusMode": "PraosMode", + "ConwayGenesisFile": "conway-genesis.json", + "EnableP2P": true, + "ExperimentalHardForksEnabled": true, + "ExperimentalProtocolsEnabled": true, "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": 3, "LastKnownBlockVersion-Minor": 1, @@ -19,79 +22,125 @@ "PBftSignatureThreshold": 1.1, "Protocol": "Cardano", "RequiresNetworkMagic": "RequiresMagic", - "TestShelleyHardForkAtEpoch": 0, + "ShelleyGenesisFile": "shelley-genesis.json", "TestAllegraHardForkAtEpoch": 0, - "TestMaryHardForkAtEpoch": 0, "TestAlonzoHardForkAtEpoch": 0, - "EnableP2P": true, - "ExperimentalProtocolsEnabled": true, - "ExperimentalHardForksEnabled": true, - "TraceAcceptPolicy": true, - "TraceBlockFetchClient": false, - "TraceBlockFetchDecisions": false, - "TraceBlockFetchProtocol": false, - "TraceBlockFetchProtocolSerialised": false, - "TraceBlockFetchServer": false, - "TraceChainDb": true, - "TraceChainSyncBlockServer": false, - "TraceChainSyncClient": false, - "TraceChainSyncHeaderServer": false, - "TraceChainSyncProtocol": false, - "TraceConnectionManager": true, - "TraceDNSResolver": true, - "TraceDNSSubscription": true, - "TraceDiffusionInitialization": true, - "TraceErrorPolicy": true, - "TraceForge": true, - "TraceHandshake": false, - "TraceInboundGovernor": true, - "TraceIpSubscription": true, - "TraceLedgerPeers": true, - "TraceLocalChainSyncProtocol": false, - "TraceLocalErrorPolicy": true, - "TraceLocalHandshake": false, - "TraceLocalRootPeers": true, - "TraceLocalTxSubmissionProtocol": false, - "TraceLocalTxSubmissionServer": false, - "TraceMempool": false, - "TraceMux": false, - "TracePeerSelection": true, - "TracePeerSelectionActions": true, - "TracePublicRootPeers": true, - "TraceServer": true, - "TraceTxInbound": false, - "TraceTxOutbound": false, - "TraceTxSubmissionProtocol": false, - "TracingVerbosity": "NormalVerbosity", - "TurnOnLogMetrics": true, - "TurnOnLogging": true, - "defaultBackends": ["KatipBK"], - "defaultScribes": [["StdoutSK", "cardano"]], - "hasEKG": 12788, - "hasPrometheus": ["0.0.0.0", 12798], - "minSeverity": "Debug", - "options": { - "mapBackends": { - "cardano.node.metrics": ["EKGViewBK"], - "cardano.node.resources": ["EKGViewBK"] - }, - "mapSubtrace": { - "cardano.node.metrics": { - "subtrace": "Neutral" - } - } - }, - "rotation": { - "rpKeepFilesNum": 10, - "rpLogLimitBytes": 5000000, - "rpMaxAgeHours": 24 + "TestMaryHardForkAtEpoch": 0, + "TestShelleyHardForkAtEpoch": 0, + "TraceOptionForwarder": { + "connQueueSize": 64, + "disconnQueueSize": 128, + "maxReconnectDelay": 30 }, - "setupBackends": ["KatipBK"], - "setupScribes": [ - { - "scFormat": "ScText", - "scKind": "StdoutSK", - "scName": "cardano" + "TraceOptionMetricsPrefix": "cardano.node.metrics.", + "TraceOptionPeerFrequency": 2000, + "TraceOptionResourceFrequency": 1000, + "TraceOptions": { + "": { + "backends": [ + "EKGBackend", + "Forwarder", + "PrometheusSimple suffix 127.0.0.1 12798", + "Stdout HumanFormatColoured" + ], + "detail": "DNormal", + "severity": "Notice" + }, + "BlockFetch.Client.CompletedBlockFetch": { + "maxFrequency": 2.0 + }, + "BlockFetch.Decision": { + "severity": "Silence" + }, + "ChainDB": { + "severity": "Info" + }, + "ChainDB.AddBlockEvent.AddBlockValidation": { + "severity": "Silence" + }, + "ChainDB.AddBlockEvent.AddBlockValidation.ValidCandidate": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToQueue": { + "maxFrequency": 2.0 + }, + "ChainDB.AddBlockEvent.AddedBlockToVolatileDB": { + "maxFrequency": 2.0 + }, + "ChainDB.CopyToImmutableDBEvent.CopiedBlockToImmutableDB": { + "maxFrequency": 2.0 + }, + "ChainDB.LedgerEvent.Forker": { + "severity": "Silence" + }, + "ChainSync.Client": { + "severity": "Warning" + }, + "Forge.Loop": { + "severity": "Info" + }, + "Forge.StateInfo": { + "severity": "Info" + }, + "Mempool": { + "severity": "Info" + }, + "Mempool.AttemptAdd": { + "severity": "Silence" + }, + "Mempool.LedgerFound": { + "severity": "Silence" + }, + "Mempool.LedgerNotFound": { + "severity": "Silence" + }, + "Mempool.SyncNotNeeded": { + "severity": "Silence" + }, + "Net.ConnectionManager.Remote": { + "severity": "Info" + }, + "Net.ConnectionManager.Remote.ConnectionManagerCounters": { + "severity": "Silence" + }, + "Net.ErrorPolicy": { + "severity": "Info" + }, + "Net.ErrorPolicy.Local": { + "severity": "Info" + }, + "Net.InboundGovernor": { + "severity": "Warning" + }, + "Net.InboundGovernor.Remote": { + "severity": "Info" + }, + "Net.Mux.Remote": { + "severity": "Info" + }, + "Net.PeerSelection": { + "severity": "Silence" + }, + "Net.Subscription.DNS": { + "severity": "Info" + }, + "Net.Subscription.IP": { + "severity": "Info" + }, + "Resources": { + "severity": "Silence" + }, + "Startup.DiffusionInit": { + "severity": "Info" } - ] + }, + "TurnOnLogMetrics": true, + "TurnOnLogging": true, + "UseTraceDispatcher": true, + "defaultBackends": [], + "defaultScribes": [], + "minSeverity": "Critical", + "options": {}, + "setupBackends": [], + "setupScribes": [] } diff --git a/configuration/cardano/update-config-files.sh b/configuration/cardano/update-config-files.sh index a4eb94cc05a..1d56f6cbcd1 100755 --- a/configuration/cardano/update-config-files.sh +++ b/configuration/cardano/update-config-files.sh @@ -29,17 +29,16 @@ echo "################################" copyCfg "mainnet-alonzo-genesis.json" copyCfg "mainnet-byron-genesis.json" copyCfg "mainnet-checkpoints.json" -copyCfg "mainnet-config.json" copyCfg "mainnet-config-bp.json" +copyCfg "mainnet-config-bp-legacy.json" +copyCfg "mainnet-config.json" +copyCfg "mainnet-config-legacy.json" copyCfg "mainnet-conway-genesis.json" copyCfg "mainnet-peer-snapshot.json" copyCfg "mainnet-shelley-genesis.json" copyCfg "mainnet-topology.json" copyCfg "mainnet-topology.json" -# IohkNix new tracing config placeholder -# copyCfg "mainnet-config-new-tracing.json" - # Testnet-template copyTmplCfg "alonzo.json" copyTmplCfg "byron.json" diff --git a/flake.lock b/flake.lock index 1b85f081568..79eae66edee 100644 --- a/flake.lock +++ b/flake.lock @@ -621,11 +621,11 @@ "sodium": "sodium" }, "locked": { - "lastModified": 1750025513, - "narHash": "sha256-WUNoYIZvU9moc5ccwJcF22r+bUJXO5dWoRyLPs8bJic=", + "lastModified": 1751421193, + "narHash": "sha256-rklXDo12dfukaSqcEyiYbze3ffRtTl2/WAAQCWfkGiw=", "owner": "input-output-hk", "repo": "iohk-nix", - "rev": "f63aa2a49720526900fb5943db4123b5b8dcc534", + "rev": "64ca6f4c0c6db283e2ec457c775bce75173fb319", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e09ca02e2ab..3b90a57f2d5 100644 --- a/flake.nix +++ b/flake.nix @@ -232,6 +232,7 @@ in { "dockerImage/node" = pkgs.dockerImage; "dockerImage/submit-api" = pkgs.submitApiDockerImage; + "dockerImage/tracer" = pkgs.tracerDockerImage; # This is a very light profile, no caching and pinning needed. workbench-ci-test = workbenchTest { @@ -492,6 +493,14 @@ imports = [./nix/nixos/cardano-submit-api-service.nix]; services.cardano-submit-api.cardanoNodePackages = lib.mkDefault (mkCardanoNodePackages flake.project.${pkgs.system}); }; + cardano-tracer = { + pkgs, + lib, + ... + }: { + imports = [./nix/nixos/cardano-tracer-service.nix]; + services.cardano-tracer.cardanoNodePackages = lib.mkDefault (mkCardanoNodePackages flake.project.${pkgs.system}); + }; }; }; } diff --git a/nix/binary-release.nix b/nix/binary-release.nix index e48d46eab5a..35abcf20024 100644 --- a/nix/binary-release.nix +++ b/nix/binary-release.nix @@ -45,6 +45,20 @@ let (builtins.toJSON (env.nodeConfigBp // genesisAttrs)); + nodeConfigLegacy= pkgs.writeText + "config-legacy.json" + (builtins.toJSON + (env.nodeConfigLegacy // genesisAttrs)); + + nodeConfigBpLegacy= pkgs.writeText + "config-bp-legacy.json" + (builtins.toJSON + (env.nodeConfigBpLegacy // genesisAttrs)); + + tracerConfig = pkgs.writeText + "tracer-config.json" + (builtins.toJSON env.tracerConfig); + peerSnapshot = pkgs.writeText "peer-snapshot.json" (builtins.toJSON env.peerSnapshot); @@ -60,6 +74,9 @@ let mkdir -p "share/${name}" jq . < "${nodeConfig}" > share/${name}/config.json jq . < "${nodeConfigBp}" > share/${name}/config-bp.json + jq . < "${nodeConfigLegacy}" > share/${name}/config-legacy.json + jq . < "${nodeConfigBpLegacy}" > share/${name}/config-bp-legacy.json + jq . < "${tracerConfig}" > share/${name}/tracer-config.json jq . < "${peerSnapshot}" > share/${name}/peer-snapshot.json jq . < "${topologyConfig}" > share/${name}/topology.json cp -n --remove-destination -v \ diff --git a/nix/docker/README.md b/nix/docker/README.md index 50e77c7a9d8..81034b78d18 100644 --- a/nix/docker/README.md +++ b/nix/docker/README.md @@ -1,4 +1,4 @@ -# Building Node and Submit API Images +# Building Node, Submit API and Tracer Images To build and load the oci images into the Docker engine, the most basic commands are: ``` @@ -36,7 +36,8 @@ docker run \ ghcr.io/intersectmbo/cardano-node:dev ``` -A similar command can be run to look around the cardano-submit-api container. +Similar commands can be run to look around the cardano-submit-api and +cardano-tracer containers. # Cardano Node Image Operation @@ -61,8 +62,9 @@ To launch cardano-node with a custom configuration, "custom" mode, provide entrypoint args starting with `run` and: * Leave the `NETWORK` env variable unset * Optionally include additional cardano-node args to the entrypoint after `run` -* Optionally include environment variables interpreted by [nix/docker/context/bin/run-node](context/bin/run-node), - or `/usr/local/bin/run-node` in the container +* Optionally include environment variables interpreted by + [nix/docker/context/node/bin/run-node](context/node/bin/run-node), or + `/usr/local/bin/run-node` in the container For example, launch a custom cardano-node container using cardano-node args and a local configuration mapped into the container: @@ -81,19 +83,19 @@ files found at `/opt/cardano/config` and organized under a subdirectory of the network's name. For example, to utilize standard configs for preprod network, but modify the cardano-node listening port: ``` - docker run \ - -v preprod-data:/data \ - -e CARDANO_CONFIG="/opt/cardano/config/preprod/config.json" \ - -e CARDANO_TOPOLOGY="/opt/cardano/config/preprod/topology.json" \ - -e CARDANO_PORT="6001" \ - ghcr.io/intersectmbo/cardano-node:dev \ - run +docker run \ + -v preprod-data:/data \ + -e CARDANO_CONFIG="/opt/cardano/config/preprod/config.json" \ + -e CARDANO_TOPOLOGY="/opt/cardano/config/preprod/topology.json" \ + -e CARDANO_PORT="6001" \ + ghcr.io/intersectmbo/cardano-node:dev \ + run ``` In "custom" mode, default state directories include `/opt/cardano/{data,ipc,logs}`, with `/opt/cardano/data/db` being the default database state location. These state directories are symlinked to root in the container: -`/opt/cardano/{data,ipc,logs} -> /{data,ipc,logs}` for more consistency between modes. +`/opt/cardano/{data,ipc,logs} -> /{data,ipc,logs}` for consistency between modes. Standard network config files can be found under `/opt/cardano/config`. @@ -107,13 +109,13 @@ Optional env variables and cardano-node args which can be used in custom mode can also be used in this mode. Merge mode uses the same default state directories as custom mode. -An example: +An example where prometheus binding is set away from localhost while preserving other defaults: ``` docker run \ -v node-ipc:/ipc \ -v mainnet-data:/data \ -e NETWORK=mainnet \ - -e CARDANO_CONFIG_JSON_MERGE='{"MaxConcurrencyBulkSync": 2}' \ + -e CARDANO_CONFIG_JSON_MERGE='{"TraceOptions":{"":{"backends":["EKGBackend","Forwarder","PrometheusSimple suffix 0.0.0.0 12798","Stdout HumanFormatColoured"]}}}' \ -e CARDANO_TOPOLOGY_JSON_MERGE='{"useLedgerAfterSlot": 147000000}' \ ghcr.io/intersectmbo/cardano-node:dev ``` @@ -208,6 +210,27 @@ sudo tree /var/lib/docker/volumes/opt-cardano/_data ``` +## Legacy Tracing System +Cardano-node now defaults to using the new tracing system. The legacy tracing +system is deprecated and will be removed in a future node version. While still +available, the legacy tracing system can be used by following the example +above in "custom" mode whereby config is passed, and in this case, the config +passed is the legacy style configuration. + +Legacy default configuration files are also available within the image at paths: +`/opt/cardano/config/$NETWORK/config[-bp]-legacy.json` + +An example of legacy tracing system usage is: +``` +docker run \ + -v preprod-data:/data \ + -e CARDANO_CONFIG="/opt/cardano/config/preprod/config-legacy.json" \ + -e CARDANO_TOPOLOGY="/opt/cardano/config/preprod/topology.json" \ + ghcr.io/intersectmbo/cardano-node:dev \ + run +``` + + # Cardano Submit API Image Operation ## Scripts Mode To launch cardano-submit-api with pre-loaded configuration, "scripts" mode, @@ -250,6 +273,131 @@ both to align the default ipc socket state directory in both the cardano-node and cardano-submit-api images and to remain backwards compatible. +# Cardano Tracer Image Operation +## Scripts Mode +To launch cardano-tracer with pre-loaded configuration, "scripts" mode, +use the `NETWORK` env variable to declare an existing cardano network name. + +An example using a docker named volume to persist socket state to the host: +``` +docker run \ + -v node-ipc:/ipc \ + -e NETWORK=mainnet \ + ghcr.io/intersectmbo/cardano-tracer:dev +``` + +In "scripts" mode, default state directories include `/{ipc,logs}` and default +mode of operation is to accept socket connections from node, `AcceptAt`, at a +path of `/ipc/tracer.socket`. Both tracer socket connection modes of +`AcceptAt` and `ConnectTo` necessitate a shared volume mount between a node +container and a tracer container. See the [Cardano-node to Cardano-tracer +Socket Connection](#cardano-node-to-cardano-tracer-socket-connection) section +for more on making the required socket connections. + + +## Custom Mode +To launch cardano-tracer with a custom configuration, "custom" mode, provide +entrypoint args starting with `run` and: +* Leave the `NETWORK` env variable unset +* Optionally include additional cardano-tracer args to the entrypoint after `run` +* Optionally include environment variables interpreted by + [nix/docker/context/tracer/bin/run-tracer](context/tracer/bin/run-tracer), or + `/usr/local/bin/run-tracer` in the container + +For example, launch a custom cardano-tracer container using cardano-tracer args and +a local configuration mapped into the container: +``` +docker run \ + -v node-ipc:/ipc \ + -v "$PWD/config/tracer:/config" \ + ghcr.io/intersectmbo/cardano-tracer:dev \ + run \ + --config /config/mainnet/config.json +``` + +Custom mode may also leverage standard mainnet or testnet network tracer config +files found at `/opt/cardano/config` and organized under a subdirectory of the +network's name. For example, to utilize standard configs for preprod network, +but modify the cardano-tracer minimum log severity: +``` +docker run \ + -e CARDANO_CONFIG="/opt/cardano/config/preprod/tracer-config.json" \ + -e CARDANO_MIN_LOG_SEVERITY="Debug" \ + ghcr.io/intersectmbo/cardano-tracer:dev \ + run +``` + +In "custom" mode, default state directories include `/opt/cardano/{ipc,logs}`. +These state directories are symlinked to root in the container: +`/opt/cardano/{ipc,logs} -> /{ipc,logs}` for consistency between modes. +Standard network tracer config files can be found under `/opt/cardano/config`. + + +## Merge Mode +With the `NETWORK` env variable set and `CARDANO_CONFIG_JSON_MERGE` env +variable set and containing valid json, cardano-tracer will run with deep +merged base `NETWORK` tracer config and json merge config. + +Optional env variables and cardano-tracer args which can be used in custom mode +can also be used in this mode. Merge mode uses the same default state +directories as custom mode. + +An example which changes the prometheus binding address from a default of +localhost (`127.0.0.1`) to `0.0.0.0`: +``` +docker run \ + -v node-ipc:/ipc \ + -e NETWORK=mainnet \ + -e CARDANO_CONFIG_JSON_MERGE='{"hasPrometheus":{"epHost": "0.0.0.0"}}' \ + ghcr.io/intersectmbo/cardano-tracer:dev +``` + +Similar bind mounting, and host mounted network tracer config considerations +exist for the cardano-tracer image as also detailed above for the cardano-node +image. + + +## Cardano-node to Cardano-tracer Socket Connection +To establish a cardano-node container to cardano-tracer container socket +connection, in addition to a shared volume mount where such a socket can be +accessed by both containers, the cardano-node container will need to be started +with an extra argument. To include the extra argument, either custom mode or +merge mode for the node image will be required. + +An example for node to connect to a tracer socket, using custom mode to +append the extra cli arg: +``` +docker run \ + -v node-ipc:/ipc \ + -e CARDANO_CONFIG="/opt/cardano/config/mainnet/config.json" \ + -e CARDANO_TOPOLOGY="/opt/cardano/config/mainnet/topology.json" \ + ghcr.io/intersectmbo/cardano-node:dev \ + run \ + --tracer-socket-path-connect /ipc/tracer.socket + +docker run \ + -v node-ipc:/ipc \ + -e NETWORK=mainnet \ + ghcr.io/intersectmbo/cardano-tracer:dev +``` + +An example for node to use a socket to accept a tracer connection, using merge +mode to set the tracer node name and append the extra cli arg via env variable: +``` +docker run \ + -v node-ipc:/ipc \ + -e NETWORK=mainnet \ + -e CARDANO_TRACER_SOCKET_PATH_ACCEPT="/ipc/node-tracer.socket" \ + -e CARDANO_CONFIG_JSON_MERGE='{"TraceOptionNodeName":"node1"}' \ + ghcr.io/intersectmbo/cardano-node:dev + +docker run \ + -v node-ipc:/ipc \ + -e NETWORK=mainnet \ + -e CARDANO_CONFIG_JSON_MERGE='{"network":{"contents":["/ipc/node-tracer.socket"],"tag":"ConnectTo"}}' \ + ghcr.io/intersectmbo/cardano-tracer:dev +``` + # Manual Testing 1. Run -e NETWORK=mainnet and check graceful shutdown SIGINT with -it 2. Run -e NETWORK=mainnet and check graceful shutdown SIGTERM with --detach diff --git a/nix/docker/context/bin/entrypoint b/nix/docker/context/node/bin/entrypoint similarity index 100% rename from nix/docker/context/bin/entrypoint rename to nix/docker/context/node/bin/entrypoint diff --git a/nix/docker/context/bin/run-client b/nix/docker/context/node/bin/run-client similarity index 100% rename from nix/docker/context/bin/run-client rename to nix/docker/context/node/bin/run-client diff --git a/nix/docker/context/bin/run-node b/nix/docker/context/node/bin/run-node similarity index 80% rename from nix/docker/context/bin/run-node rename to nix/docker/context/node/bin/run-node index a89c2b97415..c666b8b1b04 100755 --- a/nix/docker/context/bin/run-node +++ b/nix/docker/context/node/bin/run-node @@ -1,7 +1,7 @@ #!/bin/env bash set -eo pipefail -echo "Running the cardano node ..." +echo "Running cardano node ..." [[ -n $DEBUG ]] && set -x @@ -61,6 +61,8 @@ printRunEnv () { echo "CARDANO_PORT=$CARDANO_PORT" echo "CARDANO_SOCKET_PATH=$CARDANO_SOCKET_PATH" echo "CARDANO_TOPOLOGY=$CARDANO_TOPOLOGY" + [[ -n $CARDANO_TRACER_SOCKET_PATH_ACCEPT ]] && echo "CARDANO_TRACER_SOCKET_PATH_ACCEPT=$CARDANO_TRACER_SOCKET_PATH_ACCEPT" + [[ -n $CARDANO_TRACER_SOCKET_PATH_CONNECT ]] && echo "CARDANO_TRACER_SOCKET_PATH_CONNECT=$CARDANO_TRACER_SOCKET_PATH_CONNECT" if [[ ${CARDANO_BLOCK_PRODUCER} == true ]]; then @@ -92,19 +94,31 @@ cat << EOF > /usr/local/bin/env #!/usr/bin/env bash # Docker run ENV vars -CARDANO_CONFIG="$CARDANO_CONFIG" -CARDANO_TOPOLOGY="$CARDANO_TOPOLOGY" +EOF + +if [[ -n $CARDANO_TRACER_SOCKET_PATH_ACCEPT ]]; then + echo "CARDANO_TRACER_SOCKET_PATH_ACCEPT=\"$CARDANO_TRACER_SOCKET_PATH_ACCEPT\"" \ + >> /usr/local/bin/env +fi + +if [[ -n $CARDANO_TRACER_SOCKET_PATH_CONNECT ]]; then + echo "CARDANO_TRACER_SOCKET_PATH_CONNECT=\"$CARDANO_TRACER_SOCKET_PATH_CONNECT\"" \ + >> /usr/local/bin/env +fi + +cat << EOF >> /usr/local/bin/env CARDANO_BIND_ADDR="$CARDANO_BIND_ADDR" -CARDANO_PORT=$CARDANO_PORT +CARDANO_BLOCK_PRODUCER=$CARDANO_BLOCK_PRODUCER +CARDANO_CONFIG="$CARDANO_CONFIG" CARDANO_DATABASE_PATH="$CARDANO_DATABASE_PATH" -CARDANO_SOCKET_PATH="$CARDANO_SOCKET_PATH" CARDANO_LOG_DIR="$CARDANO_LOG_DIR" +CARDANO_PORT=$CARDANO_PORT +CARDANO_SOCKET_PATH="$CARDANO_SOCKET_PATH" +CARDANO_TOPOLOGY="$CARDANO_TOPOLOGY" CARDANO_PUBLIC_IP="$CARDANO_PUBLIC_IP" CARDANO_CUSTOM_PEERS="$CARDANO_CUSTOM_PEERS" -CARDANO_BLOCK_PRODUCER=$CARDANO_BLOCK_PRODUCER - # Mapping for topologyUpdater CNODE_HOSTNAME="$CARDANO_PUBLIC_IP" CNODE_PORT=$CARDANO_PORT @@ -135,6 +149,9 @@ runRelayNode () { "--port" "$CARDANO_PORT" ) + [[ -n $CARDANO_TRACER_SOCKET_PATH_ACCEPT ]] && effopts+=("--tracer-socket-path-accept" "$CARDANO_TRACER_SOCKET_PATH_ACCEPT") + [[ -n $CARDANO_TRACER_SOCKET_PATH_CONNECT ]] && effopts+=("--tracer-socket-path-connect" "$CARDANO_TRACER_SOCKET_PATH_CONNECT") + effopts+=("${filteredOpts[@]}") echo "cardano-node run ${effopts[*]}" @@ -159,6 +176,9 @@ runBlockProducerNode () { "--shelley-operational-certificate" "$CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE" ) + [[ -n $CARDANO_TRACER_SOCKET_PATH_ACCEPT ]] && effopts+=("--tracer-socket-path-accept" "$CARDANO_TRACER_SOCKET_PATH_ACCEPT") + [[ -n $CARDANO_TRACER_SOCKET_PATH_CONNECT ]] && effopts+=("--tracer-socket-path-connect" "$CARDANO_TRACER_SOCKET_PATH_CONNECT") + effopts+=("${filteredOpts[@]}") echo "cardano-node run ${effopts[*]}" @@ -169,7 +189,6 @@ runBlockProducerNode () { shift # Override default values with explicit options - options=("$@") for i in "${!options[@]}" @@ -191,6 +210,8 @@ do --shelley-kes-key) CARDANO_SHELLEY_KES_KEY=${val}; found=true;; --shelley-vrf-key) CARDANO_SHELLEY_VRF_KEY=${val}; found=true;; --shelley-operational-certificate) CARDANO_SHELLEY_OPERATIONAL_CERTIFICATE=${val}; found=true;; + --tracer-socket-path-accept) CARDANO_TRACER_SOCKET_PATH_ACCEPT=${val}; found=true;; + --tracer-socket-path-connect) CARDANO_TRACER_SOCKET_PATH_CONNECT=${val}; found=true;; esac if [[ $found == true ]]; then @@ -200,7 +221,10 @@ do done # Filter blank args from match removal above -filteredOpts=(); for arg in "${options[@]}"; do [[ $arg ]] && filteredOpts+=("$arg"); done +filteredOpts=() +for arg in "${options[@]}"; do + [[ -n $arg ]] && filteredOpts+=("$arg") +done printRunEnv writeRootEnv diff --git a/nix/docker/context/tracer/bin/entrypoint b/nix/docker/context/tracer/bin/entrypoint new file mode 100755 index 00000000000..ec2a752d1b4 --- /dev/null +++ b/nix/docker/context/tracer/bin/entrypoint @@ -0,0 +1,85 @@ +#!/bin/env bash + +[[ -n $DEBUG ]] && set -x + +# If the NETWORK env var is set to a valid cardano network, pre-defined +# configuration will be used. +if [[ -n $NETWORK ]]; then + + # If CARDANO_CONFIG_JSON_MERGE env var is set, iohk-nix + # pre-defined NETWORK configuration will be used as a starting point and + # merged with custom configuration provided as json in the environment + # variable(s). + if [[ -n $CARDANO_CONFIG_JSON_MERGE ]]; then + + CFG="/opt/cardano/config" + if ! [[ -f $CFG/$NETWORK/tracer-config.json ]]; then + echo "Network \"$NETWORK\" doesn't appear to have expected base configuration available at:" + echo " $CFG/$NETWORK/tracer-config.json" + echo + echo "Please check that the NETWORK environment variable is set to a valid cardano network name." + exit 1 + fi + + # Do a recursive deep merge of iohk-nix NETWORK config with the supplied + # json merge environment variable(s). + # + # In a jq deep merge, arrays are replaced, primitive values in the second + # object override the first, different types for the same key result in + # full replacement and null values persist. + if [[ -n $CARDANO_CONFIG_JSON_MERGE ]]; then + jq -S \ + --argjson deepMerge "$CARDANO_CONFIG_JSON_MERGE" \ + '. * $deepMerge' \ + < "$CFG/$NETWORK/tracer-config.json" \ + > "$CFG/$NETWORK/tracer-config-merged.json" + export CARDANO_CONFIG="$CFG/$NETWORK/tracer-config-merged.json" + else + export CARDANO_CONFIG="$CFG/$NETWORK/tracer-config.json" + fi + + if [[ -n $DEBUG ]]; then + echo "Cardano config in merge mode is:" + cat "$CARDANO_CONFIG" + echo + fi + + # Run cardano-tracer using iohk-nix base config merged with provided custom + # config for the requested NETWORK. + unset NETWORK + if [[ $1 == "run" ]]; then + exec /usr/local/bin/run-tracer "$@" + else + exec /usr/local/bin/run-tracer run "$@" + fi + + else + # Run cardano-tracer using "scripts" mode for the requested NETWORK. + exec /usr/local/bin/run-network "$@" + fi + +elif [[ $1 == "run" ]]; then + # Run cardano-tracer using "custom" mode. + exec /usr/local/bin/run-tracer "$@" + +else + + echo "Nothing to do! Available modes of operation are:" + echo + echo "Scripts mode:" + echo " * Set the NETWORK env var to a valid cardano network, such as mainnet to use default network config." + echo + echo "Custom mode:" + echo " * Leave the NETWORK env var unset and provide entrypoint args starting with \"run\" and:" + echo " * Optionally set environment variables interpreted by /usr/local/bin/run-tracer." + echo " * Optionally include additional cardano-tracer args to the entrypoint after \"run\"." + echo + echo "Merge mode:" + echo " * Set the NETWORK env var to a valid cardano network, such as mainnet, and" + echo " set the CARDANO_CONFIG_JSON_MERGE env var with valid json to run cardano-tracer" + echo " with deep merged base NETWORK and custom config." + echo " * The extra environment variables and cardano-tracer args that can be used in custom mode" + echo " are also available in merge mode." + exit 1 + +fi diff --git a/nix/docker/context/tracer/bin/run-tracer b/nix/docker/context/tracer/bin/run-tracer new file mode 100755 index 00000000000..f14a27f6e3a --- /dev/null +++ b/nix/docker/context/tracer/bin/run-tracer @@ -0,0 +1,96 @@ +#!/bin/env bash +set -eo pipefail + +echo "Running cardano tracer ..." + +[[ -n $DEBUG ]] && set -x + +# Define a few defaults +CARDANO_CONFIG_BASE="/opt/cardano/config" + +if [[ -z $CARDANO_CONFIG ]]; then + CARDANO_CONFIG="$CARDANO_CONFIG_BASE/mainnet/tracer-config.json" +fi + +##################################################################### +# +# Print run environment +# +printRunEnv () { + + echo "CARDANO_CONFIG=$CARDANO_CONFIG" + echo "CARDANO_MIN_LOG_SEVERITY=$CARDANO_MIN_LOG_SEVERITY" + echo "CARDANO_STATE_DIR=$CARDANO_STATE_DIR" +} + +##################################################################### +# +# Write root env file +# +writeRootEnv () { + +cat << EOF > /usr/local/bin/env +#!/usr/bin/env bash + +# Docker run ENV vars +CARDANO_CONFIG="$CARDANO_CONFIG" +CARDANO_MIN_LOG_SEVERITY="$CARDANO_MIN_LOG_SEVERITY" +CARDANO_STATE_DIR="$CARDANO_STATE_DIR" +EOF +} + +##################################################################### +# +# Run the relay node in the background +# +runTracer () { + + effopts=( + "--config" "$CARDANO_CONFIG" + "--state-dir" "$CARDANO_STATE_DIR" + ) + + effopts+=("${filteredOpts[@]}") + + echo "cardano-tracer ${effopts[*]}" + exec /usr/local/bin/cardano-tracer "${effopts[@]}" +} + +# Shift the first option by one index +shift + +# Override default values with explicit options + +options=("$@") + +for i in "${!options[@]}" +do + j=$((i + 1)) + key=${options[i]} + val=${options[j]} + found=false + + # echo "$i/$j: ${key} ${val}" + + case ${key} in + --config) CARDANO_CONFIG=${val}; found=true;; + --state-dir) CARDANO_STATE_DIR=${val}; found=true;; + --min-log-severity) CARDANO_MIN_LOG_SEVERITY=${val}; found=true;; + esac + + if [[ $found == true ]]; then + options[i]=""; + options[j]=""; + fi +done + +# Filter blank args from match removal above +filteredOpts=() +for arg in "${options[@]}"; do + [[ -n $arg ]] && filteredOpts+=("$arg") +done + +printRunEnv +writeRootEnv + +runTracer diff --git a/nix/docker/default.nix b/nix/docker/default.nix index 025dc47d4bb..345a83571d0 100644 --- a/nix/docker/default.nix +++ b/nix/docker/default.nix @@ -93,7 +93,7 @@ let ''; # The docker context with static content - context = ./context; + context = ./context/node; genCfgs = let environments' = lib.getAttrs [ "mainnet" "preprod" "preview" ] commonLib.environments; @@ -113,7 +113,7 @@ let done # Adjust genesis file, config and config-bp refs - for i in config config-bp db-sync-config; do + for i in config config-bp config-legacy config-bp-legacy db-sync-config; do if [ -f "$out/config/$ENV/$i.json" ]; then sed -i "s|\"$ENV-|\"|g" "$out/config/$ENV/$i.json" fi diff --git a/nix/docker/submit-api.nix b/nix/docker/submit-api.nix index 90195f02351..39b3ce7c627 100644 --- a/nix/docker/submit-api.nix +++ b/nix/docker/submit-api.nix @@ -82,7 +82,7 @@ let exec ${pkgs.${exe}}/bin/${exe} $@ ${clusterStatements} else - echo "Managed configuration for network "$NETWORK" does not exist" + echo "[Error] Managed configuration for network "$NETWORK" does not exist" fi ''; diff --git a/nix/docker/tracer.nix b/nix/docker/tracer.nix new file mode 100644 index 00000000000..db18fb0731f --- /dev/null +++ b/nix/docker/tracer.nix @@ -0,0 +1,172 @@ +############################################################################ +# Docker image builder for cardano-tracer +# +# To build and load into the Docker engine: +# +# nix build .#dockerImage/tracer +# docker load -i result +# +# Include `-L` in the nix build command args to see build logs. +# +# See the nix/docker/README.md file for details on modes of operation. +############################################################################ + +{ pkgs +, commonLib +, dockerTools + +# The main contents of the image. +, cardano-tracer +, scripts + +# Set gitrev to null, to ensure the version below is used +, gitrev ? null + +# Other things to include in the image. +, bashInteractive +, cacert +, coreutils +, curl +, glibcLocales +, iana-etc +, iproute2 +, iputils +, jq +, socat +, utillinux +, lib +, exe +, script +, repoName ? "ghcr.io/intersectmbo/${exe}" +}: + +let + + # Layer of tools which aren't going to change much between versions. + baseImage = dockerTools.buildImage { + name = "${repoName}-env"; + copyToRoot = pkgs.buildEnv { + name = "image-root"; + pathsToLink = ["/"]; + paths = [ + cardano-tracer # Provide cardano-tracer capability + bashInteractive # Provide the BASH shell + cacert # X.509 certificates of public CA's + coreutils # Basic utilities expected in GNU OS's + curl # CLI tool for transferring files via URLs + glibcLocales # Locale information for the GNU C Library + iana-etc # IANA protocol and port number assignments + iproute2 # Utilities for controlling TCP/IP networking + iputils # Useful utilities for Linux networking + jq # Lightweight and flexible command-line JSON processor + socat # Utility for bidirectional data transfer + utillinux # System utilities for Linux + ]; + }; + + # Set up /tmp (override with TMPDIR variable) + extraCommands = '' + mkdir -m 0777 tmp + ''; + }; + + # For "script" mode, generate scripts for iohk-nix networks which can be + # utilized by setting the environment NETWORK variable to the desired + # network in the docker command: `-e NETWORK ` + clusterStatements = lib.concatStringsSep "\n" (lib.mapAttrsToList (env: scripts: let + scriptBin = scripts.${script}; + in '' + elif [[ "$NETWORK" == "${env}" ]]; then + exec ${scriptBin}/bin/${scriptBin.name} $@ + '') scripts); + + runNetwork = pkgs.writeShellScriptBin "run-network" '' + if [[ -z "$NETWORK" ]]; then + echo "[Error] Cannot obtain NETWORK env variable" + exit 1 + ${clusterStatements} + else + echo "[Error] Managed configuration for network "$NETWORK" does not exist" + exit 1 + fi + ''; + + # The docker context with static content + context = ./context/tracer; + + genCfgs = let + environments' = lib.getAttrs [ "mainnet" "preprod" "preview" ] commonLib.environments; + cardano-deployment = commonLib.mkConfigHtml environments'; + in + pkgs.runCommand "cardano-html" {} '' + mkdir "$out" + + ENVS=(${lib.escapeShellArgs (builtins.attrNames environments')}) + for ENV in "''${ENVS[@]}"; do + # Migrate each env from a flat dir to an ENV subdir + mkdir -p "$out/config/$ENV" + for i in $(find ${cardano-deployment} -type f -name "$ENV-tracer-config*" -printf "%f\n"); do + cp -v "${cardano-deployment}/$i" "$out/config/$ENV/''${i#"$ENV-"}" + + # Adjust from iohk-nix default config for the oci environment + sed -i -r \ + -e 's|"contents": ".*"|"contents": "/ipc/tracer.socket"|g' \ + -e 's|"logRoot": ".*"|"logRoot": "/logs"|g' \ + "$out/config/$ENV/''${i#"$ENV-"}" + done + done + ''; + +in + dockerTools.buildImage { + name = "${repoName}"; + tag = "${gitrev}"; + fromImage = baseImage; + + # Set creation date to build time. Breaks reproducibility. + created = "now"; + + extraCommands = '' + # The "scripts" operation mode of this image, when the NETWORK env var is + # set to a valid network, will use the following default directories + # mounted at /: + mkdir -p ipc + + # Similarly, make a root level dir for logs: + mkdir -p logs + + # The "custom" operation mode of this image, when the NETWORK env is + # unset and "run" is provided as an entrypoint arg, will use the + # following default directories. To reduce confusion caused by default + # directory paths varying by mode, symlink these directories to the + # "scripts" mode default directories at the root location. This will + # permit use of volume mounts at the root directory location regardless + # of which mode the image is operating in. + mkdir -p opt/cardano + ln -sv /ipc opt/cardano/ipc + ln -sv /logs opt/cardano/logs + + # Setup bins + mkdir -p usr/local/bin + cp -v ${runNetwork}/bin/* usr/local/bin + cp -v ${context}/bin/* usr/local/bin + ln -sv ${cardano-tracer}/bin/cardano-tracer usr/local/bin/cardano-tracer + ln -sv ${jq}/bin/jq usr/local/bin/jq + + # Create iohk-nix network configs, organized by network directory. + SRC="${genCfgs}" + DST="opt/cardano" + + # Make the directory structure with the iohk-nix configs mutable. This + # enables creation of merge mode entrypoint configs in the respective + # NETWORK directory. Keep config files as read-only copies from the nix + # store instead of direct symlinks. This avoids volume mount failures + # caused by broken symlinks as seen from the host. + cp -R "$SRC"/* "$DST" + find "$DST" -mindepth 1 -type d -exec bash -c "chmod 0755 {}" \; + ''; + + config = { + EntryPoint = [ "entrypoint" ]; + }; + } diff --git a/nix/haskell.nix b/nix/haskell.nix index 1e801a4c11c..7e35c2a21d6 100644 --- a/nix/haskell.nix +++ b/nix/haskell.nix @@ -123,7 +123,6 @@ let modules = [ ({ lib, pkgs, ... }: { - packages.cardano-tracer.package.buildable = with pkgs.stdenv.hostPlatform; lib.mkForce (!isMusl); packages.cardano-node-chairman.components.tests.chairman-tests.buildable = lib.mkForce pkgs.stdenv.hostPlatform.isUnix; package-keys = ["plutus-tx-plugin"]; packages.plutus-tx-plugin.components.library.platforms = with lib.platforms; [ linux darwin ]; @@ -201,7 +200,7 @@ let mainnetConfigFiles = [ "configuration/cardano/mainnet-config.yaml" "configuration/cardano/mainnet-config.json" - "configuration/cardano/mainnet-config-new-tracing.json" + "configuration/cardano/mainnet-config-legacy.json" "configuration/cardano/mainnet-byron-genesis.json" "configuration/cardano/mainnet-shelley-genesis.json" "configuration/cardano/mainnet-alonzo-genesis.json" diff --git a/nix/nixos/cardano-node-service.nix b/nix/nixos/cardano-node-service.nix index c9d9759e509..d0c4fde19ac 100644 --- a/nix/nixos/cardano-node-service.nix +++ b/nix/nixos/cardano-node-service.nix @@ -5,27 +5,29 @@ with lib; with builtins; let + inherit (types) attrs attrsOf bool either enum functionTo int listOf package nullOr str; + cfg = config.services.cardano-node; envConfig = cfg.environments.${cfg.environment}; - runtimeDir = i : if cfg.runtimeDir i == null then cfg.stateDir i else "${cfg.runDirBase}${lib.removePrefix cfg.runDirBase (cfg.runtimeDir i)}"; + runtimeDir = i : if cfg.runtimeDir i == null then cfg.stateDir i else "${cfg.runDirBase}${removePrefix cfg.runDirBase (cfg.runtimeDir i)}"; suffixDir = base: i: "${base}${optionalString (i != 0) "-${toString i}"}"; - nullOrStr = types.nullOr types.str; - funcToOr = t: types.either t (types.functionTo t); + nullOrStr = nullOr str; + funcToOr = t: either t (functionTo t); newTopology = i: { localRoots = map (g: { - accessPoints = map (e: builtins.removeAttrs e ["valency"]) g.accessPoints; + accessPoints = map (e: removeAttrs e ["valency"]) g.accessPoints; advertise = g.advertise or false; valency = g.valency or (length g.accessPoints); trustable = g.trustable or false; }) (cfg.producers ++ (cfg.instanceProducers i)); publicRoots = map (g: { - accessPoints = map (e: builtins.removeAttrs e ["valency"]) g.accessPoints; + accessPoints = map (e: removeAttrs e ["valency"]) g.accessPoints; advertise = g.advertise or false; }) (cfg.publicProducers ++ (cfg.instancePublicProducers i)); bootstrapPeers = cfg.bootstrapPeers; - } // optionalAttrs (cfg.usePeersFromLedgerAfterSlot != null) { - useLedgerAfterSlot = cfg.usePeersFromLedgerAfterSlot; + } // optionalAttrs (cfg.useLedgerAfterSlot != null) { + useLedgerAfterSlot = cfg.useLedgerAfterSlot; } // optionalAttrs (cfg.peerSnapshotFile i != null) { peerSnapshotFile = cfg.peerSnapshotFile i; }; @@ -56,11 +58,11 @@ let selectTopology = i: if cfg.topology != null then cfg.topology - else toFile "topology.yaml" (toJSON (if (cfg.useNewTopology) then assertNewTopology i else oldTopology i)); + else toFile "topology.json" (toJSON (if (cfg.useNewTopology) then assertNewTopology i else oldTopology i)); topology = i: if cfg.useSystemdReload - then "/etc/cardano-node/topology-${toString i}.yaml" + then "/etc/cardano-node/topology-${toString i}.json" else selectTopology i; mkScript = cfg: @@ -120,54 +122,54 @@ let else toFile "config-${toString cfg.nodeId}-${toString i}.json" (toJSON instanceConfig); consensusParams = { RealPBFT = [ - "${lib.optionalString (cfg.signingKey != null) + "${optionalString (cfg.signingKey != null) "--signing-key ${cfg.signingKey}"}" - "${lib.optionalString (cfg.delegationCertificate != null) + "${optionalString (cfg.delegationCertificate != null) "--delegation-certificate ${cfg.delegationCertificate}"}" ]; TPraos = [ - "${lib.optionalString (cfg.vrfKey != null) + "${optionalString (cfg.vrfKey != null) "--shelley-vrf-key ${cfg.vrfKey}"}" - "${lib.optionalString (cfg.kesKey != null) + "${optionalString (cfg.kesKey != null) "--shelley-kes-key ${cfg.kesKey}"}" - "${lib.optionalString (cfg.operationalCertificate != null) + "${optionalString (cfg.operationalCertificate != null) "--shelley-operational-certificate ${cfg.operationalCertificate}"}" ]; Cardano = [ - "${lib.optionalString (cfg.signingKey != null) + "${optionalString (cfg.signingKey != null) "--signing-key ${cfg.signingKey}"}" - "${lib.optionalString (cfg.delegationCertificate != null) + "${optionalString (cfg.delegationCertificate != null) "--delegation-certificate ${cfg.delegationCertificate}"}" - "${lib.optionalString (cfg.vrfKey != null) + "${optionalString (cfg.vrfKey != null) "--shelley-vrf-key ${cfg.vrfKey}"}" - "${lib.optionalString (cfg.kesKey != null) + "${optionalString (cfg.kesKey != null) "--shelley-kes-key ${cfg.kesKey}"}" - "${lib.optionalString (cfg.operationalCertificate != null) + "${optionalString (cfg.operationalCertificate != null) "--shelley-operational-certificate ${cfg.operationalCertificate}"}" ]; }; instanceDbPath = cfg.databasePath i; - cmd = builtins.filter (x: x != "") [ + cmd = filter (x: x != "") [ "${cfg.executable} run" "--config ${nodeConfigFile}" "--database-path ${instanceDbPath}" "--topology ${topology i}" - ] ++ lib.optionals (!cfg.systemdSocketActivation) ([ + ] ++ optionals (!cfg.systemdSocketActivation) ([ "--host-addr ${cfg.hostAddr}" "--port ${if (cfg.shareIpv4port || cfg.shareIpv6port) then toString cfg.port else toString (cfg.port + i)}" "--socket-path ${cfg.socketPath i}" - ] ++ lib.optionals (cfg.ipv6HostAddr i != null) [ + ] ++ optionals (cfg.ipv6HostAddr i != null) [ "--host-ipv6-addr ${cfg.ipv6HostAddr i}" - ]) ++ lib.optionals (cfg.tracerSocketPathAccept i != null) [ + ]) ++ optionals (cfg.tracerSocketPathAccept i != null) [ "--tracer-socket-path-accept ${cfg.tracerSocketPathAccept i}" - ] ++ lib.optionals (cfg.tracerSocketPathConnect i != null) [ + ] ++ optionals (cfg.tracerSocketPathConnect i != null) [ "--tracer-socket-path-connect ${cfg.tracerSocketPathConnect i}" ] ++ consensusParams.${cfg.nodeConfig.Protocol} ++ cfg.extraArgs ++ cfg.rtsArgs; in '' echo "Starting: ${concatStringsSep "\"\n echo \"" cmd}" echo "..or, once again, in a single line:" echo "${toString cmd}" - ${lib.optionalString (i > 0) '' + ${optionalString (i > 0) '' # If exist copy state from existing instance instead of syncing from scratch: if [ ! -d ${instanceDbPath} ] && [ -d ${cfg.databasePath 0} ]; then echo "Copying existing immutable db from ${cfg.databasePath 0}" @@ -176,42 +178,67 @@ let ''} ${toString cmd}''; in { + imports = [ + # Update the option name for consistency with the cardano-node topology file key. + (mkRenamedOptionModule + [ "services" "cardano-node" "usePeersFromLedgerAfterSlot" ] [ "services" "cardano-node" "useLedgerAfterSlot" ]) + ]; + options = { services.cardano-node = { enable = mkOption { - type = types.bool; + type = bool; default = false; description = '' - Enable cardano-node, a node implementing ouroboros protocols - (the blockchain protocols running cardano). + Enable cardano-node, a node implementing ouroboros protocols; + the blockchain protocols running cardano. ''; }; instances = mkOption { - type = types.int; + type = int; default = 1; description = '' - Number of instance of the service to run. + Number of instances of the service to run. ''; }; script = mkOption { - type = types.str; + type = str; default = mkScript cfg 0; }; profiling = mkOption { - type = types.enum ["none" "time" "time-detail" "space" "space-cost" "space-module" "space-closure" "space-type" "space-retainer" "space-bio" "space-heap"]; + type = enum [ + "none" + "space" + "space-bio" + "space-closure" + "space-cost" + "space-heap" + "space-module" + "space-retainer" + "space-type" + "time" + "time-detail" + ]; default = "none"; + description = '' + Haskell profiling types which are available and will be applied to + the cardano-node binary if declared. + ''; }; eventlog = mkOption { - type = types.bool; + type = bool; default = false; + description = '' + Whether to enable eventlog profiling. + ''; }; asserts = mkOption { - type = types.bool; + type = bool; default = false; description = '' Whether to use an executable with asserts enabled. @@ -219,152 +246,152 @@ in { }; cardanoNodePackages = mkOption { - type = types.attrs; + type = attrs; default = pkgs.cardanoNodePackages or (import ../. { inherit (pkgs) system; }).cardanoNodePackages; defaultText = "cardano-node packages"; description = '' - The cardano-node packages and library that should be used. - Main usage is sharing optimization: - reduce eval time when service is instantiated multiple times. + The cardano-node packages and library that should be used. The main + use case is for a sharing optimization which reduces eval time when + cardano node packages are instantiated multiple times. ''; }; package = mkOption { - type = types.package; + type = package; default = if (cfg.profiling != "none") then cfg.cardanoNodePackages.cardano-node.passthru.profiled else if cfg.asserts then cfg.cardanoNodePackages.cardano-node.passthru.asserted else cfg.cardanoNodePackages.cardano-node; defaultText = "cardano-node"; description = '' - The cardano-node package that should be used + The cardano-node package that should be used. ''; }; executable = mkOption { - type = types.str; + type = str; default = "exec ${cfg.package}/bin/cardano-node"; defaultText = "cardano-node"; description = '' - The cardano-node executable invocation to use + The cardano-node executable invocation to use. ''; }; - environments = mkOption { - type = types.attrs; - default = cfg.cardanoNodePackages.cardanoLib.environments; + environment = mkOption { + type = enum (attrNames cfg.environments); + default = "preview"; description = '' - environment node will connect to + The environment cardano-node will connect to. ''; }; - environment = mkOption { - type = types.enum (builtins.attrNames cfg.environments); - default = "testnet"; + environments = mkOption { + type = attrs; + default = cfg.cardanoNodePackages.cardanoLib.environments; description = '' - environment node will connect to + The environments cardano-node will possibly utilize. ''; }; isProducer = mkOption { - type = types.bool; + type = bool; default = false; description = '' Whether this node is intended to be a producer. - Internal option for inter-module communication. + An internal option for inter-module communication. ''; }; # Byron signing/delegation signingKey = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Signing key + The signing key. ''; }; delegationCertificate = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Delegation certificate + The delegation certificate. ''; }; # Shelley kes/vrf keys and operation cert kesKey = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Signing key + The KES or key evolving signature key. ''; }; vrfKey = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Signing key + The VRF or verifable random function key. ''; }; operationalCertificate = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Operational certificate + The operational certificate. ''; }; hostAddr = mkOption { - type = types.str; + type = str; default = "127.0.0.1"; description = '' - The host address to bind to + The host address to bind to. ''; }; ipv6HostAddr = mkOption { type = funcToOr nullOrStr; default = _: null; - apply = ip: if (lib.isFunction ip) then ip else _: ip; + apply = ip: if lib.isFunction ip then ip else _: ip; description = '' The ipv6 host address to bind to. Set to null to disable. ''; }; additionalListenStream = mkOption { - type = types.functionTo (types.listOf types.str); + type = functionTo (listOf str); default = _: []; description = '' - List of additional sockets to listen to. Only available with `systemdSocketActivation`. + A List of additional sockets to listen to. Only available with `systemdSocketActivation`. ''; }; stateDirBase = mkOption { - type = types.str; + type = str; default = "/var/lib/"; description = '' - Base directory to store blockchain data, for each instance. + The base directory to store blockchain data. ''; }; stateDir = mkOption { - type = funcToOr types.str; + type = funcToOr str; default = "${cfg.stateDirBase}cardano-node"; - apply = x : if (lib.isFunction x) then x else i: x; + apply = x : if lib.isFunction x then x else i: x; description = '' - Directory to store blockchain data, for each instance. + The directory to store blockchain data, for each instance. ''; }; runDirBase = mkOption { - type = types.str; + type = str; default = "/run/"; description = '' - Base runtime directory, for each instance. + The base runtime directory. ''; }; @@ -373,15 +400,15 @@ in { default = i: ''${cfg.runDirBase}${suffixDir "cardano-node" i}''; apply = x : if lib.isFunction x then x else if x == null then _: null else "${cfg.runDirBase}${suffixDir "cardano-node" x}"; description = '' - Runtime directory relative to ${cfg.runDirBase}, for each instance + The runtime directory relative to ${cfg.runDirBase}, for each instance. ''; }; databasePath = mkOption { - type = funcToOr types.str; + type = funcToOr str; default = i : "${cfg.stateDir i}/${cfg.dbPrefix i}"; apply = x : if lib.isFunction x then x else _ : x; - description = ''Node database path, for each instance.''; + description = ''The node database path, for each instance.''; }; lmdbDatabasePath = mkOption { @@ -389,16 +416,16 @@ in { default = null; apply = x : if lib.isFunction x then x else if x == null then _: null else _: x; description = '' - Node UTxO-HD LMDB path for performant disk I/O, for each instance. + A node UTxO-HD LMDB path for performant disk I/O, for each instance. This could point to a direct-access SSD, with a specifically created journal-less file system and optimized mount options. ''; }; socketPath = mkOption { - type = funcToOr types.str; + type = funcToOr str; default = i : "${runtimeDir i}/node.socket"; apply = x : if lib.isFunction x then x else _ : x; - description = ''Local communication socket path, for each instance.''; + description = ''A local communication socket path, for each instance.''; }; tracerSocketPathAccept = mkOption { @@ -406,7 +433,7 @@ in { default = null; apply = x : if lib.isFunction x then x else _ : x; description = '' - Listen for incoming cardano-tracer connection on a local socket, + Listen for an incoming cardano-tracer connection on a local socket, for each instance. ''; }; @@ -416,97 +443,97 @@ in { default = null; apply = x : if lib.isFunction x then x else _ : x; description = '' - Connect to cardano-tracer listening on a local socket, + Connect to a cardano-tracer listening on a local socket, for each instance. ''; }; socketGroup = mkOption { - type = types.str; + type = str; default = "cardano-node"; description = '' - systemd socket group owner. - Note: only applies to sockets created by systemd + The systemd socket group owner. + Note: this only applies to sockets created by systemd (ie. when `systemdSocketActivation` is turned on). ''; }; systemdSocketActivation = mkOption { - type = types.bool; + type = bool; default = false; description = ''Use systemd socket activation''; }; extraServiceConfig = mkOption { - type = types.functionTo types.attrs + type = functionTo attrs // { merge = loc: foldl' (res: def: i: recursiveUpdate (res i) (def.value i)) (i: {}); }; default = i: {}; description = '' - Extra systemd service config (apply to all instances). + Extra systemd service config which applies to all instances. ''; }; extraSocketConfig = mkOption { - type = types.functionTo types.attrs + type = functionTo attrs // { merge = loc: foldl' (res: def: i: recursiveUpdate (res i) (def.value i)) (i: {}); }; default = i: {}; description = '' - Extra systemd socket config (apply to all instances). + Extra systemd socket config which applies to all instances. ''; }; dbPrefix = mkOption { - type = types.either types.str (types.functionTo types.str); + type = either str (functionTo str); default = suffixDir "db-${cfg.environment}"; apply = x : if lib.isFunction x then x else suffixDir x; description = '' - Prefix of database directories inside `stateDir`. - (eg. for "db", there will be db-0, etc.). + The prefix of database directories inside `stateDir`. + (eg. for "db", there will be db-0, etc.), for each instance. ''; }; port = mkOption { - type = types.either types.int types.str; + type = either int str; default = 3001; description = '' - The port number + The port number to listen on. ''; }; shareIpv4port = mkOption { - type = types.bool; + type = bool; default = cfg.systemdSocketActivation; description = '' - Should instances on same machine share ipv4 port. - Default: true if systemd activated socket. Otherwise false. - If false use port increments starting from `port`. + Whether instances on the same machine should share an ipv4 port. + Default: true if the socket is systemd activated, otherwise false. + If false, use port increments starting from `port`. ''; }; shareIpv6port = mkOption { - type = types.bool; + type = bool; default = cfg.systemdSocketActivation; description = '' - Should instances on same machine share ipv6 port. - Default: true if systemd activated socket. Otherwise false. - If false use port increments starting from `port`. + Whether instances on the same machine should share an ipv6 port. + Default: true if the socket is systemd activated, otherwise false. + If false, use port increments starting from `port`. ''; }; nodeId = mkOption { - type = types.int; + type = int; default = 0; description = '' - The ID for this node + The ID for this node. ''; }; publicProducers = mkOption { - type = types.listOf types.attrs; + type = listOf attrs; default = []; example = [{ accessPoints = [{ @@ -515,17 +542,24 @@ in { }]; advertise = false; }]; - description = ''Routes to public peers. Only used if slot < usePeersFromLedgerAfterSlot''; + description = '' + Routes to public peers. Only used if slot is less than + useLedgerAfterSlot. + ''; }; instancePublicProducers = mkOption { - type = types.functionTo (types.listOf types.attrs); + type = functionTo (listOf attrs); default = _: []; - description = ''Routes to public peers. Only used if slot < usePeersFromLedgerAfterSlot and specific to a given instance (when multiple instances are used).''; + description = '' + Routes to public peers. Only used if slot is less than + useLedgerAfterSlot and specific to a given instance when + multiple instances are used. + ''; }; producers = mkOption { - type = types.listOf types.attrs; + type = listOf attrs; default = []; example = [{ accessPoints = [{ @@ -539,67 +573,70 @@ in { }; instanceProducers = mkOption { - type = types.functionTo (types.listOf types.attrs); + type = functionTo (listOf attrs); default = _: []; description = '' - Static routes to local peers, specific to a given instance (when multiple instances are used). + Static routes to local peers, specific to a given instance when + multiple instances are used. ''; }; useNewTopology = mkOption { - type = types.bool; + type = bool; default = cfg.nodeConfig.EnableP2P or false; description = '' - Use new, p2p/ledger peers compatible topology. + Use new, peer to peer and ledger peers compatible topology. ''; }; useLegacyTracing = mkOption { - type = types.bool; - default = true; + type = bool; + default = false; description = '' Use the legacy tracing, based on iohk-monitoring-framework. ''; }; - usePeersFromLedgerAfterSlot = mkOption { - type = types.nullOr types.int; + useLedgerAfterSlot = mkOption { + type = nullOr int; default = if cfg.kesKey != null then null - else envConfig.usePeersFromLedgerAfterSlot or null; + else envConfig.useLedgerAfterSlot or null; description = '' If set, bootstraps from public roots until it reaches given slot, - then it switches to using the ledger as a source of peers. It maintains a connection to its local roots. - Default to null for block producers. + then it switches to using the ledger as a source of peers. It + maintains a connection to its local roots. Defaults to null for block + producers. ''; }; bootstrapPeers = mkOption { - type = types.nullOr (types.listOf types.attrs); + type = nullOr (listOf attrs); default = map (e: {address = e.addr; inherit (e) port;}) envConfig.edgeNodes; description = '' - If set, it will enable bootstrap peers. - To disable, set this to null. - To enable, set this to a list of attributes of address and port, example: [{ address = "addr"; port = 3001; }] + If set, it will enable bootstrap peers. To disable, set this to null. + To enable, set this to a list of attributes of address and port, + example: [{ address = "addr"; port = 3001; }] ''; }; topology = mkOption { - type = types.nullOr (types.either types.str types.path); + type = nullOr (either str path); default = null; description = '' - Cluster topology. If not set `producers` array is used to generated topology file. + The cluster topology. If not set the `producers` array is used to + generate a topology file. ''; }; useSystemdReload = mkOption { - type = types.bool; + type = bool; default = false; description = '' If set, systemd will reload cardano-node service units instead of restarting them if only the topology file has changed and p2p is in use. Cardano-node topology files will be stored in /etc as: - /etc/cardano-node/topology-''${toString i}.yaml + /etc/cardano-node/topology-''${toString i}.json For peerSharing enabled networks, peer sharing files will be stored in /etc as: /etc/cardano-node/peer-sharing-''${toString i}.json @@ -610,15 +647,15 @@ in { }; nodeConfig = mkOption { - type = types.attrs // { + type = attrs // { merge = loc: foldl' (res: def: recursiveUpdate res def.value) {}; }; default = envConfig.nodeConfig; - description = ''Internal representation of the config.''; + description = ''The internal representation of the config.''; }; targetNumberOfRootPeers = mkOption { - type = types.nullOr types.int; + type = nullOr int; default = null; description = '' Limits the maximum number of root peers the node will know about. @@ -627,7 +664,7 @@ in { }; targetNumberOfKnownPeers = mkOption { - type = types.nullOr types.int; + type = nullOr int; default = null; description = '' Target number for known peers (root peers + peers known through gossip). @@ -636,7 +673,7 @@ in { }; targetNumberOfEstablishedPeers = mkOption { - type = types.nullOr types.int; + type = nullOr int; default = null; description = '' Number of peers the node will be connected to, but not necessarily following their chain. @@ -645,7 +682,7 @@ in { }; targetNumberOfActivePeers = mkOption { - type = types.nullOr types.int; + type = nullOr int; default = null; description = '' Number of peers your node is actively downloading headers and blocks from. @@ -654,7 +691,7 @@ in { }; extraNodeConfig = mkOption { - type = types.attrs // { + type = attrs // { merge = loc: foldl' (res: def: recursiveUpdate res def.value) {}; }; default = {}; @@ -662,7 +699,7 @@ in { }; extraNodeInstanceConfig = mkOption { - type = types.functionTo types.attrs + type = functionTo attrs // { merge = loc: foldl' (res: def: i: recursiveUpdate (res i) (def.value i)) (i: {}); }; @@ -673,54 +710,54 @@ in { nodeConfigFile = mkOption { type = nullOrStr; default = null; - description = ''Actual configuration file (shell expression).''; + description = ''The actual configuration file.''; }; forceHardForks = mkOption { - type = types.attrsOf types.int; + type = attrsOf int; default = {}; description = '' - A developer-oriented dictionary option to force hard forks for given eras at given epochs. Maps capitalised era names (Shelley, Allegra, Mary, etc.) to hard fork epoch number. - ''; - }; - - withCardanoTracer = mkOption { - type = types.bool; - default = false; + A developer-oriented dictionary option to force hard forks for given + eras at given epochs. Maps capitalised era names (Shelley, Allegra, + Mary, etc) to hard fork epoch number. + ''; }; withUtxoHdLmdb = mkOption { - type = funcToOr types.bool; + type = funcToOr bool; default = false; apply = x: if lib.isFunction x then x else _: x; - description = ''On an UTxO-HD enabled node, the in-memory backend is the default. This activates the on-disk backend (LMDB) instead.''; + description = '' + On a UTxO-HD enabled node, the in-memory backend is the default. + This activates the on-disk backend (LMDB) instead. + ''; }; extraArgs = mkOption { - type = types.listOf types.str; + type = listOf str; default = []; - description = ''Extra CLI args for 'cardano-node'.''; + description = ''Extra CLI args for cardano-node.''; }; rts_flags_override = mkOption { - type = types.listOf types.str; + type = listOf str; default = []; description = ''RTS flags override from profile content.''; }; rtsArgs = mkOption { - type = types.listOf types.str; + type = listOf str; default = [ "-N2" "-I0" "-A16m" "-qg" "-qb" "--disable-delayed-os-memory-return" ]; apply = args: if (args != [] || cfg.profilingArgs != [] || cfg.rts_flags_override != []) then ["+RTS"] ++ cfg.profilingArgs ++ args ++ cfg.rts_flags_override ++ ["-RTS"] else []; - description = ''Extra CLI args for 'cardano-node', to be surrounded by "+RTS"/"-RTS"''; + description = ''Extra CLI args for cardano-node, to be surrounded by "+RTS"/"-RTS"''; }; profilingArgs = mkOption { - type = types.listOf types.str; + type = listOf str; default = let commonProfilingArgs = ["--machine-readable" "-tcardano-node.stats" "-pocardano-node"] - ++ lib.optional (cfg.eventlog) "-l"; + ++ optional (cfg.eventlog) "-l"; in if cfg.profiling == "time" then ["-p"] ++ commonProfilingArgs else if cfg.profiling == "time-detail" then ["-P"] ++ commonProfilingArgs else if cfg.profiling == "space" then ["-h"] ++ commonProfilingArgs @@ -762,10 +799,10 @@ in { }; config = mkIf cfg.enable ( let - lmdbPaths = filter (x: x != null) (map (e: cfg.lmdbDatabasePath e) (builtins.genList lib.trivial.id cfg.instances)); + lmdbPaths = filter (x: x != null) (map (e: cfg.lmdbDatabasePath e) (genList trivial.id cfg.instances)); genInstanceConf = f: listToAttrs (if cfg.instances > 1 then genList (i: let n = "cardano-node-${toString i}"; in nameValuePair n (f n i)) cfg.instances - else [ (nameValuePair "cardano-node" (f "cardano-node" 0)) ]); in lib.mkMerge [ + else [ (nameValuePair "cardano-node" (f "cardano-node" 0)) ]); in mkMerge [ { users.groups.cardano-node.gid = 10016; users.users.cardano-node = { @@ -778,12 +815,16 @@ in { environment.etc = mkMerge [ (mkIf cfg.useSystemdReload (foldl' - (acc: i: recursiveUpdate acc {"cardano-node/topology-${toString i}.yaml".source = selectTopology i;}) {} + (acc: i: recursiveUpdate acc {"cardano-node/topology-${toString i}.json".source = selectTopology i;}) {} (range 0 (cfg.instances - 1))) ) (mkIf (cfg.useNewTopology && cfg.useSystemdReload) (foldl' - (acc: i: recursiveUpdate acc {"cardano-node/peer-snapshot-${toString i}.json".source = toFile "peer-snapshot.json" (toJSON (envConfig.peerSnapshot));}) {} + (acc: i: recursiveUpdate acc ( + optionalAttrs (cfg.peerSnapshotFile i != null) { + "cardano-node/peer-snapshot-${toString i}.json".source = toFile "peer-snapshot.json" (toJSON (envConfig.peerSnapshot)); + } + )) {} (range 0 (cfg.instances - 1))) ) ]; @@ -808,19 +849,19 @@ in { Group = "cardano-node"; ExecReload = mkIf (cfg.useSystemdReload && cfg.useNewTopology) "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "always"; - RuntimeDirectory = lib.mkIf (!cfg.systemdSocketActivation) - (lib.removePrefix cfg.runDirBase (runtimeDir i)); + RuntimeDirectory = mkIf (!cfg.systemdSocketActivation) + (removePrefix cfg.runDirBase (runtimeDir i)); WorkingDirectory = cfg.stateDir i; # This assumes cfg.stateDirBase is a prefix of cfg.stateDir. # This is checked as an assertion below. - StateDirectory = lib.removePrefix cfg.stateDirBase (cfg.stateDir i); - NonBlocking = lib.mkIf cfg.systemdSocketActivation true; - # time to sleep before restarting a service + StateDirectory = removePrefix cfg.stateDirBase (cfg.stateDir i); + NonBlocking = mkIf cfg.systemdSocketActivation true; + # Time to sleep before restarting a service RestartSec = 1; }; } (cfg.extraServiceConfig i)); - systemd.sockets = genInstanceConf (n: i: lib.mkIf cfg.systemdSocketActivation (recursiveUpdate { + systemd.sockets = genInstanceConf (n: i: mkIf cfg.systemdSocketActivation (recursiveUpdate { description = "Socket of the ${n} service."; wantedBy = [ "sockets.target" ]; partOf = [ "${n}.service" ]; @@ -829,7 +870,7 @@ in { ++ optional (cfg.ipv6HostAddr i != null) "[${cfg.ipv6HostAddr i}]:${toString (if cfg.shareIpv6port then cfg.port else cfg.port + i)}" ++ (cfg.additionalListenStream i) ++ [(cfg.socketPath i)]; - RuntimeDirectory = lib.removePrefix cfg.runDirBase (cfg.runtimeDir i); + RuntimeDirectory = removePrefix cfg.runDirBase (cfg.runtimeDir i); NoDelay = "yes"; ReusePort = "yes"; SocketMode = "0660"; @@ -840,8 +881,8 @@ in { } (cfg.extraSocketConfig i))); } { - # oneshot service start allows to easily control all instances at once. - systemd.services.cardano-node = lib.mkIf (cfg.instances > 1) { + # Oneshot service start allows to easily control all instances at once. + systemd.services.cardano-node = mkIf (cfg.instances > 1) { description = "Control all ${toString cfg.instances} at once."; enable = true; wants = genList (i: "cardano-node-${toString i}.service") cfg.instances; @@ -852,15 +893,15 @@ in { Group = "cardano-node"; ExecStart = "${pkgs.coreutils}/bin/echo Starting ${toString cfg.instances} cardano-node instances"; WorkingDirectory = cfg.stateDir i; - StateDirectory = lib.removePrefix cfg.stateDirBase (cfg.stateDir i); + StateDirectory = removePrefix cfg.stateDirBase (cfg.stateDir i); }; }; } { assertions = [ { - assertion = builtins.all (i : lib.hasPrefix cfg.stateDirBase (cfg.stateDir i)) - (builtins.genList lib.trivial.id cfg.instances); + assertion = all (i : hasPrefix cfg.stateDirBase (cfg.stateDir i)) + (genList trivial.id cfg.instances); message = "The option services.cardano-node.stateDir should have ${cfg.stateDirBase} as a prefix, for each instance!"; } @@ -873,7 +914,7 @@ in { message = "Systemd socket activation cannot be used with p2p topology due to a systemd socket re-use issue."; } { - assertion = (length lmdbPaths) == (length (lib.lists.unique lmdbPaths)); + assertion = (length lmdbPaths) == (length (lists.unique lmdbPaths)); message = "When configuring multiple LMDB enabled nodes on one instance, lmdbDatabasePath must be unique."; } ]; diff --git a/nix/nixos/cardano-tracer-service-workbench.nix b/nix/nixos/cardano-tracer-service-workbench.nix new file mode 100644 index 00000000000..21f0c6c6d75 --- /dev/null +++ b/nix/nixos/cardano-tracer-service-workbench.nix @@ -0,0 +1,113 @@ +# This workbench cardano-tracer service module requires commonLib from the +# cardano-node flake overlay which prevents a simple non-flake service module +# import and also requires knowledge of the commonLib functions to use. +# +# This makes this workbench service module suitable for internal purposes, but +# not for a general purpose single import cardano-tracer service module. +# +# The module at nix/nixos/cardano-tracer-service.nix is the preferred module +# for general purpose use. +pkgs: +let serviceConfigToJSON = + cfg: + { + inherit (cfg) networkMagic resourceFreq metricsHelp; + # loRequestNum = 100; + network = + if cfg.acceptingSocket != null + then { + tag = "AcceptAt"; + contents = cfg.acceptingSocket; + } else if cfg.connectToSocket != null + then { + tag = "ConnectTo"; + contents = cfg.connectToSocket; + } else + throw "cardano-tracer-service: either acceptingSocket or connectToSocket must be provided."; + logging = [{ + inherit (cfg) logRoot; + + logMode = "FileMode"; + logFormat = "ForMachine"; + }]; + rotation = { + rpFrequencySecs = 15; + rpKeepFilesNum = 10; + rpLogLimitBytes = 1000000000; + rpMaxAgeHours = 24; + } // (cfg.rotation or {}); + + hasEKG = { + epHost = "127.0.0.1"; + epPort = cfg.ekgPortBase; + }; + ekgRequestFreq = 1; + hasPrometheus = { + epHost = "127.0.0.1"; + epPort = 3200; ## supervisord.portShiftPrometheus + } // (cfg.prometheus or {}); + # Just an example for metrics compatibility mapping. + # An entry means the first entry has the second entry as alias. + # The Metrics is then avalable, both with the original and the mapped name. + # Only one mapping per message is supported. + # metricsComp = { + # "Mempool.TxsInMempool" = "Mempool.TxsInMempool.Mapped"; + # "ChainDB.SlotNum" = "ChainDB.SlotNum.Mapped"; + # }; + } // pkgs.lib.optionalAttrs ((cfg.RTView or {}) != {}) + { + hasRTView = cfg.RTView; + }; +in pkgs.commonLib.defServiceModule + (lib: with lib; + { svcName = "cardano-tracer"; + svcDesc = "Cardano trace processor"; + + svcPackageSelector = + pkgs: ## Local: + pkgs.cardanoNodePackages.cardano-tracer + ## Imported by another repo, that adds an overlay: + or pkgs.cardano-tracer; + ## TODO: that's actually a bit ugly and could be improved. + ## This exe has to be available in the selected package. + exeName = "cardano-tracer"; + + extraOptionDecls = { + ### You can actually change those! + networkMagic = opt int 764824073 "Network magic (764824073 for Cardano mainnet)."; + acceptingSocket = mayOpt str "Socket path: as acceptor."; + connectToSocket = mayOpt str "Socket path: connect to."; + logRoot = opt str null "Log storage root directory."; + rotation = opt attrs {} "Log rotation overrides: see cardano-tracer documentation."; + RTView = opt attrs {} "RTView config overrides: see cardano-tracer documentation."; + ekgPortBase = opt int 3100 "EKG port base."; + ekgRequestFreq = opt int 1 "EKG request frequency"; + prometheus = opt attrs {} "Prometheus overrides: see cardano-tracer documentation."; + resourceFreq = mayOpt int "Frequency (1/ms) for tracing resource usage."; + metricsHelp = mayOpt str "JSON file containing metrics help annotations for Prometheus"; + + ### Here be dragons, on the other hand.. + configFile = mayOpt str + "Config file path override -- only set if you know what you're doing. Shudder. Your 'eminence'.."; + configJSONfn = opt (functionTo attrs) serviceConfigToJSON + "This is NOT meant to be overridden, at all -- we only expose it so it's externally accessible."; + }; + + configExeArgsFn = cfg: [ + "--config" (if cfg.configFile != null then cfg.configFile + else "${pkgs.writeText "cardano-tracer-config.json" + (__toJSON (serviceConfigToJSON cfg))}") + ]; + + configSystemdExtraConfig = _: {}; + + configSystemdExtraServiceConfig = + cfg: with cfg; { + Type = "exec"; + User = "cardano-node"; + Group = "cardano-node"; + Restart = "always"; + # RuntimeDirectory = localNodeConf.runtimeDir; + # WorkingDirectory = localNodeConf.stateDir; + }; + }) diff --git a/nix/nixos/cardano-tracer-service.nix b/nix/nixos/cardano-tracer-service.nix index dea2dcc6095..90cdb409480 100644 --- a/nix/nixos/cardano-tracer-service.nix +++ b/nix/nixos/cardano-tracer-service.nix @@ -1,97 +1,856 @@ -pkgs: -let serviceConfigToJSON = - cfg: - { - inherit (cfg) networkMagic resourceFreq metricsHelp; - # loRequestNum = 100; - network = - if cfg.acceptingSocket != null - then { - tag = "AcceptAt"; - contents = cfg.acceptingSocket; - } else if cfg.connectToSocket != null - then { - tag = "ConnectTo"; - contents = cfg.connectToSocket; - } else - throw "cardano-tracer-service: either acceptingSocket or connectToSocket must be provided."; - logging = [{ - inherit (cfg) logRoot; - - logMode = "FileMode"; - logFormat = "ForMachine"; - }]; - rotation = { - rpFrequencySecs = 15; - rpKeepFilesNum = 10; - rpLogLimitBytes = 1000000000; - rpMaxAgeHours = 24; - } // (cfg.rotation or {}); - - hasEKG = { - epHost = "127.0.0.1"; - epPort = cfg.ekgPortBase; +{ + config, + lib, + pkgs, + ... +}: +with lib; +with builtins; let + inherit (types) attrs attrsOf bool either enum ints listOf package path port nullOr str submodule; + + cfg = config.services.cardano-tracer; + + configFile = + if !isNull cfg.configFile + then cfg.configFile + else if isNull cfg.configFilePath + then prettyConfig + else cfg.configFilePath; + + tracerConfig = + { + inherit + (cfg) + ekgRequestFreq + ekgRequestFull + loRequestNum + logging + metricsHelp + metricsNoSuffix + networkMagic + resourceFreq + verbosity + ; + + network = + optionalAttrs (!isNull cfg.acceptingSocket) { + tag = "AcceptAt"; + contents = cfg.acceptingSocket; + } + // optionalAttrs (!isNull cfg.connectToSocket) { + tag = "ConnectTo"; + contents = cfg.connectToSocket; }; - ekgRequestFreq = 1; - hasPrometheus = { - epHost = "127.0.0.1"; - epPort = 3200; ## supervisord.portShiftPrometheus - } // (cfg.prometheus or {}); - } // pkgs.lib.optionalAttrs ((cfg.RTView or {}) != {}) - { - hasRTView = cfg.RTView; - }; -in pkgs.commonLib.defServiceModule - (lib: with lib; - { svcName = "cardano-tracer"; - svcDesc = "Cardano trace processor"; - - svcPackageSelector = - pkgs: ## Local: - pkgs.cardanoNodePackages.cardano-tracer - ## Imported by another repo, that adds an overlay: - or pkgs.cardano-tracer; - ## TODO: that's actually a bit ugly and could be improved. - ## This exe has to be available in the selected package. - exeName = "cardano-tracer"; - - extraOptionDecls = { - ### You can actually change those! - networkMagic = opt int 764824073 "Network magic (764824073 for Cardano mainnet)."; - acceptingSocket = mayOpt str "Socket path: as acceptor."; - connectToSocket = mayOpt str "Socket path: connect to."; - logRoot = opt str null "Log storage root directory."; - rotation = opt attrs {} "Log rotation overrides: see cardano-tracer documentation."; - RTView = opt attrs {} "RTView config overrides: see cardano-tracer documentation."; - ekgPortBase = opt int 3100 "EKG port base."; - ekgRequestFreq = opt int 1 "EKG request frequency"; - prometheus = opt attrs {} "Prometheus overrides: see cardano-tracer documentation."; - resourceFreq = mayOpt int "Frequency (1/ms) for tracing resource usage."; - metricsHelp = mayOpt str "JSON file containing metrics help annotations for Prometheus"; - metricsNoSuffix = mayOpt bool "Drop suffixes like '_int' in Prometheus exposition, increasing similiarity with legacy system names."; - - ### Here be dragons, on the other hand.. - configFile = mayOpt str - "Config file path override -- only set if you know what you're doing. Shudder. Your 'eminence'.."; - configJSONfn = opt (functionTo attrs) serviceConfigToJSON - "This is NOT meant to be overridden, at all -- we only expose it so it's externally accessible."; - }; - - configExeArgsFn = cfg: [ - "--config" (if cfg.configFile != null then cfg.configFile - else "${pkgs.writeText "cardano-tracer-config.json" - (__toJSON (serviceConfigToJSON cfg))}") + + rotation = + if isNull cfg.rotation + then null + else + { + inherit + (cfg.rotation) + rpFrequencySecs + rpKeepFilesNum + rpLogLimitBytes + ; + } + // optionalAttrs (!isNull cfg.rotation.rpMaxAgeHours) { + inherit (cfg.rotation) rpMaxAgeHours; + } + // optionalAttrs (!isNull cfg.rotation.rpMaxAgeMinutes) { + inherit (cfg.rotation) rpMaxAgeMinutes; + }; + } + // optionalAttrs cfg.ekgEnable { + hasEKG = { + epHost = cfg.ekgHost; + epPort = cfg.ekgPort; + }; + } + // optionalAttrs cfg.prometheusEnable { + hasPrometheus = { + epHost = cfg.prometheusHost; + epPort = cfg.prometheusPort; + }; + } + // optionalAttrs cfg.rtviewEnable { + hasRTView = { + epHost = cfg.rtviewHost; + epPort = cfg.rtviewPort; + }; + } + // cfg.extraConfig; + + prettyConfig = + (pkgs.runCommandNoCCLocal "cardano-tracer-config.json" {} '' + ${getExe pkgs.jq} --sort-keys \ + < ${toFile "cardano-tracer-unpretty-config.json" (toJSON tracerConfig)} \ + > $out + '') + .out; + + mkScript = let + cmd = + filter (x: x != "") + [ + "${cfg.executable}" + "--config ${configFile}" + ] + ++ optionals (!isNull cfg.minLogSeverity) [ + "--min-log-severity ${cfg.minLogSeverity}" + ] + ++ optionals (!isNull cfg.stateDir) [ + "--state-dir ${cfg.stateDir}" + ] + ++ cfg.extraArgs + ++ cfg.rtsArgs; + in '' + echo "Starting: ${concatStringsSep "\"\n echo \"" cmd}" + + echo "..or, once again, in a single line:" + echo "${toString cmd}" + + ${toString cmd} + ''; + + runtimeDir = if cfg.runtimeDir == null then cfg.stateDir else "${cfg.runDirBase}${removePrefix cfg.runDirBase cfg.runtimeDir}"; +in { + options = { + services.cardano-tracer = { + enable = mkOption { + type = bool; + default = false; + description = '' + Enable cardano-tracer, a service for logging and monitoring of log + and metrics providers such as cardano-node. + ''; + }; + + ##################################### + # # + # Alphabetical nixos module options # + # # + ##################################### + + acceptingSocket = mkOption { + type = nullOr (either str path); + default = "${runtimeDir}/tracer.socket"; + description = '' + Declaring this option means that cardano-tracer will operate in an + `AcceptAt` tag mode where cardano-tracer works as a server: it + receives network connections from providers such as node via a single + local socket provided by cardano-tracer. + + Except for special use cases, declaring this `acceptingSocket` option + instead of the `connectToSocket` option is recommended, as the + `AcceptAt` tag mode supports dynamic provider addition or removal + without requiring cardano-tracer reconfiguration and restart. + + Either this option, or the connectToSocket option must be declared. + ''; + }; + + asserts = mkOption { + type = bool; + default = false; + description = '' + Whether to use an executable with asserts enabled. + ''; + }; + + cardanoNodePackages = mkOption { + type = attrs; + default = pkgs.cardanoNodePackages or (import ../. {inherit (pkgs) system;}).cardanoNodePackages; + defaultText = "cardano-node packages"; + description = '' + The cardano-node packages and library that should be used. The main + use case is for a sharing optimization which reduces eval time when + cardano node packages are instantiated multiple times. + ''; + }; + + configFile = mkOption { + type = nullOr (either str path); + default = null; + description = '' + The actual cardano-tracer configuration file. If this option is set + to null, a configuration file will be built based on the nixos + options. The target location for a default configuration file will + depend on the configFilePath option. + ''; + }; + + configFilePath = mkOption { + type = nullOr (either str path); + default = null; + example = "/etc/cardano-tracer/config.json"; + description = '' + If a default config file is to be used, ie the configFile option is null, + the configFile will be located in: + * The nix store if this option is null, or + * Symlinked to an explicitly declared `/etc` prefixed path + + The `/etc` prefix is a requirement of the nixos implementation. + ''; + }; + + connectToSocket = mkOption { + type = nullOr (listOf (either str path)); + default = null; + description = '' + Declaring this option means that cardano-tracer will operate in a + `ConnectTo` tag mode where cardano-tracer works as a client: it + establishes network connections to local socket(s) provided by the + provider(s). In this case a socket is used for each provider. + + Except for special use cases, declaring `acceptingSocket` instead of + this option is recommended, as the `AcceptAt` tag mode supports + dynamic provider addition or removal without requiring cardano-tracer + reconfiguration and restart. + + Either this option, or the acceptingSocket option must be declared. + ''; + }; + + ekgEnable = mkOption { + type = bool; + default = true; + description = '' + Whether to enable an EKG http interface for process monitoring. + ''; + }; + + ekgHost = mkOption { + type = str; + default = "127.0.0.1"; + description = '' + The host to bind if EKG is enabled. + ''; + }; + + ekgPort = mkOption { + type = port; + default = 12788; + description = '' + The port to listen on if EKG is enabled. + ''; + }; + + ekgRequestFull = mkOption { + type = nullOr bool; + default = null; + description = '' + When receiving forwarded metrics, cardano-tracer can request a full + set of EKG metrics, or a delta from the previous request. + + If true, a full set of metrics will be sent on each request. + Otherwise, on false, only a metrics delta to the previous request + will be sent. + + If null cardano-tracer will set a default: false. + ''; + }; + + ekgRequestFreq = mkOption { + type = nullOr ints.positive; + default = null; + description = '' + This optional attribute specifies the period of how often EKG metrics + will be requested, in seconds. For example, if ekgRequestFreq is 10, + cardano-tracer will ask for new EKG metrics every ten seconds. There + is no limit as loRequestNum, so every request returns all the metrics + the provider has at that moment of time. + + If null cardano-tracer will set a default: 1. + ''; + }; + + environment = mkOption { + type = enum (attrNames cfg.environments); + default = "preview"; + description = '' + The environment cardano-tracer will connect to. + ''; + }; + + environments = mkOption { + type = attrs; + default = cfg.cardanoNodePackages.cardanoLib.environments; + description = '' + The environments cardano-tracer will possibly utilize. + ''; + }; + + eventlog = mkOption { + type = bool; + default = false; + description = '' + Whether to enable eventlog profiling. + ''; + }; + + executable = mkOption { + type = str; + default = "exec ${cfg.package}/bin/cardano-tracer"; + description = '' + The cardano-tracer executable invocation to use. + ''; + }; + + extraArgs = mkOption { + type = listOf str; + default = []; + description = '' + Extra CLI args for cardano-tracer. + ''; + }; + + extraConfig = mkOption { + type = attrs; + default = {}; + description = '' + Extra configuration attributes for cardano-tracer which will be + merged into default cardano-tracer configuration when option + `configFile` is null. + ''; + }; + + group = mkOption { + type = str; + default = "cardano-node"; + description = '' + The default group to run the systemd service as. + + This group is assumed to already exist. + ''; + }; + + logging = mkOption { + type = listOf (submodule { + options = { + logFormat = mkOption { + type = enum ["ForHuman" "ForMachine"]; + default = "ForHuman"; + description = '' + The logFormat option specifies the format of logs. There are two + possible modes: `ForMachine` and `ForHuman`. ForMachine is for JSON + format, ForHuman is for human-friendly text format. Since the logging + option accepts a list, more than one logging section can be declared. + ''; + }; + + logMode = mkOption { + type = enum ["FileMode" "JournalMode"]; + default = "JournalMode"; + description = '' + The logMode option specifies logging mode. There are two possible + modes: `FileMode` and `JournalMode`. FileMode is for storing logs to + the files, JournalMode is for storing them in systemd's journal. If + you choose JournalMode, the logRoot option, will be ignored. + ''; + }; + + logRoot = mkOption { + type = str; + default = cfg.stateDir; + description = '' + The logRoot option specifies the path to the root directory. This + directory will contain all the subdirectories with the log files + inside. Remember that each subdirectory corresponds to the particular + provider. If the root directory does not exist, it will be created. + ''; + }; + }; + }); + default = [{}]; + description = '' + The logging option describes the logging operation of cardano-tracer + and is a list of a submodule of which each contains a `logFormat`, + `logMode` and `logRoot`. + + See the descriptions for each available submodule option. + ''; + }; + + loRequestNum = mkOption { + type = nullOr ints.positive; + default = null; + description = '' + This optional attribute specifies the number of log items that will + be requested from the providing source. For example, if loRequestNum + is 10, cardano-tracer will periodically ask for 10 log items in one + request. This value is useful for fine-tuning network traffic: it is + possible to ask 50 log items in one request, or ask for them in 50 + requests one at a time. loRequestNum is the maximum number of log + items. For example, if cardano-tracer requests 50 log items but the + provider has only 40 at that moment, these 40 items will be returned, + and the request won't block to wait for an additional 10 items. + + If null cardano-tracer will set a default: 100. + ''; + }; + + minLogSeverity = mkOption { + type = nullOr (enum ["Debug" "Info" "Notice" "Warning" "Error" "Critical" "Alert" "Emergency"]); + default = null; + description = '' + Setting this will cause cardano-tracer to drop its own log messages + that are less severe than the level declared. + + If null cardano-tracer will set a default: Info. + ''; + }; + + metricsHelp = mkOption { + type = nullOr (either str (attrsOf str)); + default = null; + description = '' + Passing metrics help annotations to cardano-tracer can be done as an + attribute set of strings from metric's name to help text where + cardano-tracer's internal metric names have to be used as the + attribute names. + + If such a set is already available as JSON in a file, this option can + be declared as a string of the path to such a file. + + Any metrics prefix declared in provider config, such as + `TraceOptionMetricsPrefix` in cardano-node, should not be included in + the attribute name. Similarly, metric type suffixes such as `.int` or + `.real`, should also not be included. + + The effect of this option applies to prometheus metrics only, ie: not + EKG. + ''; + example = { + "Mem.resident" = "Kernel-reported RSS (resident set size)"; + "RTS.gcMajorNum" = "Major GCs"; + }; + }; + + metricsNoSuffix = mkOption { + type = nullOr bool; + default = null; + description = '' + If set true, metrics name suffixes, like "_int", will be dropped, + thus increasing the similarity with legacy tracing system names. + + The effect of this option applies to prometheus metrics only, ie: not + EKG. + + If null cardano-tracer will set a default: false. + ''; + }; + + networkMagic = mkOption { + type = ints.positive; + default = (fromJSON (readFile cfg.environments.${cfg.environment}.nodeConfig.ShelleyGenesisFile)).networkMagic; + description = '' + The network magic of the cardano environment which will be connected + with cardano-tracer. + ''; + }; + + package = mkOption { + type = package; + default = + if (cfg.profiling != "none") + then cfg.cardanoNodePackages.cardano-tracer.passthru.profiled + else if cfg.eventlog + then cfg.cardanoNodePackages.cardano-tracer.passthru.eventlogged + else if cfg.asserts + then cfg.cardanoNodePackages.cardano-tracer.passthru.asserted + else cfg.cardanoNodePackages.cardano-tracer; + defaultText = "cardano-tracer"; + description = '' + The cardano-tracer package that should be used. + ''; + }; + + profiling = mkOption { + type = enum [ + "none" + "space" + "space-bio" + "space-closure" + "space-cost" + "space-heap" + "space-module" + "space-retainer" + "space-type" + "time" + "time-detail" ]; + default = "none"; + description = '' + Haskell profiling types which are available and will be applied to + the cardano-tracer binary if declared. + ''; + }; + + profilingArgs = mkOption { + type = listOf str; + default = let + commonProfilingArgs = + ["--machine-readable" "-tcardano-tracer.stats" "-pocardano-tracer"] + ++ optional (cfg.eventlog) "-l"; + in + if cfg.profiling == "time" + then ["-p"] ++ commonProfilingArgs + else if cfg.profiling == "time-detail" + then ["-P"] ++ commonProfilingArgs + else if cfg.profiling == "space" + then ["-h"] ++ commonProfilingArgs + else if cfg.profiling == "space-cost" + then ["-hc"] ++ commonProfilingArgs + else if cfg.profiling == "space-module" + then ["-hm"] ++ commonProfilingArgs + else if cfg.profiling == "space-closure" + then ["-hd"] ++ commonProfilingArgs + else if cfg.profiling == "space-type" + then ["-hy"] ++ commonProfilingArgs + else if cfg.profiling == "space-retainer" + then ["-hr"] ++ commonProfilingArgs + else if cfg.profiling == "space-bio" + then ["-hb"] ++ commonProfilingArgs + else if cfg.profiling == "space-heap" + then ["-hT"] ++ commonProfilingArgs + else []; + description = '' + RTS profiling options. + ''; + }; + + prometheusEnable = mkOption { + type = bool; + default = true; + description = '' + Whether to enable a prometheus export of metrics. + ''; + }; - configSystemdExtraConfig = _: {}; + prometheusHost = mkOption { + type = str; + default = "127.0.0.1"; + description = '' + The host to bind if prometheus is enabled. + ''; + }; + + prometheusPort = mkOption { + type = port; + default = 12808; + description = '' + The port to listen on if prometheus is enabled. - configSystemdExtraServiceConfig = - cfg: with cfg; { - Type = "exec"; - User = "cardano-node"; - Group = "cardano-node"; - Restart = "always"; - # RuntimeDirectory = localNodeConf.runtimeDir; - # WorkingDirectory = localNodeConf.stateDir; + Defaults to the legacy prometheus listening port, 12798, plus 10. + This avoids a conflict with the cardano-node default metrics port binding + when PrometheusSimple backend is in use. + ''; + }; + + resourceFreq = mkOption { + type = nullOr ints.positive; + default = null; + description = '' + The period for tracing cardano-tracer's own resource usage in + milliseconds. For example, if set to 60000, resources will traced + every 60 seconds. If null cardano-tracer will not display resource + usage. + ''; + }; + + rotation = mkOption { + type = nullOr (submodule ({config, ...}: { + options = { + rpFrequencySecs = mkOption { + type = ints.positive; + description = '' + The rpFrequencySecs option specifies the rotation check period, + in seconds. + ''; + }; + + rpKeepFilesNum = mkOption { + type = ints.positive; + description = '' + The rpKeepFilesNum option specifies the number of the log + files that will be kept. The last (newest) log files will + always be the ones kept, whereas the first (oldest) log files + will be purged. + ''; + }; + + rpLogLimitBytes = mkOption { + type = ints.positive; + description = '' + The rpLogLimitBytes option specifies the maximum size of the + log file, in bytes. Once the size of the current log file + reaches this value, a new log file will be created. + ''; + }; + + rpMaxAgeMinutes = mkOption { + type = nullOr ints.positive; + default = null; + description = '' + The rpMaxAgeMinutes option specifies the lifetime of the log + file in minutes. Once the log file reaches this value, it is + treated as outdated and will be deleted. Please note that N + last log files, specified by option rpKeepFilesNum, will be + kept even if they are outdated. If the rpMaxAgeHours option is + also declared this option takes precedence. + ''; + }; + + rpMaxAgeHours = mkOption { + type = nullOr ints.positive; + default = null; + description = '' + The rpMaxAgeHours option specifies the lifetime of the log + file in hours. Once the log file reaches this value, it is + treated as outdated and will be deleted. Please note that N + last log files, specified by option rpKeepFilesNum, will be + kept even if they are outdated. If the rpMaxAgeMinutes option + is also declared then it takes precedence. + ''; + }; + }; + })); + default = { + # Provide some sane defaults + rpFrequencySecs = 60; + rpKeepFilesNum = 14; + rpMaxAgeHours = 24; + rpLogLimitBytes = 10 * 1000 * 1000; }; - }) + apply = rot: + if isNull rot + then rot + else if (isNull rot.rpMaxAgeHours && isNull rot.rpMaxAgeMinutes) + then + throw '' + In services.cardano-tracer.rotation at least one of + rpMaxAgeMinutes and rpMaxAgeHours must be declared. + '' + else if (!isNull rot.rpMaxAgeHours && !isNull rot.rpMaxAgeMinutes) + then + warn '' + In services.cardano-tracer.rotation both rpMaxAgeMinutes and + rpMaxAgeHours have been declared. The latter will be ignored by + cardano-tracer. + '' + rot + else rot; + description = '' + The rotation option describes the log rotation operation of + cardano-tracer and is either null or a submodule with options of + `rpFrequencySecs`, `rpKeepFilesNum`, `rpLogLimitBytes`, + `rpMaxAgeMinutes`. + + Please note that if the rotation declaration is skipped, all log items will + be stored in a single file, and usually that's not what is desired. + + This option will be ignored if all logging has `logMode` configured + as `JournalMode`. + + See the descriptions for each available submodule option. + ''; + }; + + rts_flags_override = mkOption { + type = listOf str; + default = []; + description = '' + RTS flags override from profile content. + ''; + }; + + rtsArgs = mkOption { + type = listOf str; + default = []; + apply = args: + if (args != [] || cfg.profilingArgs != [] || cfg.rts_flags_override != []) + then ["+RTS"] ++ cfg.profilingArgs ++ args ++ cfg.rts_flags_override ++ ["-RTS"] + else []; + description = '' + Extra CLI args for cardano-tracer, to be surrounded by "+RTS"/"-RTS" + ''; + }; + + rtviewEnable = mkOption { + type = bool; + default = false; + description = '' + Whether to enable an RTView client. + + As of node release 9.1 this option has no effect unless node was + built with `-f +rtview`. + + Ref: + https://github.com/IntersectMBO/cardano-node/pull/5846 + ''; + }; + + rtviewHost = mkOption { + type = str; + default = "127.0.0.1"; + description = '' + The host to bind if RTView is enabled. + ''; + }; + + rtviewPort = mkOption { + type = port; + default = 3300; + description = '' + The port to listen on if RTView is enabled. + ''; + }; + + runtimeDir = mkOption { + type = nullOr str; + default = "${cfg.runDirBase}cardano-tracer"; + description = '' + The directory to store any cardano-tracer runtime related data. + + If creating a cardano-tracer socket, it will default to this + location. + ''; + }; + + runDirBase = mkOption { + type = str; + default = "/run/"; + description = '' + The base runtime directory for cardano-tracer. + ''; + }; + + script = mkOption { + type = str; + default = mkScript; + internal = true; + description = '' + The default nixos generated shell script used in the + scripts.$ENV.tracer package attribute and workbench profile + generation. + ''; + }; + + stateDir = mkOption { + type = nullOr str; + default = "${cfg.stateDirBase}cardano-tracer"; + description = '' + The directory to store any cardano-tracer process related data. + + RTView if enabled will save its state in this directory. + + For non-systemd use cases, this can be set to null or any other + string path. + ''; + }; + + stateDirBase = mkOption { + type = str; + default = "/var/lib/"; + description = '' + The base state directory for cardano-tracer. + ''; + }; + + tracerConfig = mkOption { + type = attrs; + default = tracerConfig; + internal = true; + description = '' + The default nixos tracerConfig attribute set used in workbench + profile generation. + ''; + }; + + user = mkOption { + type = str; + default = "cardano-node"; + description = '' + The default user to run the systemd service as. + + This user is assumed to already exist. + ''; + }; + + verbosity = mkOption { + type = nullOr (enum ["Minimum" "ErrorsOnly" "Maximum"]); + default = null; + description = '' + The verbosity optional attribute specifies the level for + cardano-tracer itself. There are 3 levels: + + Minimum - cardano-tracer will work as silently as possible. + ErrorsOnly - messages about problems will be shown in standard output. + Maximum - all the messages will be shown in standard output. Caution: the number of messages can be huge. + + If null cardano-tracer will set a default: ErrorsOnly. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.etc."cardano-tracer/config.json".source = mkIf (isNull cfg.configFile && isNull cfg.configFilePath) prettyConfig; + + systemd.services.cardano-tracer = { + description = "cardano-tracer service"; + wantedBy = ["multi-user.target"]; + + # If cardano-tracer implements SIGHUP config reload support in the + # future, this can be changed to reloadTriggers. + restartTriggers = [ + ( + if isNull cfg.configFile + then prettyConfig + else configFile + ) + ]; + + environment.HOME = cfg.stateDir; + + path = [cfg.package]; + + # Allow up to 10 failures with 30 second restarts in a 15 minute window + # before entering failure state which may trigger alerts if set up. + startLimitBurst = 10; + startLimitIntervalSec = 900; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + + LimitNOFILE = "65535"; + + WorkingDirectory = cfg.stateDir; + StateDirectory = removePrefix cfg.stateDirBase cfg.stateDir; + RuntimeDirectory = removePrefix cfg.runDirBase runtimeDir; + + # Ensure quick restarts on any condition + Restart = "always"; + RestartSec = 30; + + ExecStart = getExe (pkgs.writeShellApplication { + name = "cardano-tracer"; + text = mkScript; + }); + }; + }; + + assertions = [ + { + assertion = (!isNull cfg.acceptingSocket) != (!isNull cfg.connectToSocket); + message = "In services.cardano-tracer, exactly one of acceptingSocket or connectToSocket must be declared"; + } + { + assertion = isNull cfg.configFilePath || hasPrefix "/etc/" cfg.configFilePath; + message = "In services.cardano-tracer.configFilePath a non-null path must be prefixed with `/etc/`"; + } + ]; + }; +} diff --git a/nix/nixos/module-list.nix b/nix/nixos/module-list.nix index 4fd14193844..ff7b385401f 100644 --- a/nix/nixos/module-list.nix +++ b/nix/nixos/module-list.nix @@ -1,4 +1,5 @@ [ ./cardano-node-service.nix ./cardano-submit-api-service.nix + ./cardano-tracer-service.nix ] diff --git a/nix/nixos/tests/cardano-node-artifact.nix b/nix/nixos/tests/cardano-node-artifact.nix index bc2131c422e..c2f3484fbd6 100644 --- a/nix/nixos/tests/cardano-node-artifact.nix +++ b/nix/nixos/tests/cardano-node-artifact.nix @@ -39,6 +39,8 @@ }; }; + # Only newer nixpkgs have have timeout args for all wait_for_.* fns. + # Use the generic wait_until_succeeds w/ timeout arg until nixpkgs is bumped. mkScriptTest = env: '' machine.systemctl("start cardano-node-${env}") machine.wait_until_succeeds("[ -S /var/lib/cardano-node-${env}/node.socket ]", timeout=${timeout}) diff --git a/nix/nixos/tests/cardano-node-edge.nix b/nix/nixos/tests/cardano-node-edge.nix index 8202dad1c99..06a974687f7 100644 --- a/nix/nixos/tests/cardano-node-edge.nix +++ b/nix/nixos/tests/cardano-node-edge.nix @@ -1,65 +1,68 @@ -{ pkgs, ... }: -with pkgs; -{ +{pkgs, ...}: +with pkgs; let + environment = "mainnet"; + + # NixosTest script fns supporting a timeout have a default of 900 seconds. + timeout = toString 30; +in { name = "cardano-node-edge-test"; nodes = { - machine = { config, ... }: { + machine = {config, ...}: { nixpkgs.pkgs = pkgs; imports = [ ../. ]; - services.cardano-node = { - enable = true; - port = 3001; - hostAddr = "127.0.0.1"; - environment = "mainnet"; - topology = commonLib.mkEdgeTopologyP2P { - edgeNodes = [ - { - addr = "127.0.0.1"; - port = 3001; - } - ]; + + services = { + cardano-node = { + inherit environment; + + enable = true; + port = 3001; + hostAddr = "127.0.0.1"; + topology = commonLib.mkEdgeTopologyP2P { + edgeNodes = [ + { + addr = "127.0.0.1"; + port = 3001; + } + ]; + }; + + # Default tracing system logging is to stdout and default prometheus + # metrics are exported to localhost on port 12798. + nodeConfig = config.services.cardano-node.environments.${environment}.nodeConfig; }; - nodeConfig = config.services.cardano-node.environments.${config.services.cardano-node.environment}.nodeConfig // { - hasPrometheus = [ config.services.cardano-node.hostAddr 12798 ]; - # Use Journald output: - setupScribes = [{ - scKind = "JournalSK"; - scName = "cardano"; - scFormat = "ScText"; - }]; - defaultScribes = [ - [ - "JournalSK" - "cardano" - ] - ]; + + cardano-submit-api = { + enable = true; + port = 8101; + network = environment; + socketPath = config.services.cardano-node.socketPath 0; }; }; - systemd.services.cardano-node.serviceConfig.Restart = lib.mkForce "no"; - services.cardano-submit-api = { - enable = true; - port = 8101; - network = "mainnet"; - socketPath = config.services.cardano-node.socketPath 0; + + systemd.services = { + cardano-node.serviceConfig.Restart = lib.mkForce "no"; + cardano-submit-api.serviceConfig.SupplementaryGroups = "cardano-node"; }; - systemd.services.cardano-submit-api.serviceConfig.SupplementaryGroups = "cardano-node"; }; }; + + # Only newer nixpkgs have have timeout args for all wait_for_.* fns. + # Use the generic wait_until_succeeds w/ timeout arg until nixpkgs is bumped. testScript = '' start_all() - machine.wait_for_unit("cardano-node.service") - machine.wait_for_file("/run/cardano-node/node.socket") - machine.wait_for_open_port(12798) - machine.wait_for_open_port(3001) + machine.wait_for_unit("cardano-node.service", timeout=${timeout}) + machine.wait_until_succeeds("[ -S /run/cardano-node/node.socket ]", timeout=${timeout}) + machine.wait_until_succeeds("nc -z localhost 12798", timeout=${timeout}) + machine.wait_until_succeeds("nc -z localhost 3001", timeout=${timeout}) machine.succeed("systemctl status cardano-node") - # FIXME reenable and check the cli syntax when https://github.com/intersectmbo/cardano-node/pull/4664 is merged - #machine.succeed( - # "${cardanoNodePackages.cardano-cli}/bin/cardano-cli ping -h 127.0.0.1 -c 1 -q --json | ${jq}/bin/jq -c" - #) - machine.wait_for_open_port(8101) + out = machine.succeed( + "${cardanoNodePackages.cardano-cli}/bin/cardano-cli ping -h 127.0.0.1 -c 1 -q --json | ${jq}/bin/jq -c" + ) + print("ping:", out) + machine.wait_until_succeeds("nc -z localhost 8101", timeout=${timeout}) machine.succeed("systemctl status cardano-submit-api") ''; - } diff --git a/nix/pkgs.nix b/nix/pkgs.nix index cedd315e413..6f7993ce225 100644 --- a/nix/pkgs.nix +++ b/nix/pkgs.nix @@ -1,7 +1,8 @@ -# our packages overlay +# Our packages overlay final: prev: let + inherit (builtins) foldl' fromJSON listToAttrs map readFile; inherit (final) pkgs; inherit (prev.pkgs) lib; inherit (prev) customConfig; @@ -45,7 +46,7 @@ in with final; index-state = "2024-12-24T12:56:48Z"; }; - # The ghc-hls point release compatibility table is documented at + # The ghc-hls point release compatibility table is documented at: # https://haskell-language-server.readthedocs.io/en/latest/support/ghc-version-support.html haskell-language-server = haskell-nix.tool compiler-nix-name "haskell-language-server" rec { src = { @@ -58,7 +59,7 @@ in with final; ghc964 = haskell-nix.sources."hls-2.6"; ghc981 = haskell-nix.sources."hls-2.6"; }.${compiler-nix-name} or haskell-nix.sources."hls-2.10"; - cabalProject = builtins.readFile (src + "/cabal.project"); + cabalProject = readFile (src + "/cabal.project"); sha256map."https://github.com/pepeiborra/ekg-json"."7a0af7a8fd38045fd15fb13445bdcc7085325460" = "sha256-fVwKxGgM0S4Kv/4egVAAiAjV7QB5PBqMVMCfsv7otIQ="; }; @@ -81,8 +82,11 @@ in with final; cardanolib-py = callPackage ./cardanolib-py { }; - scripts = lib.recursiveUpdate (import ./scripts.nix { inherit pkgs; }) - (import ./scripts-submit-api.nix { inherit pkgs; }); + scripts = foldl' lib.recursiveUpdate {} [ + (import ./scripts.nix { inherit pkgs; }) + (import ./scripts-submit-api.nix { inherit pkgs; }) + (import ./scripts-tracer.nix { inherit pkgs; }) + ]; clusterTests = import ./workbench/tests { inherit pkgs; }; @@ -119,12 +123,35 @@ in with final; script = "submit-api"; }; + tracerDockerImage = + let + defaultConfig = rec { + acceptingSocket = "/ipc/tracer.socket"; + stateDir = "/logs"; + logging = [ + { + logRoot = stateDir; + logMode = "FileMode"; + logFormat = "ForHuman"; + } + ]; + }; + in + callPackage ./docker/tracer.nix { + exe = "cardano-tracer"; + scripts = import ./scripts-tracer.nix { + inherit pkgs; + customConfigs = [ defaultConfig customConfig ]; + }; + script = "tracer"; + }; + all-profiles-json = workbench.profile-names-json; # The profile data and backend data of the cloud / "*-nomadperf" profiles. # Useful to mix workbench and cardano-node commits, mostly because of scripts. - profile-data-nomadperf = builtins.listToAttrs ( - builtins.map + profile-data-nomadperf = listToAttrs ( + map (cloudName: # Only Conway era cloud profiles are flake outputs. let profileName = "${cloudName}-coay"; @@ -163,7 +190,7 @@ in with final; } ) # Fetch all "*-nomadperf" profiles. - (__fromJSON (__readFile + (fromJSON (readFile (pkgs.runCommand "cardano-profile-names-cloud-noera" {} '' ${cardanoNodePackages.cardano-profile}/bin/cardano-profile names-cloud-noera > $out '' diff --git a/nix/scripts-submit-api.nix b/nix/scripts-submit-api.nix index 7a549fa8673..3e24c7104f7 100644 --- a/nix/scripts-submit-api.nix +++ b/nix/scripts-submit-api.nix @@ -25,9 +25,8 @@ let passthru = { inherit service; }; }; - # Until complete removal of some iohk-nix deprecated environments which have - # dangling dependencies such as shelley_qa, explicitly declare the - # environments we we want included. + # Allow list envs we specifically want scripts for as others in iohk-nix may + # be transient test networks. environments' = pkgs.lib.getAttrs [ "mainnet" "preprod" "preview" ] environments; scripts = forEnvironmentsCustom (environment: recurseIntoAttrs { diff --git a/nix/scripts-tracer.nix b/nix/scripts-tracer.nix new file mode 100644 index 00000000000..513fbec8822 --- /dev/null +++ b/nix/scripts-tracer.nix @@ -0,0 +1,45 @@ +{ pkgs +, customConfigs ? [ pkgs.customConfig ] +}: +with pkgs.commonLib; +let + mkScript = envConfig: let + service = evalService { + inherit pkgs customConfigs; + serviceName = "cardano-tracer"; + modules = [ + ./nixos/cardano-tracer-service.nix + ({config, ...}: let cfg = config.services.cardano-tracer; in { + services.cardano-tracer = rec { + environment = mkDefault envConfig.name; + stateDir = mkDefault "state-tracer-${cfg.environment}"; + runtimeDir = mkDefault null; + logging = mkDefault [ + { + logRoot = stateDir; + logMode = "FileMode"; + logFormat = "ForHuman"; + } + ]; + }; + }) + ]; + }; + scriptBin = pkgs.writeScriptBin "cardano-tracer-${service.environment}" '' + #!${pkgs.runtimeShell} + export PATH=$PATH:${makeBinPath [ pkgs.coreutils ]} + set -euo pipefail + mkdir -p "$(dirname "${service.acceptingSocket or service.connectToSocket}")" + ${service.script} $@ + ''; + in scriptBin // { + exePath = "${scriptBin}/bin/cardano-tracer-${service.environment}"; + }; + + # Allow list envs we specifically want scripts for as others in iohk-nix may + # be transient test networks. + environments' = pkgs.lib.getAttrs [ "mainnet" "preprod" "preview" ] environments; + +in forEnvironmentsCustom (environment: recurseIntoAttrs { + tracer = mkScript environment; +}) environments' diff --git a/nix/scripts.nix b/nix/scripts.nix index 9188f04c200..421d09f6530 100644 --- a/nix/scripts.nix +++ b/nix/scripts.nix @@ -33,11 +33,10 @@ let exePath = "${scriptBin}/bin/cardano-node-${service.environment}"; }; - # Until complete removal of some iohk-nix deprecated environments which have - # dangling dependencies such as shelley_qa, explicitly declare the - # environments we we want included. + # Allow list envs we specifically want scripts for as others in iohk-nix may + # be transient test networks. environments' = pkgs.lib.getAttrs [ "mainnet" "preprod" "preview" ] environments; -in forEnvironmentsCustom (environment: recurseIntoAttrs rec { +in forEnvironmentsCustom (environment: recurseIntoAttrs { node = mkScript environment; }) environments' diff --git a/nix/workbench/service/tracer.nix b/nix/workbench/service/tracer.nix index 86c666c92bf..5d84268145b 100644 --- a/nix/workbench/service/tracer.nix +++ b/nix/workbench/service/tracer.nix @@ -8,6 +8,9 @@ with pkgs.lib; let + # For testing the transition from cardano-tracer-service-workbench to + # cardano-tracer-service. + useWorkbenchTracerService = true; ## Given an env config, evaluate it and produce the service. ## @@ -17,17 +20,12 @@ let let tracerConfig = { + enable = true; ## In both the local and remote scenarios, it's most frequently ## convenient to act as an acceptor. acceptingSocket = "tracer.socket"; networkMagic = profile.genesis.network_magic; - dsmPassthrough = { - # rtsOpts = ["-xc"]; - } // optionalAttrs (profile.tracer.withresources or false) { - rtsOpts = [ "-scardano-tracer.gcstats" ]; - }; configFile = "config.json"; - logRoot = "."; metricsHelp = "../../../cardano-tracer/configuration/metrics_help.json"; } // optionalAttrs backend.useCabalRun { executable = "cardano-tracer"; @@ -38,6 +36,25 @@ let }; } // optionalAttrs (profile.tracer.withresources or false) { resourceFreq = 1000; + } // optionalAttrs useWorkbenchTracerService { + dsmPassthrough = { + # rtsOpts = ["-xc"]; + } // optionalAttrs (profile.tracer.withresources or false) { + rtsOpts = [ "-scardano-tracer.gcstats" ]; + }; + logRoot = "."; + } // optionalAttrs (!useWorkbenchTracerService) { + logging = [ + { + logRoot = "."; + logMode = "FileMode"; + logFormat = "ForMachine"; + } + ]; + rtsArgs = + # ["-xc"] ++ + optionals (profile.tracer.withresources or false) ["-scardano-tracer.gcstats"]; + stateDir = null; } ; systemdCompat.options = { @@ -47,27 +64,25 @@ let assertions = mkOption {}; environment = mkOption {}; }; - eval = - let - extra = { - services.cardano-tracer = { - enable = true; - } // tracerConfig; - }; - in evalModules { - prefix = []; - modules = import ../../nixos/module-list.nix - ++ [ - (import ../../nixos/cardano-tracer-service.nix pkgs) - systemdCompat - extra - { config._module.args = { inherit pkgs; }; } - ] - ++ [ backend.service-modules.tracer or {} ] + eval = evalModules { + prefix = []; + + modules = [ + (import ../../nixos/cardano-node-service.nix) + (import ../../nixos/cardano-submit-api-service.nix) + { config._module.args = { inherit pkgs; }; } + { services.cardano-tracer = tracerConfig; } + systemdCompat + ] + ++ [ backend.service-modules.tracer or {} ] + ++ optionals useWorkbenchTracerService + [ (import ../../nixos/cardano-tracer-service-workbench.nix pkgs) ] + ++ optionals (!useWorkbenchTracerService) + [ (import ../../nixos/cardano-tracer-service.nix) ] ; - # args = { inherit pkgs; }; - } - ; + + # args = { inherit pkgs; }; + }; in eval.config.services.cardano-tracer; @@ -78,7 +93,9 @@ let (nodeSpecs: let nixosServiceConfig = tracerConfigServiceConfig; - execConfig = nixosServiceConfig.configJSONfn nixosServiceConfig; + execConfig = if useWorkbenchTracerService + then nixosServiceConfig.configJSONfn nixosServiceConfig + else nixosServiceConfig.tracerConfig; in { start = '' diff --git a/scripts/lite/mainnet-new-tracing.sh b/scripts/lite/mainnet-legacy-tracing.sh similarity index 83% rename from scripts/lite/mainnet-new-tracing.sh rename to scripts/lite/mainnet-legacy-tracing.sh index edf95dcb429..3fbe4b3d2ae 100755 --- a/scripts/lite/mainnet-new-tracing.sh +++ b/scripts/lite/mainnet-legacy-tracing.sh @@ -14,11 +14,10 @@ mkdir -p "${socket_dir}" # Launch a node cabal run exe:cardano-node -- run \ - --config "${configuration}/mainnet-config-new-tracing.json" \ + --config "${configuration}/mainnet-config-legacy.json" \ --topology "${configuration}/mainnet-topology.json" \ --database-path "${db_dir}" \ --socket-path "${socket_dir}/node-1-socket" \ - --tracer-socket-path-connect "${socket_dir}/tracer.socket" \ --host-addr "0.0.0.0" \ --port "3001" diff --git a/scripts/lite/mainnet.sh b/scripts/lite/mainnet.sh index ef93f734b55..f7c1af884ae 100755 --- a/scripts/lite/mainnet.sh +++ b/scripts/lite/mainnet.sh @@ -18,6 +18,7 @@ cabal run exe:cardano-node -- run \ --topology "${configuration}/mainnet-topology.json" \ --database-path "${db_dir}" \ --socket-path "${socket_dir}/node-1-socket" \ + --tracer-socket-path-connect "${socket_dir}/tracer.socket" \ --host-addr "0.0.0.0" \ --port "3001"