def _get_cli_compliance(obj):
    """This function performs the actual compliance for cli configuration."""
    feature = {
        "ordered": obj.rule.config_ordered,
        "name": obj.rule,
    }
    feature.update({"section": obj.rule.match_config.splitlines()})
    value = feature_compliance(feature, obj.actual, obj.intended,
                               get_platform(obj.device.platform.slug))
    compliance = value["compliant"]
    if compliance:
        compliance_int = 1
        ordered = value["ordered_compliant"]
    else:
        compliance_int = 0
        ordered = value["ordered_compliant"]
    missing = _null_to_empty(value["missing"])
    extra = _null_to_empty(value["extra"])
    return {
        "compliance": compliance,
        "compliance_int": compliance_int,
        "ordered": ordered,
        "missing": missing,
        "extra": extra,
    }
    def save(self, *args, **kwargs):
        """Performs the actual compliance check."""
        feature = {
            "ordered": self.rule.config_ordered,
            "name": self.rule,
        }
        if self.rule.config_type == ComplianceRuleTypeChoice.TYPE_JSON:
            feature.update({"section": self.rule.match_config})

            diff = DeepDiff(self.actual,
                            self.intended,
                            ignore_order=self.ordered,
                            report_repetition=True)
            if not diff:
                self.compliance_int = 1
                self.compliance = True
                self.missing = ""
                self.extra = ""
            else:
                self.compliance_int = 0
                self.compliance = False
                self.missing = null_to_empty(
                    self._normalize_diff(diff, "added"))
                self.extra = null_to_empty(
                    self._normalize_diff(diff, "removed"))
        else:
            feature.update({"section": self.rule.match_config.splitlines()})
            value = feature_compliance(feature, self.actual, self.intended,
                                       get_platform(self.device.platform.slug))
            self.compliance = value["compliant"]
            if self.compliance:
                self.compliance_int = 1
            else:
                self.compliance_int = 0
                self.ordered = value["ordered_compliant"]
                self.missing = null_to_empty(value["missing"])
                self.extra = null_to_empty(value["extra"])
        super().save(*args, **kwargs)
Exemple #3
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)
 def test_get_platform_no_settings_definition(self):
     """Test defaults when settings platform_slug_map not used."""
     self.assertEqual(get_platform("cisco"), "cisco")
 def test_get_platform_defined_but_not_relevant(self):
     """Test user defined platform mappings not relevant."""
     self.assertEqual(get_platform("cisco_ios"), "cisco_ios")
 def test_get_platform_user_defined(self):
     """Test user defined platform mappings."""
     self.assertEqual(get_platform("cisco"), "cisco_ios")
 def test_get_platform_with_key_none(self):
     """Test user defined platform mappings and defaults key defined and set to None."""
     self.assertEqual(get_platform("cisco"), "cisco")