lol

nixos/victoriatraces: init service module

Add service module for VictoriaTraces, following the same patterns
as the existing victorialogs and victoriametrics modules.

+312
+1
nixos/modules/module-list.nix
··· 540 540 ./services/databases/tigerbeetle.nix 541 541 ./services/databases/victorialogs.nix 542 542 ./services/databases/victoriametrics.nix 543 + ./services/databases/victoriatraces.nix 543 544 ./services/desktops/accountsservice.nix 544 545 ./services/desktops/ayatana-indicators.nix 545 546 ./services/desktops/bamf.nix
+173
nixos/modules/services/databases/victoriatraces.nix
··· 1 + { 2 + config, 3 + pkgs, 4 + lib, 5 + utils, 6 + ... 7 + }: 8 + let 9 + inherit (lib) 10 + escapeShellArgs 11 + getBin 12 + hasPrefix 13 + literalExpression 14 + mkBefore 15 + mkEnableOption 16 + mkIf 17 + mkOption 18 + mkPackageOption 19 + optionalString 20 + types 21 + ; 22 + cfg = config.services.victoriatraces; 23 + startCLIList = [ 24 + "${cfg.package}/bin/victoria-traces" 25 + "-storageDataPath=/var/lib/${cfg.stateDir}" 26 + "-httpListenAddr=${cfg.listenAddress}" 27 + ] 28 + ++ lib.optionals (cfg.basicAuthUsername != null) [ 29 + "-httpAuth.username=${cfg.basicAuthUsername}" 30 + ] 31 + ++ lib.optionals (cfg.basicAuthPasswordFile != null) [ 32 + "-httpAuth.password=file://%d/basic_auth_password" 33 + ]; 34 + in 35 + { 36 + options.services.victoriatraces = { 37 + enable = mkEnableOption "VictoriaTraces is an open source distributed traces storage and query engine from VictoriaMetrics"; 38 + package = mkPackageOption pkgs "victoriatraces" { }; 39 + listenAddress = mkOption { 40 + default = ":10428"; 41 + type = types.str; 42 + description = '' 43 + TCP address to listen for incoming http requests. 44 + ''; 45 + }; 46 + stateDir = mkOption { 47 + type = types.str; 48 + default = "victoriatraces"; 49 + description = '' 50 + Directory below `/var/lib` to store VictoriaTraces data. 51 + This directory will be created automatically using systemd's StateDirectory mechanism. 52 + ''; 53 + }; 54 + retentionPeriod = mkOption { 55 + type = types.str; 56 + default = "7d"; 57 + example = "30d"; 58 + description = '' 59 + Retention period for trace data. Data older than retentionPeriod is automatically deleted. 60 + ''; 61 + }; 62 + basicAuthUsername = lib.mkOption { 63 + default = null; 64 + type = lib.types.nullOr lib.types.str; 65 + description = '' 66 + Basic Auth username used to protect VictoriaTraces instance by authorization 67 + ''; 68 + }; 69 + 70 + basicAuthPasswordFile = lib.mkOption { 71 + default = null; 72 + type = lib.types.nullOr lib.types.str; 73 + description = '' 74 + File that contains the Basic Auth password used to protect VictoriaTraces instance by authorization 75 + ''; 76 + }; 77 + extraOptions = mkOption { 78 + type = types.listOf types.str; 79 + default = [ ]; 80 + example = literalExpression '' 81 + [ 82 + "-loggerLevel=WARN" 83 + "-retention.maxDiskSpaceUsageBytes=1073741824" 84 + ] 85 + ''; 86 + description = '' 87 + Extra options to pass to VictoriaTraces. See {command}`victoria-traces -help` for 88 + possible options. 89 + ''; 90 + }; 91 + }; 92 + config = mkIf cfg.enable { 93 + 94 + assertions = [ 95 + { 96 + assertion = 97 + (cfg.basicAuthUsername == null && cfg.basicAuthPasswordFile == null) 98 + || (cfg.basicAuthUsername != null && cfg.basicAuthPasswordFile != null); 99 + message = "Both basicAuthUsername and basicAuthPasswordFile must be set together to enable basicAuth functionality, or neither should be set."; 100 + } 101 + ]; 102 + 103 + systemd.services.victoriatraces = { 104 + description = "VictoriaTraces distributed traces database"; 105 + wantedBy = [ "multi-user.target" ]; 106 + after = [ "network.target" ]; 107 + startLimitBurst = 5; 108 + 109 + serviceConfig = { 110 + ExecStart = lib.concatStringsSep " " [ 111 + (escapeShellArgs (startCLIList ++ [ "-retentionPeriod=${cfg.retentionPeriod}" ])) 112 + (utils.escapeSystemdExecArgs cfg.extraOptions) 113 + ]; 114 + DynamicUser = true; 115 + LoadCredential = lib.optional ( 116 + cfg.basicAuthPasswordFile != null 117 + ) "basic_auth_password:${cfg.basicAuthPasswordFile}"; 118 + RestartSec = 1; 119 + Restart = "on-failure"; 120 + RuntimeDirectory = "victoriatraces"; 121 + RuntimeDirectoryMode = "0700"; 122 + StateDirectory = cfg.stateDir; 123 + StateDirectoryMode = "0700"; 124 + 125 + # Increase the limit to avoid errors like 'too many open files' when handling many trace spans 126 + LimitNOFILE = 1048576; 127 + 128 + # Hardening 129 + DeviceAllow = [ "/dev/null rw" ]; 130 + DevicePolicy = "strict"; 131 + LockPersonality = true; 132 + MemoryDenyWriteExecute = true; 133 + NoNewPrivileges = true; 134 + PrivateDevices = true; 135 + PrivateTmp = true; 136 + PrivateUsers = true; 137 + ProtectClock = true; 138 + ProtectControlGroups = true; 139 + ProtectHome = true; 140 + ProtectHostname = true; 141 + ProtectKernelLogs = true; 142 + ProtectKernelModules = true; 143 + ProtectKernelTunables = true; 144 + ProtectProc = "invisible"; 145 + ProtectSystem = "full"; 146 + RemoveIPC = true; 147 + RestrictAddressFamilies = [ 148 + "AF_INET" 149 + "AF_INET6" 150 + "AF_UNIX" 151 + ]; 152 + RestrictNamespaces = true; 153 + RestrictRealtime = true; 154 + RestrictSUIDSGID = true; 155 + SystemCallArchitectures = "native"; 156 + SystemCallFilter = [ 157 + "@system-service" 158 + "~@privileged" 159 + ]; 160 + }; 161 + 162 + postStart = 163 + let 164 + bindAddr = (optionalString (hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress; 165 + in 166 + mkBefore '' 167 + until ${getBin pkgs.curl}/bin/curl -s -o /dev/null http://${bindAddr}/ping; do 168 + sleep 1; 169 + done 170 + ''; 171 + }; 172 + }; 173 + }
+1
nixos/tests/all-tests.nix
··· 1581 1581 vengi-tools = runTest ./vengi-tools.nix; 1582 1582 victorialogs = import ./victorialogs { inherit runTest; }; 1583 1583 victoriametrics = import ./victoriametrics { inherit runTest; }; 1584 + victoriatraces = import ./victoriatraces { inherit runTest; }; 1584 1585 vikunja = runTest ./vikunja.nix; 1585 1586 virtualbox = handleTestOn [ "x86_64-linux" ] ./virtualbox.nix { }; 1586 1587 vm-variant = handleTest ./vm-variant.nix { };
+5
nixos/tests/victoriatraces/default.nix
··· 1 + { runTest }: 2 + { 3 + service-endpoints = runTest ./service-endpoints.nix; 4 + otlp-ingestion = runTest ./otlp-ingestion.nix; 5 + }
+96
nixos/tests/victoriatraces/otlp-ingestion.nix
··· 1 + { lib, pkgs, ... }: 2 + let 3 + # Simple protobuf trace 4 + traceGenerator = pkgs.writeScriptBin "trace-generator" '' 5 + #!${ 6 + pkgs.python3.withPackages ( 7 + ps: with ps; [ 8 + requests 9 + protobuf 10 + opentelemetry-proto 11 + opentelemetry-api 12 + opentelemetry-sdk 13 + opentelemetry-exporter-otlp-proto-http 14 + ] 15 + ) 16 + }/bin/python3 17 + 18 + import time 19 + from opentelemetry import trace 20 + from opentelemetry.sdk.trace import TracerProvider 21 + from opentelemetry.sdk.trace.export import BatchSpanProcessor 22 + from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter 23 + from opentelemetry.sdk.resources import Resource 24 + 25 + resource = Resource.create({ 26 + "service.name": "test-service", 27 + "service.version": "1.0.0" 28 + }) 29 + 30 + provider = TracerProvider(resource=resource) 31 + 32 + otlp_exporter = OTLPSpanExporter( 33 + endpoint="http://localhost:10428/insert/opentelemetry/v1/traces", 34 + headers={}, 35 + ) 36 + 37 + provider.add_span_processor(BatchSpanProcessor(otlp_exporter)) 38 + trace.set_tracer_provider(provider) 39 + 40 + tracer = trace.get_tracer("test-tracer", "1.0.0") 41 + 42 + # Test span 43 + with tracer.start_as_current_span("test-span") as span: 44 + span.set_attribute("http.method", "GET") 45 + span.set_attribute("http.url", "/test") 46 + time.sleep(0.1) 47 + 48 + provider.force_flush() 49 + 50 + print("Test trace sent") 51 + ''; 52 + in 53 + { 54 + name = "victoriatraces-otlp-ingestion"; 55 + meta.maintainers = with lib.maintainers; [ cmacrae ]; 56 + 57 + nodes.machine = 58 + { pkgs, ... }: 59 + { 60 + services.victoriatraces = { 61 + enable = true; 62 + retentionPeriod = "1d"; 63 + }; 64 + 65 + environment.systemPackages = with pkgs; [ 66 + curl 67 + jq 68 + traceGenerator 69 + ]; 70 + }; 71 + 72 + testScript = '' 73 + machine.wait_for_unit("victoriatraces.service") 74 + machine.wait_for_open_port(10428) 75 + machine.succeed("curl --fail http://localhost:10428/") 76 + machine.succeed("trace-generator") 77 + 78 + # Wait for trace to be indexed 79 + machine.wait_until_succeeds(""" 80 + curl -s 'http://localhost:10428/select/jaeger/api/services' | \ 81 + jq -e '.data[] | select(. == "test-service")' 82 + """, timeout=10) 83 + 84 + # Query for traces from our test service 85 + machine.succeed(""" 86 + curl -s 'http://localhost:10428/select/jaeger/api/traces?service=test-service' | \ 87 + jq -e '.data[0].spans[0].operationName' | grep -q 'test-span' 88 + """) 89 + 90 + # Verify the trace has the expected attributes 91 + machine.succeed(""" 92 + curl -s 'http://localhost:10428/select/jaeger/api/traces?service=test-service' | \ 93 + jq -e '.data[0].spans[0].tags[] | select(.key == "http.method") | .value == "GET"' 94 + """) 95 + ''; 96 + }
+36
nixos/tests/victoriatraces/service-endpoints.nix
··· 1 + { lib, ... }: 2 + { 3 + name = "victoriatraces-service-endpoints"; 4 + meta.maintainers = with lib.maintainers; [ cmacrae ]; 5 + 6 + nodes.machine = 7 + { pkgs, ... }: 8 + { 9 + services.victoriatraces = { 10 + enable = true; 11 + extraOptions = [ 12 + "-loggerLevel=WARN" 13 + ]; 14 + }; 15 + 16 + environment.systemPackages = with pkgs; [ 17 + curl 18 + jq 19 + ]; 20 + }; 21 + 22 + testScript = '' 23 + machine.wait_for_unit("victoriatraces.service") 24 + machine.wait_for_open_port(10428) 25 + 26 + with subtest("Service endpoints are accessible"): 27 + machine.succeed("curl --fail http://localhost:10428/") 28 + machine.succeed("curl --fail http://localhost:10428/select/vmui") 29 + machine.succeed("curl --fail http://localhost:10428/metrics | grep -E '^(vm_|process_)'") 30 + machine.succeed("curl --fail http://localhost:10428/select/jaeger/api/services") 31 + 32 + with subtest("OTLP trace ingestion endpoint accepts requests"): 33 + machine.succeed("curl --fail -X POST http://localhost:10428/insert/opentelemetry/v1/traces -H 'Content-Type: application/x-protobuf'") 34 + machine.succeed("test -d /var/lib/victoriatraces") 35 + ''; 36 + }