An Example¶
We want to check if a network is connected to a known pool of networks representing for example internet access or a corporate internal network through a sequence of routers. To simplify, we will not look at actual routes or ACL but only at the existence of a path.
Let us call root1 the litteral defining the roots of the first group of
networks. root1("N1"). means that network whose name is “N1” belongs to the
group. It must be provided extensively by the operator as a list of facts (This
can be in a separate file generated automatically).
The program computing the networks accessible from those roots is the following:
linked(X,Y) :-
port(id=Z, network_id=X, device_id=T),
router(id=T, name=U),
port(id=V, network_id=Y, device_id=T).
connect1(X) :- root1(Y), network(id=X, name=Y).
connect1(X) :- linked(X, Y), connect1(Y).
connectName1(Y) :- network(id=X, name=Y), connect1(X).
linked defines the fact that two networks are directly connected (through a
router). It exploits the OpenStack tables for ports and routers.
connect1 is defined inductively:
- The first clause (base case) states that a root network is member of
connect1 - The second clause (inductive case) states that a network linked to a member
of
connect1is also a member ofconnect1
connectName1 is used to retrieve the names of networks instead of unreadable
uuids.
A query will typically be connectName1(X) and will give back all the networks
connected.
Now we can define two sets of roots (root1 and root2) and two associated
connect1 and connect2 predicates. root1 could be for example our
production networks and root2 our test networks.
We would like to check if there exists VMs attached to a
network linked to root1 and a network linked to root2. Here is the
predicate that checks such double attachments:
connectVM1(X) :- port(id=Z, network_id=Y, device_id=X), connect1(Y).
connectVM2(X) :- port(id=Z, network_id=Y, device_id=X), connect2(Y).
doubleAttach(Y):- connectVM1(X), connectVM2(X), server(id=X, name=Y).
connectVM1 and connectVM2 define devices that are connected to respectively
root1 and root2.
doubleAttach gives back the name of the VMs members of both groups. We use
the server primitive predicate to find the name of the VM.
Here is a sample output:
$ octant --config-file sample.conf --theory sample.dtl \
--query 'connectName1("N12121")' --query 'connectName1("N21212")' \
--query 'doubleAttach(X)' --time
Parsing time: 0.0034239999999999826
Data retrieval: 1.262298
********************************************************************************
connectName1("N12121")
Query time: 0.012639000000000067
--------------------------------------------------------------------------------
True
********************************************************************************
connectName1("N21212")
Query time: 0.011633999999999922
--------------------------------------------------------------------------------
False
********************************************************************************
doubleAttach(X)
Query time: 0.012620999999999993
--------------------------------------------------------------------------------
['C1', 'C3']
********************************************************************************