Added: aurora/site/publish/documentation/0.7.0-incubating/design/command-hooks/index.html URL: http://svn.apache.org/viewvc/aurora/site/publish/documentation/0.7.0-incubating/design/command-hooks/index.html?rev=1719807&view=auto ============================================================================== --- aurora/site/publish/documentation/0.7.0-incubating/design/command-hooks/index.html (added) +++ aurora/site/publish/documentation/0.7.0-incubating/design/command-hooks/index.html Sun Dec 13 17:04:12 2015 @@ -0,0 +1,198 @@ +<!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</h5> +<select onChange="window.location.href='/documentation/' + this.value"> + <option value="0.10.0"> + 0.10.0 + (latest) + </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> + +<h1 id="command-hooks-for-the-aurora-client">Command Hooks for the Aurora Client</h1> + +<h2 id="introduction-motivation">Introduction/Motivation</h2> + +<p>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.</p> + +<p>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!</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 “all”:</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 “test” and “iq”.</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">Copyright 2014 <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>
Added: aurora/site/publish/documentation/0.8.0/design/command-hooks/index.html URL: http://svn.apache.org/viewvc/aurora/site/publish/documentation/0.8.0/design/command-hooks/index.html?rev=1719807&view=auto ============================================================================== --- aurora/site/publish/documentation/0.8.0/design/command-hooks/index.html (added) +++ aurora/site/publish/documentation/0.8.0/design/command-hooks/index.html Sun Dec 13 17:04:12 2015 @@ -0,0 +1,198 @@ +<!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</h5> +<select onChange="window.location.href='/documentation/' + this.value"> + <option value="0.10.0"> + 0.10.0 + (latest) + </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> + +<h1 id="command-hooks-for-the-aurora-client">Command Hooks for the Aurora Client</h1> + +<h2 id="introduction-motivation">Introduction/Motivation</h2> + +<p>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.</p> + +<p>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!</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 “all”:</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 “test” and “iq”.</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">Copyright 2014 <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> Added: aurora/site/publish/documentation/0.9.0/design/command-hooks/index.html URL: http://svn.apache.org/viewvc/aurora/site/publish/documentation/0.9.0/design/command-hooks/index.html?rev=1719807&view=auto ============================================================================== --- aurora/site/publish/documentation/0.9.0/design/command-hooks/index.html (added) +++ aurora/site/publish/documentation/0.9.0/design/command-hooks/index.html Sun Dec 13 17:04:12 2015 @@ -0,0 +1,198 @@ +<!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</h5> +<select onChange="window.location.href='/documentation/' + this.value"> + <option value="0.10.0"> + 0.10.0 + (latest) + </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> + +<h1 id="command-hooks-for-the-aurora-client">Command Hooks for the Aurora Client</h1> + +<h2 id="introduction-motivation">Introduction/Motivation</h2> + +<p>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.</p> + +<p>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!</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 “all”:</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 “test” and “iq”.</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">Copyright 2014 <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> Added: aurora/site/publish/documentation/latest/design/command-hooks/index.html URL: http://svn.apache.org/viewvc/aurora/site/publish/documentation/latest/design/command-hooks/index.html?rev=1719807&view=auto ============================================================================== --- aurora/site/publish/documentation/latest/design/command-hooks/index.html (added) +++ aurora/site/publish/documentation/latest/design/command-hooks/index.html Sun Dec 13 17:04:12 2015 @@ -0,0 +1,198 @@ +<!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</h5> +<select onChange="window.location.href='/documentation/' + this.value"> + <option value="0.10.0"> + 0.10.0 + (latest) + </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> + +<h1 id="command-hooks-for-the-aurora-client">Command Hooks for the Aurora Client</h1> + +<h2 id="introduction-motivation">Introduction/Motivation</h2> + +<p>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.</p> + +<p>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!</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 “all”:</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 “test” and “iq”.</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">Copyright 2014 <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> Modified: aurora/site/publish/sitemap.xml URL: http://svn.apache.org/viewvc/aurora/site/publish/sitemap.xml?rev=1719807&r1=1719806&r2=1719807&view=diff ============================================================================== --- aurora/site/publish/sitemap.xml (original) +++ aurora/site/publish/sitemap.xml Sun Dec 13 17:04:12 2015 @@ -85,6 +85,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.10.0/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.10.0/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -181,6 +185,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.5.0-incubating/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.5.0-incubating/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -253,6 +261,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.6.0-incubating/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.6.0-incubating/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -341,6 +353,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.7.0-incubating/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.7.0-incubating/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -433,6 +449,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.8.0/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.8.0/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -529,6 +549,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/0.9.0/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/0.9.0/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -633,6 +657,10 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/latest/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/latest/developing-aurora-client/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> @@ -641,6 +669,110 @@ <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> <url> + <loc>http://aurora.apache.org/documentation/latest/docs/build-system/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/client-cluster-configuration/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/client-commands/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/committers/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/configuration-reference/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/configuration-tutorial/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/cron-jobs/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/deploying-aurora-scheduler/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/design/command-hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/developing-aurora-client/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/developing-aurora-scheduler/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/hooks/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/monitoring/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/presentations/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/README/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/resources/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/scheduler-storage/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/security/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/sla/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/storage-config/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/storage/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/test-resource-generation/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/thrift-deprecation/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/tutorial/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/user-guide/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> + <loc>http://aurora.apache.org/documentation/latest/docs/vagrant/</loc> + <lastmod>2015-12-13T00:00:00+00:00</lastmod> + </url> + <url> <loc>http://aurora.apache.org/documentation/latest/hooks/</loc> <lastmod>2015-12-13T00:00:00+00:00</lastmod> </url> Added: aurora/site/source/documentation/0.10.0/design/command-hooks.md URL: http://svn.apache.org/viewvc/aurora/site/source/documentation/0.10.0/design/command-hooks.md?rev=1719807&view=auto ============================================================================== --- aurora/site/source/documentation/0.10.0/design/command-hooks.md (added) +++ aurora/site/source/documentation/0.10.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.5.0-incubating/design/command-hooks.md URL: http://svn.apache.org/viewvc/aurora/site/source/documentation/0.5.0-incubating/design/command-hooks.md?rev=1719807&view=auto ============================================================================== --- aurora/site/source/documentation/0.5.0-incubating/design/command-hooks.md (added) +++ aurora/site/source/documentation/0.5.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.
