From 4fa3a8b55184b29fa01cf40cfd214e9707046e18 Mon Sep 17 00:00:00 2001 From: m3tam3re Date: Sat, 4 Oct 2025 17:03:46 +0200 Subject: [PATCH] +lib +portshelper --- QUICKSTART.md | 50 +++++++++++ README.md | 80 +++++++++++++++++ examples/ports-example.nix | 180 +++++++++++++++++++++++++++++++++++++ flake.nix | 8 ++ lib/default.nix | 12 +++ lib/ports.nix | 113 +++++++++++++++++++++++ 6 files changed, 443 insertions(+) create mode 100644 examples/ports-example.nix create mode 100644 lib/default.nix create mode 100644 lib/ports.nix diff --git a/QUICKSTART.md b/QUICKSTART.md index 583974b..f4c01c2 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -125,6 +125,56 @@ When working on your system configuration: } ``` +### 6. Use Library Functions + +The repository includes helper functions for common configuration tasks. + +#### Port Management Example + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs"; + }; + + outputs = {nixpkgs, m3ta-nixpkgs, ...}: { + nixosConfigurations.laptop = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = {inherit inputs; system = "x86_64-linux";}; + modules = [ + ({inputs, system, config, ...}: let + # Import the library + m3taLib = inputs.m3ta-nixpkgs.lib.${system}; + + # Define all your ports centrally + myPorts = { + ports = { + nginx = 80; + grafana = 3000; + prometheus = 9090; + }; + hostPorts = { + laptop = {nginx = 8080;}; # Override on laptop + }; + }; + + # Create port helpers + ports = m3taLib.ports.mkPortHelpers myPorts; + hostname = config.networking.hostName; + in { + # Use in configuration + services.nginx.defaultHTTPListenPort = ports.getPort "nginx" hostname; + services.grafana.settings.server.http_port = ports.getPort "grafana" hostname; + }) + ]; + }; + }; +} +``` + +See `examples/ports-example.nix` for more examples and `lib/README.md` for full documentation. + ## Available Packages | Package | Description | Command | diff --git a/README.md b/README.md index bab8fee..e2d1008 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ My personal Nix repository containing custom packages, overlays, NixOS modules, - 🔄 **Overlays**: Package modifications and enhancements - ⚙️ **NixOS Modules**: System-level configuration modules - 🏠 **Home Manager Modules**: User-level configuration modules +- 📚 **Library Functions**: Helper utilities for configuration management - ❄️ **Flakes Only**: Modern Nix flakes support (no channels) ## Repository Structure @@ -35,6 +36,11 @@ m3ta-nixpkgs/ │ └── home-manager/ # Home Manager modules │ ├── default.nix │ └── zellij-ps.nix +├── lib/ # Library functions +│ ├── default.nix # Library entry point +│ └── ports.nix # Port management utilities +├── examples/ # Usage examples +│ └── ports-example.nix └── templates/ # Templates for new packages/modules ``` @@ -233,6 +239,80 @@ homeManagerModules = { }; ``` +### Using Library Functions + +The repository includes helper functions to simplify common configuration tasks. + +#### Port Management + +Centrally manage service ports across multiple hosts with automatic host-specific overrides: + +```nix +# In your flake.nix or configuration +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs"; + }; + + outputs = { self, nixpkgs, m3ta-nixpkgs, ... }: { + nixosConfigurations.laptop = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { inherit inputs; system = "x86_64-linux"; }; + modules = [ + ({ inputs, system, config, ... }: let + # Import the library + m3taLib = inputs.m3ta-nixpkgs.lib.${system}; + + # Define all ports in one place + myPorts = { + ports = { + nginx = 80; + grafana = 3000; + prometheus = 9090; + }; + hostPorts = { + laptop = { + nginx = 8080; # Non-privileged port on laptop + }; + }; + }; + + # Create helper functions + ports = m3taLib.ports.mkPortHelpers myPorts; + hostname = config.networking.hostName; + in { + # Use in your configuration + services.nginx.defaultHTTPListenPort = ports.getPort "nginx" hostname; + services.grafana.settings.server.http_port = ports.getPort "grafana" hostname; + + # Get all ports for current host + environment.etc."service-ports.json".text = + builtins.toJSON (ports.getHostPorts hostname); + }) + ]; + }; + }; +} +``` + +**Benefits:** + +- Single source of truth for all port assignments +- Automatic host-specific overrides (laptop, server, VM, etc.) +- Works across both NixOS and Home Manager configurations +- Easy to see and manage all ports in one place + +**Available Functions:** + +- `mkPortHelpers`: Create port helper functions from a configuration +- `getPort`: Get port for a service with optional host override +- `getHostPorts`: Get all ports for a specific host (merged defaults + overrides) +- `getDefaultPort`: Get default port without host override +- `listServices`: List all defined service names + +See `examples/ports-example.nix` for comprehensive usage examples. + ## Available Packages | Package | Description | diff --git a/examples/ports-example.nix b/examples/ports-example.nix new file mode 100644 index 0000000..aa91b0c --- /dev/null +++ b/examples/ports-example.nix @@ -0,0 +1,180 @@ +# Example: Using the port management library +# +# This example demonstrates how to use the m3ta-nixpkgs port management +# utilities to centralize port configuration across multiple hosts. +{ + inputs, + system, + ... +}: let + # Import the library + m3taLib = inputs.m3ta-nixpkgs.lib.${system}; + + # Define all your ports in one central place + # This makes it easy to see and manage all port assignments + myPortsConfig = { + # Default ports for all services + ports = { + # Web services + nginx = 80; + nginx-ssl = 443; + homepage = 8080; + grafana = 3000; + + # Monitoring + prometheus = 9090; + node-exporter = 9100; + loki = 3100; + + # Development + dev-server = 8000; + dev-api = 8001; + + # Media + jellyfin = 8096; + transmission = 9091; + + # Other services + ssh = 22; + gitea = 3001; + }; + + # Host-specific overrides + # Use this when you need different ports on different machines + hostPorts = { + # On the laptop, run nginx on unprivileged port + laptop = { + nginx = 8080; + nginx-ssl = 8443; + }; + + # On the server, override specific services + server = { + homepage = 3002; + dev-server = 3003; + }; + + # On a VM, use different ports to avoid conflicts + vm = { + nginx = 8888; + grafana = 4000; + prometheus = 9999; + }; + }; + }; + + # Create the port helper functions + ports = m3taLib.ports.mkPortHelpers myPortsConfig; + + # You can also get your hostname dynamically + # hostname = config.networking.hostName; + hostname = "laptop"; # or "server" or "vm" +in { + # ============================================================================ + # Example 1: Using in NixOS configuration + # ============================================================================ + + # Simple usage: get port for current host + services.nginx.defaultHTTPListenPort = ports.getPort "nginx" hostname; + services.nginx.defaultSSLListenPort = ports.getPort "nginx-ssl" hostname; + + services.grafana.settings.server.http_port = ports.getPort "grafana" hostname; + services.prometheus.port = ports.getPort "prometheus" hostname; + + # Without host override (uses default port) + services.openssh.ports = [(ports.getPort "ssh" null)]; + + # Or use getDefaultPort helper for cleaner syntax + services.gitea.settings.server.HTTP_PORT = + m3taLib.ports.getDefaultPort myPortsConfig "gitea"; + + # ============================================================================ + # Example 2: Using in Home Manager configuration + # ============================================================================ + + # Configure development environment with correct ports + home.sessionVariables = { + DEV_SERVER_PORT = toString (ports.getPort "dev-server" hostname); + DEV_API_PORT = toString (ports.getPort "dev-api" hostname); + }; + + # ============================================================================ + # Example 3: Advanced usage - get all ports for current host + # ============================================================================ + + # Get merged view of all ports (defaults + host overrides) + environment.etc."service-ports.json".text = + builtins.toJSON (ports.getHostPorts hostname); + + # This creates a file at /etc/service-ports.json containing: + # { + # "nginx": 8080, // overridden on laptop + # "nginx-ssl": 8443, // overridden on laptop + # "homepage": 8080, // default + # "grafana": 3000, // default + # ... + # } + + # ============================================================================ + # Example 4: Using in systemd services + # ============================================================================ + + systemd.services.my-custom-service = { + description = "My Custom Service"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + + environment = { + PORT = toString (ports.getPort "homepage" hostname); + }; + + serviceConfig = { + ExecStart = "/path/to/service --port ${toString (ports.getPort "homepage" hostname)}"; + }; + }; + + # ============================================================================ + # Example 5: Conditional configuration based on host + # ============================================================================ + + # You can use the same port config across all your machines + # and they'll automatically use the right ports + services.jellyfin = { + enable = true; + # Will use 8096 on all hosts (no override defined) + }; + + # ============================================================================ + # Example 6: List all configured services + # ============================================================================ + + # Useful for debugging or documentation + environment.etc."configured-services.txt".text = + builtins.concatStringsSep "\n" ports.listServices; + + # ============================================================================ + # Example 7: Using in a flake-based configuration + # ============================================================================ + + # In your flake.nix: + # + # { + # inputs = { + # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs"; + # }; + # + # outputs = { self, nixpkgs, m3ta-nixpkgs, ... }: { + # nixosConfigurations.laptop = nixpkgs.lib.nixosSystem { + # system = "x86_64-linux"; + # specialArgs = { + # inherit inputs system; + # }; + # modules = [ + # ./configuration.nix + # ./ports-config.nix # Import this example file + # ]; + # }; + # }; + # } +} diff --git a/flake.nix b/flake.nix index 72af6ef..581e83d 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,14 @@ # Add more individual modules as you create them }; + # Library functions - helper utilities for your configuration + lib = forAllSystems ( + system: let + pkgs = pkgsFor system; + in + import ./lib {lib = pkgs.lib;} + ); + # Development shell for working on this repository devShells = forAllSystems ( system: let diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..e6deac0 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,12 @@ +# Library of helper functions for m3ta-nixpkgs +# Usage in your configuration: +# let +# m3taLib = inputs.m3ta-nixpkgs.lib.${system}; +# in ... +{lib}: { + # Port management utilities + ports = import ./ports.nix {inherit lib;}; + + # Add more helper modules here as needed + # example = import ./example.nix { inherit lib; }; +} diff --git a/lib/ports.nix b/lib/ports.nix new file mode 100644 index 0000000..91b9c89 --- /dev/null +++ b/lib/ports.nix @@ -0,0 +1,113 @@ +# Port management utilities +# +# This module provides functions to manage service ports across multiple hosts +# in a centralized way. Ports are defined in your configuration and can have +# host-specific overrides. +# +# Usage in your configuration: +# +# # In your flake or configuration, define your ports: +# let +# m3taLib = inputs.m3ta-nixpkgs.lib.${system}; +# +# myPorts = { +# ports = { +# nginx = 80; +# grafana = 3000; +# prometheus = 9090; +# homepage = 8080; +# }; +# hostPorts = { +# laptop = { +# nginx = 8080; # Override nginx port on laptop +# }; +# server = { +# homepage = 3001; # Override homepage port on server +# }; +# }; +# }; +# +# portHelpers = m3taLib.ports.mkPortHelpers myPorts; +# in { +# # Use in your config: +# services.nginx.port = portHelpers.getPort "nginx" "laptop"; +# # Returns: 8080 (host-specific override) +# +# services.grafana.port = portHelpers.getPort "grafana" "laptop"; +# # Returns: 3000 (default port) +# +# # Get all ports for a specific host (defaults + overrides): +# allLaptopPorts = portHelpers.getHostPorts "laptop"; +# # Returns: { nginx = 8080; grafana = 3000; prometheus = 9090; homepage = 8080; } +# } +{lib}: { + # Create port helper functions from a ports configuration + # + # Args: + # portsConfig: An attribute set with structure: + # { + # ports = { service-name = port-number; ... }; + # hostPorts = { hostname = { service-name = port-number; ... }; ... }; + # } + # + # Returns: + # An attribute set containing helper functions: + # - getPort: Get port for a service with optional host override + # - getHostPorts: Get all ports for a specific host + # - listServices: List all defined services + mkPortHelpers = portsConfig: let + ports = portsConfig.ports or {}; + hostPorts = portsConfig.hostPorts or {}; + in { + # Get port for a service, with optional host-specific override + # + # Args: + # service: The service name (string) + # host: The hostname (string) + # + # Returns: + # Port number (int) or null if service not found + # + # Example: + # getPort "nginx" "laptop" # Returns host-specific port if defined + # getPort "nginx" null # Returns default port + getPort = service: host: + if host != null && hostPorts ? ${host} && hostPorts.${host} ? ${service} + then hostPorts.${host}.${service} + else ports.${service} or null; + + # Get all ports for a specific host (merges defaults with host overrides) + # + # Args: + # host: The hostname (string) + # + # Returns: + # Attribute set of all ports for the host + # + # Example: + # getHostPorts "laptop" # { nginx = 8080; grafana = 3000; ... } + getHostPorts = host: + ports // (hostPorts.${host} or {}); + + # List all defined service names + # + # Returns: + # List of service names (strings) + listServices = lib.attrNames ports; + }; + + # Simple helper to get a port without host override + # Useful when you don't need host-specific ports + # + # Args: + # portsConfig: Same structure as mkPortHelpers + # service: The service name (string) + # + # Returns: + # Port number (int) or null if service not found + # + # Example: + # getDefaultPort myPorts "nginx" # Returns default port only + getDefaultPort = portsConfig: service: + portsConfig.ports.${service} or null; +}