help-cfengine
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is this quirky for a simple copy, editfiles operation?


From: Brendan Strejcek
Subject: Re: Is this quirky for a simple copy, editfiles operation?
Date: Thu, 12 May 2005 13:46:27 -0500
User-agent: Mutt/1.5.6+20040907i

Ed Brown wrote:

> On Thu, 2005-05-12 at 09:20, Brendan Strejcek wrote:
> > cfagent could figure out all ordering using class dependencies. 
> 
> Could you illustrate this with an example?  Is this tied in with the
> hierarchy of imports, or am I not getting it?  I'm really interested in
> seeing how another approach can improve flexibility and simplicity of
> ordering operations by cfengine, when that's necessary. 

Here is an example. Say you have a daemon config file that you want to
edit. After you edit this file you will need to restart the daemon. For
the sake of the example, assume that restarting the daemon causes some
logfile permissions to get messed up, so upon a successful restart of
the daemon, you will also need to check and correct the permissions of
the log file. Thus, a clear ordering of the three actions is necessary.
Using the present cfengine, this might be accomplished by something
like:

    control:
        actionsequence = ( editfiles shellcommands files )

    editfiles:
        { /daemon/config/file
            # Edits
            DefineClasses "daemon_config_file_edited"
        }

    shellcommands:
        daemon_config_file_edited::
            "/some/daemon/command restart"
                define=daemon_restarted

    files:
        daemon_restarted::
            /some/daemon/log/file
                mode=some_mode
                owner=some_uid
                group=some_gid
                action=fixall

This works, but is problematic because you may have another set of
operations that have need of the opposite order. For example, consider
a scenario where you need to fix the permissions on a executable, run
the executable, and then edit a file that the executable created on
the filesystem. This requires an order of files, shellcommands, and
the editfiles, the opposite of the above. How does an admin know what
action sequence to use? In any even moderately complicated case, it is
impractical for an admin to figure this out by hand, and there are some
cases where the current two-pass strategy does not work.

Here is a more general exposition of the problem. Say we have action
types A, B, and D (analogous to cfagent actions such as copy,
shellcommands, etc) with specific instances: a (of A), b (of B), and d
(of D), where d depends upon b and b depends upon a. Let us also assume
that there are further instances of these actions: aa (of A), bb (of B),
and dd (of D), where aa depends upon bb, and bb depends upon dd. This is
actually a simple case, and it should be relatively obvious what I mean
with some pseudo-code:

    A:
        any:: a  define=a
        bb::  aa
    B:
        a::   b  define=b
        dd::  bb define=bb
    D:
        b::   d
        any:: dd define=dd

For simplicity, a < b means that b depends on a.

So, encoding the previous example, we obtain two dependency statements:

    (1) a  < b  < d
    (2) dd < bb < aa

Now, there are six possible actionsequence values:

    ABD ADB BAD BDA DAB DBA

In reality, cfagent makes two passes over the actionsequence, so we have
the following actual actionsequence values:

    ABDABD (does not satisfy DBA)
    ADBADB (does not satisfy BDA)
    BADBAD (does not satisfy DAB)
    BDABDA (does not satisfy ADB)
    DABDAB (does not satisfy BAD)
    DBADBA (does not satisfy ABD)

Our example above (a < b < d and dd < bb < aa) is satisfied by the
middle four two-pass scenarios, but each two-pass scenario fails to
satisfy one possible action ordering. The first and last scenarios fail
to satisfy one or the other of the two dependency relationships that we
postulated, so in the current implementation it is possible for an admin
to create a situation where cfagent will not be able to complete one
sequence or the other. You can get around this (if you are aware of the
problem) by using class definitions in the actionsequence, such as:

    control:
        actionsequence = (
            editfiles.daemonconfig
            shellcommands.daemonconfig
            files.daemonconfig
            files.fixexecutable
            shellcommands.fixexecutable
            editfiles.fixexecutable
        )

(Referencing the first example given.) The above is not optimal, but
consider if the policy is broken into several per-task fragments that
are assembled with import.

I think it is clear that if you have N kinds of actions, you need N
passes to ensure that all dependencies are resolved. Of course, N passes
are only necessary if you actually have instances of all possible
orders, which in most cases one will not. cfagent should be able to
construct an optimal ordering be examining each action, and noting which
classes it is contingent upon and which classes it may define. This
is not a proof, so there may be other possible pitfalls that I am not
accounting for, but this certainly seems like the way to go, to me. The
admin should not have to worry about this sort of thing.

Please let me know if anyone can find a flaw in my reasoning or
examples. I do not pretend to be a mathematician, so it is quite
possible that I got some of the above wrong. :-) I hope it is at least
clear.

I was going to include some experimental verification of all these
things, but this message has gotten too long. Maybe in a future message.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]