interfaces: { name, lib, pkgs, config, ... }: let cfg = config; in with lib; { options = { deployement = { targetHost = mkOption { type = types.str; }; cmd = mkOption { type = types.package; readOnly = true; }; }; vlans = let range_type.options = { begin = mkOption { type = types.ints.unsigned; }; end = mkOption { type = types.ints.unsigned; }; }; vlan_type.options = { ids = mkOption { type = types.either types.ints.unsigned (types.listOf (types.either types.ints.unsigned (types.submodule range_type))); default = [ ]; }; management = mkOption { # FIXME : support ipv4, either static or dhcp (with the coffee) type = types.nullOr types.str; default = null; description = '' IP address with wich to permit management on this vlan. Only one vlan can set an IP (this module limitation, not switch). ''; }; }; in mkOption { type = types.attrsOf (types.submodule vlan_type); }; interfaces = let template = name: { enable = mkEnableOption "the interface ${name}"; interface-mode = mkOption { type = types.nullOr (types.enum [ "trunk" "access" ]); default = null; }; vlans = mkOption { type = let vlan_type = types.either (types.strMatching "[^\n\r]+") (types.ints.unsigned); in types.listOf vlan_type; default = [ ]; }; # TODO: use this option dhcp_trusted = mkOption { type = types.bool; default = false; }; management = mkOption { # FIXME : support ipv6, either static or dhcp (with the coffee) type = types.nullOr types.str; default = null; }; }; in builtins.listToAttrs (map (name: { inherit name; value = template name; }) interfaces); }; config.deployement.cmd = let intf_xmlGen = name: let disable_flag = if !cfg.interfaces.${name}.enable then "" else ""; # FIXME : need to enforce address in reality mgmt_fam = if !builtins.isNull cfg.interfaces.${name}.management then ''
${cfg.interfaces.${name}.management}
'' else ""; members = map (vlan: "${builtins.toString vlan}") cfg.interfaces.${name}.vlans; eth_switch = if builtins.isNull cfg.interfaces.${name}.interface-mode then "" else '' ${cfg.interfaces.${name}.interface-mode} ${builtins.concatStringsSep "" members} default ''; in '' ${name} ${disable_flag} 0 ${mgmt_fam} ${eth_switch} ''; interface_xmls = map intf_xmlGen interfaces; rstp_gen = name: if cfg.interfaces.${name}.enable && !builtins.isNull cfg.interfaces.${name}.interface-mode then "${name}" else ""; rstps = map rstp_gen interfaces; vlan_trust_table = let vlan_map = inter: vlan: if builtins.isString vlan && cfg.interfaces.${inter}.enable then if cfg.interfaces.${inter}.dhcp_trusted then { ${vlan}.trust = inter; } else { ${vlan}.notrust = inter; } else {}; int_map = inter: map (vlan_map inter) cfg.interfaces.${inter}.vlans; in builtins.zipAttrsWith (vlan: values: builtins.zipAttrsWith (_: ints: ints ) values) (builtins.concatMap int_map interfaces); vlans = let id_map = id: let list = if builtins.isInt id then builtins.toString id else "${builtins.toString id.begin}-${builtins.toString id.end}"; in ''${list}''; vlan_map = vlan: let ids = if !builtins.isList cfg.vlans.${vlan}.ids then [ "${builtins.toString cfg.vlans.${vlan}.ids}" ] else map id_map cfg.vlans.${vlan}.ids; mgmt_flag = if !builtins.isNull cfg.vlans.${vlan}.management then "irb.0" else ""; in '' ${vlan} ${mgmt_flag} ${builtins.concatStringsSep "\n" ids} ''; in map vlan_map (builtins.attrNames cfg.vlans); irb_intf = let addresses = map (vlan: vlan.management) (builtins.attrValues cfg.vlans); addr = builtins.foldl' (acc: addr: if !builtins.isNull addr then addr else acc) null addresses; in if !builtins.isNull addr then '' irb 0
${addr}
'' else ""; config = '' ${builtins.concatStringsSep "\n" interface_xmls} ${irb_intf} ${builtins.concatStringsSep "\n" rstps} ${builtins.concatStringsSep "\n" vlans} ''; rpc_requests = pkgs.writeText "config-${name}_rpc.xml" '' ${config} ''; in pkgs.writeShellScript "deploy-${name}.sh" '' ${pkgs.openssh}/bin/ssh ${cfg.deployement.targetHost} -p 830 -s netconf < ${rpc_requests} '' ; }