def run_template(  # pylint: disable=too-many-arguments
        task: Task, logger, global_settings, job_result, jinja_root_path,
        intended_root_folder) -> 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

    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_path_template_obj = check_jinja_template(
        obj, logger, global_settings.intended_path_template)
    output_file_location = os.path.join(intended_root_folder,
                                        intended_path_template_obj)

    jinja_template = check_jinja_template(obj, logger,
                                          global_settings.jinja_path_template)

    status, device_data = graph_ql_query(job_result.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(),
    )[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)
コード例 #2
0
 def test_check_jinja_template_exceptions_templateerror(
         self, template_mock):
     """Cause issue to cause TemplateError form Jinja2 Template."""
     log_mock = Mock()
     with self.assertRaises(NornirNautobotException):
         template_mock.side_effect = TemplateError
         template_render = check_jinja_template("test-obj", log_mock,
                                                "template")
         self.assertEqual(template_render, TemplateError)
         template_mock.assert_called_once()
コード例 #3
0
def run_backup(  # pylint: disable=too-many-arguments
        task: Task, logger, global_settings, remove_regex_dict,
        replace_regex_dict, backup_root_folder) -> 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_path_template_obj = check_jinja_template(
        obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_root_folder, 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 backed up device.")

    return Result(host=task.host, result=running_config)
コード例 #4
0
def run_backup(task: Task, logger, global_settings, backup_root_folder) -> Result:
    """Backup configurations to disk.

    Args:
        task (Task): Nornir task individual object

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

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

    backup_path_template_obj = check_jinja_template(obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_root_folder, backup_path_template_obj)
    substitute_lines = get_substitute_lines(global_settings.substitute_lines)

    if global_settings.backup_test_connectivity is not False:
        task.run(
            task=dispatcher,
            name="TEST CONNECTIVITY",
            method="check_connectivity",
            obj=obj,
            logger=logger,
        )
    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=global_settings.remove_lines.splitlines(),
        substitute_lines=substitute_lines,
    )[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 backed up device.")

    return Result(host=task.host, result=running_config)
コード例 #5
0
 def test_check_jinja_template_exceptions_syntaxerror(self):
     """Use invalid templating to cause TemplateSyntaxError from Jinja2 Template."""
     log_mock = Mock()
     with self.assertRaises(NornirNautobotException):
         check_jinja_template("test-obj", log_mock, "{{ obj.fake }")
コード例 #6
0
 def test_check_jinja_template_exceptions_undefined(self):
     """Use fake obj key to cause UndefinedError from Jinja2 Template."""
     log_mock = Mock()
     with self.assertRaises(NornirNautobotException):
         check_jinja_template("test-obj", log_mock, "{{ obj.fake }}")
コード例 #7
0
 def test_check_jinja_template_success(self):
     """Simple success test to return template."""
     worker = check_jinja_template("obj", "logger", "fake-template-name")
     self.assertEqual(worker, "fake-template-name")
コード例 #8
0
def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
    task: Task,
    logger,
    global_settings,
    backup_root_path,
    intended_root_folder,
    features,
) -> 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_path_template_obj = check_jinja_template(
        obj, logger, global_settings.intended_path_template)

    intended_file = os.path.join(intended_root_folder,
                                 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_template = check_jinja_template(
        obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_root_path, 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 features.get(platform):
        logger.log_failure(
            obj,
            f"There is no `user` defined feature mapping 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 feature in features[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=feature["obj"],
            defaults={
                "actual":
                section_config(feature, backup_cfg, get_platform(platform)),
                "intended":
                section_config(feature, 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.")

    return Result(host=task.host)
コード例 #9
0
def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
    task: Task,
    logger,
    global_settings,
    backup_root_path,
    intended_root_folder,
    features,
) -> 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 = GoldenConfiguration.objects.filter(device=obj).first()
    if not compliance_obj:
        compliance_obj = GoldenConfiguration.objects.create(device=obj)
    compliance_obj.compliance_last_attempt_date = task.host.defaults.data[
        "now"]
    compliance_obj.save()

    intended_path_template_obj = check_jinja_template(
        obj, logger, global_settings.intended_path_template)

    intended_file = os.path.join(intended_root_folder,
                                 intended_path_template_obj)

    backup_template = check_jinja_template(
        obj, logger, global_settings.backup_path_template)
    backup_file = os.path.join(backup_root_path, backup_template)

    platform = obj.platform.slug
    if not features.get(platform):
        logger.log_failure(
            obj,
            f"There is no `user` defined feature mapping for platform slug {platform}."
        )
        raise NornirNautobotException()

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

    feature_data = task.run(
        task=dispatcher,
        name="GET COMPLIANCE FOR CONFIG",
        method="compliance_config",
        obj=obj,
        logger=logger,
        backup_file=backup_file,
        intended_file=intended_file,
        features=features[platform],
        platform=platform,
    )[1].result["feature_data"]

    for feature, value in feature_data.items():
        defaults = {
            "actual": null_to_empty(value["actual"]),
            "intended": null_to_empty(value["intended"]),
            "missing": null_to_empty(value["missing"]),
            "extra": null_to_empty(value["extra"]),
            "compliance": value["compliant"],
            "ordered": value["ordered_compliant"],
        }
        # using update_or_create() method to conveniently update actual obj or create new one.
        ConfigCompliance.objects.update_or_create(
            device=obj,
            feature=feature,
            defaults=defaults,
        )

    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 complinace.")

    return Result(host=task.host, result=feature_data)