Added: aurora/site/source/documentation/0.6.0-incubating/design/command-hooks.md
URL: 
http://svn.apache.org/viewvc/aurora/site/source/documentation/0.6.0-incubating/design/command-hooks.md?rev=1719807&view=auto
==============================================================================
--- aurora/site/source/documentation/0.6.0-incubating/design/command-hooks.md 
(added)
+++ aurora/site/source/documentation/0.6.0-incubating/design/command-hooks.md 
Sun Dec 13 17:04:12 2015
@@ -0,0 +1,263 @@
+# Command Hooks for the Aurora Client
+
+## Introduction/Motivation
+
+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.
+
+## Registering Hooks
+
+These hooks will be registered two ways:
+* Project hooks file. If a file named `AuroraHooks` is in the project directory
+  where an aurora command is being executed, that file will be read,
+  and its hooks will be registered.
+* Configuration plugins. A configuration plugin can register hooks using an 
API.
+  Hooks registered this way are, effectively, hardwired into the client 
executable.
+
+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.
+
+
+### Global Hooks
+
+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.
+
+In the implementation, hooks are registered in the module
+`apache.aurora.client.cli.command_hooks`, using the class 
`GlobalCommandHookRegistry`.  A
+global hook can be registered by calling 
`GlobalCommandHookRegistry.register_command_hook`
+in a configuration plugin.
+
+### Hook Files
+
+A hook file is a file containing Python source code. It will be
+dynamically loaded by the Aurora command line executable. After
+loading, the client will check the module for a global variable named
+"hooks", which contains a list of hook objects, which will be added to
+the hook registry.
+
+A project hooks file will be named `AuroraHooks`,
+and will be located in either the directory where the command is being
+executed, or one of its parent directories, up to the nearest git/mercurial
+repository base.
+
+### The API
+
+    class CommandHook(object)
+      @property
+      def name(self):
+        """Returns a name for the hook."
+
+      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
+        """
+
+    class GlobalCommandHookRegistry(object):
+      @classmethod
+      def register_command_hook(self, hook):
+        pass
+
+## Skipping Hooks
+
+In a perfect world, hooks would represent a global property or policy
+that should always be enforced. Unfortunately, we don't live in a
+perfect world, which means that sometimes, every rule needs to get
+broken.
+
+For example, an organization could decide that every configuration
+must be checked in to source control before it could be
+deployed. That's an entirely reasonable policy. It would be easy to
+implement it using a hook. But what if there's a problem, and the
+source repos is down?
+
+The easiest solution is just to allow a user to add a `--skip-hooks`
+flag to the command-line. But doing that means that an organization
+can't actually use hooks to enforce policy, because users can skip
+them whenever they want.
+
+Instead, we'd like to have a system where it's possible to create
+hooks to enforce policy, and then include a way of building policy
+about when hooks can be skipped.
+
+I'm using sudo as a rough model for this. Many organizations need to
+give people the ability to run privileged commands, but they still
+want to have some control. Sudo allows them to specify who is allowed
+to run a privileged command; where they're allowed to run it; and what
+command(s) they're allowed to run.  All of that is specified in a
+special system file located in `/etc/sudoers` on a typical unix
+machine.
+
+In a world of distributed systems, this approach has one grave
+weakness. An aurora client can be located on any machine that has
+network access to a Mesos/Aurora cluster. It can be run by a user in
+pretty much any way they want - from a machine they control, from a
+special chroot they created, etc. Relying an a file being in a special
+location on their machine isn't sufficient - it's too easy to
+maliciously or erroneously run a command in an environment with an
+invalid hooks exceptions file.
+
+Instead, we've got two basic choices: hook exception rules can be
+baked into the client executable, or they can be provided in a
+network location.
+
+### Specifying when hooks can be skipped
+
+#### Hooks File
+
+The module `apache.aurora.client.cli` contains a variable named
+`GLOBAL_HOOK_SKIP_RULES_URL`. In the default distribution of Aurora, tihs 
variable contains
+`None`. Users can modify this value for their local environments, providing
+a site specific URL. If users attempt to bypass command hooks, and this
+URL is not `None`, then the client will fetch the contents of that URL, and
+attempt to interpret it as a hooks exception file.
+
+The hooks exception file is written in JSON, with the following structure:
+
+    { "rulename":
+      {
+      "hooks": [ "hook-name ", ... ],
+      "users": [ string, ...],
+      "commands": { "job": ["kill", "killall", ...], ... },
+      "arg-patterns": [ "regexp-str", ... ]
+      },
+         ...
+    }
+
+* `hooks` is a list of hook identifiers which can be skipped by a user
+  that satisfies this rule. If omitted, then this rule applies to _all hooks_.
+  (Omitting the `hooks` field is equivalent to giving it the value `['*']`.)
+* `users` is a list of user names, or glob expressions that range over user
+  names. This rule gives permission to those users to skip hooks. If omitted,
+  then this rule allows _any user_ to skip hooks that satisfy the rest of this 
rule.
+  Note that this is _user_ names, not
+  _role_ names: the rules specify users that are allowed to skip commands.
+  Some users that are allowed to work with a role account may be allowed to
+  skip, while others cannot.
+* `commands` is a map from nouns to lists of verbs. If a command `aurora n v`
+  is being executed, this rule allows the hooks to be skipped if
+  `v` is in `commands[n]`. If this is omitted, then it allows hooks to be 
skipped for all
+  commands that satisfy the rest of the rule.
+* `arg_patterns` is a list of glob patterns ranging over parameters.
+  If any of the parameters of the command match the parameters in this list,
+  the hook can be skipped. If ommitted, then this applies regardless of 
arguments.
+
+For example, the following is a hook rules file which allows:
+* The user "root" to skip any hook.
+* Any user to skip hooks for test jobs.
+* A specific group of users to skip hooks for jobs in cluster `east`
+* Another group of users to skip hooks for `job kill` in cluster `west`.
+
+    {
+      "allow-admin": { "users": ["root"] },
+         "allow-test": { "users": ["\*"], "arg-patterns": ["\*/\*/test/\*"] },
+         "allow-east-users": { "users"=['john', 'mary', 'mike', 'sue'],
+          "arg-patterns": ["east/\*/\*/\*"] },
+         "allow-west-kills": { "users": ["anne", "bill", "chris"],
+          "commands": { "job": ["kill"]}, "arg-patterns" = ["west/\*/\*/\*"] }
+    }
+
+#### Programmatic Hooks Exceptions
+
+The `GlobalHooksRegistry` contains the method `add_hooks_exception`, which 
allows
+users to register local hooks exceptions using the `ConfigurationPlugin` 
mechanism.
+A hooks exception object implements the following interface:
+
+    class HooksException(object):
+         def allow_exception(self, hooks, role, noun, verb, args):
+           """Params:
+        - hooks: a list of hook-names that the user wants to skip. If this
+                 is ommitted, then this applies to all hooks.
+               - role: the role requesting that hooks be skipped.
+               - noun, verb: the noun and verb being executed.
+               - the other command-line arguments.
+               Returns: True if the user should be allowed to skip the 
requested hooks.
+               """
+           return False
+
+When a user supplies the `--skip-hooks` argument, `allow_exception` is invoked 
on
+each of the `HooksException` arguments. If _any_ of the hooks exception objects
+returns `True`, then the user will be permitted to skip the hooks.
+
+### Skipping Hooks
+
+To skip a hook, a user uses a command-line option, `--skip-hooks`. The option 
can either
+specify specific hooks to skip, or "all":
+
+* `aurora --skip-hooks=all job create east/bozo/devel/myjob` will create a job
+  without running any hooks.
+* `aurora --skip-hooks=test,iq create east/bozo/devel/myjob` will create a job,
+  and will skip only the hooks named "test" and "iq".
+
+
+## Changes
+
+4/30:
+* Rule exceptions are defined in JSON, and they are specified to be loaded from
+  a URL, not from a local file.
+* Rule exceptions specify users, not roles.
+
+4/27:
+Major changes between this and the last version of this proposal.
+* Command hooks can't be declared in a configuration file. There's a simple
+  reason why: hooks run before a command's implementation is invoked.
+  Config files are read during the commands invocation if necessary. If the
+  hook is declared in the config file, by the time you know that it should
+  have been run, it's too late. So I've removed config-hooks from the
+  proposal. (API hooks defined by configs still work.)
+* Skipping hooks. We expect aurora to be used inside of large
+  organizations. One of the primary use-cases of hooks is to create
+  enforcable policy that are specific to an organization. If hooks
+  can just be skipped because a user wants to skip them, it means that
+  the policy can't be enforced, which defeats the purpose of having them.
+  So in this update, I propose a mechanism, loosely based on a `sudo`-like
+  mechanism for defining when hooks can be skipped.

