Add dhclient basic configuration
Allows configuring general section as well as configuring
each dhcp enabled interface separetly.
Does not allow alias or lease configuration.
diff --git a/README.rst b/README.rst
index 2cccd1d..f6e0a83 100644
--- a/README.rst
+++ b/README.rst
@@ -491,14 +491,14 @@
https: http://maas-01:8080
...
proxy:
- # package manager fallback defaults
+ # package manager fallback defaults
# used if linux:system:repo:apt-mk:proxy has no protocol specific entries
pkg:
enabled: true
ftp: ftp://proxy.host.local:2121
#http: http://proxy.host.local:3142
#https: https://proxy.host.local:3143
- ...
+ ...
# global system fallback system defaults
ftp: ftp://proxy.host.local:2121
http: http://proxy.host.local:3142
@@ -772,6 +772,82 @@
use_interfaces:
- eth1
+DHCP client configuration
+
+None of the keys is mandatory, include only those you really need. For full list
+of available options under send, supersede, prepend, append refer to dhcp-options(5)
+
+.. code-block:: yaml
+
+ linux:
+ network:
+ dhclient:
+ enabled: true
+ backoff_cutoff: 15
+ initial_interval: 10
+ reboot: 10
+ retry: 60
+ select_timeout: 0
+ timeout: 120
+ send:
+ - option: host-name
+ declaration: "= gethostname()"
+ supersede:
+ - option: host-name
+ declaration: "spaceship"
+ - option: domain-name
+ declaration: "domain.home"
+ #- option: arp-cache-timeout
+ # declaration: 20
+ prepend:
+ - option: domain-name-servers
+ declaration:
+ - 8.8.8.8
+ - 8.8.4.4
+ - option: domain-search
+ declaration:
+ - example.com
+ - eng.example.com
+ #append:
+ #- option: domain-name-servers
+ # declaration: 127.0.0.1
+ # ip or subnet to reject dhcp offer from
+ reject:
+ - 192.33.137.209
+ - 10.0.2.0/24
+ request:
+ - subnet-mask
+ - broadcast-address
+ - time-offset
+ - routers
+ - domain-name
+ - domain-name-servers
+ - domain-search
+ - host-name
+ - dhcp6.name-servers
+ - dhcp6.domain-search
+ - dhcp6.fqdn
+ - dhcp6.sntp-servers
+ - netbios-name-servers
+ - netbios-scope
+ - interface-mtu
+ - rfc3442-classless-static-routes
+ - ntp-servers
+ require:
+ - subnet-mask
+ - domain-name-servers
+ # if per interface configuration required add below
+ interface:
+ ens2:
+ initial_interval: 11
+ reject:
+ - 192.33.137.210
+ ens3:
+ initial_interval: 12
+ reject:
+ - 192.33.137.211
+
+
Configure global environment variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/linux/files/dhclient.conf b/linux/files/dhclient.conf
new file mode 100644
index 0000000..1f767c6
--- /dev/null
+++ b/linux/files/dhclient.conf
@@ -0,0 +1,106 @@
+{# Macro, put quotation marks around strings that are not ipv4 address #}
+{%- macro quote_if_not_ip(var) -%}
+{%- set var_split_str = var.split(".") -%}
+ {%- if var_split_str|length == 4 -%}
+ {%- set var_is_ipaddr = True -%}
+ {%- for octet in var_split_str -%}
+ {%- if not octet|int in range(255) -%}
+ {%- set var_is_ipaddr = False -%}
+ {%- endif -%}
+ {%- endfor -%}
+ {%- endif -%}
+ {%- if var_is_ipaddr is defined and var_is_ipaddr == True -%}
+{{ var }}
+ {%- else -%}
+"{{ var }}"
+ {%- endif -%}
+{%- endmacro -%}
+
+{# Macro, renders nested options for specific key #}
+{%- macro render_key(section, key) -%}
+{%- if section.get(key) and section.get(key)|length > 0 %}
+ {%- for item in section.get(key) %}
+ {%- if item.declaration is string %}
+{{ key }} {{ item.option }} {{ quote_if_not_ip(item.declaration) }};
+ {%- elif item.declaration is sequence %}
+{{ key }} {{ item.option }}
+ {%- for value in item.declaration -%}
+ {%- set space = " " -%}
+{{ space }}{{ quote_if_not_ip(value) }}
+ {%- if not loop.last -%},{%- endif -%}
+ {%- endfor -%}
+;
+ {%- else %}
+{{ key }} {{ item.option }} {{ item.declaration }};
+ {%- endif -%}
+ {%- endfor -%}
+{%- endif -%}
+{%- endmacro -%}
+
+{# Macro, renders set of options for global section or for interface section #}
+{%- macro render_section(section) -%}
+{%- if section.backoff_cutoff is defined %}
+backoff-cutoff {{ section.backoff_cutoff|default(15, true) }};
+{%- endif -%}
+
+{%- if section.initial_interval is defined %}
+initial-interval {{ section.initial_interval|default(10, true) }};
+{%- endif -%}
+
+{%- if section.reboot is defined %}
+# The reboot statement sets the time that must elapse after the client
+# first tries to reacquire its old address before it gives up and tries
+# to discover a new address.
+reboot {{ section.reboot|default(10, true) }};
+{%- endif -%}
+
+{%- if section.retry is defined %}
+retry {{ section.retry|default(60, true) }};
+{%- endif -%}
+
+{%- if section.select_timeout is defined %}
+# The select-timeout is the time after the client sends its first lease
+# discovery request at which it stops waiting for offers from servers,
+# assuming that it has received at least one such offer
+select-timeout {{ section.select_timeout|default(0, True) }};
+{%- endif -%}
+
+{%- if section.timeout is defined %}
+timeout {{ section.timeout|default(120, True) }};
+{%- endif -%}
+
+{{ render_key(section, "send") }}
+{{ render_key(section, "supersede") }}
+{{ render_key(section, "prepend") }}
+{{ render_key(section, "append") }}
+
+{%- if section.reject is defined and section.reject|length > 0 %}
+reject {{ section.reject|join(",\n ") }};
+{%- endif %}
+
+{%- if section.request is defined and section.request|length > 0 %}
+request {{ section.request|join(",\n ") }};
+{%- endif %}
+
+{%- if section.require is defined and section.require|length > 0 %}
+require {{ section.require|join(",\n ") }};
+{% endif -%}
+{%- endmacro -%}
+
+{# Actual template start #}
+{%- from "linux/map.jinja" import network with context -%}
+{%- set dhclient = network.get('dhclient', {}) %}
+# dhclient.conf(5) file managed by salt-minion(1)
+# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
+option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
+{{ render_section(dhclient) }}
+{%- if dhclient.get("interface") -%}
+{%- for iface_name, options in dhclient.interface.iteritems() %}
+{%- if network.interface.get(iface_name) and network.interface.get(iface_name).enabled == True
+ and network.interface.get(iface_name).proto == 'dhcp' -%}
+interface "{{ iface_name }}" {
+ {{ render_section(options)|indent }}
+}
+{%- endif -%}
+{%- endfor %}
+{%- endif -%}
diff --git a/linux/map.jinja b/linux/map.jinja
index 045212d..64e805b 100644
--- a/linux/map.jinja
+++ b/linux/map.jinja
@@ -110,6 +110,7 @@
'host': 'none',
},
'host': {},
+ 'dhclient_config': '/etc/dhcp/dhclient.conf',
},
'Debian': {
'hostname_file': '/etc/hostname',
@@ -124,6 +125,7 @@
'host': 'none'
},
'host': {},
+ 'dhclient_config': '/etc/dhcp/dhclient.conf',
},
'RedHat': {
'bridge_pkgs': ['bridge-utils'],
@@ -137,6 +139,7 @@
'host': 'none'
},
'host': {},
+ 'dhclient_config': '/etc/dhcp/dhclient.conf',
},
}, grain='os_family', merge=salt['pillar.get']('linux:network')) %}
diff --git a/linux/network/dhclient.sls b/linux/network/dhclient.sls
new file mode 100644
index 0000000..6de2cfd
--- /dev/null
+++ b/linux/network/dhclient.sls
@@ -0,0 +1,11 @@
+{%- from "linux/map.jinja" import network with context %}
+
+{%- if network.dhclient.enabled|default(False) %}
+
+dhclient_conf:
+ file.managed:
+ - name: {{ network.dhclient_config }}
+ - source: salt://linux/files/dhclient.conf
+ - template: jinja
+
+{%- endif %}
diff --git a/linux/network/init.sls b/linux/network/init.sls
index 53d394b..21069d3 100644
--- a/linux/network/init.sls
+++ b/linux/network/init.sls
@@ -10,6 +10,9 @@
{%- if network.dpdk is defined %}
- linux.network.dpdk
{%- endif %}
+{%- if network.dhclient is defined %}
+- linux.network.dhclient
+{%- endif %}
{%- if network.interface|length > 0 %}
- linux.network.interface
{%- endif %}
diff --git a/tests/pillar/network.sls b/tests/pillar/network.sls
index bf8b176..f862ed1 100644
--- a/tests/pillar/network.sls
+++ b/tests/pillar/network.sls
@@ -24,3 +24,67 @@
#type: vlan
#use_interfaces:
#- interface: ${linux:interface:eth0}
+ dhclient:
+ enabled: true
+ backoff_cutoff: 15
+ initial_interval: 10
+ reboot: 10
+ retry: 60
+ select_timeout: 0
+ timeout: 120
+ send:
+ - option: host-name
+ declaration: "= gethostname()"
+ supersede:
+ - option: host-name
+ declaration: linux
+ - option: domain-name
+ declaration: ci.local
+ #- option: arp-cache-timeout
+ # declaration: 20
+ prepend:
+ - option: domain-name-servers
+ declaration:
+ - 8.8.8.8
+ - 8.8.4.4
+ - option: domain-search
+ declaration:
+ - example.com
+ - eng.example.com
+ # ip or subnet to reject dhcp offer from
+ reject:
+ - 10.0.2.0/24
+ request:
+ - subnet-mask
+ - broadcast-address
+ - time-offset
+ - routers
+ - domain-name
+ - domain-name-servers
+ - domain-search
+ - host-name
+ - dhcp6.name-servers
+ - dhcp6.domain-search
+ - dhcp6.fqdn
+ - dhcp6.sntp-servers
+ - netbios-name-servers
+ - netbios-scope
+ - interface-mtu
+ - rfc3442-classless-static-routes
+ - ntp-servers
+ require:
+ - subnet-mask
+ - domain-name-servers
+ # if per interface configuration required add below
+ # interface:
+ # ens2:
+ # initial_interval: 11
+ # request:
+ # - subnet-mask
+ # - broadcast-address
+ # reject:
+ # - 10.0.3.0/24
+ # ens3:
+ # initial_interval: 12
+ # reject:
+ # - 10.0.4.0/24