port module simplified

This commit is contained in:
m3tam3re
2025-10-05 12:37:57 +02:00
parent 62a85af9bc
commit 735c22cf36
4 changed files with 42 additions and 421 deletions

View File

@@ -42,11 +42,8 @@ m3ta-nixpkgs/
│ ├── default.nix # Library entry point │ ├── default.nix # Library entry point
│ └── ports.nix # Port management utilities │ └── ports.nix # Port management utilities
├── examples/ # Usage examples ├── examples/ # Usage examples
── ports/ # Port management examples ── home-manager-standalone.nix
├── README.md └── nixos-configuration.nix
│ ├── nixos-example.nix
│ ├── home-manager-example.nix
│ └── flake-example.nix
└── templates/ # Templates for new packages/modules └── templates/ # Templates for new packages/modules
``` ```
@@ -391,14 +388,15 @@ For advanced use cases, you can use the underlying library functions without the
### Documentation ### Documentation
See comprehensive examples and documentation: See library documentation:
- `examples/ports/README.md` - Complete guide with all features
- `examples/ports/nixos-example.nix` - Full NixOS configuration example
- `examples/ports/home-manager-example.nix` - Full Home Manager configuration example
- `examples/ports/flake-example.nix` - Complete multi-host flake setup
- `lib/ports.nix` - Library source code with inline documentation - `lib/ports.nix` - Library source code with inline documentation
Example configurations:
- `examples/nixos-configuration.nix` - NixOS configuration example
- `examples/home-manager-standalone.nix` - Home Manager configuration example
## Available Packages ## Available Packages
| Package | Description | | Package | Description |
@@ -417,4 +415,4 @@ Individual packages may have their own licenses. Check each package's `meta.lice
## Maintainer ## Maintainer
[@m3tam3re](https://github.com/m3tam3re) [@m3tam3re](https://m3ta.dev)

View File

@@ -1,180 +0,0 @@
# 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
# ];
# };
# };
# }
}

View File

@@ -55,10 +55,8 @@
with lib; let with lib; let
cfg = config.m3ta.ports; cfg = config.m3ta.ports;
# Import the ports library
portsLib = import ../../lib/ports.nix {inherit lib;}; portsLib = import ../../lib/ports.nix {inherit lib;};
# Create port helpers from the configuration
portHelpers = portHelpers =
if cfg.enable if cfg.enable
then then
@@ -74,168 +72,71 @@ in {
definitions = mkOption { definitions = mkOption {
type = types.attrsOf types.port; type = types.attrsOf types.port;
default = {}; default = {};
example = literalExpression '' description = "Default port definitions for user services.";
{
vscodium = 8080;
jupyter = 8888;
dev-server = 3000;
local-api = 8000;
}
'';
description = ''
Default port definitions for user services.
These ports will be used unless overridden by host-specific settings.
'';
}; };
hostOverrides = mkOption { hostOverrides = mkOption {
type = types.attrsOf (types.attrsOf types.port); type = types.attrsOf (types.attrsOf types.port);
default = {}; default = {};
example = literalExpression '' description = "Host-specific port overrides.";
{
laptop = {
dev-server = 3001;
vscodium = 8081;
};
desktop = {
jupyter = 9999;
};
}
'';
description = ''
Host-specific port overrides.
Keys are hostnames, values are attribute sets of service-name to port mappings.
'';
}; };
currentHost = mkOption { currentHost = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "laptop"; description = "Hostname to use for port resolution.";
description = ''
The current hostname to use for port resolution.
Set to null to disable host-specific overrides.
Note: In Home Manager, you may need to set this manually unless
you pass config.networking.hostName from your NixOS configuration.
'';
}; };
# Computed option - provides access to port helpers # Internal computed options
get = mkOption { get = mkOption {
type = types.functionTo types.port; type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get a port for a service.
Automatically uses the current host for overrides.
'';
}; };
getForHost = mkOption { getForHost = mkOption {
type = types.functionTo (types.functionTo types.port); type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get a port for a service on a specific host.
Usage: config.m3ta.ports.getForHost "hostname" "service"
'';
}; };
all = mkOption { all = mkOption {
type = types.attrsOf types.port; type = types.attrsOf types.port;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
All ports for the current host (defaults merged with overrides).
'';
}; };
allForHost = mkOption { allForHost = mkOption {
type = types.functionTo (types.attrsOf types.port); type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get all ports for a specific host.
Usage: config.m3ta.ports.allForHost "hostname"
'';
}; };
services = mkOption { services = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
List of all defined service names.
'';
}; };
# Convenience option for generating shell variables # Env var generation
generateEnvVars = mkOption { generateEnvVars = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
example = true; description = "Generate environment variables for all ports.";
description = ''
Whether to automatically generate environment variables for all ports.
Variables will be named as: PORT_<SERVICE_NAME> (uppercase, dashes to underscores).
Example: service "dev-server" becomes PORT_DEV_SERVER
'';
}; };
envVarPrefix = mkOption { envVarPrefix = mkOption {
type = types.str; type = types.str;
default = "PORT_"; default = "PORT_";
example = "MY_APP_PORT_"; description = "Prefix for generated environment variables.";
description = ''
Prefix for generated environment variables when generateEnvVars is enabled.
'';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost;
{ m3ta.ports.getForHost = host: service: portHelpers.getPort service host;
assertion = cfg.definitions != {}; m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost;
message = "m3ta.ports.definitions must not be empty when m3ta.ports.enable is true"; m3ta.ports.allForHost = portHelpers.getHostPorts;
} m3ta.ports.services = portHelpers.listServices;
];
m3ta.ports = {
# Function to get port for current host
get = service:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions";
portHelpers.getPort service cfg.currentHost;
# Function to get port for specific host
getForHost = host: service:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions";
portHelpers.getPort service host;
# All ports for current host
all =
if portHelpers != null
then portHelpers.getHostPorts cfg.currentHost
else {};
# Function to get all ports for specific host
allForHost = host:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
portHelpers.getHostPorts host;
# List all services
services =
if portHelpers != null
then portHelpers.listServices
else [];
};
# Optional: Automatically generate environment variables for all ports
home.sessionVariables = mkIf cfg.generateEnvVars ( home.sessionVariables = mkIf cfg.generateEnvVars (
let let
# Convert service name to env var name: "dev-server" -> "DEV_SERVER"
toEnvVarName = service: toEnvVarName = service:
cfg.envVarPrefix + (lib.toUpper (builtins.replaceStrings ["-"] ["_"] service)); cfg.envVarPrefix + (lib.toUpper (builtins.replaceStrings ["-"] ["_"] service));
in in
@@ -248,14 +149,11 @@ in {
) )
); );
# Create a JSON file with all ports for easy inspection home.file.".config/m3ta/ports.json".text = builtins.toJSON {
home.file.".config/m3ta/ports.json" = {
text = builtins.toJSON {
hostname = cfg.currentHost; hostname = cfg.currentHost;
ports = cfg.all; ports = cfg.all;
allDefinitions = cfg.definitions; allDefinitions = cfg.definitions;
hostOverrides = cfg.hostOverrides; hostOverrides = cfg.hostOverrides;
}; };
}; };
};
} }

