% vim set ft=prolog % rule(src, dst, proto, port, source(..)). :- module(firewall, [ %fw_rule/2, warning/1, retract_all_from/1]). :- use_module(library(assoc)). :- use_module(library(csv)). :- use_module(library(dcgs)). :- use_module(library(files)). :- use_module(library(format)). :- use_module(library(lists)). :- use_module(library(serialization/json)). :- use_module(hosts, [ router_link/3]). :- dynamic(fw_rule/2). warning(Msg) :- fw_rule(Host, Attr), \+ get_assoc("from", Attr, _), format("Missing 'from' on fw_rule for host '~w', ~w", [Host, Attr], Msg). rules_from(From, Rules) :- findall( fw_rule(H, Attr), ( fw_rule(H, Attr), get_assoc("from", Attr, From) ), Rules). retract_all_from(From) :- rules_from(From, Rules), retract_rules(Rules). retract_rules([R|Rules]) :- retract(R), retract_rules(Rules). retract_rules([]). ansible(Basedir) :- setof(Host, Attrs^fw_rule(Host, Attrs), Hosts), ansible_host(Basedir, Hosts). ansible_host(Basedir, [Host|Hosts]) :- atom_chars(Host, HostS), append(Basedir, [HostS], DirPs), path_segments(Dir, DirPs), append(Basedir, [HostS, "firewall.csv"], FilePs), path_segments(File, FilePs), format("mkdir ~s~n", [Dir]), make_directory_path(Dir), ansible_firewall(File, Host), ansible_host(Basedir, Hosts). get_opt(Key, Assoc, Value) :- (get_assoc(Key, Assoc, Value) -> true; Value=''). to_csv(Host, Attrs, Row) :- get_opt(family, Attrs, Family), get_opt(src, Attrs, Src), get_opt(dst, Attrs, Dst), Row = [Host, Family, Src, Dst]. ansible_firewall(File, Host) :- format("ansible_firewall: ~s~n", [File]), findall(Attrs, fw_rule(Host, Attrs), Rules), maplist(to_csv(Host), Rules, Rows), write_csv(File, frame(['host','family','src','dst'], Rows)).