[pmg-devel] [PATCH pmg-api v2 04/10] add rule attributes and/invert (for each relevant type)

Dominik Csapak d.csapak at proxmox.com
Wed Feb 21 13:24:30 CET 2024


like with the objectgroups, add an attributes table for groups, and an
'and'/'invert' attribute for each relevant object type
(what/when/from/to).

This is intended to modify the behaviour for the matching regarding
object groups, so that one has more choice in the logical matching.

Also adds the new table to cluster sync, backup and factory reset.

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
changes from v1:
* add comment for rollback
* remove unnecessary transaction for 'load_rules'
  (we didn't actually load the attributes there)
* delete attrubutes on rule delete
* add handling to cluster sync, backup and factory reset
* use a regex for checking the props in the db instead of using a
  loop label for early exit

 src/PMG/API2/ObjectGroupHelpers.pm |   8 ++
 src/PMG/API2/Rules.pm              |  53 +++++++++++-
 src/PMG/Backup.pm                  |   1 +
 src/PMG/Cluster.pm                 |   2 +
 src/PMG/DBTools.pm                 |  16 ++++
 src/PMG/RuleDB.pm                  | 130 ++++++++++++++++++++++++-----
 6 files changed, 186 insertions(+), 24 deletions(-)

diff --git a/src/PMG/API2/ObjectGroupHelpers.pm b/src/PMG/API2/ObjectGroupHelpers.pm
index a08a6a3..3060157 100644
--- a/src/PMG/API2/ObjectGroupHelpers.pm
+++ b/src/PMG/API2/ObjectGroupHelpers.pm
@@ -31,6 +31,14 @@ sub format_rule {
 	active => $rule->{active},
 	direction => $rule->{direction},
     };
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+    for my $type ($types->@*) {
+	for my $attribute ($attributes->@*) {
+	    my $opt = "${type}-${attribute}";
+	    $data->{$opt} = $rule->{$opt} if defined($rule->{$opt});
+	}
+    }
 
     $cond_create_group->($data, 'from', $from);
     $cond_create_group->($data, 'to', $to);
diff --git a/src/PMG/API2/Rules.pm b/src/PMG/API2/Rules.pm
index c48370f..1ebadc2 100644
--- a/src/PMG/API2/Rules.pm
+++ b/src/PMG/API2/Rules.pm
@@ -149,6 +149,54 @@ my $rule_params = {
 	type => 'boolean',
 	optional => 1,
     },
+    'what-and' => {
+	description => "Flag to 'and' combine WHAT group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'what-invert' => {
+	description => "Flag to invert WHAT group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'when-and' => {
+	description => "Flag to 'and' combine WHEN group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'when-invert' => {
+	description => "Flag to invert WHEN group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'from-and' => {
+	description => "Flag to 'and' combine FROM group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'from-invert' => {
+	description => "Flag to invert FROM group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'to-and' => {
+	description => "Flag to 'and' combine TO group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
+    'to-invert' => {
+	description => "Flag to invert TO group matches.",
+	type => 'boolean',
+	default => 0,
+	optional => 1,
+    },
 };
 
 sub get_rule_params {
@@ -203,7 +251,10 @@ __PACKAGE__->register_method ({
 
 	my $rule = $rdb->load_rule($id);
 
-	for my $key (qw(name active direction priority)) {
+	my $keys = ["name", "priority"];
+	push $keys->@*, keys get_rule_params()->%*;
+
+	for my $key ($keys->@*) {
 	    $rule->{$key} = $param->{$key} if defined($param->{$key});
 	}
 
diff --git a/src/PMG/Backup.pm b/src/PMG/Backup.pm
index 9fc91f8..5891afb 100644
--- a/src/PMG/Backup.pm
+++ b/src/PMG/Backup.pm
@@ -95,6 +95,7 @@ sub dumpdb {
 
 	dump_table($dbh, 'attribut', $ofh);
 	dump_table($dbh, 'objectgroup_attributes', $ofh);
+	dump_table($dbh, 'rule_attributes', $ofh);
 	dump_table($dbh, 'object', $ofh, 'object_id_seq', 'id');
 	dump_table($dbh, 'objectgroup', $ofh, 'objectgroup_id_seq', 'id');
 	dump_table($dbh, 'rule', $ofh, 'rule_id_seq', 'id');
diff --git a/src/PMG/Cluster.pm b/src/PMG/Cluster.pm
index ac50cff..f468618 100644
--- a/src/PMG/Cluster.pm
+++ b/src/PMG/Cluster.pm
@@ -533,6 +533,7 @@ sub sync_ruledb_from_master {
 	$ldb->do("DELETE FROM Object");
 	$ldb->do("DELETE FROM Attribut");
 	$ldb->do("DELETE FROM Objectgroup_Attributes");
+	$ldb->do("DELETE FROM Rule_Attributes");
 
 	eval {
 	    $rdb->begin_work;
@@ -545,6 +546,7 @@ sub sync_ruledb_from_master {
 	    PMG::DBTools::copy_table($ldb, $rdb, "ObjectGroup");
 	    PMG::DBTools::copy_table($ldb, $rdb, "Object", 'value');
 	    PMG::DBTools::copy_table($ldb, $rdb, "Attribut", 'value');
+	    PMG::DBTools::copy_table($ldb, $rdb, "Rule_Attributes");
 	    PMG::DBTools::copy_table($ldb, $rdb, "Objectgroup_Attributes");
 	};
 
diff --git a/src/PMG/DBTools.pm b/src/PMG/DBTools.pm
index 3c8d181..3e814dc 100644
--- a/src/PMG/DBTools.pm
+++ b/src/PMG/DBTools.pm
@@ -295,6 +295,18 @@ my $userprefs_ctablecmd =  <<__EOD;
 
 __EOD
 
+my $rule_attributes_cmd = <<__EOD;
+    CREATE TABLE Rule_Attributes (
+      Rule_ID INTEGER NOT NULL,
+      Name VARCHAR(20) NOT NULL,
+      Value BYTEA NULL,
+      PRIMARY KEY (Rule_ID, Name)
+    );
+
+    CREATE INDEX Rule_Attributes_Rule_ID_Index ON Rule_Attributes(Rule_ID);
+
+__EOD
+
 my $object_group_attributes_cmd = <<__EOD;
     CREATE TABLE Objectgroup_Attributes (
       Objectgroup_ID INTEGER NOT NULL,
@@ -452,6 +464,8 @@ sub create_ruledb {
 
         $virusinfo_stat_ctablecmd;
 
+        $rule_attributes_cmd;
+
         $object_group_attributes_cmd;
 EOD
     );
@@ -508,6 +522,7 @@ sub upgradedb {
 	'CStatistic', $cstatistic_ctablecmd,
 	'ClusterInfo', $clusterinfo_ctablecmd,
 	'VirusInfo', $virusinfo_stat_ctablecmd,
+	'Rule_Attributes', $rule_attributes_cmd,
 	'Objectgroup_Attributes', $object_group_attributes_cmd,
     };
 
@@ -620,6 +635,7 @@ sub init_ruledb {
 	$dbh->do(
 	    "DELETE FROM Rule;"
 	    ." DELETE FROM RuleGroup;"
+	    ." DELETE FROM Rule_Attributes;"
 	    ." DELETE FROM Objectgroup_Attributes;"
 	    ." DELETE FROM Attribut WHERE Object_ID NOT IN ($glids);"
 	    ." DELETE FROM Object WHERE ID NOT IN ($glids);"
diff --git a/src/PMG/RuleDB.pm b/src/PMG/RuleDB.pm
index 0b112b4..e5fe56e 100644
--- a/src/PMG/RuleDB.pm
+++ b/src/PMG/RuleDB.pm
@@ -668,6 +668,35 @@ sub delete_object {
     return 1;
 }
 
+sub update_rule_attributes {
+    my ($self, $rule) = @_;
+
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+
+    for my $type ($types->@*) {
+	for my $attribute ($attributes->@*) {
+	    my $prop = "$type-$attribute";
+
+	    # only save the values if they're set to 1
+	    if ($rule->{$prop}) {
+		$self->{dbh}->do(
+		    "INSERT INTO Rule_Attributes (Rule_ID, Name, Value) " .
+		    "VALUES (?, ?, ?) ".
+		    "ON CONFLICT (Rule_ID, Name) DO UPDATE SET Value = ?", undef,
+		    $rule->{id}, $prop, $rule->{$prop}, $rule->{$prop},
+		);
+	    } else {
+		$self->{dbh}->do(
+		    "DELETE FROM Rule_Attributes " .
+		    "WHERE Rule_ID = ? AND Name = ?", undef,
+		    $rule->{id}, $prop,
+		);
+	    }
+	}
+    }
+}
+
 sub save_rule {
     my ($self, $rule) = @_;
 
@@ -682,28 +711,53 @@ sub save_rule {
 
     my $rulename = encode('UTF-8', $rule->{name});
     if (defined($rule->{id})) {
+	$self->{dbh}->begin_work;
+
+	eval {
+	    $self->{dbh}->do(
+		"UPDATE Rule " .
+		"SET Name = ?, Priority = ?, Active = ?, Direction = ? " .
+		"WHERE ID = ?", undef,
+		$rulename, $rule->{priority}, $rule->{active},
+		$rule->{direction}, $rule->{id});
 
-	$self->{dbh}->do(
-	    "UPDATE Rule " .
-	    "SET Name = ?, Priority = ?, Active = ?, Direction = ? " .
-	    "WHERE ID = ?", undef,
-	    $rulename, $rule->{priority}, $rule->{active},
-	    $rule->{direction}, $rule->{id});
+	    $self->update_rule_attributes($rule);
 
-	return $rule->{id};
+	    $self->{dbh}->commit;
+	};
 
+	if (my $err = $@) {
+	    $self->{dbh}->rollback;
+	    syslog('err', $err);
+	    return undef;
+	}
     } else {
-	my $sth = $self->{dbh}->prepare(
-	    "INSERT INTO Rule (Name, Priority, Active, Direction) " .
-	    "VALUES (?, ?, ?, ?);");
+	$self->{dbh}->begin_work;
+
+	eval {
+	    my $sth = $self->{dbh}->prepare(
+		"INSERT INTO Rule (Name, Priority, Active, Direction) " .
+		"VALUES (?, ?, ?, ?);");
+
+	    $sth->execute($rulename, $rule->priority, $rule->active,
+		$rule->direction);
+
+
+	    $rule->{id} = PMG::Utils::lastid($self->{dbh}, 'rule_id_seq');
 
-	$sth->execute($rulename, $rule->priority, $rule->active,
-		      $rule->direction);
+	    $self->update_rule_attributes($rule);
 
-	return $rule->{id} = PMG::Utils::lastid($self->{dbh}, 'rule_id_seq');
+	    $self->{dbh}->commit;
+	};
+
+	if (my $err = $@) {
+	    $self->{dbh}->rollback;
+	    syslog('err', $err);
+	    return undef;
+	}
     }
 
-    return undef;
+    return $rule->{id};
 }
 
 sub delete_rule {
@@ -718,6 +772,8 @@ sub delete_rule {
 			 "WHERE ID = ?", undef, $ruleid);
 	$self->{dbh}->do("DELETE FROM RuleGroup " .
 			 "WHERE Rule_ID = ?", undef, $ruleid);
+	$self->{dbh}->do("DELETE FROM Rule_Attributes " .
+			 "WHERE Rule_ID = ?", undef, $ruleid);
 
 	$self->{dbh}->commit;
     };
@@ -829,24 +885,52 @@ sub rule_remove_group {
     return 1;
 }
 
+sub load_rule_attributes {
+    my ($self, $rule) = @_;
+
+    my $types = [qw(what when from to)];
+    my $attributes = [qw(and invert)];
+
+    my $attribute_sth = $self->{dbh}->prepare("SELECT * FROM Rule_Attributes WHERE Rule_ID = ?");
+    $attribute_sth->execute($rule->{id});
+
+    while (my $ref = $attribute_sth->fetchrow_hashref()) {
+	if ($ref->{name} =~ m/^((?:what|when|from|to)-(?:and|invert))$/) {
+	    my $prop = $1;
+	    $rule->{$prop} = $ref->{value};
+	}
+    }
+}
+
 sub load_rule {
     my ($self, $id) = @_;
 
     defined($id) || die "undefined id: ERROR";
 
-    my $sth = $self->{dbh}->prepare(
-	"SELECT * FROM Rule where id = ? ORDER BY Priority DESC");
+    $self->{dbh}->begin_work;
 
-    my $rules = ();
+    my $rule;
+
+    eval {
+	my $sth = $self->{dbh}->prepare(
+	    "SELECT * FROM Rule where id = ? ORDER BY Priority DESC");
 
-    $sth->execute($id);
+	$sth->execute($id);
 
-    my $ref = $sth->fetchrow_hashref();
-    die "rule '$id' does not exist\n" if !defined($ref);
+	my $ref = $sth->fetchrow_hashref();
+	die "rule '$id' does not exist\n" if !defined($ref);
+
+	$rule = PMG::RuleDB::Rule->new($ref->{name}, $ref->{priority},
+					  $ref->{active}, $ref->{direction});
+	$rule->{id} = $ref->{id};
+
+	$self->load_rule_attributes($rule);
+    };
+    my $err = $@;
+
+    $self->{dbh}->rollback; # finish transaction
 
-    my $rule = PMG::RuleDB::Rule->new($ref->{name}, $ref->{priority},
-				      $ref->{active}, $ref->{direction});
-    $rule->{id} = $ref->{id};
+    die $err if $err;
 
     return $rule;
 }
-- 
2.30.2





More information about the pmg-devel mailing list