blob: 59eb063273a37b771ae9909aac3c81c18de4c209 [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 + '/development/design/command-hooks/'"
value="0.16.0">
<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"
selected="selected">
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"
>
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 via 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="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>
<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>
</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>