From 5d32574fb90a453b1c5a768d2c6ba2167f2ce478 Mon Sep 17 00:00:00 2001 From: catvayor Date: Fri, 13 Dec 2024 16:03:36 +0100 Subject: [PATCH] broken! feat(xml)!: use xml generator --- default.nix | 33 +++++++--------- junos/default.nix | 16 ++------ junos/interfaces.nix | 93 +++++++++++++++++++------------------------- junos/poe.nix | 29 ++++++-------- junos/protocols.nix | 21 ++-------- junos/system.nix | 54 ++++++++++++------------- junos/vlans.nix | 46 +++++++++------------- npins/default.nix | 81 ++++++++++++++++++++++++++++++++++++++ npins/sources.json | 22 +++++++++++ 9 files changed, 221 insertions(+), 174 deletions(-) create mode 100644 npins/default.nix create mode 100644 npins/sources.json diff --git a/default.nix b/default.nix index cb246cc..60e3505 100644 --- a/default.nix +++ b/default.nix @@ -1,13 +1,13 @@ -{ - pkgs ? (import { }), -}: let + sources = import ./npins; + pkgs = import sources.kat-pkgs { }; lib = pkgs.lib; hive_mod = { lib, config, name, + xml, ... }: let @@ -32,21 +32,17 @@ let }; }; config.deployment = rec { - rpc = pkgs.writeText "config-${name}_rpc.xml" '' - - - - ${config.netconf.xmls.configuration} - - - - - - - - - - ''; + rpc = xml.generate "config-${name}_rpc.xml" { + rpc = [ + { + edit-config = { + config.configuration = config.netconf.xml; + target.candidate = ""; + }; + } + { commit = { }; } + ]; + }; cmd = pkgs.writeShellApplication { name = "deploy-${name}.sh"; runtimeInputs = with pkgs; [ openssh ]; @@ -60,6 +56,7 @@ let cfg = pkgs.lib.evalModules { specialArgs = { inherit name; + xml = pkgs.formats.xml { }; }; modules = [ ./junos diff --git a/junos/default.nix b/junos/default.nix index a00e805..e776f59 100644 --- a/junos/default.nix +++ b/junos/default.nix @@ -1,6 +1,7 @@ { lib, config, + xml, ... }: let @@ -10,7 +11,6 @@ let ; inherit (lib.types) bool - str attrsOf submodule ; @@ -33,9 +33,8 @@ in ./system.nix ]; options = { - netconf.xmls.configuration = mkOption { - type = str; - readOnly = true; + netconf.xml = mkOption { + type = xml.type; description = '' The full configuration to send to a JunOS. ''; @@ -65,13 +64,4 @@ in mkIntf = _: _: { }; in mapAttrs mkIntf config.netconf.mandatoryInterfaces; - config.netconf.xmls.configuration = '' - - ${config.netconf.xmls.system} - ${config.netconf.xmls.interfaces} - ${config.netconf.xmls.protocols} - ${config.netconf.xmls.vlans} - ${config.netconf.xmls.poe} - - ''; } diff --git a/junos/interfaces.nix b/junos/interfaces.nix index 31ddc72..3fb719f 100644 --- a/junos/interfaces.nix +++ b/junos/interfaces.nix @@ -1,10 +1,17 @@ -{ lib, config, ... }: +{ + lib, + config, + xml, + ... +}: let inherit (lib) mkEnableOption mkOption optionalString mapAttrsToList + mkMerge + mkIf ; inherit (lib.types) enum @@ -19,7 +26,6 @@ let interface = { name, config, ... }: let - intf-name = name; unit = { name, config, ... }: { @@ -74,46 +80,36 @@ let }; }; xml = mkOption { - type = str; + type = xml.type; visible = false; readOnly = true; }; }; config.xml = let - members = map ( - vlan: "${builtins.toString vlan}" - ) config.family.ethernet-switching.vlans; - eth = optionalString config.family.ethernet-switching.enable '' - - ${config.family.ethernet-switching.interface-mode} - ${builtins.concatStringsSep "" members} - default - - ''; + eth = mkIf config.family.ethernet-switching.enable { + family.ethernet-switching = { + interface-mode = config.family.ethernet-switching.interface-mode; + vlan.members = map toString config.family.ethernet-switching.vlans; + storm-control.profile-name = "default"; + }; + }; - addr4 = map (addr: "${addr}") config.family.inet.addresses; - inet = optionalString config.family.inet.enable '' - -
${builtins.concatStringsSep "" addr4}
-
- ''; + addr4 = map (name: { inherit name; }) config.family.inet.addresses; + inet = mkIf config.family.inet.enable { family.inet.address = addr4; }; - addr6 = map (addr: "${addr}") config.family.inet6.addresses; - inet6 = optionalString config.family.inet6.enable '' - -
${builtins.concatStringsSep "" addr6}
-
- ''; + addr6 = map (name: { inherit name; }) config.family.inet6.addresses; + inet6 = mkIf config.family.inet6.enable { family.inet6.address = addr6; }; in - '' - - ${name} - ${optionalString (!config.enable) ""} - - ${eth}${inet}${inet6} - - ''; + mkMerge [ + { + inherit name; + } + (mkIf (!config.enable) { disable = { }; }) + eth + inet + inet6 + ]; }; in { @@ -127,22 +123,21 @@ let ''; }; xml = mkOption { - type = str; + type = xml.type; visible = false; readOnly = true; }; }; config.xml = let - units = mapAttrsToList (_: unit: unit.xml) config.unit; + unit = mapAttrsToList (_: unit: unit.xml) config.unit; in - '' - - ${name} - ${optionalString (!config.enable) ""} - ${builtins.concatStringsSep "" units} - - ''; + mkMerge [ + { + inherit name unit; + } + (mkIf (!config.enable) { disable = { }; }) + ]; }; in { @@ -153,15 +148,9 @@ in The interfaces configuration. ''; }; - netconf.xmls.interfaces = mkOption { - type = str; - visible = false; - readOnly = true; - }; }; - config.netconf.xmls.interfaces = '' - - ${builtins.concatStringsSep "" (mapAttrsToList (_: intf: intf.xml) config.interfaces)} - - ''; + config.netconf.xml.interfaces = { + "@operation" = "replace"; + interface = mapAttrsToList (_: intf: intf.xml) config.interfaces; + }; } diff --git a/junos/poe.nix b/junos/poe.nix index 36124dd..c05c2c3 100644 --- a/junos/poe.nix +++ b/junos/poe.nix @@ -1,13 +1,13 @@ -{ lib, config, ... }: +{ lib, config, xml, ... }: let inherit (lib) mkOption mkEnableOption mapAttrsToList - optionalString + mkIf + mkMerge ; inherit (lib.types) - str attrsOf submodule ; @@ -18,14 +18,15 @@ let options = { enable = mkEnableOption "the PoE for this interface"; xml = mkOption { - type = str; + type = xml.type; visible = false; readOnly = true; }; }; - config.xml = '' - ${name}${optionalString (!config.enable) ""} - ''; + config.xml = mkMerge [ + { inherit name; } + (mkIf (!config.enable) { disable = { }; }) + ]; }; in { @@ -37,15 +38,9 @@ in PoE configuration of interfaces. ''; }; - netconf.xmls.poe = mkOption { - type = str; - visible = false; - readOnly = true; - }; }; - config.netconf.xmls.poe = '' - - ${builtins.concatStringsSep "" (mapAttrsToList (_: intf: intf.xml) config.poe.interfaces)} - - ''; + config.netconf.xml.poe = { + "@operation" = "replace"; + interface = mapAttrsToList (_: intf: intf.xml) config.poe.interfaces; + }; } diff --git a/junos/protocols.nix b/junos/protocols.nix index 33e82fd..11306af 100644 --- a/junos/protocols.nix +++ b/junos/protocols.nix @@ -2,7 +2,6 @@ let inherit (lib) mkOption - concatStringsSep ; inherit (lib.types) listOf @@ -17,21 +16,9 @@ in List of interfaces on which Rapid Spanning Tree Protocol should be enabled. ''; }; - netconf.xmls.protocols = mkOption { - type = str; - visible = false; - readOnly = true; - }; }; - config.netconf.xmls.protocols = - let - rstps = map (intf: "${intf}") config.protocols.rstp; - in - '' - - - ${concatStringsSep "" rstps} - - - ''; + config.netconf.xml.protocols.rstp = { + "@operation" = "replace"; + interface = map (name: { inherit name; }) config.protocols.rstp; + }; } diff --git a/junos/system.nix b/junos/system.nix index 492f243..dc6036a 100644 --- a/junos/system.nix +++ b/junos/system.nix @@ -6,7 +6,6 @@ let length hasPrefix filter - concatStrings concatStringsSep ; inherit (lib.types) @@ -50,39 +49,34 @@ in }; }; }; - netconf.xmls.system = mkOption { - type = str; - visible = false; - readOnly = true; - }; }; - config.netconf.xmls.system = + config.netconf.xml.system = let ssh-keys1 = map (splitString " ") config.system.root-authentication.ssh-keys; ssh-keys2 = map (key: if length key < 3 then key ++ [ "foo@bar" ] else key) ssh-keys1; ssh-keys = map (concatStringsSep " ") ssh-keys2; - edsca = map (key: "${key}") ( - filter (hasPrefix "ssh-edsca ") ssh-keys - ); - rsa = map (key: "${key}") (filter (hasPrefix "ssh-rsa ") ssh-keys); - ed25519 = map (key: "${key}") ( - filter (hasPrefix "ssh-ed25519 ") ssh-keys - ); + ssh-edsca = map (name: { inherit name; }) (filter (hasPrefix "ssh-edsca ") ssh-keys); + ssh-rsa = map (name: { inherit name; }) (filter (hasPrefix "ssh-rsa ") ssh-keys); + ssh-ed25519 = map (name: { inherit name; }) (filter (hasPrefix "ssh-ed25519 ") ssh-keys); in - '' - - ${config.system.host-name} - - ${config.system.root-authentication.hashedPasswd} - ${concatStrings (edsca ++ rsa ++ ed25519)} - - - ${config.system.services.ssh.root-login} - - ${toString config.system.services.netconf.port} - - - - - ''; + { + host-name = { + "@operation" = "replace"; + "#text" = config.system.host-name; + }; + root-authentication = { + "@operation" = "replace"; + encrypted-password = config.system.root-authentication.hashedPasswd; + inherit ssh-edsca ssh-rsa ssh-ed25519; + }; + services = { + "@operation" = "replace"; + ssh.root-login = config.system.services.ssh.root-login; + netconf = { + ssh.port = config.system.services.netconf.port; + rfc-compliant = {}; + yang-compliant = {}; + }; + }; + }; } diff --git a/junos/vlans.nix b/junos/vlans.nix index a129cc4..69a1a49 100644 --- a/junos/vlans.nix +++ b/junos/vlans.nix @@ -1,11 +1,11 @@ -{ lib, config, ... }: +{ lib, config, xml, ... }: let inherit (lib) mkOption - optionalString assertMsg - concatStringsSep mapAttrsToList + mkMerge + mkIf ; inherit (lib.types) nullOr @@ -80,30 +80,28 @@ let ''; }; xml = mkOption { - type = str; + type = xml.type; readOnly = true; visible = false; }; }; config.xml = let - id = optionalString (!isNull config.id) "${toString config.id}"; - id-list = concatStringsSep "" ( - map (vlan: "${toString vlan}") config.id-list - ); - l3-intf = optionalString ( - !isNull config.l3-interface - ) "${config.l3-interface}"; + id = mkIf (!isNull config.id) { vlan-id = toString config.id; }; + id-list = mkIf (config.id-list != [ ]) { + vlan-id-list = map toString config.id-list; + }; + l3-intf = mkIf (!isNull config.l3-interface) { inherit (config) l3-interface; }; in assert assertMsg ( config.id == null || config.id-list == [ ] ) "vlans.${name}.id and vlans.${name}.id-list are incompatible."; - '' - - ${name} - ${id}${id-list}${l3-intf} - - ''; + mkMerge [ + { inherit name; } + id + id-list + l3-intf + ]; }; in { @@ -115,15 +113,9 @@ in instead of just using their IDs. ''; }; - netconf.xmls.vlans = mkOption { - type = str; - visible = false; - readOnly = true; - }; }; - config.netconf.xmls.vlans = '' - - ${builtins.concatStringsSep "" (mapAttrsToList (_: vlan: vlan.xml) config.vlans)} - - ''; + config.netconf.xml.vlans = { + "@operation" = "replace"; + vlan = mapAttrsToList (_: vlan: vlan.xml) config.vlans; + }; } diff --git a/npins/default.nix b/npins/default.nix new file mode 100644 index 0000000..d256a27 --- /dev/null +++ b/npins/default.nix @@ -0,0 +1,81 @@ +# Generated by npins. Do not modify; will be overwritten regularly +let + data = builtins.fromJSON (builtins.readFile ./sources.json); + version = data.version; + + mkSource = + spec: + assert spec ? type; + let + path = + if spec.type == "Git" then + mkGitSource spec + else if spec.type == "GitRelease" then + mkGitSource spec + else if spec.type == "PyPi" then + mkPyPiSource spec + else if spec.type == "Channel" then + mkChannelSource spec + else + builtins.throw "Unknown source type ${spec.type}"; + in + spec // { outPath = path; }; + + mkGitSource = + { + repository, + revision, + url ? null, + hash, + branch ? null, + ... + }: + assert repository ? type; + # At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository + # In the latter case, there we will always be an url to the tarball + if url != null then + (builtins.fetchTarball { + inherit url; + sha256 = hash; # FIXME: check nix version & use SRI hashes + }) + else + assert repository.type == "Git"; + let + urlToName = + url: rev: + let + matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url; + + short = builtins.substring 0 7 rev; + + appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else ""; + in + "${if matched == null then "source" else builtins.head matched}${appendShort}"; + name = urlToName repository.url revision; + in + builtins.fetchGit { + url = repository.url; + rev = revision; + inherit name; + allRefs = true; + # hash = hash; + }; + + mkPyPiSource = + { url, hash, ... }: + builtins.fetchurl { + inherit url; + sha256 = hash; + }; + + mkChannelSource = + { url, hash, ... }: + builtins.fetchTarball { + inherit url; + sha256 = hash; + }; +in +if version == 3 then + builtins.mapAttrs (_: mkSource) data.pins +else + throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`" diff --git a/npins/sources.json b/npins/sources.json new file mode 100644 index 0000000..f26cbe7 --- /dev/null +++ b/npins/sources.json @@ -0,0 +1,22 @@ +{ + "pins": { + "kat-pkgs": { + "type": "Git", + "repository": { + "type": "Git", + "url": "https://git.dgnum.eu/lbailly/kat-pkgs.git" + }, + "branch": "master", + "revision": "191cb1dacb273078455b86006941386642681644", + "url": null, + "hash": "14rwcg92mnyb0azac27v05k72lm62pgl43cqj0np711sssjkmhv1" + }, + "nixpkgs": { + "type": "Channel", + "name": "nixpkgs-unstable", + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre720687.5a48e3c2e435/nixexprs.tar.xz", + "hash": "06g8b0ga935dnziyzhxznwcx1vb2clc84hcxwrcqb26lgjgwsgbf" + } + }, + "version": 3 +} \ No newline at end of file