Newer
Older
""" This module generates a Vagrantfile from input device definitions. """
from modules.file_manager import generate_file, open_yaml
VAGRANT_MAPPING = open_yaml("conf/vagrant_mapping.yml")
VIRTUALBOX_MAPPING = open_yaml("conf/virtualbox_mapping.yml")
BASE_PLAYBOOK = "base_provisioning/device_configuration.yml"
USER_PLAYBOOK = "provisioning/playbook.yml"
def _create_simple_attribute(key, value, attribute_type):
""" Creates simple vagrant attributes like string, integer or boolean. """
attribute = dict()
attribute["type"] = attribute_type
attribute["command"] = key
attribute["value"] = value
return attribute
def _create_complex_attribute(key, value):
""" Creates complex vagrant attributes that are not string, integer or
boolean.
"""
SEPARATORS = {VAGRANT_MAPPING["other"]["synced_folder"]: ""}
attribute = dict()
attribute["type"] = "other"
attribute["command"] = key
attribute["separator"] = SEPARATORS[key]
attribute["value"] = value
return attribute
def _create_commands(device_attributes, device_type, input_definitions, flags):
""" This function creates basic vagrant definition commands for a device. """
commands = []
vb_commands = []
for attribute, value in device_attributes.items():
if attribute in VAGRANT_MAPPING["string"]:
commands.append(_create_simple_attribute(VAGRANT_MAPPING["string"][attribute], value, "string"))
elif attribute in VAGRANT_MAPPING["boolean"]:
commands.append(_create_simple_attribute(VAGRANT_MAPPING["boolean"][attribute], value, "boolean"))
elif attribute in VAGRANT_MAPPING["integer"]:
commands.append(_create_simple_attribute(VAGRANT_MAPPING["integer"][attribute], value, "integer"))
elif attribute in VAGRANT_MAPPING["other"]:
commands.append(_create_complex_attribute(VAGRANT_MAPPING["other"][attribute], value))
elif attribute in VIRTUALBOX_MAPPING["integer"]:
vb_commands.append(_create_simple_attribute(VIRTUALBOX_MAPPING["integer"][attribute], value, "integer"))
if vb_commands:
vb = dict()
vb["type"] = "provider"
vb["name"] = "virtualbox"
vb["commands"] = vb_commands
commands.append(vb)
def _create_ansible_commands(playbook_location, input_definitions, flags):
""" Creates commands for running a playbook from the Vagrantfile. """
commands = []
playbook = dict()
playbook["type"] = "string"
playbook["command"] = "playbook"
playbook["value"] = playbook_location
commands.append(playbook)
if "verbose_ansible" in flags and flags["verbose_ansible"]:
verbosity = dict()
groups["type"] = "groups"
groups["groups"] = dict()
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"])
groups["groups"]["routers"] = router_names
commands.append(groups)
if "ansible_local" in flags and flags["ansible_local"]:
extravars = dict()
extravars["type"] = "dictionary"
extravars["command"] = "extra_vars"
extravars["dictionary"] = dict()
extravars["dictionary"]["ansible_python_interpreter"] = "\"/usr/bin/python3\""
commands.append(extravars)
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
return commands
def _find_netmask(network_name, networks):
""" Returns the netmask of a network address from network name. """
for network in networks:
if network['name'] == network_name:
address, netmask = network['cidr'].split('/')
return netmask
def _add_networks_to_device(definition, mappings, input_definitions):
""" Adds networks to the vagrant definition of one device. """
for mapping in mappings:
if mapping[definition["type"]] == definition["name"]:
network = dict()
network["type"] = "network"
network["network_type"] = "private_network"
network["name"] = mapping["network"]
network["ip"] = mapping["ip"]
network["netmask"] = _find_netmask(mapping["network"], input_definitions["networks"])
definition["commands"].append(network)
def _add_all_networks(vagrant_definitions, input_definitions, flags):
""" Adds all networks to vagrant definitions. """
for definition in vagrant_definitions:
if definition["type"] == "host":
_add_networks_to_device(definition, input_definitions["net_mappings"], input_definitions)
elif definition["type"] == "router":
_add_networks_to_device(definition, input_definitions["router_mappings"], input_definitions)
def _call_provisioner(input_definitions, flags):
""" Creates entry to vagrant definitions for calling the provisioner. """
provisioner_calls = []
config_playbook = dict()
config_playbook["type"] = "provision"
if "ansible_local" in flags and flags["ansible_local"]:
config_playbook["provisioner"] = "ansible_local"
else:
config_playbook["provisioner"] = "ansible"
config_playbook["note"] = "basic configuration of devices and networks"
config_playbook["commands"] = _create_ansible_commands(
BASE_PLAYBOOK, input_definitions, flags)
provisioner_calls.append(config_playbook)
user_playbook = dict()
user_playbook["type"] = "provision"
if "ansible_local" in flags and flags["ansible_local"]:
user_playbook["provisioner"] = "ansible_local"
else:
user_playbook["provisioner"] = "ansible"
user_playbook["note"] = "user configuration of devices"
user_playbook["commands"] = _create_ansible_commands(
USER_PLAYBOOK, input_definitions, flags)
provisioner_calls.append(user_playbook)
return provisioner_calls
def _build_vagrant_definitions(input_definitions, flags):
"""
Creates a definition structure that is more suitable for Vagrantfile
generation than input definitions.
"""
vagrant_definitions = []
for router in input_definitions["routers"]:
device = dict()
device["type"] = "router"
device["name"] = router["name"]
device["commands"] = _create_commands(router, "router", input_definitions, flags)
vagrant_definitions.append(device)
device = dict()
device["type"] = "host"
device["name"] = host["name"]
device["commands"] = _create_commands(host, "host", input_definitions, flags)
vagrant_definitions.append(device)
_add_all_networks(vagrant_definitions, input_definitions, flags)
vagrant_definitions.extend(_call_provisioner(input_definitions, flags))
return vagrant_definitions
def generate_vagrantfile(input_definitions, flags):
"""
This method is responsible for Vagrantfile generation.
:param input_definitions: device definitions from the input file
:param flags: command line flags
"""
vagrant_definitions = _build_vagrant_definitions(input_definitions, flags)
generate_file("vagrantfile", "Vagrantfile", defs=vagrant_definitions)