From 25b51367ea29b07b4e4427979266b6a372ac7baf Mon Sep 17 00:00:00 2001
From: Attila Farkas <x394097@fi.muni.cz>
Date: Wed, 15 Apr 2020 13:26:13 +0200
Subject: [PATCH] modify exception handeling

---
 create.py                    | 54 ++++--------------------
 modules/border_router.py     |  7 +---
 modules/file_manager.py      | 81 +++++++++++++++++++++++-------------
 modules/preprocessing.py     | 30 +++++++++----
 modules/vagrant_generator.py | 14 ++-----
 5 files changed, 89 insertions(+), 97 deletions(-)

diff --git a/create.py b/create.py
index 289c21d..ea506e7 100644
--- a/create.py
+++ b/create.py
@@ -14,53 +14,15 @@ from modules.input_file_validator import validate_device_definitions
 from modules.preprocessing import preprocess
 
 
-""" Parsing the input arguments. """
 flags = dict()
+input_file_name = parse_input_args(sys.argv, flags)
+device_definitions = open_yaml(input_file_name)
 
-try:
-    input_file_name = parse_input_args(sys.argv, flags)
-except Exception:
-    print("Input arguments could not be parsed.")
-    sys.exit(1)
+validate_device_definitions(device_definitions)
+preprocess(device_definitions, flags)
+prepare_directories(device_definitions)
 
-""" Parsing the definitions file. """
-try:
-    device_definitions = open_yaml(input_file_name)
-except Exception:
-    print("Definitions file could not be parsed.")
-    sys.exit(1)
-
-""" Validating device definitions. """
-try:
-    validate_device_definitions(device_definitions)
-except Exception:
-    print("Device definition validation was not sussessful.")
-    sys.exit(1)
-
-""" Preprocessing the definitions before device creation. """
-try:
-    preprocess(device_definitions, flags)
-except Exception:
-    print("Preprocessing was not successful.")
-    sys.exit(1)
-
-""" Preparing the directory structure. """
-try:
-    prepare_directories(device_definitions)
-except Exception:
-    print("Directory structure was not created.")
-    sys.exit(1)
-
-""" Generating Vagrantfile. """
-try:
-    generate_vagrantfile(device_definitions, flags)
-except Exception:
-    print("Vagrantfile was not created.")
-    sys.exit(1)
-
-""" Generating ansible playbooks. """
-#try:
+generate_vagrantfile(device_definitions, flags)
 generate_playbooks(device_definitions, flags)
-#except Exception:
-#    print("Playbooks could not be created.")
-#    sys.exit(1)
+
+print("Sandbox was successfully created.")
diff --git a/modules/border_router.py b/modules/border_router.py
index 1a60353..68cffc6 100644
--- a/modules/border_router.py
+++ b/modules/border_router.py
@@ -20,7 +20,6 @@ def _are_br_parameters_free(definitions):
         if net_mapping["ip"] == BORDER_ROUTER_IP:
             return False
 
-
     for router_mapping in definitions["router_mappings"]:
         if router_mapping["ip"] == BORDER_ROUTER_IP:
             return False
@@ -34,8 +33,7 @@ def _create_mappings_to_border_router(definitions):
     for router in definitions["routers"]:
         num = definitions["routers"].index(router) + 5
         if num > 255:
-            print("Error: Too many routers.")
-            raise IndexError
+            raise IndexError("Too many routers.")
 
         ip = BORDER_ROUTER_IP[:(0-len(str(num)))]
         ip += str(num)
@@ -54,8 +52,7 @@ def create_border_router(definitions):
 
     # TODO this should be later moved to input check
     if not _are_br_parameters_free(definitions):
-        print("Error: A device with the same name as border router already exists.")
-        raise ValueError
+        raise ValueError("A device with the same name as border router already exists.")
     
     _create_mappings_to_border_router(definitions)
 
