diff --git a/modules/ansible_generator.py b/modules/ansible_generator.py index daa9a18b0a53f8a1de5a528a122b4038e0867b97..00ee4668543d3afb6392e1c18dd06d8390e80579 100644 --- a/modules/ansible_generator.py +++ b/modules/ansible_generator.py @@ -1,39 +1,14 @@ from modules.file_manager import generate_file +from modules.ansible_vars_generator import generate_ansible_vars -def _create_inventory(input_definitions): - """ Creates an inventory file with host groups. """ - - host_names = [] - for host in input_definitions["hosts"]: - host_names.append(host["name"]) - - router_names = [] - for router in input_definitions["routers"]: - router_names.append(router["name"]) - - generate_file("inventory", "provisioning/inventory.ini", hosts=host_names, routers=router_names) - - -def _create_config(input_definitions, flags): - """ Creates a file with common variables for all roles. """ - - hosts = [] - for host in input_definitions["hosts"]: - new_host = dict() - new_host["name"] = host["name"] - hosts.append(new_host) - - routers = [] - for router in input_definitions["routers"]: - new_router = dict() - new_router["name"] = router["name"] - routers.append(new_router) - - generate_file("config", "base_provisioning/config.yml", hosts=hosts, routers=routers) def _create_config_playbooks(input_definitions, flags): """ Generates playbooks and roles for basic device configuration. """ - # TODO create playbooks + + for device in input_definitions["hosts"] + input_definitions["routers"]: + generate_file("separate_devices", "base_provisioning/roles/" + device["name"] + "/tasks/main.yml") + + # TODO create other playbooks return @@ -51,15 +26,12 @@ def _create_user_playbooks(input_definitions): generate_file("user_separate_routers", "provisioning/roles/" + router["name"] + "/tasks/main.yml", router_name=router["name"]) - def generate_playbooks(input_definitions, flags): - """ Generates ansible playbooks. + """ Generates ansible vars and playbooks. :param definitions: device definitions structure :param flags: command line input flags """ - - _create_inventory(input_definitions) - _create_config(input_definitions, flags) + generate_ansible_vars(input_definitions, flags) _create_config_playbooks(input_definitions, flags) _create_user_playbooks(input_definitions) diff --git a/modules/ansible_vars_generator.py b/modules/ansible_vars_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..48f2692ab3570ddcd953bb9a2f33905822811aa1 --- /dev/null +++ b/modules/ansible_vars_generator.py @@ -0,0 +1,171 @@ +from modules.file_manager import generate_file, dump_to_yaml +from conf.border_router import BORDER_ROUTER_NETWORK_NAME + + +def _create_inventory(input_definitions): + """ Creates an inventory file with host groups. """ + + host_names = [] + for host in input_definitions["hosts"]: + host_names.append(host["name"]) + + router_names = [] + for router in input_definitions["routers"]: + router_names.append(router["name"]) + + generate_file("inventory", "provisioning/inventory.ini", hosts=host_names, routers=router_names) + + +def _find_networks_of_device(name, input_definitions): + """ Returns a list of network names in which the device have an + interface. + """ + + networks = [] + + for net_mapping in input_definitions["net_mappings"]: + if net_mapping["host"] == name: + networks.append(net_mapping["network"]) + + if len(networks) == 1: + return networks + + if len(networks) > 1: + print("Error: Hosts can have only one interface.") + raise AttributeError + + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["router"] == name: + networks.append(router_mapping["network"]) + + return networks + + +def _add_aliases(device_name, input_definitions, flags): + """ Generates aliases for the given device. """ + + home_networks = _find_networks_of_device(device_name, input_definitions) + + aliases = dict() + + for host_mapping in input_definitions["net_mappings"]: + aliases[host_mapping["host"]] = host_mapping["ip"] + continue + + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["network"] in home_networks: + aliases[router_mapping["router"]] = router_mapping["ip"] + continue + + for router in input_definitions["routers"]: + if router["name"] not in aliases: +# TODO uncomment when br flag is active +# if "border_router" not in flags: +# print("Error: " + device_name + " has no connection to " + router["name"] + " .") +# raise AttributeError + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["router"] == router["name"] and router_mapping["network"] == BORDER_ROUTER_NETWORK_NAME: + aliases[router_mapping["router"]] = router_mapping["ip"] + continue + + for router in input_definitions["routers"]: + if router["name"] not in aliases: + print("Error: " + device_name + " has no connection to " + router["name"] + " .") + raise AttributeError + + return aliases + + +def _generate_device_vars(input_definitions, flags): + """ Generates vars files for all devices separately. """ + + for target_host in input_definitions["hosts"]: + variables = dict() + variables["aliases"] = _add_aliases(target_host["name"], input_definitions, flags) + dump_to_yaml(variables, "base_provisioning/roles/" + target_host["name"] + "/vars/main.yml") + + for target_router in input_definitions["routers"]: + variables = dict() + variables["aliases"] = _add_aliases(target_router["name"], input_definitions, flags) + dump_to_yaml(variables, "base_provisioning/roles/" + target_router["name"] + "/vars/main.yml") + + +def _create_inventory(input_definitions): + """ Creates an inventory file with host groups. """ + + host_names = [] + for host in input_definitions["hosts"]: + host_names.append(host["name"]) + + router_names = [] + for router in input_definitions["routers"]: + router_names.append(router["name"]) + + generate_file("inventory", "provisioning/inventory.ini", hosts=host_names, routers=router_names) + + +def _generate_hosts_vars(input_definitions, flags): + """ Generates vars file for all hosts. """ + + return + + +def _generate_routers_vars(input_definitions, flags): + """ Generates vars file for all routers. """ + + return + +def _find_ip(device_name, input_definitions): + """ Returns a dictionary with all network names and ips of a device. """ + + networks = dict() + + for host_mapping in input_definitions["net_mappings"]: + if host_mapping["host"] == device_name: + networks[host_mapping["network"]] = host_mapping["ip"] + + for router_mapping in input_definitions["router_mappings"]: + if router_mapping["router"] == device_name: + networks[router_mapping["network"]] = router_mapping["ip"] + + return networks + + +def _find_default_route(device_name, input_definitions, flags): + """ Returns the ip to which the device should be routed defaultly and + None if the change of default routing is not required. + """ + + return None + + +def _generate_config_vars(input_definitions, flags): + """ Generates vars file for all devices. """ + + hosts = [] + for host in input_definitions["hosts"]: + new_host = dict() + new_host["name"] = host["name"] + new_host["networks"] = _find_ip(host["name"], input_definitions) + new_host["route_to"] = _find_default_route(host["name"], input_definitions, flags) + hosts.append(new_host) + + routers = [] + for router in input_definitions["routers"]: + new_router = dict() + new_router["name"] = router["name"] + new_router["networks"] = _find_ip(router["name"], input_definitions) + new_router["route_to"] = _find_default_route(router["name"], input_definitions, flags) + routers.append(new_router) + + generate_file("config", "base_provisioning/config.yml", hosts=hosts, routers=routers) + + +def generate_ansible_vars(input_definitions, flags): + """ Generates files with variables for ansible. """ + + _create_inventory(input_definitions) + _generate_config_vars(input_definitions, flags) + _generate_hosts_vars(input_definitions, flags) + _generate_routers_vars(input_definitions, flags) + _generate_device_vars(input_definitions, flags) diff --git a/modules/file_manager.py b/modules/file_manager.py index d31cf25f9178d8c33b0eff5d0cdf88a14aab76d2..1eba16810dc802c2a9da21cce4b391b76a7429a2 100644 --- a/modules/file_manager.py +++ b/modules/file_manager.py @@ -20,6 +20,23 @@ def open_yaml(file_name): input_file.close() +def dump_to_yaml(data, filename): + """ Writes a data structure to a YAML document. + + :param data: a dict or list which should be written to file + :param filename: name of the target file + """ + + try: + stream = open(OUTPUT_DIRECTORY + "/" + filename, 'w') + yaml.dump(data, stream) + except IOError: + print("Error: cannot write to this location.") + raise + finally: + stream.close() + + def generate_file(template, filename, **template_args): """ Generates a file using a template. @@ -61,16 +78,20 @@ def _create_provisioning_directories(directory, device_definitions): if device_definitions["hosts"]: os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/hosts") os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/hosts/tasks") + os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/hosts/vars") for host in device_definitions["hosts"]: os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + host["name"]) os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + host["name"] + "/tasks") + os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + host["name"] + "/vars") if device_definitions["routers"]: os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/routers") os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/routers/tasks") + os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/routers/vars") for router in device_definitions["routers"]: os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + router["name"]) os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + router["name"] + "/tasks") + os.mkdir(OUTPUT_DIRECTORY + "/" + directory + "/roles/" + router["name"] + "/vars") except FileExistsError: pass diff --git a/templates/config b/templates/config index 473bea92d67be268b9d915dead91af026b2ddad8..0280902ffb67b4405908ffeb9692a19c30d4b37f 100644 --- a/templates/config +++ b/templates/config @@ -1,9 +1,21 @@ hosts: {% for host in hosts %} - name: {{ host.name }} + {% if "networks" in host %} + - networks: + {% endif %} + {% for network, ip in host.networks.items() %} + {{ network }}: {{ ip }} + {% endfor %} {% endfor %} routers: {% for router in routers %} - name: {{ router.name }} + {% if "networks" in router %} + - networks: + {% endif %} + {% for network, ip in router.networks.items() %} + {{ network }}: {{ ip }} + {% endfor %} {% endfor %} diff --git a/templates/device_configuration b/templates/device_configuration index 4acf99f13188a14b3b17f94eb7d21a5966ca4e8f..d123d0dd02c9eb11818fe988721ae634f9109b78 100644 --- a/templates/device_configuration +++ b/templates/device_configuration @@ -1,27 +1,31 @@ --- # Basic configuration of all defined devices +- name: include common variables + include_vars: + file: config.yml + name: config + - name: Configuring all hosts hosts: hosts become: yes roles: - hosts -- name: Configuring host {{ item.name }} separately - hosts: {{ item.name }} +- name: Configuring hosts separately + hosts: {{ "{{ item.name }}" }} become: yes - loop: "{{ hosts }}" + loop: {{ "\"{{ config.hosts }}\"" }} roles: - - {{ item.name }} + - {{ "{{ item.name }}" }} {# TODO finish playbook #} -{% for host in hosts %} - name: Configuring host {{ host.host_name }} - hosts: {{ host.host_name }} + hosts: hosts become: yes tasks: {% for network_ip in network_ips %} @@ -29,7 +33,10 @@ command: route add -net {{ network_ip }} gw {{ host.router_ip }} {{ host.interface }} {% endfor %} -{% endfor %} + + + + - name: Configuring all routers hosts: {{ routers|map(attribute='router_name')|unique|reject('eq', border_router_name)|join(',') }} become: yes diff --git a/templates/hosts b/templates/hosts index e9254f11c31650636be65efaf1f4cdc53326191e..33cdbc5ed8dde28d8f9d1dd331f792026c917325 100644 --- a/templates/hosts +++ b/templates/hosts @@ -2,22 +2,8 @@ # Basic configuration of all host devices - name: Install net-tools - command: apt install net-tools - -{% for host in hosts %} -- name: Add {{ host.host_name }} alias - lineinfile: - path: /etc/hosts - line: {{ host.host_ip }} {{ host.host_name }} - -{% endfor %} -{% for router in routers %} -- name: Add {{ router.router_name }} alias - lineinfile: - path: /etc/hosts - line: {{ router.router_ip }} {{ router.router_name }} - -{% endfor %} + apt: + name: net-tools - name: Delete default gateway command: route del default diff --git a/templates/routers b/templates/routers index 96d9d5926138897fa1e51f290842f753bd671b60..52a027509342ae79caa656470c3bf155c1233c26 100644 --- a/templates/routers +++ b/templates/routers @@ -9,20 +9,6 @@ - name: Restarting procps service command: /etc/init.d/procps restart -{% for host in hosts %} -- name: Add {{ host.host_name }} alias - lineinfile: - path: /etc/hosts - line: {{ host.host_ip }} {{ host.host_name }} - -{% endfor %} -{% for router in routers %} -- name: Add {{ router.router_name }} alias - lineinfile: - path: /etc/hosts - line: {{ router.router_ip }} {{ router.router_name }} - -{% endfor %} - name: Delete default gateway command: route del default diff --git a/templates/separate_devices b/templates/separate_devices new file mode 100644 index 0000000000000000000000000000000000000000..9309bbb2b09415dc259ed56c6e46ace10869f5b2 --- /dev/null +++ b/templates/separate_devices @@ -0,0 +1,5 @@ +- name: Add aliases + loop: {{ "{{ aliases|dict2items }}" }} + lineinfile: + path: /etc/hosts + line: {{ "{{ item.value }} \"{{ item.key }}\"" }}