From c2438526018277af027ffc42993c72e0a057f2ce Mon Sep 17 00:00:00 2001 From: pazpi Date: Sun, 25 Aug 2024 15:44:51 +0200 Subject: [PATCH] WIP: New module for handling podman pod Handles basic container, needs to be expanded to all options --- modules/virtualisation/podman-pod.nix | 170 ++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 modules/virtualisation/podman-pod.nix diff --git a/modules/virtualisation/podman-pod.nix b/modules/virtualisation/podman-pod.nix new file mode 100644 index 0000000..814a7d7 --- /dev/null +++ b/modules/virtualisation/podman-pod.nix @@ -0,0 +1,170 @@ +# Save this as podman-pod.nix +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.podmanPods; + + podOptions = { name, config, ... }: { + options = { + name = mkOption { + type = types.str; + description = "Name of the pod"; + }; + ports = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "List of port mappings (e.g. ['8080:80'])"; + }; + containers = mkOption { + type = types.attrsOf (types.submodule { + options = { + image = mkOption { + type = types.str; + description = "Docker image for the container"; + }; + extraOptions = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Additional options for the container"; + }; + }; + }); + default = { }; + description = "Containers to run in the pod"; + }; + }; + }; + + createPodScript = name: podDef: + let + podDefinitionString = builtins.toJSON { inherit (podDef) ports; }; + in + pkgs.writeScript "manage-pod-${name}.sh" '' + #!/usr/bin/env nix-shell + #!nix-shell -i bash -p htop curl + + set -e + + POD_NAME="${name}" + POD_DEFINITION='${podDefinitionString}' + + create_pod() { + podman pod create --name "$POD_NAME" \ + ${concatStringsSep " " (map (port: "--publish ${port}") podDef.ports)} + } + + if podman pod exists "$POD_NAME"; then + CURRENT_CONFIG=$(podman pod inspect "$POD_NAME" | jq -c '.[0] | {ports: [.PortMappings[].HostPort | tostring + ":" + (.ContainerPort | tostring)]}') + if [ "$CURRENT_CONFIG" != "$POD_DEFINITION" ]; then + echo "Pod configuration has changed. Recreating pod..." + podman pod rm -f "$POD_NAME" + create_pod + else + echo "Pod configuration unchanged." + fi + else + echo "Pod does not exist. Creating..." + create_pod + fi + ''; +in +{ + options.services.podmanPods = mkOption { + type = types.attrsOf (types.submodule podOptions); + default = { }; + description = "Podman pods to create"; + }; + + config = mkIf (cfg != { }) { + virtualisation.podman.enable = true; + virtualisation.oci-containers.backend = "podman"; + + environment.systemPackages = [ pkgs.jq ]; + + systemd.services = mapAttrs' + (name: podDef: + nameValuePair "podman-pod-${name}" { + description = "Manage Podman pod: ${name}"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${createPodScript name podDef}"; + }; + path = [ pkgs.podman ]; + wantedBy = [ "multi-user.target" ]; + } + ) + cfg // + mapAttrs' + (podName: podDef: + nameValuePair "podman-pod-${podName}" { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + } + ) + cfg // + mapAttrs' + (podName: podDef: + nameValuePair "podman-${podName}" { + after = [ "podman-pod-${podName}.service" ]; + requires = [ "podman-pod-${podName}.service" ]; + partOf = [ "podman-pod-${podName}.service" ]; + } + ) + (flattenAttrs (mapAttrsToList + (podName: podDef: + mapAttrs' + (containerName: containerDef: + nameValuePair "${podName}-${containerName}" containerDef + ) + podDef.containers + ) + cfg)); + + virtualisation.oci-containers.containers = flatten (mapAttrsToList + (podName: podDef: + mapAttrsToList + (containerName: containerDef: + nameValuePair "${podName}-${containerName}" ({ + inherit (containerDef) image; + extraOptions = [ "--pod=${podName}" ] ++ containerDef.extraOptions; + }) + ) + podDef.containers + ) + cfg); + + networking.firewall.allowedTCPPorts = flatten (mapAttrsToList + (name: podDef: + map (portMapping: lib.toInt (lib.head (lib.splitString ":" portMapping))) podDef.ports + ) + cfg); + + # systemd.services = mapAttrs' + # (podName: podDef: + # nameValuePair "podman-pod-${podName}" { + # after = [ "network.target" ]; + # wantedBy = [ "multi-user.target" ]; + # } + # ) + # cfg // + # mapAttrs' + # (podName: podDef: + # nameValuePair "podman-${podName}" { + # after = [ "podman-pod-${podName}.service" ]; + # requires = [ "podman-pod-${podName}.service" ]; + # partOf = [ "podman-pod-${podName}.service" ]; + # } + # ) + # (flattenAttrs (mapAttrsToList + # (podName: podDef: + # mapAttrs' + # (containerName: containerDef: + # nameValuePair "${podName}-${containerName}" containerDef + # ) + # podDef.containers + # ) + # cfg)); + }; +}