diff --git a/modules/file_manager.py b/modules/file_manager.py
index 9bf0091..75524ea 100644
--- a/modules/file_manager.py
+++ b/modules/file_manager.py
@@ -1,23 +1,25 @@
 """ This module handles file imports and creations in general. """
 
 import os
-from jinja2 import Environment, FileSystemLoader
-from shutil import copyfile, rmtree
-from yaml import dump, safe_load
+import shutil
+import sys
+
+import jinja2
+import yaml
 
 OUTPUT_DIRECTORY = "sandbox"
 
 
 def open_yaml(file_name):
     """ Opens and returns a file from the argument. """
+
     try:
-        input_file = open(str(file_name))
-        return safe_load(input_file)
+        with open(str(file_name)) as input_file:
+            return yaml.safe_load(input_file)
+    except yaml.YAMLError:
+        cleanup_and_exit("Could not parse yaml file " + str(file_name) + ".")
     except IOError:
-        print("Error: Cannot open the required file: " + str(file_name))
-        raise
-    finally:
-        input_file.close()
+        cleanup_and_exit("Could not open yaml file " + str(file_name) + ".")
 
 
 def copy_template_file(template, destination):
@@ -26,10 +28,9 @@ def copy_template_file(template, destination):
     """
 
     try:
-        copyfile("templates/" + template, "sandbox/" + destination)
+        shutil.copyfile("templates/" + template, "sandbox/" + destination)
     except IOError:
-        print("Error: cannot write to this location.")
-        raise
+        cleanup_and_exit("Could not copy template file " + str(file_name) + ".")
 
 
 def dump_to_yaml(data, filename):
@@ -39,14 +40,13 @@ def dump_to_yaml(data, filename):
     :param filename: name of the target file
     """
 
+    file_path = OUTPUT_DIRECTORY + "/" + str(filename)
+
     try:
-        stream = open(OUTPUT_DIRECTORY + "/" + filename, 'w')
-        dump(data, stream)
+        with open(file_path, 'w') as stream:
+            yaml.dump(data, stream)
     except IOError:
-        print("Error: cannot write to this location.")
-        raise
-    finally:
-        stream.close()
+        cleanup_and_exit("Could not create yaml file " + file_path + ".")
 
 
 def generate_file(template, filename, **template_args):
@@ -69,16 +69,29 @@ def _write_to_file(filename, output_string):
         new_file = open(OUTPUT_DIRECTORY + "/" + filename, "w")
         new_file.write(output_string)
     except IOError:
-        print("Error: cannot write to this location.")
-        raise
+        cleanup_and_exit("Could not create file " + str(filename) + ".")
 
 
 def _load_template(template_name):
     """ Returns a loaded jinja2 template. """
 
-    template_loader = FileSystemLoader(searchpath="templates")
-    template_env = Environment(loader=template_loader, trim_blocks=True, lstrip_blocks=True)
-    return template_env.get_template(template_name)
+    try:
+        template_loader = jinja2.FileSystemLoader(searchpath="templates")
+        template_env = jinja2.Environment(loader=template_loader, trim_blocks=True, lstrip_blocks=True)
+        return template_env.get_template(template_name)
+    except jinja2.TemplateNotFound:
+        cleanup_and_exit("Could not find template " + str(template_name) + ".")
+
+
+def _copy_directory(source, destination):
+    """ Copies directory recursively form templates directory to the
+    destination.
+    """
+
+    try:
+        shutil.copytree("./templates/" + source, destination)
+    except OSError:
+        cleanup_and_exit("Could not copy directory " + str(source) + ".")
 
 
 def _create_provisioning_directories(directory, device_definitions):
@@ -109,20 +122,32 @@ def _create_provisioning_directories(directory, device_definitions):
     except FileExistsError:
         pass
     except IOError:
-        print("Could not create directories for provisioning.")
-        raise
+        cleanup_and_exit("Could not create directories for provisioning.")
 
 
 def prepare_directories(device_definitions):
     """ Prepares the necessary directory structure. """
 
