diff --git a/modules/ansible_generator.py b/modules/ansible_generator.py index 4bf98b72c4169703a5bb329a66f6c4f8475fdc51..bdef379d6032099926e1830ed2543237ec28945a 100644 --- a/modules/ansible_generator.py +++ b/modules/ansible_generator.py @@ -12,6 +12,10 @@ def _create_config_playbooks(input_definitions): copy_template_file("hosts", "base_provisioning/roles/hosts/tasks/main.yml") + if input_definitions["routers"]: + copy_template_file("routers", + "base_provisioning/roles/routers/tasks/main.yml") + for device in input_definitions["hosts"] + input_definitions["routers"]: copy_template_file("separate_devices", "base_provisioning/roles/" + device["name"] + "/tasks/main.yml") diff --git a/modules/routing_generator.py b/modules/routing_generator.py index c1f7dd3763acd15e2ef583c6ea70cde2442a3a2b..0c19a37cc38df8316765ff646633a7d07f563575 100644 --- a/modules/routing_generator.py +++ b/modules/routing_generator.py @@ -46,9 +46,26 @@ def _find_iface_ip_in_network(device_name, network, input_definitions): raise AttributeError +def _find_router_ip_in_br_network(other_network, input_definitions): + """Find a router inside of a network and returns its ip in br network.""" + router = None + + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["network"] == other_network: + router = router_mapping["router"] + + if not router: + return None + + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["router"] == router and\ + router_mapping["network"] == BORDER_ROUTER_NETWORK_NAME: + return router_mapping["ip"] + def _create_host_routing(target_host_name, input_definitions, flags): """Generate routings for the given host.""" - routings = [] + simple_routings = [] + default_routings = [] for host_mapping in input_definitions["net_mappings"]: if host_mapping["host"] == target_host_name: @@ -57,18 +74,16 @@ def _create_host_routing(target_host_name, input_definitions, flags): if flags["border_router"]: routing_to_router = dict() - routing_to_router["default"] = True routing_to_router["interface_ip"] = mapping["ip"] gateway = _find_router_in_network(mapping["network"], input_definitions) routing_to_router["gateway"] = gateway - routings.append(routing_to_router) + default_routings.append(routing_to_router) else: for network in input_definitions["networks"]: if network["name"] == mapping["network"]: continue routing_to_other_hosts = dict() - routing_to_other_hosts["default"] = False routing_to_other_hosts["interface_ip"] = mapping["ip"] gateway = _find_router_in_network(mapping["network"], input_definitions) @@ -76,84 +91,77 @@ def _create_host_routing(target_host_name, input_definitions, flags): net_ip, mask = network["cidr"].split('/') routing_to_other_hosts["network"] = net_ip routing_to_other_hosts["netmask"] = mask - routings.append(routing_to_other_hosts) + simple_routings.append(routing_to_other_hosts) - return routings + return simple_routings, default_routings def _create_router_routing(router_name, input_definitions, flags): """Generate routings for the given router.""" - routings = [] + simple_routings = [] + default_routings = [] if flags["border_router"]: routing_to_br = dict() - routing_to_br["default"] = True interface_ip = _find_iface_ip_in_network(router_name, BORDER_ROUTER_NETWORK_NAME, input_definitions) routing_to_br["interface_ip"] = interface_ip routing_to_br["gateway"] = BORDER_ROUTER_IP - routings.append(routing_to_br) - else: - for network in input_definitions["networks"]: - if network["name"] in _find_networks_of_device(router_name, - input_definitions): - continue - routing_to_other_router = dict() - routing_to_other_router["default"] = False - interface_ip = _find_iface_ip_in_network(router_name, - network["name"], - input_definitions) - routing_to_br["interface_ip"] = interface_ip - gateway = _find_router_in_network(network["name"], - input_definitions) - routing_to_other_router["gateway"] = gateway - net_ip, mask = network["cidr"].split('/') - routing_to_other_router["network"] = net_ip - routing_to_other_router["netmask"] = mask - routings.append(routing_to_other_router) + default_routings.append(routing_to_br) - return routings + return simple_routings, default_routings def _create_border_router_routing(input_definitions, flags): """Generate routings for the border router.""" - routings = [] + simple_routings = [] + default_routings = [] for network in input_definitions["networks"]: if network["name"] == BORDER_ROUTER_NETWORK_NAME: continue routing_to_hosts = dict() - routing_to_hosts["default"] = False routing_to_hosts["interface_ip"] = BORDER_ROUTER_IP net_ip, mask = network["cidr"].split('/') routing_to_hosts["network"] = net_ip routing_to_hosts["netmask"] = mask - gateway = _find_router_in_network(network["name"], input_definitions) + gateway = _find_router_ip_in_br_network(network["name"], + input_definitions) routing_to_hosts["gateway"] = gateway - routings.append(routing_to_hosts) + simple_routings.append(routing_to_hosts) - return routings + return simple_routings, default_routings def add_routings(device_name, device_type, input_definitions, flags): - """Generate routings for the given device. + """Generate simple and default routings for the given device. Returns a list of dicts with the syntax: - - default: True/False - gateway: ip of the target device + - gateway: ip of the target device interface_ip: ip of the device on the given interface network: ip of the network (if default is False) netmask: mask of the network (if default is False) """ if not input_definitions["routers"]: - return [] + return dict() + + routings = {"simple": [], "default": []} if device_type == "host": - return _create_host_routing(device_name, input_definitions, flags) + simple, default = _create_host_routing(device_name, input_definitions, + flags) + routings["simple"].extend(simple) + routings["default"].extend(default) elif device_type == "router": if device_name != BORDER_ROUTER_NAME: - return _create_router_routing(device_name, input_definitions, - flags) - return _create_border_router_routing(input_definitions, flags) - return [] + simple, default = _create_router_routing(device_name, + input_definitions, flags) + routings["simple"].extend(simple) + routings["default"].extend(default) + else: + simple, default = _create_border_router_routing(input_definitions, + flags) + routings["simple"].extend(simple) + routings["default"].extend(default) + return routings diff --git a/sandbox.yml b/sandbox.yml index c53b54d0e2ac286fe728197f90e4f7f631fb0322..9a686249ec1a37139ff783e9c770d39836233e66 100644 --- a/sandbox.yml +++ b/sandbox.yml @@ -16,24 +16,24 @@ routers: networks: - name: server-switch - cidr: 10.10.20.0/24 + cidr: 192.168.20.0/24 - name: home-switch - cidr: 10.10.30.0/24 + cidr: 192.168.30.0/24 net_mappings: - host: server network: server-switch - ip: 10.10.20.5 + ip: 192.168.20.5 - host: home network: home-switch - ip: 10.10.30.5 + ip: 192.168.30.5 router_mappings: - router: router network: server-switch - ip: 10.10.20.1 + ip: 192.168.20.1 - router: router network: home-switch - ip: 10.10.30.1 + ip: 192.168.30.1 diff --git a/templates/common/meta/main.yml b/templates/common/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..edff08cf19051df266730d50704938dbf642e748 --- /dev/null +++ b/templates/common/meta/main.yml @@ -0,0 +1,15 @@ + +galaxy_info: + role_name: common + author: Kamil Andoniadis + description: This role provide common macros, templates or files + licence: MIT + min_ansible_version: 2.3.3 + platforms: + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all + diff --git a/templates/common/templates/config.j2 b/templates/common/templates/config.j2 new file mode 100644 index 0000000000000000000000000000000000000000..929abb78e17c01dca63d9b607556121a5283fa02 --- /dev/null +++ b/templates/common/templates/config.j2 @@ -0,0 +1,3 @@ +{%- macro yaml_config_key_regexp(key) -%} + ^(#.*)?{{ key }}:.* +{%- endmacro -%} diff --git a/templates/common/templates/network.j2 b/templates/common/templates/network.j2 new file mode 100644 index 0000000000000000000000000000000000000000..f409e1ca0c933d39d1f5db773aa7b5ae52ca68d2 --- /dev/null +++ b/templates/common/templates/network.j2 @@ -0,0 +1,30 @@ +{%- set common_network = namespace( + interfaces=[] +) -%} +{%- for ansible_interface in ansible_interfaces -%} + {%- set common_network.interfaces = common_network.interfaces + [hostvars[inventory_hostname]['ansible_' + ansible_interface]] -%} +{%- endfor -%} + +{%- macro mac_to_interface(mac) -%} + {{ + ( + common_network.interfaces | selectattr('macaddress', 'defined') | + selectattr('macaddress', 'equalto', mac) | map(attribute='device') | list + ) [0] | default('') + }} +{%- endmacro -%} + +{%- macro ip_to_interface(ip) -%} + {{ + ( + common_network.interfaces | selectattr('ipv4', 'defined') | selectattr('ipv4.address', 'defined') | + selectattr('ipv4.address', 'equalto', ip) | map(attribute='device') | list + ) [0] | default('') + }} +{%- endmacro -%} + +{%- macro get_inactive_interfaces() -%} + {{ + common_network.interfaces | selectattr("active", "equalto", False) | list + }} +{%- endmacro -%} diff --git a/templates/config b/templates/config index 0280902ffb67b4405908ffeb9692a19c30d4b37f..9c73ad703a3a50a2c1d5fbd1ed2a8c6e1b0f53a5 100644 --- a/templates/config +++ b/templates/config @@ -1,3 +1,4 @@ +{% if hosts %} hosts: {% for host in hosts %} - name: {{ host.name }} @@ -8,7 +9,11 @@ hosts: {{ network }}: {{ ip }} {% endfor %} {% endfor %} +{% else %} +hosts: [] +{% endif %} +{% if routers %} routers: {% for router in routers %} - name: {{ router.name }} @@ -19,3 +24,6 @@ routers: {{ network }}: {{ ip }} {% endfor %} {% endfor %} +{% else %} +routers: [] +{% endif %} diff --git a/templates/device_configuration b/templates/device_configuration index d6951767bd0b148d236ca2e467411a70a4e9ef3f..90697be2a11c70a7579980c5badacf792197c143 100644 --- a/templates/device_configuration +++ b/templates/device_configuration @@ -12,39 +12,21 @@ - name: Configuring hosts hosts: hosts + become: yes roles: - hosts -#- name: Configuring routers -# hosts: routers -# roles: -# - routers +- name: Configuring routers + hosts: routers + become: yes + roles: + - routers - name: Configuring devices separately hosts: all + become: yes tasks: - - name: include role include_role: name: "{{ inventory_hostname }}" ... - - - - -#- name: Configuring host {{ host.host_name }} -# hosts: hosts -# become: yes -# tasks: -#{% for network_ip in network_ips %} -# - name: Add gateway for {{ network_ip }} -# command: route add -net {{ network_ip }} gw {{ host.router_ip }} {{ host.interface }} -#{% endfor %} - - -#- name: Configuring border router -# hosts: {{ border_router_name }} -# become: yes -# roles: -# - br -#... diff --git a/templates/hosts b/templates/hosts index 05ebab4386403488d89ef30804683cc47a0625e3..34e8296b1bf6323068655bdd749d110801b52869 100644 --- a/templates/hosts +++ b/templates/hosts @@ -3,8 +3,5 @@ - name: Install net-tools apt: - name: net-tools - -# name: Delete default gateway -# command: route del default + name: "net-tools" ... diff --git a/templates/interface/defaults/main.yml b/templates/interface/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..0910da5b26381303fbc25deb652f190995339756 --- /dev/null +++ b/templates/interface/defaults/main.yml @@ -0,0 +1,40 @@ + +interface_default_file: /etc/network/interfaces +interface_directory: '{{ interface_default_file }}.d' +interface_file_name: +interface_file: ' + {%- if interface_file_name is defined and interface_file_name -%} + {{ interface_directory }}/{{ interface_file_name }} + {%- else -%} + {{ interface_default_file }} + {%- endif %}' + +interface_clean: True +interface_mtu: 1442 + +interface_ip: +interface_mac: +interface_name: +interface_default_gateway: +interface_routes: [] +# - gateway: +# network: +# mask: + +interface_device: ' + {%- import "roles/common/templates/network.j2" as network with context -%} + {%- if interface_ip is defined and interface_ip -%} + {{ network.ip_to_interface(interface_ip) | default("") }} + {%- endif -%} + {%- if interface_mac is defined and interface_mac -%} + {{ network.mac_to_interface(interface_mac) | default("") }} + {%- endif -%} + {%- if interface_name is defined and interface_name -%} + {{ interface_name }} + {%- endif -%}' +interface_identifiers: + interface_ip: '{{ interface_ip }}' + interface_mac: '{{ interface_mac }}' + interface_name: '{{ interface_name }}' +interface_condition_single_interface_identifier: '{{ interface_identifiers | dict2items | map(attribute="value") | select("string") | select("ne", "") | list | length != 1 }}' + diff --git a/templates/interface/handlers/main.yml b/templates/interface/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..34553f66237ce5bfa2b75cff663b452a2402eae4 --- /dev/null +++ b/templates/interface/handlers/main.yml @@ -0,0 +1,6 @@ + +- name: interface_networking_restart + service: + name: networking + state: restarted + diff --git a/templates/interface/meta/main.yml b/templates/interface/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..58ecda581c150aac8a05d5d99e63955a1cae7073 --- /dev/null +++ b/templates/interface/meta/main.yml @@ -0,0 +1,19 @@ + +dependencies: + - src: git@gitlab.ics.muni.cz:CSIRT-MU-public/ansible-roles/common.git + scm: git + +galaxy_info: + role_name: interface + author: Kamil Andoniadis + description: Basic network interface configuration + licence: MIT + min_ansible_version: 2.3.3 + platforms: + - name: Debian + versions: + - all + - name: Ubuntu + versions: + - all + diff --git a/templates/interface/tasks/clean.yml b/templates/interface/tasks/clean.yml new file mode 100644 index 0000000000000000000000000000000000000000..36a651b9e5b6bff74029196dc471219b519fcc64 --- /dev/null +++ b/templates/interface/tasks/clean.yml @@ -0,0 +1,31 @@ + +- name: find all interfaces configuration files + find: + paths: + - '{{ interface_directory }}' + register: interface_extra_files + +- set_fact: + interface_config_files: '{{ (interface_extra_files.files | map(attribute="path") | list) + [interface_default_file] }}' + +- name: remove old iface settings for retrieved interface name + replace: + path: '{{ item }}' + regexp: ^iface[ \t]{{ interface_device }}[ \t].*(\n[ \t]+.*)* + notify: interface_networking_restart + with_items: '{{ interface_config_files }}' + +- name: remove the rest of old settings for retrieved interface name + replace: + path: '{{ item }}' + regexp: '^.*(?<=\s){{ interface_device }}(?=\s).*$' + notify: interface_networking_restart + with_items: '{{ interface_config_files }}' + +- name: remove multiple consecutive new line characters + replace: + path: '{{ item }}' + regexp: '(\n)+' + replace: '\n' + with_items: '{{ interface_config_files }}' + diff --git a/templates/interface/tasks/interface.yml b/templates/interface/tasks/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..9946165d81cbeb53dc6a885e4a90ba78ff099e59 --- /dev/null +++ b/templates/interface/tasks/interface.yml @@ -0,0 +1,25 @@ + +- name: configure interface + blockinfile: + path: '{{ interface_file }}' + create: yes + marker: '# {mark} {{ interface_device }}' + block: | + allow-hotplug {{ interface_device }} + auto {{ interface_device }} + iface {{ interface_device }} inet static + address {{ interface_ip }} + netmask {{ interface_routes[0]['mask'] }} + mtu {{ interface_mtu }} + {% if interface_default_gateway -%} + gateway {{ interface_default_gateway }} + up route add default gw {{ interface_default_gateway }} + {% endif -%} + {% if interface_routes -%} + {% for route in interface_routes -%} + post-up ip route add {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }} + pre-down ip route del {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }} + {% endfor %} + {% endif %} + notify: interface_networking_restart + diff --git a/templates/interface/tasks/main.yml b/templates/interface/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..7e69f74724ae2ed1bf954c99f929b0a53dceccf5 --- /dev/null +++ b/templates/interface/tasks/main.yml @@ -0,0 +1,11 @@ + +- name: check existence of single interface identifier + fail: + msg: there must be set exactly one of [interface_ip|interface_mac|interface_name] variables, got {{ interface_identifiers }} + when: interface_condition_single_interface_identifier + +- include: clean.yml + when: interface_clean is defined and interface_clean + +- include: interface.yml + diff --git a/templates/routers b/templates/routers index 52a027509342ae79caa656470c3bf155c1233c26..2e1724cbf267a7eb1af1ecacd07ac08d3087782b 100644 --- a/templates/routers +++ b/templates/routers @@ -2,16 +2,9 @@ # Configuration of all router devices - name: Enable IP forwarding - copy: - dest: "/etc/sysctl.conf" - content: "net.ipv4.ip_forward=1" - -- name: Restarting procps service - command: /etc/init.d/procps restart - -- name: Delete default gateway - command: route del default - -- name: Add default path to border router - command: route add default gw {{ border_router_ip }} eth3 + sysctl: + name: net.ipv4.ip_forward + value: '1' + sysctl_set: yes + reload: yes ... diff --git a/templates/separate_devices b/templates/separate_devices index 212d1244e737062d61067f425b29d8001773aa30..83f5b705907ad11cc9df3eb4152c740346d46865 100644 --- a/templates/separate_devices +++ b/templates/separate_devices @@ -1,5 +1,28 @@ -- name: Add aliases - loop: "{{ aliases|dict2items }}" +- name: Adding aliases + loop: "{{ aliases | dict2items }}" lineinfile: path: /etc/hosts - line: {{ item.value }} "{{ item.key }}" + line: "{{ item.value }} {{ item.key }}" + +- name: Configuring nondefault routes + include_role: + name: interface + vars: + interface_ip: "{{ route.interface_ip }}" + interface_routes: + - gateway: "{{ route.gateway }}" + network: "{{ route.network }}" + mask: "{{ route.netmask }}" + loop: "{{ routings.simple }}" + loop_control: + loop_var: route + +- name: Configuring default routes + include_role: + name: interface + vars: + interface_ip: "{{ route.interface_ip }}" + interface_default_gateway: "{{ route.gateway }}" + loop: "{{ routings.default }}" + loop_control: + loop_var: route diff --git a/templates/vagrantfile b/templates/vagrantfile index ae000d70a14bf288c015ff8eb92b763d593503af..664f569a5b63a022d605442c9e515a138fd51485 100644 --- a/templates/vagrantfile +++ b/templates/vagrantfile @@ -49,10 +49,32 @@ {{ namespace }}.{{ item.command }} = {{ item.value }} {% endmacro -%} +{# Macro for general items (not str int or bool) #} +{% macro other(item, namespace) %} +{% if item.separator %} + {{ namespace }}.{{ item.command }} {{ item.separator }} {{ item.value }} +{% else %} + {{ namespace }}.{{ item.command }} {{ item.value }} +{% endif %} +{% endmacro -%} + {# Macro for dictionaries #} {% macro dictionary(item, namespace) %} {{ namespace }}.{{ item.command }} = { {% for key, value in item.dictionary.items() %} + {% if loop.last %} + {{ key }}: {{ value }} + {% else %} + {{ key }}: {{ value }}, + {% endif %} + {% endfor %} + } +{% endmacro -%} + +{# Macro for dictionaries #} +{% macro groups(item, namespace) %} + {{ namespace }}.groups = { + {% for key, value in item.groups.items() %} {% if loop.last %} "{{ key }}" => {{ value }} {% else %} @@ -96,12 +118,16 @@ end {{ boolean(item, namespace) -}} {% elif item.type == "integer" %} {{ integer(item, namespace) -}} +{% elif item.type == "other" %} + {{ other(item, namespace) -}} {% elif item.type == "provider" %} {{ provider(item, namespace) -}} {% elif item.type == "network" %} {{ network(item, namespace) -}} {% elif item.type == "dictionary" %} {{ dictionary(item, namespace) -}} +{% elif item.type == "groups" %} + {{ groups(item, namespace) -}} {% endif %} {% endfor %} end