Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F3769348
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/_modules/node.py b/_modules/node.py
index 28fc3c9..4ec9b53 100644
--- a/_modules/node.py
+++ b/_modules/node.py
@@ -1,261 +1,317 @@
# -*- coding: utf-8 -*-
# -------------------------------------------------------------
# Salt — Node execution module
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Project: Nasqueron
# Created: 2017-10-21
# Description: Functions related to the nodes' pillar entry
# License: BSD-2-Clause
# -------------------------------------------------------------
from salt.exceptions import CommandExecutionError, SaltCloudConfigError
from salt._compat import ipaddress
def _get_all_nodes():
return __pillar__.get("nodes", {})
def get_all_properties(nodename=None):
"""
A function to get a node pillar configuration.
CLI Example:
salt * node.get_all_properties
"""
if nodename is None:
nodename = __grains__["id"]
all_nodes = _get_all_nodes()
if nodename not in all_nodes:
raise CommandExecutionError(
SaltCloudConfigError("Node {0} not declared in pillar.".format(nodename))
)
return all_nodes[nodename]
def get(key, nodename=None):
"""
A function to get a node pillar configuration key.
CLI Example:
salt * node.get hostname
"""
return _get_property(key, nodename, None)
def _explode_key(k):
return k.split(":")
def _get_first_key(k):
return _explode_key(k)[0]
def _strip_first_key(k):
return ":".join(_explode_key(k)[1:])
def _get_property(key, nodename, default_value, parent=None):
if parent is None:
parent = get_all_properties(nodename)
if ":" in key:
first_key = _get_first_key(key)
if first_key in parent:
return _get_property(
_strip_first_key(key), nodename, default_value, parent[first_key]
)
elif key in parent:
return parent[key]
return default_value
def get_list(key, nodename=None):
"""
A function to get a node pillar configuration.
Returns a list if found, or an empty list if not found.
CLI Example:
salt * node.list network:ipv4_aliases
"""
return _get_property(key, nodename, [])
def has(key, nodename=None):
"""
A function to get a node pillar configuration.
Returns a boolean, False if not found.
CLI Example:
salt * node.has network:ipv6_tunnel
"""
value = _get_property(key, nodename, False)
return bool(value)
def has_role(role, nodename=None):
"""
A function to determine if a node has the specified role.
Returns a boolean, False if not found.
CLI Example:
salt * node.has_role devserver
"""
return role in get_list("roles", nodename)
def filter_by_role(pillar_key, nodename=None):
"""
A function to filter a dictionary by roles.
The dictionary must respect the following structure:
- keys are role to check the current node against
- values are list of items
If a key '*' is also present, it will be included
for every role.
Returns a list, extending all the filtered lists.
CLI Example:
salt * node.filter_by_role web_content_sls
"""
roles = get_list("roles", nodename)
dictionary = __pillar__.get(pillar_key, {})
filtered_list = []
for role, items in dictionary.items():
if role == "*" or role in roles:
filtered_list.extend(items)
return filtered_list
def filter_by_name(pillar_key, nodename=None):
"""
A function to filter a dictionary by node name.
The dictionary must respect the following structure:
- keys are names to check the current node against
- values are list of items
If a key '*' is also present, it will be included
for every node.
Returns a list, extending all the filtered lists.
CLI Example:
salt * node.filter_by_name mars
"""
if nodename is None:
nodename = __grains__["id"]
dictionary = __pillar__.get(pillar_key, {})
filtered_list = []
for name, items in dictionary.items():
if name == "*" or name == nodename:
filtered_list.extend(items)
return filtered_list
def has_web_content(content, nodename=None):
return content in filter_by_role("web_content_sls", nodename)
def get_wwwroot(nodename=None):
"""
A function to determine the wwwroot folder to use.
Returns a string depending on the FQDN.
CLI Example:
salt * node.get_wwwroot
"""
hostname = _get_property("hostname", nodename, None)
if hostname is None:
raise CommandExecutionError(
SaltCloudConfigError(
"Node {0} doesn't have a hostname property".format(nodename)
)
)
if hostname.count(".") < 2:
return "wwwroot/{0}/www".format(hostname)
fqdn = hostname.split(".")
return "wwwroot/{1}/{0}".format(".".join(fqdn[0:-2]), ".".join(fqdn[-2:]))
def get_ipv6_list():
"""
A function to get a list of IPv6, enclosed by [].
Returns a string depending on the IPv6 currently assigned.
CLI Example:
salt * node.get_ipv6_list
"""
ipv6 = __grains__.get("ipv6")
return " ".join(["[" + ip + "]" for ip in ipv6])
def resolve_network():
"""
A function to determine canonical properties of networks
from the nodes pillar.
CLI Example:
salt * node.resolve_network
"""
network = {
"ipv4_address": "",
"ipv4_gateway": "",
}
private_network = network.copy()
interfaces = _get_property("network:interfaces", __grains__["id"], {})
for interface_name, interface in interfaces.items():
if "ipv4" not in interface:
continue
ipv4 = interface["ipv4"]["address"]
if ipaddress.ip_address(ipv4).is_private:
target = private_network
else:
target = network
if target["ipv4_address"] != "":
continue
target["ipv4_address"] = ipv4
try:
target["ipv4_gateway"] = interface["ipv4"]["gateway"]
except KeyError:
pass
if network["ipv4_address"] == "":
return private_network
return network
+
+
+def _resolve_gre_tunnels_for_router(network, netmask):
+ tunnels = []
+
+ for node, tunnel in __pillar__.get(f"{network}_gre_tunnels", {}).items():
+ tunnels.append(
+ {
+ "description": f"{network}_to_{node}",
+ "interface": tunnel["router"]["interface"],
+ "src": tunnel["router"]["addr"],
+ "dst": tunnel["node"]["addr"],
+ "netmask": netmask,
+ "icann_src": get("network")["canonical_public_ipv4"],
+ "icann_dst": get("network", node)["canonical_public_ipv4"],
+ }
+ )
+
+ return tunnels
+
+
+def resolve_gre_tunnels():
+ """
+ A function to get the GRE tunnels for a node
+
+ CLI Example:
+ salt * node.resolve_gre_tunnels
+ """
+ gre_tunnels = []
+
+ for network, network_args in __pillar__.get("networks", {}).items():
+ if __grains__["id"] == network_args["router"]:
+ gre_tunnels += _resolve_gre_tunnels_for_router(
+ network, network_args["netmask"]
+ )
+ continue
+
+ tunnel = __salt__["pillar.get"](f"{network}_gre_tunnels:{__grains__['id']}")
+ if not tunnel:
+ continue
+
+ gre_tunnels.append(
+ {
+ "description": f"{network}_via_{network_args['router']}",
+ "interface": tunnel["node"].get("interface", "gre0"),
+ "src": tunnel["node"]["addr"],
+ "dst": tunnel["router"]["addr"],
+ "netmask": network_args["netmask"],
+ "icann_src": get("network")["canonical_public_ipv4"],
+ "icann_dst": get("network", network_args["router"])[
+ "canonical_public_ipv4"
+ ],
+ }
+ )
+
+ return gre_tunnels
diff --git a/pillar/core/network.sls b/pillar/core/network.sls
index 8afb63c..ab5e9b8 100644
--- a/pillar/core/network.sls
+++ b/pillar/core/network.sls
@@ -1,29 +1,49 @@
networks:
drake:
netmask: 255.255.255.0
- addr:
- cloudhugger: 172.27.27.28
- router-001: 172.27.27.1
- windriver: 172.27.27.35
- ysul: 172.27.27.33
+ router: router-001
-gre_tunnels:
- windriver:
- wind-cloud:
- interface: gre0
- network: drake
- to: cloudhugger
-
- wind-ysul:
- interface: gre0
- network: drake
- to: ysul
+# -------------------------------------------------------------
+# Drake - GRE tunnels
+#
+# Describe GRE tunnels between a node and {networks.drake.router}
+#
+# {id}:
+# router:
+# interface: gre0, gre1, ... / increment for each tunnel
+# addr: The tunnel IPv4 on the router in 172.27.27.240/28
+#
+# node:
+# interface: Not needed on Linux as the interface name will be
+# descriptive: gre-drake_via_{networks.drake.router}
+#
+# Not needed on FreeBSD if default value "gre0" is fine.
+# If there is several GRE tunnels, can be gre1, gre2, etc.
+#
+# addr: The canonical IPv4 for the server in 172.27.27.0/24
+#
+# IP should be sync between the pillar and the Operations grimoire
+# at https://agora.nasqueron.org/Operations_grimoire/Network
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+drake_gre_tunnels:
ysul:
- wind-ysul: &gre_drake_to_windriver
+ router:
interface: gre0
- network: drake
- to: windriver
+ addr: 172.27.27.252
+ node:
+ addr: 172.27.27.33
cloudhugger:
- wind-cloud: *gre_drake_to_windriver
+ router:
+ interface: gre1
+ addr: 172.27.27.253
+ node:
+ addr: 172.27.27.28
+
+ windriver:
+ router:
+ interface: gre2
+ addr: 172.27.27.254
+ node:
+ addr: 172.27.27.35
diff --git a/roles/core/network/gre.sls b/roles/core/network/gre.sls
index 0a6dd6f..2738cad 100644
--- a/roles/core/network/gre.sls
+++ b/roles/core/network/gre.sls
@@ -1,79 +1,54 @@
# -------------------------------------------------------------
# Salt — Network — GRE tunnels
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Project: Nasqueron
# Created: 2020-09-20
# License: Trivial work, not eligible to copyright
# -------------------------------------------------------------
-{% set network = salt['node.get']('network') %}
-{% set gre_tunnels = salt['pillar.get']("gre_tunnels:" + grains['id'], {}) %}
+{% from "roles/core/network/map.jinja" import gre with context %}
{% set boot_loader = namespace(gre=false) %}
# -------------------------------------------------------------
# Tunnels network configuration files
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-{% for description, tunnel in gre_tunnels.items() %}
+{% for tunnel in salt['node.resolve_gre_tunnels']() %}
{% set boot_loader.gre = True %}
-{% set tunnel_network = pillar['networks'][tunnel['network']] %}
-{% if grains['os'] == 'FreeBSD' %}
-/etc/rc.conf.d/netif/gre_{{ description }}:
+{{ gre.config_path }}{{ tunnel["description"] }}:
file.managed:
- - source: salt://roles/core/network/files/FreeBSD/netif_gre.rc
+ - source: salt://roles/core/network/files/{{ gre.source_path }}
- makedirs: True
- template: jinja
- - context:
- description: {{ description }}
- interface: {{ tunnel['interface'] }}
-
- src: {{ tunnel_network['addr'][grains['id']] }}
- dst: {{ tunnel_network['addr'][tunnel['to']] }}
-
- icann_src: {{ network['ipv4_address'] }}
- icann_dst: {{ salt['node.get']('network', tunnel['to'])['ipv4_address'] }}
-{% endif %}
-
+ - defaults: {{ tunnel }}
{% if grains['os_family'] == 'Debian' %}
-/etc/network/interfaces.d/10-gre-{{ description }}:
- file.managed:
- - source: salt://roles/core/network/files/Debian/10-gre.jinja
- - makedirs: True
- - template: jinja
- context:
interface: gre-{{ description }}
-
- src: {{ tunnel_network['addr'][grains['id']] }}
- dst: {{ tunnel_network['addr'][tunnel['to']] }}
- netmask: {{ tunnel_network['netmask'] }}
-
- icann_src: {{ network['ipv4_address'] }}
- icann_dst: {{ salt['node.get']('network', tunnel['to'])['ipv4_address'] }}
{% endif %}
{% endfor %}
# -------------------------------------------------------------
# Kernel configuration
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% if boot_loader.gre %}
{% if grains['os'] == 'FreeBSD' %}
load_gre_kernel_module:
file.append:
- name: /boot/loader.conf
- text: |
if_gre_load="YES"
{% endif %}
{% if grains['os_family'] == 'Debian' %}
ip_gre:
kmod.present:
- persist: True
{% endif %}
{% endif %}
diff --git a/roles/core/network/map.jinja b/roles/core/network/map.jinja
index 6cb6f46..5961208 100644
--- a/roles/core/network/map.jinja
+++ b/roles/core/network/map.jinja
@@ -1,34 +1,51 @@
# -------------------------------------------------------------
# Salt — Network
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Project: Nasqueron
# License: Trivial work, not eligible to copyright
# -------------------------------------------------------------
# -------------------------------------------------------------
# Interface configuration by OS/distro
#
# config_path: the configuration file to write in OS
# source_path: in this repo, roles/core/network/files/<source_path>
#
# Don't set default value, so we MUST define them
# for EACH os/distro.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% set interface_config = salt['grains.filter_by']({
'FreeBSD': {
"config_path": "/etc/rc.conf.d/netif/ipv4_",
"source_path": "FreeBSD/netif_ipv4.rc",
"suffix": "interface",
},
'RedHat': {
"config_path": "/etc/sysconfig/network-scripts/ifcfg-",
"source_path": "RedHat/ifcfg",
"suffix": "device",
},
'Debian': {
"config_path": "/etc/network/interfaces.d/10-net-",
"source_path": "Debian/10-net.jinja",
"suffix": "device",
},
}) %}
+
+# -------------------------------------------------------------
+# GRE tunnels configuration by OS/distro
+#
+# See interface configuration for the documentation.
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+{% set gre = salt['grains.filter_by']({
+ 'FreeBSD': {
+ "config_path": "/etc/rc.conf.d/netif/gre_",
+ "source_path": "FreeBSD/netif_gre.rc",
+ },
+ 'Debian': {
+ "config_path": "/etc/network/interfaces.d/10-gre-",
+ "source_path": "Debian/10-gre.jinja",
+ },
+}) %}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Nov 25, 14:16 (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2260339
Default Alt Text
(14 KB)
Attached To
Mode
rOPS Nasqueron Operations
Attached
Detach File
Event Timeline
Log In to Comment