Since I'm still stuck waiting on reviews, I figured I'd move on to one of
the next things on my agenda - Aurora-270, hooks for client commands.
Here's what Id like to implement - please beat me up with any criticisms
you have.

We've got hooks in the client that surround API calls. These are pretty
awkward,
because they don't correlate with user actions. For example, suppose we
wanted a policy that said users weren't allowed to kill all instances of a
production job at once.

Right now, all that we could hook would be the "killJob" api call. But
kill (at least in newer versions of the client) normally runs in
batches. If a user called killall, what we would see on the API level
is a series of "killJob" calls, each of which specified a batch of
instances. We woudn't be able to distinguish between really killing all
instances of
a job (which is forbidden under this policy), and carefully killing in
batches (which is permitted.) In each case, the hook would just see a
series of API calls, and couldn't find out what the actual command being
executed was!

For most policy enforcement, what we really want to be able to do is look at
and vet the commands that a user is performing, not the API calls that the
client uses to implement those commands.

So I propose that we add a new kind of hooks, which surround noun/verb
commands. A hook will register itself to handle a collection of (noun,
verb) pairs. Whenever any of those noun/verb commands are invoked, the
hooks methods will be called around the execution of the verb. A pre-hook
will have the ability to reject a command, preventing the verb from being
executed.

These hooks will be registered two ways:
* By the global variable `COMMAND_HOOKS` in a configuration file;
* By a python method call. Hooks registered this way are, effectively,
hardwired into the client executable.

Commands registered by the python call are called _global_ hooks, because
they
will run for all configurations, whether or not they specify any hooks in
the
configuration file.

The order of execution of hooks is unspecified: they may be called in
any order. There is no way to guarantee that one hook will execute
before some other hook.

Users can disable hooks by adding the option `--disable-all-command-hooks`.
The fact that they disabled the hooks will be logged.


The API:

    class Hook(object)
      def get_nouns(self):
        """Return the nouns that have verbs that should invoke this hook."""

      def get_verbs(self, noun):
        """Return the verbs for a particular noun that should invoke his
hook."""

      @abstractmethod
      def pre_command(self, noun, verb, context, commandline):
    """Execute a hook before invoking a verb.
        * noun: the noun being invoked.
* verb: the verb being invoked.
* context: the context object that will be used to invoke the verb.
   The options object will be initialized before calling the hook
        * commandline: the original argv collection used to invoke the
client.
Returns: True if the command should be allowed to proceed; False if the
command
  should be rejected.
        """

      def post_command(self, noun, verb, context, commandline, result):
    """Execute a hook after invoking a verb.
        * noun: the noun being invoked.
* verb: the verb being invoked.
* context: the context object that will be used to invoke the verb.
   The options object will be initialized before calling the hook
        * commandline: the original argv collection used to invoke the
client.
* result: the result code returned by the verb.
Returns: nothing
"""

Reply via email to