Added: aurora/site/source/documentation/0.7.0-incubating/design/command-hooks.md
URL: 
http://svn.apache.org/viewvc/aurora/site/source/documentation/0.7.0-incubating/design/command-hooks.md?rev=1719807&view=auto
==============================================================================
--- aurora/site/source/documentation/0.7.0-incubating/design/command-hooks.md 
(added)
+++ aurora/site/source/documentation/0.7.0-incubating/design/command-hooks.md 
Sun Dec 13 17:04:12 2015
@@ -0,0 +1,102 @@
+# Command Hooks for the Aurora Client
+
+## Introduction/Motivation
+
+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.
+
+## Registering Hooks
+
+These hooks will be registered via configuration plugins. A configuration 
plugin
+can register hooks using an API. Hooks registered this way are, effectively,
+hardwired into the client executable.
+
+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.
+
+
+### Global Hooks
+
+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.
+
+In the implementation, hooks are registered in the module
+`apache.aurora.client.cli.command_hooks`, using the class
+`GlobalCommandHookRegistry`. A global hook can be registered by calling
+`GlobalCommandHookRegistry.register_command_hook` in a configuration plugin.
+
+### The API
+
+    class CommandHook(object)
+      @property
+      def name(self):
+        """Returns a name for the hook."
+
+      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
+        """
+
+    class GlobalCommandHookRegistry(object):
+      @classmethod
+      def register_command_hook(self, hook):
+        pass
+
+### Skipping Hooks
+
+To skip a hook, a user uses a command-line option, `--skip-hooks`. The option 
can either
+specify specific hooks to skip, or "all":
+
+* `aurora --skip-hooks=all job create east/bozo/devel/myjob` will create a job
+  without running any hooks.
+* `aurora --skip-hooks=test,iq create east/bozo/devel/myjob` will create a job,
+  and will skip only the hooks named "test" and "iq".

