feat(lib): Init netconf-junos
The code is copied from netconf-module, `with lib;` have been replaced by inherits
This commit is contained in:
parent
1980d3c34e
commit
318f6927c1
6 changed files with 546 additions and 0 deletions
74
lib/netconf-junos/default.nix
Normal file
74
lib/netconf-junos/default.nix
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mapAttrs mkOption;
|
||||||
|
|
||||||
|
inherit (lib.types)
|
||||||
|
attrsOf
|
||||||
|
bool
|
||||||
|
str
|
||||||
|
submodule
|
||||||
|
;
|
||||||
|
|
||||||
|
mandatory.options = {
|
||||||
|
supportPoE = mkOption {
|
||||||
|
type = bool;
|
||||||
|
example = true;
|
||||||
|
description = ''
|
||||||
|
Wether this interface supports PoE.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./interfaces.nix
|
||||||
|
./poe.nix
|
||||||
|
./protocols.nix
|
||||||
|
./system.nix
|
||||||
|
./vlans.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options = {
|
||||||
|
netconf.xmls.configuration = mkOption {
|
||||||
|
type = str;
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
The full configuration to send to a JunOS.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
netconf.mandatoryInterfaces = mkOption {
|
||||||
|
type = attrsOf (submodule mandatory);
|
||||||
|
example = {
|
||||||
|
"ge-0/0/0" = {
|
||||||
|
supportPoE = true;
|
||||||
|
};
|
||||||
|
"ge-0/0/1" = {
|
||||||
|
supportPoE = true;
|
||||||
|
};
|
||||||
|
"xe-0/0/0" = {
|
||||||
|
supportPoE = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
JunOS require some interfaces to always be configured (even if they are disabled),
|
||||||
|
which correspond to physical interfaces of the switch. They have to be declared here
|
||||||
|
with some information about it (only if it supports PoE for now).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.interfaces =
|
||||||
|
let
|
||||||
|
mkIntf = _: _: { };
|
||||||
|
in
|
||||||
|
mapAttrs mkIntf config.netconf.mandatoryInterfaces;
|
||||||
|
config.netconf.xmls.configuration = with config.netconf.xmls; ''
|
||||||
|
<configuration>
|
||||||
|
${system}
|
||||||
|
${interfaces}
|
||||||
|
${protocols}
|
||||||
|
${vlans}
|
||||||
|
${poe}
|
||||||
|
</configuration>
|
||||||
|
'';
|
||||||
|
}
|
168
lib/netconf-junos/interfaces.nix
Normal file
168
lib/netconf-junos/interfaces.nix
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mapAttrsToList
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
optionalString
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.types)
|
||||||
|
attrsOf
|
||||||
|
either
|
||||||
|
enum
|
||||||
|
ints
|
||||||
|
listOf
|
||||||
|
str
|
||||||
|
submodule
|
||||||
|
;
|
||||||
|
|
||||||
|
interface =
|
||||||
|
{ name, config, ... }:
|
||||||
|
let
|
||||||
|
unit =
|
||||||
|
{ name, config, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
enable = mkEnableOption "this logical interface" // {
|
||||||
|
default = true;
|
||||||
|
example = false;
|
||||||
|
};
|
||||||
|
family = {
|
||||||
|
ethernet-switching = {
|
||||||
|
enable = mkEnableOption "the ethernet switching on this logical interface";
|
||||||
|
interface-mode = mkOption {
|
||||||
|
type = enum [
|
||||||
|
"trunk"
|
||||||
|
"access"
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
Mode of operation for vlan addressing of this interface.
|
||||||
|
"trunk" means that the traffic is tagged, "access" means the
|
||||||
|
traffic is tagged by the switch.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vlans = mkOption {
|
||||||
|
type = listOf (either str ints.unsigned);
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Vlans that can be used on this interface.
|
||||||
|
Only one ID should be here for "access" mode of operation.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#TODO : DHCP
|
||||||
|
inet = {
|
||||||
|
enable = mkEnableOption "the IPv4 configuration of this logical interface";
|
||||||
|
addresses = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
ipv4 addresses of this interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
inet6 = {
|
||||||
|
enable = mkEnableOption "the IPv6 configuration of this logical interface";
|
||||||
|
addresses = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
ipv6 addresses of this interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
xml = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.xml =
|
||||||
|
let
|
||||||
|
members = map (
|
||||||
|
vlan: "<members>${builtins.toString vlan}</members>"
|
||||||
|
) config.family.ethernet-switching.vlans;
|
||||||
|
eth = optionalString config.family.ethernet-switching.enable ''
|
||||||
|
<ethernet-switching>
|
||||||
|
<interface-mode>${config.family.ethernet-switching.interface-mode}</interface-mode>
|
||||||
|
<vlan>${builtins.concatStringsSep "" members}</vlan>
|
||||||
|
<storm-control><profile-name>default</profile-name></storm-control>
|
||||||
|
</ethernet-switching>
|
||||||
|
'';
|
||||||
|
|
||||||
|
addr4 = map (addr: "<name>${addr}</name>") config.family.inet.addresses;
|
||||||
|
inet = optionalString config.family.inet.enable ''
|
||||||
|
<inet>
|
||||||
|
<address>${builtins.concatStringsSep "" addr4}</address>
|
||||||
|
</inet>
|
||||||
|
'';
|
||||||
|
|
||||||
|
addr6 = map (addr: "<name>${addr}</name>") config.family.inet6.addresses;
|
||||||
|
inet6 = optionalString config.family.inet6.enable ''
|
||||||
|
<inet6>
|
||||||
|
<address>${builtins.concatStringsSep "" addr6}</address>
|
||||||
|
</inet6>
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
''
|
||||||
|
<unit>
|
||||||
|
<name>${name}</name>
|
||||||
|
${optionalString (!config.enable) "<disable/>"}
|
||||||
|
<family>
|
||||||
|
${eth}${inet}${inet6}
|
||||||
|
</family>
|
||||||
|
</unit>'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
enable = mkEnableOption "this physical interface";
|
||||||
|
unit = mkOption {
|
||||||
|
type = attrsOf (submodule unit);
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Configuration of the logical interfaces on this physical interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
xml = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.xml =
|
||||||
|
let
|
||||||
|
units = mapAttrsToList (_: unit: unit.xml) config.unit;
|
||||||
|
in
|
||||||
|
''
|
||||||
|
<interface>
|
||||||
|
<name>${name}</name>
|
||||||
|
${optionalString (!config.enable) "<disable/>"}
|
||||||
|
${builtins.concatStringsSep "" units}
|
||||||
|
</interface>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
interfaces = mkOption {
|
||||||
|
type = attrsOf (submodule interface);
|
||||||
|
description = ''
|
||||||
|
The interfaces configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
netconf.xmls.interfaces = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.netconf.xmls.interfaces = ''
|
||||||
|
<interfaces operation="replace">
|
||||||
|
${builtins.concatStringsSep "" (mapAttrsToList (_: intf: intf.xml) config.interfaces)}
|
||||||
|
</interfaces>
|
||||||
|
'';
|
||||||
|
}
|
49
lib/netconf-junos/poe.nix
Normal file
49
lib/netconf-junos/poe.nix
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mapAttrsToList
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
optionalString
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.types) attrsOf str submodule;
|
||||||
|
|
||||||
|
interface-module =
|
||||||
|
{ name, config, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
enable = mkEnableOption "the PoE for this interface";
|
||||||
|
xml = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.xml = ''
|
||||||
|
<interface><name>${name}</name>${optionalString (!config.enable) "<disable/>"}</interface>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
poe.interfaces = mkOption {
|
||||||
|
type = attrsOf (submodule interface-module);
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
PoE configuration of interfaces.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
netconf.xmls.poe = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.netconf.xmls.poe = ''
|
||||||
|
<poe operation="replace">
|
||||||
|
${builtins.concatStringsSep "" (mapAttrsToList (_: intf: intf.xml) config.poe.interfaces)}
|
||||||
|
</poe>
|
||||||
|
'';
|
||||||
|
}
|
33
lib/netconf-junos/protocols.nix
Normal file
33
lib/netconf-junos/protocols.nix
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) concatMapStringsSep mkOption;
|
||||||
|
|
||||||
|
inherit (lib.types) listOf str;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
protocols.rstp = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = ''
|
||||||
|
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 = ''
|
||||||
|
<protocols>
|
||||||
|
<rstp operation="replace">
|
||||||
|
${
|
||||||
|
concatMapStringsSep "" (intf: "<interface><name>${intf}</name></interface>") config.protocols.rstp
|
||||||
|
}
|
||||||
|
</rstp>
|
||||||
|
</protocols>
|
||||||
|
'';
|
||||||
|
}
|
91
lib/netconf-junos/system.nix
Normal file
91
lib/netconf-junos/system.nix
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
concatStrings
|
||||||
|
concatStringsSep
|
||||||
|
filter
|
||||||
|
hasPrefix
|
||||||
|
length
|
||||||
|
mkOption
|
||||||
|
splitString
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.types)
|
||||||
|
enum
|
||||||
|
listOf
|
||||||
|
port
|
||||||
|
str
|
||||||
|
;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
system = {
|
||||||
|
host-name = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "The hostname of the switch.";
|
||||||
|
};
|
||||||
|
root-authentication = {
|
||||||
|
hashedPasswd = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Hashed password for root.";
|
||||||
|
};
|
||||||
|
ssh-keys = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "ssh keys for root user.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
services = {
|
||||||
|
ssh.root-login = mkOption {
|
||||||
|
type = enum [
|
||||||
|
"allow"
|
||||||
|
"deny"
|
||||||
|
"deny-password"
|
||||||
|
];
|
||||||
|
description = "Login policy to use for root.";
|
||||||
|
};
|
||||||
|
netconf.port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Port to use for netconf.";
|
||||||
|
default = 830;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
netconf.xmls.system = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.netconf.xmls.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: "<ssh-edsca><name>${key}</name></ssh-edsca>") (
|
||||||
|
filter (hasPrefix "ssh-edsca ") ssh-keys
|
||||||
|
);
|
||||||
|
rsa = map (key: "<ssh-rsa><name>${key}</name></ssh-rsa>") (filter (hasPrefix "ssh-rsa ") ssh-keys);
|
||||||
|
ed25519 = map (key: "<ssh-ed25519><name>${key}</name></ssh-ed25519>") (
|
||||||
|
filter (hasPrefix "ssh-ed25519 ") ssh-keys
|
||||||
|
);
|
||||||
|
in
|
||||||
|
''
|
||||||
|
<system>
|
||||||
|
<host-name operation="replace">${config.system.host-name}</host-name>
|
||||||
|
<root-authentication operation="replace">
|
||||||
|
<encrypted-password>${config.system.root-authentication.hashedPasswd}</encrypted-password>
|
||||||
|
${concatStrings (edsca ++ rsa ++ ed25519)}
|
||||||
|
</root-authentication>
|
||||||
|
<services operation="replace">
|
||||||
|
<ssh><root-login>${config.system.services.ssh.root-login}</root-login></ssh>
|
||||||
|
<netconf>
|
||||||
|
<ssh><port>${toString config.system.services.netconf.port}</port></ssh>
|
||||||
|
<rfc-compliant/><yang-compliant/>
|
||||||
|
</netconf>
|
||||||
|
</services>
|
||||||
|
</system>
|
||||||
|
'';
|
||||||
|
}
|
131
lib/netconf-junos/vlans.nix
Normal file
131
lib/netconf-junos/vlans.nix
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
assertMsg
|
||||||
|
concatStringsSep
|
||||||
|
mapAttrsToList
|
||||||
|
mkOption
|
||||||
|
optionalString
|
||||||
|
;
|
||||||
|
|
||||||
|
inherit (lib.types)
|
||||||
|
attrsOf
|
||||||
|
either
|
||||||
|
ints
|
||||||
|
listOf
|
||||||
|
nullOr
|
||||||
|
str
|
||||||
|
submodule
|
||||||
|
unspecified
|
||||||
|
;
|
||||||
|
|
||||||
|
vlan =
|
||||||
|
{ name, config, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
id = mkOption {
|
||||||
|
type = nullOr ints.unsigned;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
The ID of this vlan, `null` means no ID.
|
||||||
|
Incompatible with vlans.${name}.id-list.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
id-list = mkOption {
|
||||||
|
type =
|
||||||
|
let
|
||||||
|
range_type =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
config.__toString = _: "${toString config.begin}-${toString config.end}";
|
||||||
|
options = {
|
||||||
|
begin = mkOption {
|
||||||
|
type = ints.unsigned;
|
||||||
|
visible = false;
|
||||||
|
};
|
||||||
|
end = mkOption {
|
||||||
|
type = ints.unsigned;
|
||||||
|
visible = false;
|
||||||
|
};
|
||||||
|
__toString = mkOption {
|
||||||
|
visible = false;
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
type = unspecified;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
listOf (either ints.unsigned (submodule range_type));
|
||||||
|
default = [ ];
|
||||||
|
example = [
|
||||||
|
42
|
||||||
|
{
|
||||||
|
begin = 100;
|
||||||
|
end = 200;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
List of IDs or IDs range to classify as this vlan.
|
||||||
|
Incompatible with vlans.${name}.id.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
l3-interface = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "irb.0";
|
||||||
|
description = ''
|
||||||
|
Switch's logical interface to connect directly to this vlan.
|
||||||
|
This allows to communicate with the switch from a vlan without
|
||||||
|
having a cable looping back on it's management interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
xml = mkOption {
|
||||||
|
type = str;
|
||||||
|
readOnly = true;
|
||||||
|
visible = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.xml =
|
||||||
|
let
|
||||||
|
id = optionalString (config.id != null) "<vlan-id>${toString config.id}</vlan-id>";
|
||||||
|
id-list = concatStringsSep "" (
|
||||||
|
map (vlan: "<vlan-id-list>${toString vlan}</vlan-id-list>") config.id-list
|
||||||
|
);
|
||||||
|
l3-intf = optionalString (
|
||||||
|
config.l3-interface != null
|
||||||
|
) "<l3-interface>${config.l3-interface}</l3-interface>";
|
||||||
|
in
|
||||||
|
assert assertMsg (
|
||||||
|
config.id == null || config.id-list == [ ]
|
||||||
|
) "vlans.${name}.id and vlans.${name}.id-list are incompatible.";
|
||||||
|
''
|
||||||
|
<vlan>
|
||||||
|
<name>${name}</name>
|
||||||
|
${id}${id-list}${l3-intf}
|
||||||
|
</vlan>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
vlans = mkOption {
|
||||||
|
type = attrsOf (submodule vlan);
|
||||||
|
description = ''
|
||||||
|
Named vlans configuration. Allows to name vlans inside interface configuration,
|
||||||
|
instead of just using their IDs.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
netconf.xmls.vlans = mkOption {
|
||||||
|
type = str;
|
||||||
|
visible = false;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.netconf.xmls.vlans = ''
|
||||||
|
<vlans operation="replace">
|
||||||
|
${builtins.concatStringsSep "" (mapAttrsToList (_: vlan: vlan.xml) config.vlans)}
|
||||||
|
</vlans>
|
||||||
|
'';
|
||||||
|
}
|
Loading…
Reference in a new issue