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