Added: aurora/site/source/documentation/0.8.0/design/command-hooks.md
URL: 
http://svn.apache.org/viewvc/aurora/site/source/documentation/0.8.0/design/command-hooks.md?rev=1719807&view=auto
==============================================================================
--- aurora/site/source/documentation/0.8.0/design/command-hooks.md (added)
+++ aurora/site/source/documentation/0.8.0/design/command-hooks.md Sun Dec 13 
17:04:12 2015
@@ -0,0 +1,102 @@
+# Command Hooks for the Aurora Client
+
+## Introduction/Motivation
+
+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.
+
+## Registering Hooks
+
+These hooks will be registered via configuration plugins. A configuration 
plugin
+can register hooks using an API. Hooks registered this way are, effectively,
+hardwired into the client executable.
+
+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.
+
+
+### Global Hooks
+
+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.
+
+In the implementation, hooks are registered in the module
+`apache.aurora.client.cli.command_hooks`, using the class
+`GlobalCommandHookRegistry`. A global hook can be registered by calling
+`GlobalCommandHookRegistry.register_command_hook` in a configuration plugin.
+
+### The API
+
+    class CommandHook(object)
+      @property
+      def name(self):
+        """Returns a name for the hook."
+
+      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
+        """
+
+    class GlobalCommandHookRegistry(object):
+      @classmethod
+      def register_command_hook(self, hook):
+        pass
+
+### Skipping Hooks
+
+To skip a hook, a user uses a command-line option, `--skip-hooks`. The option 
can either
+specify specific hooks to skip, or "all":
+
+* `aurora --skip-hooks=all job create east/bozo/devel/myjob` will create a job
+  without running any hooks.
+* `aurora --skip-hooks=test,iq create east/bozo/devel/myjob` will create a job,
+  and will skip only the hooks named "test" and "iq".

