Exemplo n.º 1
0
 def test_render_jinja_template_exceptions_syntaxerror(
         self, mock_device, mock_nornir_logger):
     """Use invalid templating to cause TemplateSyntaxError from Jinja2 Template."""
     with self.assertRaises(NornirNautobotException):
         with self.assertRaises(jinja_errors.TemplateSyntaxError):
             render_jinja_template(mock_device, mock_nornir_logger,
                                   "{{ obj.fake }")
     mock_nornir_logger.log_failure.assert_called_once()
Exemplo n.º 2
0
 def test_render_jinja_template_exceptions_undefined(
         self, mock_device, mock_nornir_logger):
     """Use fake obj key to cause UndefinedError from Jinja2 Template."""
     with self.assertRaises(NornirNautobotException):
         with self.assertRaises(jinja_errors.UndefinedError):
             render_jinja_template(mock_device, mock_nornir_logger,
                                   "{{ obj.fake }}")
     mock_nornir_logger.log_failure.assert_called_once()
Exemplo n.º 3
0
 def test_render_jinja_template_exceptions_templateerror(
         self, template_mock, mock_device, mock_nornir_logger):
     """Cause issue to cause TemplateError form Jinja2 Template."""
     with self.assertRaises(NornirNautobotException):
         with self.assertRaises(jinja_errors.TemplateError):
             template_mock.side_effect = jinja_errors.TemplateRuntimeError
             render_jinja_template(mock_device, mock_nornir_logger,
                                   "template")
     mock_nornir_logger.log_failure.assert_called_once()
Exemplo n.º 4
0
 def test_render_jinja_template_success_render_context(self, mock_device):
     """Test that device object is passed to template context."""
     platform = "mock_platform"
     mock_device.platform = platform
     rendered_template = render_jinja_template(mock_device, "logger",
                                               "{{ obj.platform }}")
     self.assertEqual(rendered_template, platform)
Exemplo n.º 5
0
def run_backup(  # pylint: disable=too-many-arguments
        task: Task, logger, global_settings, remove_regex_dict,
        replace_regex_dict) -> Result:
    r"""Backup configurations to disk.

    Args:
        task (Task): Nornir task individual object
        remove_regex_dict (dict): {'cisco_ios': ['^Building\\s+configuration.*\\n', '^Current\\s+configuration.*\\n', '^!\\s+Last\\s+configuration.*'], 'arista_eos': ['.s*']}
        replace_regex_dict (dict): {'cisco_ios': [{'regex_replacement': '<redacted_config>', 'regex_search': 'username\\s+\\S+\\spassword\\s+5\\s+(\\S+)\\s+role\\s+\\S+'}]}

    Returns:
        result (Result): Result from Nornir task
    """
    obj = task.host.data["obj"]

    backup_obj = GoldenConfig.objects.filter(device=obj).first()
    if not backup_obj:
        backup_obj = GoldenConfig.objects.create(device=obj, )
    backup_obj.backup_last_attempt_date = task.host.defaults.data["now"]
    backup_obj.save()

    backup_directory = get_repository_working_dir("backup", obj, logger,
                                                  global_settings)
    backup_path_template_obj = render_jinja_template(
        obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_directory, backup_path_template_obj)

    if global_settings.backup_test_connectivity is not False:
        task.run(
            task=dispatcher,
            name="TEST CONNECTIVITY",
            method="check_connectivity",
            obj=obj,
            logger=logger,
            default_drivers_mapping=get_dispatcher(),
        )
    running_config = task.run(
        task=dispatcher,
        name="SAVE BACKUP CONFIGURATION TO FILE",
        method="get_config",
        obj=obj,
        logger=logger,
        backup_file=backup_file,
        remove_lines=remove_regex_dict.get(obj.platform.slug, []),
        substitute_lines=replace_regex_dict.get(obj.platform.slug, []),
        default_drivers_mapping=get_dispatcher(),
    )[1].result["config"]

    backup_obj.backup_last_success_date = task.host.defaults.data["now"]
    backup_obj.backup_config = running_config
    backup_obj.save()

    logger.log_success(
        obj, "Successfully extracted running configuration from device.")

    return Result(host=task.host, result=running_config)
