blob: 4bb466dfd4e32af5dde62fa8aee2739b5dcd3773 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Apache Aurora</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<link href="/assets/css/main.css" rel="stylesheet">
<!-- Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-45879646-1']);
_gaq.push(['_setDomainName', 'apache.org']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div class="container-fluid section-header">
<div class="container">
<div class="nav nav-bar">
<a href="/"><img src="/assets/img/aurora_logo_dkbkg.svg" width="300" alt="Transparent Apache Aurora logo with dark background"/></a>
<ul class="nav navbar-nav navbar-right">
<li><a href="/documentation/latest/">Documentation</a></li>
<li><a href="/community/">Community</a></li>
<li><a href="/downloads/">Downloads</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
</div>
</div>
<div class="container-fluid">
<div class="container content">
<div class="col-md-12 documentation">
<h5 class="page-header text-uppercase">Documentation
<select onChange="window.location.href='/documentation/' + this.value + '/design/command-hooks/'"
value="0.5.0-incubating">
<option value="0.22.0"
>
0.22.0
(latest)
</option>
<option value="0.21.0"
>
0.21.0
</option>
<option value="0.20.0"
>
0.20.0
</option>
<option value="0.19.1"
>
0.19.1
</option>
<option value="0.19.0"
>
0.19.0
</option>
<option value="0.18.1"
>
0.18.1
</option>
<option value="0.18.0"
>
0.18.0
</option>
<option value="0.17.0"
>
0.17.0
</option>
<option value="0.16.0"
>
0.16.0
</option>
<option value="0.15.0"
>
0.15.0
</option>
<option value="0.14.0"
>
0.14.0
</option>
<option value="0.13.0"
>
0.13.0
</option>
<option value="0.12.0"
>
0.12.0
</option>
<option value="0.11.0"
>
0.11.0
</option>
<option value="0.10.0"
>
0.10.0
</option>
<option value="0.9.0"
>
0.9.0
</option>
<option value="0.8.0"
>
0.8.0
</option>
<option value="0.7.0-incubating"
>
0.7.0-incubating
</option>
<option value="0.6.0-incubating"
>
0.6.0-incubating
</option>
<option value="0.5.0-incubating"
selected="selected">
0.5.0-incubating
</option>
</select>
</h5>
<h1 id="command-hooks-for-the-aurora-client">Command Hooks for the Aurora Client</h1>
<h2 id="introduction-motivation">Introduction/Motivation</h2>
<p>We&rsquo;ve got hooks in the client that surround API calls. These are
pretty awkward, because they don&rsquo;t correlate with user actions. For
example, suppose we wanted a policy that said users weren&rsquo;t allowed to
kill all instances of a production job at once.</p>
<p>Right now, all that we could hook would be the &ldquo;killJob&rdquo; 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 &ldquo;killJob&rdquo; calls, each of which specified a batch of
instances. We woudn&rsquo;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&rsquo;t find out what
the actual command being executed was!</p>
<p>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.</p>
<p>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.</p>
<h2 id="registering-hooks">Registering Hooks</h2>
<p>These hooks will be registered two ways:
* Project hooks file. If a file named <code>AuroraHooks</code> 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.</p>
<p>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.</p>
<h3 id="global-hooks">Global Hooks</h3>
<p>Commands registered by the python call are called <em>global</em> hooks,
because they will run for all configurations, whether or not they
specify any hooks in the configuration file.</p>
<p>In the implementation, hooks are registered in the module
<code>apache.aurora.client.cli.command_hooks</code>, using the class <code>GlobalCommandHookRegistry</code>. A
global hook can be registered by calling <code>GlobalCommandHookRegistry.register_command_hook</code>
in a configuration plugin.</p>
<h3 id="hook-files">Hook Files</h3>
<p>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
&ldquo;hooks&rdquo;, which contains a list of hook objects, which will be added to
the hook registry.</p>
<p>A project hooks file will be named <code>AuroraHooks</code>,
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.</p>
<h3 id="the-api">The API</h3>
<pre class="highlight objective_c"><code><span style="background-color: #f8f8f8">class</span> <span style="background-color: #f8f8f8">CommandHook</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">object</span><span style="background-color: #f8f8f8">)</span>
<span style="color: #000000;font-weight: bold">@property</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">name</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #d14">"""Returns a name for the hook."</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">get_nouns</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #d14">"""Return the nouns that have verbs that should invoke this hook."""</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">get_verbs</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">noun</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #d14">"""Return the verbs for a particular noun that should invoke his hook."""</span>
<span style="color: #a61717;background-color: #e3d2d2">@abstractmethod</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">pre_command</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">noun</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">verb</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">context</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">commandline</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #d14">"""Execute a hook before invoking a verb.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * noun: the noun being invoked.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * verb: the verb being invoked.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * context: the context object that will be used to invoke the verb.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> The options object will be initialized before calling the hook</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * commandline: the original argv collection used to invoke the client.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> Returns: True if the command should be allowed to proceed; False if the command</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> should be rejected.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> """</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">post_command</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">noun</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">verb</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">context</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">commandline</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">result</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #d14">"""Execute a hook after invoking a verb.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * noun: the noun being invoked.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * verb: the verb being invoked.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * context: the context object that will be used to invoke the verb.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> The options object will be initialized before calling the hook</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * commandline: the original argv collection used to invoke the client.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> * result: the result code returned by the verb.</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> Returns: nothing</span><span style="color: #a61717;background-color: #e3d2d2">
</span><span style="color: #d14"> """</span>
<span style="background-color: #f8f8f8">class</span> <span style="background-color: #f8f8f8">GlobalCommandHookRegistry</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">object</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="color: #a61717;background-color: #e3d2d2">@classmethod</span>
<span style="background-color: #f8f8f8">def</span> <span style="background-color: #f8f8f8">register_command_hook</span><span style="background-color: #f8f8f8">(</span><span style="background-color: #f8f8f8">self</span><span style="background-color: #f8f8f8">,</span> <span style="background-color: #f8f8f8">hook</span><span style="background-color: #f8f8f8">)</span><span style="color: #000000;font-weight: bold">:</span>
<span style="background-color: #f8f8f8">pass</span>
</code></pre>
<h2 id="skipping-hooks">Skipping Hooks</h2>
<p>In a perfect world, hooks would represent a global property or policy
that should always be enforced. Unfortunately, we don&rsquo;t live in a
perfect world, which means that sometimes, every rule needs to get
broken.</p>
<p>For example, an organization could decide that every configuration
must be checked in to source control before it could be
deployed. That&rsquo;s an entirely reasonable policy. It would be easy to
implement it using a hook. But what if there&rsquo;s a problem, and the
source repos is down?</p>
<p>The easiest solution is just to allow a user to add a <code>--skip-hooks</code>
flag to the command-line. But doing that means that an organization
can&rsquo;t actually use hooks to enforce policy, because users can skip
them whenever they want.</p>
<p>Instead, we&rsquo;d like to have a system where it&rsquo;s possible to create
hooks to enforce policy, and then include a way of building policy
about when hooks can be skipped.</p>
<p>I&rsquo;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&rsquo;re allowed to run it; and what
command(s) they&rsquo;re allowed to run. All of that is specified in a
special system file located in <code>/etc/sudoers</code> on a typical unix
machine.</p>
<p>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&rsquo;t sufficient - it&rsquo;s too easy to
maliciously or erroneously run a command in an environment with an
invalid hooks exceptions file.</p>
<p>Instead, we&rsquo;ve got two basic choices: hook exception rules can be
baked into the client executable, or they can be provided in a
network location.</p>
<h3 id="specifying-when-hooks-can-be-skipped">Specifying when hooks can be skipped</h3>
<h4 id="hooks-file">Hooks File</h4>
<p>The module <code>apache.aurora.client.cli</code> contains a variable named
<code>GLOBAL_HOOK_SKIP_RULES_URL</code>. In the default distribution of Aurora, tihs variable contains
<code>None</code>. 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 <code>None</code>, then the client will fetch the contents of that URL, and
attempt to interpret it as a hooks exception file.</p>
<p>The hooks exception file is written in JSON, with the following structure:</p>
<pre class="highlight json"><code><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"rulename"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb">
</span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"hooks"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #bbbbbb"> </span><span style="color: #d14">"hook-name "</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">],</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"users"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">string</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="background-color: #f8f8f8">],</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"commands"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"job"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"kill"</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #d14">"killall"</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="background-color: #f8f8f8">],</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">}</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"arg-patterns"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #bbbbbb"> </span><span style="color: #d14">"regexp-str"</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">]</span><span style="color: #bbbbbb">
</span><span style="background-color: #f8f8f8">},</span><span style="color: #bbbbbb">
</span><span style="color: #a61717;background-color: #e3d2d2">...</span><span style="color: #bbbbbb">
</span><span style="color: #a61717;background-color: #e3d2d2">}</span><span style="color: #bbbbbb">
</span></code></pre>
<ul>
<li><code>hooks</code> is a list of hook identifiers which can be skipped by a user
that satisfies this rule. If omitted, then this rule applies to <em>all hooks</em>.
(Omitting the <code>hooks</code> field is equivalent to giving it the value <code>[&#39;*&#39;]</code>.)</li>
<li><code>users</code> 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 <em>any user</em> to skip hooks that satisfy the rest of this rule.
Note that this is <em>user</em> names, not
<em>role</em> 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.</li>
<li><code>commands</code> is a map from nouns to lists of verbs. If a command <code>aurora n v</code>
is being executed, this rule allows the hooks to be skipped if
<code>v</code> is in <code>commands[n]</code>. If this is omitted, then it allows hooks to be skipped for all
commands that satisfy the rest of the rule.</li>
<li><code>arg_patterns</code> 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.</li>
</ul>
<p>For example, the following is a hook rules file which allows:
* The user &ldquo;root&rdquo; to skip any hook.
* Any user to skip hooks for test jobs.
* A specific group of users to skip hooks for jobs in cluster <code>east</code>
* Another group of users to skip hooks for <code>job kill</code> in cluster <code>west</code>.</p>
<pre class="highlight json"><code><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"allow-admin"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"users"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"root"</span><span style="background-color: #f8f8f8">]</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">},</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"allow-test"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"users"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"\*"</span><span style="background-color: #f8f8f8">],</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"arg-patterns"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"\*/\*/test/\*"</span><span style="background-color: #f8f8f8">]</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">},</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"allow-east-users"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"users"</span><span style="color: #a61717;background-color: #e3d2d2">=['john',</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">'mary',</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">'mike',</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">'sue'],</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"arg-patterns"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"east/\*/\*/\*"</span><span style="background-color: #f8f8f8">]</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">},</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"allow-west-kills"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"users"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"anne"</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #d14">"bill"</span><span style="background-color: #f8f8f8">,</span><span style="color: #bbbbbb"> </span><span style="color: #d14">"chris"</span><span style="background-color: #f8f8f8">],</span><span style="color: #bbbbbb">
</span><span style="color: #000080">"commands"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">{</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"job"</span><span style="background-color: #f8f8f8">:</span><span style="color: #bbbbbb"> </span><span style="background-color: #f8f8f8">[</span><span style="color: #d14">"kill"</span><span style="background-color: #f8f8f8">]},</span><span style="color: #bbbbbb"> </span><span style="color: #000080">"arg-patterns"</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">=</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">[</span><span style="color: #000080">"west/\*/\*/\*"</span><span style="color: #a61717;background-color: #e3d2d2">]</span><span style="color: #bbbbbb"> </span><span style="color: #a61717;background-color: #e3d2d2">}</span><span style="color: #bbbbbb">
</span><span style="background-color: #f8f8f8">}</span><span style="color: #bbbbbb">
</span></code></pre>
<h4 id="programmatic-hooks-exceptions">Programmatic Hooks Exceptions</h4>
<p>The <code>GlobalHooksRegistry</code> contains the method <code>add_hooks_exception</code>, which allows
users to register local hooks exceptions using the <code>ConfigurationPlugin</code> mechanism.
A hooks exception object implements the following interface:</p>
<pre class="highlight plaintext"><code>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
</code></pre>
<p>When a user supplies the <code>--skip-hooks</code> argument, <code>allow_exception</code> is invoked on
each of the <code>HooksException</code> arguments. If <em>any</em> of the hooks exception objects
returns <code>True</code>, then the user will be permitted to skip the hooks.</p>
<h3 id="skipping-hooks">Skipping Hooks</h3>
<p>To skip a hook, a user uses a command-line option, <code>--skip-hooks</code>. The option can either
specify specific hooks to skip, or &ldquo;all&rdquo;:</p>
<ul>
<li><code>aurora --skip-hooks=all job create east/bozo/devel/myjob</code> will create a job
without running any hooks.</li>
<li><code>aurora --skip-hooks=test,iq create east/bozo/devel/myjob</code> will create a job,
and will skip only the hooks named &ldquo;test&rdquo; and &ldquo;iq&rdquo;.</li>
</ul>
<h2 id="changes">Changes</h2>
<p>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.</p>
<p>4/27:
Major changes between this and the last version of this proposal.
* Command hooks can&rsquo;t be declared in a configuration file. There&rsquo;s a simple
reason why: hooks run before a command&rsquo;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&rsquo;s too late. So I&rsquo;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&rsquo;t be enforced, which defeats the purpose of having them.
So in this update, I propose a mechanism, loosely based on a <code>sudo</code>-like
mechanism for defining when hooks can be skipped.</p>
</div>
</div>
</div>
<div class="container-fluid section-footer buffer">
<div class="container">
<div class="row">
<div class="col-md-2 col-md-offset-1"><h3>Quick Links</h3>
<ul>
<li><a href="/downloads/">Downloads</a></li>
<li><a href="/community/">Mailing Lists</a></li>
<li><a href="http://issues.apache.org/jira/browse/AURORA">Issue Tracking</a></li>
<li><a href="/documentation/latest/contributing/">How To Contribute</a></li>
</ul>
</div>
<div class="col-md-2"><h3>The ASF</h3>
<ul>
<li><a href="http://www.apache.org/licenses/">License</a></li>
<li><a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="http://www.apache.org/foundation/thanks.html">Thanks</a></li>
<li><a href="http://www.apache.org/security/">Security</a></li>
</ul>
</div>
<div class="col-md-6">
<p class="disclaimer">&copy; 2014-2017 <a href="http://www.apache.org/">Apache Software Foundation</a>. Licensed under the <a href="http://www.apache.org/licenses/">Apache License v2.0</a>. The <a href="https://www.flickr.com/photos/trondk/12706051375/">Aurora Borealis IX photo</a> displayed on the homepage is available under a <a href="https://creativecommons.org/licenses/by-nc-nd/2.0/">Creative Commons BY-NC-ND 2.0 license</a>. Apache, Apache Aurora, and the Apache feather logo are trademarks of The Apache Software Foundation.</p>
</div>
</div>
</div>
</body>
</html>