Added: aurora/site/source/documentation/0.9.0/design/command-hooks.md
URL: 
http://svn.apache.org/viewvc/aurora/site/source/documentation/0.9.0/design/command-hooks.md?rev=1719807&view=auto
==============================================================================
--- aurora/site/source/documentation/0.9.0/design/command-hooks.md (added)
+++ aurora/site/source/documentation/0.9.0/design/command-hooks.md Sun Dec 13 
17:04:12 2015
@@ -0,0 +1,102 @@
+# Command Hooks for the Aurora Client
+
+## Introduction/Motivation
+
+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.
+
+## Registering Hooks
+
+These hooks will be registered via configuration plugins. A configuration 
plugin
+can register hooks using an API. Hooks registered this way are, effectively,
+hardwired into the client executable.
+
+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.
+
+
+### Global Hooks
+
+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.
+
+In the implementation, hooks are registered in the module
+`apache.aurora.client.cli.command_hooks`, using the class
+`GlobalCommandHookRegistry`. A global hook can be registered by calling
+`GlobalCommandHookRegistry.register_command_hook` in a configuration plugin.
+
+### The API
+
+    class CommandHook(object)
+      @property
+      def name(self):
+        """Returns a name for the hook."
+
+      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
+        """
+
+    class GlobalCommandHookRegistry(object):
+      @classmethod
+      def register_command_hook(self, hook):
+        pass
+
+### Skipping Hooks
+
+To skip a hook, a user uses a command-line option, `--skip-hooks`. The option 
can either
+specify specific hooks to skip, or "all":
+
+* `aurora --skip-hooks=all job create east/bozo/devel/myjob` will create a job
+  without running any hooks.
+* `aurora --skip-hooks=test,iq create east/bozo/devel/myjob` will create a job,
+  and will skip only the hooks named "test" and "iq".

Added: aurora/site/source/documentation/latest/design/command-hooks.md
URL: 
http://svn.apache.org/viewvc/aurora/site/source/documentation/latest/design/command-hooks.md?rev=1719807&view=auto
==============================================================================
--- aurora/site/source/documentation/latest/design/command-hooks.md (added)
+++ aurora/site/source/documentation/latest/design/command-hooks.md Sun Dec 13 
17:04:12 2015
@@ -0,0 +1,102 @@
+# Command Hooks for the Aurora Client
+
+## Introduction/Motivation
+
+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.
+
+## Registering Hooks
+
+These hooks will be registered via configuration plugins. A configuration 
plugin
+can register hooks using an API. Hooks registered this way are, effectively,
+hardwired into the client executable.
+
+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.
+
+
+### Global Hooks
+
+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.
+
+In the implementation, hooks are registered in the module
+`apache.aurora.client.cli.command_hooks`, using the class
+`GlobalCommandHookRegistry`. A global hook can be registered by calling
+`GlobalCommandHookRegistry.register_command_hook` in a configuration plugin.
+
+### The API
+
+    class CommandHook(object)
+      @property
+      def name(self):
+        """Returns a name for the hook."
+
+      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
+        """
+
+    class GlobalCommandHookRegistry(object):
+      @classmethod
+      def register_command_hook(self, hook):
+        pass
+
+### Skipping Hooks
+
+To skip a hook, a user uses a command-line option, `--skip-hooks`. The option 
can either
+specify specific hooks to skip, or "all":
+
+* `aurora --skip-hooks=all job create east/bozo/devel/myjob` will create a job
+  without running any hooks.
+* `aurora --skip-hooks=test,iq create east/bozo/devel/myjob` will create a job,
+  and will skip only the hooks named "test" and "iq".


Reply via email to