Exemplo n.º 6
0
def run_template(  # pylint: disable=too-many-arguments
        task: Task, logger, global_settings, nautobot_job,
        jinja_root_path) -> Result:
    """Render Jinja Template.

    Only one template is supported, so the expectation is that that template includes all other templates.

    Args:
        task (Task): Nornir task individual object
        logger (NornirLogger): Logger to log messages to.
        global_settings (GoldenConfigSetting): The settings for GoldenConfigPlugin.
        nautobot_job (Result): The the output from the Nautobot Job instance being run.
        jinja_root_path (str): The root path to the Jinja2 intended config file.

    Returns:
        result (Result): Result from Nornir task
    """
    obj = task.host.data["obj"]

    intended_obj = GoldenConfig.objects.filter(device=obj).first()
    if not intended_obj:
        intended_obj = GoldenConfig.objects.create(device=obj)
    intended_obj.intended_last_attempt_date = task.host.defaults.data["now"]
    intended_obj.save()

    intended_directory = get_repository_working_dir("intended", obj, logger,
                                                    global_settings)
    intended_path_template_obj = render_jinja_template(
        obj, logger, global_settings.intended_path_template)
    output_file_location = os.path.join(intended_directory,
                                        intended_path_template_obj)

    jinja_template = render_jinja_template(obj, logger,
                                           global_settings.jinja_path_template)
    status, device_data = graph_ql_query(nautobot_job.request, obj,
                                         global_settings.sot_agg_query)
    if status != 200:
        logger.log_failure(
            obj,
            f"The GraphQL query return a status of {str(status)} with error of {str(device_data)}"
        )
        raise NornirNautobotException()
    task.host.data.update(device_data)

    generated_config = task.run(
        task=dispatcher,
        name="GENERATE CONFIG",
        method="generate_config",
        obj=obj,
        logger=logger,
        jinja_template=jinja_template,
        jinja_root_path=jinja_root_path,
        output_file_location=output_file_location,
        default_drivers_mapping=get_dispatcher(),
        jinja_filters=jinja_env.filters,
    )[1].result["config"]
    intended_obj.intended_last_success_date = task.host.defaults.data["now"]
    intended_obj.intended_config = generated_config
    intended_obj.save()

    logger.log_success(obj,
                       "Successfully generated the intended configuration.")

    return Result(host=task.host, result=generated_config)
def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
    task: Task,
    logger,
    global_settings,
    rules,
) -> Result:
    """Prepare data for compliance task.

    Args:
        task (Task): Nornir task individual object

    Returns:
        result (Result): Result from Nornir task
    """
    obj = task.host.data["obj"]

    compliance_obj = GoldenConfig.objects.filter(device=obj).first()
    if not compliance_obj:
        compliance_obj = GoldenConfig.objects.create(device=obj)
    compliance_obj.compliance_last_attempt_date = task.host.defaults.data[
        "now"]
    compliance_obj.save()

    intended_directory = get_repository_working_dir("intended", obj, logger,
                                                    global_settings)

    intended_path_template_obj = render_jinja_template(
        obj, logger, global_settings.intended_path_template)
    intended_file = os.path.join(intended_directory,
                                 intended_path_template_obj)
    if not os.path.exists(intended_file):
        logger.log_failure(
            obj,
            f"Unable to locate intended file for device at {intended_file}")
        raise NornirNautobotException()

    backup_directory = get_repository_working_dir("backup", obj, logger,
                                                  global_settings)

    backup_template = render_jinja_template(
        obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_directory, backup_template)
    if not os.path.exists(backup_file):
        logger.log_failure(
            obj, f"Unable to locate backup file for device at {backup_file}")
        raise NornirNautobotException()

    platform = obj.platform.slug
    if not rules.get(platform):
        logger.log_failure(
            obj,
            f"There is no defined `Configuration Rule` for platform slug `{platform}`."
        )
        raise NornirNautobotException()

    if get_platform(platform) not in parser_map.keys():
        logger.log_failure(
            obj,
            f"There is currently no parser support for platform slug `{get_platform(platform)}`."
        )
        raise NornirNautobotException()

    backup_cfg = _open_file_config(backup_file)
    intended_cfg = _open_file_config(intended_file)

    # TODO: Make this atomic with compliance_obj step.
    for rule in rules[obj.platform.slug]:
        # using update_or_create() method to conveniently update actual obj or create new one.
        ConfigCompliance.objects.update_or_create(
            device=obj,
            rule=rule["obj"],
            defaults={
                "actual":
                section_config(rule, backup_cfg, get_platform(platform)),
                "intended":
                section_config(rule, intended_cfg, get_platform(platform)),
                "missing":
                "",
                "extra":
                "",
            },
        )

    compliance_obj.compliance_last_success_date = task.host.defaults.data[
        "now"]
    compliance_obj.compliance_config = "\n".join(
        diff_files(backup_file, intended_file))
    compliance_obj.save()
    logger.log_success(obj, "Successfully tested compliance job.")

    return Result(host=task.host)
Exemplo n.º 8
0
 def test_render_jinja_template_success_with_filter(self, mock_device):
     """Test custom template and jinja filter are accessible."""
     rendered_template = render_jinja_template(mock_device, "logger",
                                               "{{ data | return_a }}")
     self.assertEqual(rendered_template, "a")
Exemplo n.º 9
0
 def test_render_jinja_template_success(self, mock_device):
     """Simple success test to return template."""
     worker = render_jinja_template(mock_device, "logger",
                                    "fake-template-contents")
     self.assertEqual(worker, "fake-template-contents")