-    rmtree(OUTPUT_DIRECTORY, True)
+    shutil.rmtree(OUTPUT_DIRECTORY, True)
     
     try:
         os.mkdir(OUTPUT_DIRECTORY)
     except IOError:
-        print("Could not create directory ./" + OUTPUT_DIRECTORY + ".")
-        raise
+        cleanup_and_exit("Could not create directory ./" + OUTPUT_DIRECTORY + ".")
 
     _create_provisioning_directories("base_provisioning", device_definitions)
     _create_provisioning_directories("provisioning", device_definitions)
+
+    _copy_directory("interface", OUTPUT_DIRECTORY + "/base_provisioning/roles/interface")
+    _copy_directory("common", OUTPUT_DIRECTORY + "/base_provisioning/roles/common")
+
+
+def cleanup_and_exit(error):
+    """ A cleanup function that is called in case of an error. """
+
+    # TODO cleanup
+
+    print("Sandbox creation was NOT successful:")
+    print("Error: ", error)
+
+    sys.exit(1)
diff --git a/modules/preprocessing.py b/modules/preprocessing.py
index 5f97a38..01054bf 100644
--- a/modules/preprocessing.py
+++ b/modules/preprocessing.py
@@ -8,6 +8,20 @@ from modules.file_manager import open_yaml
 FLAVORS = open_yaml("conf/flavors.yml")
 ROUTER_ATTRIBUTES = open_yaml("conf/router_attributes.yml")
 
+def _add_missing_tags(definitions):
+    """ Adds necessary structures to the input if they are missing. """
+
+    if "routers" not in definitions:
+        definitions["routers"] = []
+    if "router_mappings" not in definitions:
+        definitions["router_mappings"] = []
+    if "hosts" not in definitions:
+        definitions["hosts"] = []
+    if "net_mappings" not in definitions:
+        definitions["net_mappings"] = []
+    if "networks" not in definitions:
+        definitions["networks"] = []
+
 
 def _configure_routers(definitions):
     """ Adds predefined parameters to all routers if they are not defined in
@@ -44,21 +58,23 @@ def preprocess(definitions, flags):
     :param flags: a structure with command line flags
     """
 
+    try:
+        _add_missing_tags(definitions)
+    except Exception:
+        cleanup_and_exit("Preprocessing not successful: Could not add missing tags.")
+
     try:
         if "border_router" in flags and flags["border_router"]:
             create_border_router(definitions)
-    except Exception:
-        print("Could not create border router.")
-        raise
+    except (ValueError, IndexError) as e:
+        cleanup_and_exit("Preprocessing not successful: Could not create border router (" + e + ")")
 
     try:
         _configure_routers(definitions)
     except Exception:
-        print("Could not add router configurations to definitions.")
-        raise
+        cleanup_and_exit("Preprocessing not successful: Could not add router configurations to definitions.")
 
     try:
         _add_flavors(definitions)
     except Exception:
-        print("Could not add flavor.")
-        raise
+        cleanup_and_exit("Preprocessing not successful: Could not add flavors.")
diff --git a/modules/vagrant_generator.py b/modules/vagrant_generator.py
index d02f949..fd01571 100644
--- a/modules/vagrant_generator.py
+++ b/modules/vagrant_generator.py
@@ -183,14 +183,6 @@ def generate_vagrantfile(input_definitions, flags):
     :param flags: command line flags
     """
 
-    try:
-        vagrant_definitions = _build_vagrant_definitions(input_definitions, flags)
-    except Exception:
-       print("Could not create definitions for Vagrantfile.")
-       raise
-
-    try:
-       generate_file("vagrantfile", "Vagrantfile", defs=vagrant_definitions)
-    except Exception:
-       print("Could not generate Vagrantfile.")
-       raise
+    vagrant_definitions = _build_vagrant_definitions(input_definitions, flags)
+
+    generate_file("vagrantfile", "Vagrantfile", defs=vagrant_definitions)
-- 
GitLab