View File

@@ -45,16 +45,13 @@
{ {
config, config,
lib, lib,
pkgs,
... ...
}: }:
with lib; let with lib; let
cfg = config.m3ta.ports; cfg = config.m3ta.ports;
# Import the ports library
portsLib = import ../../lib/ports.nix {inherit lib;}; portsLib = import ../../lib/ports.nix {inherit lib;};
# Create port helpers from the configuration
portHelpers = portHelpers =
if cfg.enable if cfg.enable
then then
@@ -70,150 +67,58 @@ in {
definitions = mkOption { definitions = mkOption {
type = types.attrsOf types.port; type = types.attrsOf types.port;
default = {}; default = {};
example = literalExpression '' description = "Default port definitions for services.";
{
nginx = 80;
grafana = 3000;
prometheus = 9090;
ssh = 22;
}
'';
description = ''
Default port definitions for services.
These ports will be used unless overridden by host-specific settings.
'';
}; };
hostOverrides = mkOption { hostOverrides = mkOption {
type = types.attrsOf (types.attrsOf types.port); type = types.attrsOf (types.attrsOf types.port);
default = {}; default = {};
example = literalExpression '' description = "Host-specific port overrides.";
{
laptop = {
nginx = 8080;
ssh = 2222;
};
server = {
nginx = 443;
};
}
'';
description = ''
Host-specific port overrides.
Keys are hostnames, values are attribute sets of service-name to port mappings.
'';
}; };
currentHost = mkOption { currentHost = mkOption {
type = types.nullOr types.str; type = types.str;
default = config.networking.hostName; default = config.networking.hostName;
defaultText = literalExpression "config.networking.hostName"; description = "Hostname to use for port resolution.";
example = "laptop";
description = ''
The current hostname to use for port resolution.
Defaults to the system's hostname.
Set to null to disable host-specific overrides.
'';
}; };
# Computed option - provides access to port helpers # Internal computed options
get = mkOption { get = mkOption {
type = types.functionTo types.port; type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get a port for a service.
Automatically uses the current host for overrides.
'';
}; };
getForHost = mkOption { getForHost = mkOption {
type = types.functionTo (types.functionTo types.port); type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get a port for a service on a specific host.
Usage: config.m3ta.ports.getForHost "hostname" "service"
'';
}; };
all = mkOption { all = mkOption {
type = types.attrsOf types.port; type = types.attrsOf types.port;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
All ports for the current host (defaults merged with overrides).
'';
}; };
allForHost = mkOption { allForHost = mkOption {
type = types.functionTo (types.attrsOf types.port); type = types.raw;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
Function to get all ports for a specific host.
Usage: config.m3ta.ports.allForHost "hostname"
'';
}; };
services = mkOption { services = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
readOnly = true; readOnly = true;
internal = true; internal = true;
description = ''
List of all defined service names.
'';
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost;
{ m3ta.ports.getForHost = host: service: portHelpers.getPort service host;
assertion = cfg.definitions != {}; m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost;
message = "m3ta.ports.definitions must not be empty when m3ta.ports.enable is true"; m3ta.ports.allForHost = portHelpers.getHostPorts;
} m3ta.ports.services = portHelpers.listServices;
];
m3ta.ports = {
# Function to get port for current host
get = service:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions";
portHelpers.getPort service cfg.currentHost;
# Function to get port for specific host
getForHost = host: service:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions";
portHelpers.getPort service host;
# All ports for current host
all =
if portHelpers != null
then portHelpers.getHostPorts cfg.currentHost
else {};
# Function to get all ports for specific host
allForHost = host:
assert assertMsg (portHelpers != null) "Port helpers not initialized";
portHelpers.getHostPorts host;
# List all services
services =
if portHelpers != null
then portHelpers.listServices
else [];
};
# Optional: Create a JSON file with all ports for easy inspection
environment.etc."m3ta/ports.json" = mkIf cfg.enable {
text = builtins.toJSON {
hostname = cfg.currentHost;
ports = cfg.all;
allDefinitions = cfg.definitions;
hostOverrides = cfg.hostOverrides;
};
mode = "0444";
};
}; };
} }