<!DOCTYPE html> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>pylorax.api.queue — Lorax 29.11 documentation</title> <link rel="stylesheet" href="../../../_static/css/theme.css" type="text/css" /> <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> <link rel="index" title="Index" href="../../../genindex.html" /> <link rel="search" title="Search" href="../../../search.html" /> <script src="../../../_static/js/modernizr.min.js"></script> </head> <body class="wy-body-for-nav"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search"> <a href="../../../index.html" class="icon icon-home"> Lorax </a> <div class="version"> 29.11 </div> <div role="search"> <form id="rtd-search-form" class="wy-form" action="../../../search.html" method="get"> <input type="text" name="q" placeholder="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> </div> <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation"> <ul> <li class="toctree-l1"><a class="reference internal" href="../../../intro.html">Introduction to Lorax</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../intro.html#before-lorax">Before Lorax</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../lorax.html">Lorax</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../livemedia-creator.html">livemedia-creator</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../lorax-composer.html">lorax-composer</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../composer-cli.html">composer-cli</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../product-images.html">Product and Updates Images</a></li> <li class="toctree-l1"><a class="reference internal" href="../../../modules.html">src</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> <nav class="wy-nav-top" aria-label="top navigation"> <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="../../../index.html">Lorax</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="breadcrumbs navigation"> <ul class="wy-breadcrumbs"> <li><a href="../../../index.html">Docs</a> »</li> <li><a href="../../index.html">Module code</a> »</li> <li><a href="../../pylorax.html">pylorax</a> »</li> <li>pylorax.api.queue</li> <li class="wy-breadcrumbs-aside"> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <h1>Source code for pylorax.api.queue</h1><div class="highlight"><pre> <span></span><span class="c1"># Copyright (C) 2018 Red Hat, Inc.</span> <span class="c1">#</span> <span class="c1"># This program is free software; you can redistribute it and/or modify</span> <span class="c1"># it under the terms of the GNU General Public License as published by</span> <span class="c1"># the Free Software Foundation; either version 2 of the License, or</span> <span class="c1"># (at your option) any later version.</span> <span class="c1">#</span> <span class="c1"># This program is distributed in the hope that it will be useful,</span> <span class="c1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span> <span class="c1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span> <span class="c1"># GNU General Public License for more details.</span> <span class="c1">#</span> <span class="c1"># You should have received a copy of the GNU General Public License</span> <span class="c1"># along with this program. If not, see <http://www.gnu.org/licenses/>.</span> <span class="c1">#</span> <span class="sd">""" Functions to monitor compose queue and run anaconda"""</span> <span class="kn">import</span> <span class="nn">logging</span> <span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">"pylorax"</span><span class="p">)</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">grp</span> <span class="kn">from</span> <span class="nn">glob</span> <span class="k">import</span> <span class="n">glob</span> <span class="kn">import</span> <span class="nn">multiprocessing</span> <span class="k">as</span> <span class="nn">mp</span> <span class="kn">import</span> <span class="nn">pytoml</span> <span class="k">as</span> <span class="nn">toml</span> <span class="kn">import</span> <span class="nn">pwd</span> <span class="kn">import</span> <span class="nn">shutil</span> <span class="kn">import</span> <span class="nn">subprocess</span> <span class="kn">from</span> <span class="nn">subprocess</span> <span class="k">import</span> <span class="n">Popen</span><span class="p">,</span> <span class="n">PIPE</span> <span class="kn">import</span> <span class="nn">time</span> <span class="kn">from</span> <span class="nn">pylorax</span> <span class="k">import</span> <span class="n">find_templates</span> <span class="kn">from</span> <span class="nn">pylorax.api.compose</span> <span class="k">import</span> <span class="n">move_compose_results</span> <span class="kn">from</span> <span class="nn">pylorax.api.recipes</span> <span class="k">import</span> <span class="n">recipe_from_file</span> <span class="kn">from</span> <span class="nn">pylorax.api.timestamp</span> <span class="k">import</span> <span class="n">TS_CREATED</span><span class="p">,</span> <span class="n">TS_STARTED</span><span class="p">,</span> <span class="n">TS_FINISHED</span><span class="p">,</span> <span class="n">write_timestamp</span><span class="p">,</span> <span class="n">timestamp_dict</span> <span class="kn">from</span> <span class="nn">pylorax.base</span> <span class="k">import</span> <span class="n">DataHolder</span> <span class="kn">from</span> <span class="nn">pylorax.creator</span> <span class="k">import</span> <span class="n">run_creator</span> <span class="kn">from</span> <span class="nn">pylorax.sysutils</span> <span class="k">import</span> <span class="n">joinpaths</span> <div class="viewcode-block" id="start_queue_monitor"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.start_queue_monitor">[docs]</a><span class="k">def</span> <span class="nf">start_queue_monitor</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uid</span><span class="p">,</span> <span class="n">gid</span><span class="p">):</span> <span class="sd">"""Start the queue monitor as a mp process</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uid: User ID that owns the queue</span> <span class="sd"> :type uid: int</span> <span class="sd"> :param gid: Group ID that owns the queue</span> <span class="sd"> :type gid: int</span> <span class="sd"> :returns: None</span> <span class="sd"> """</span> <span class="n">lib_dir</span> <span class="o">=</span> <span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">)</span> <span class="n">share_dir</span> <span class="o">=</span> <span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"share_dir"</span><span class="p">)</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"tmp"</span><span class="p">)</span> <span class="n">monitor_cfg</span> <span class="o">=</span> <span class="n">DataHolder</span><span class="p">(</span><span class="n">composer_dir</span><span class="o">=</span><span class="n">lib_dir</span><span class="p">,</span> <span class="n">share_dir</span><span class="o">=</span><span class="n">share_dir</span><span class="p">,</span> <span class="n">uid</span><span class="o">=</span><span class="n">uid</span><span class="p">,</span> <span class="n">gid</span><span class="o">=</span><span class="n">gid</span><span class="p">,</span> <span class="n">tmp</span><span class="o">=</span><span class="n">tmp</span><span class="p">)</span> <span class="n">p</span> <span class="o">=</span> <span class="n">mp</span><span class="o">.</span><span class="n">Process</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">monitor</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">monitor_cfg</span><span class="p">,))</span> <span class="n">p</span><span class="o">.</span><span class="n">daemon</span> <span class="o">=</span> <span class="kc">True</span> <span class="n">p</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></div> <div class="viewcode-block" id="monitor"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.monitor">[docs]</a><span class="k">def</span> <span class="nf">monitor</span><span class="p">(</span><span class="n">cfg</span><span class="p">):</span> <span class="sd">"""Monitor the queue for new compose requests</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: DataHolder</span> <span class="sd"> :returns: Does not return</span> <span class="sd"> The queue has 2 subdirectories, new and run. When a compose is ready to be run</span> <span class="sd"> a symlink to the uniquely named results directory should be placed in ./queue/new/</span> <span class="sd"> When the it is ready to be run (it is checked every 30 seconds or after a previous</span> <span class="sd"> compose is finished) the symlink will be moved into ./queue/run/ and a STATUS file</span> <span class="sd"> will be created in the results directory.</span> <span class="sd"> STATUS can contain one of: RUNNING, FINISHED, FAILED</span> <span class="sd"> If the system is restarted while a compose is running it will move any old symlinks</span> <span class="sd"> from ./queue/run/ to ./queue/new/ and rerun them.</span> <span class="sd"> """</span> <span class="k">def</span> <span class="nf">queue_sort</span><span class="p">(</span><span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Sort the queue entries by their mtime, not their names"""</span> <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/new"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">))</span><span class="o">.</span><span class="n">st_mtime</span> <span class="c1"># Move any symlinks in the run queue back to the new queue</span> <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/run"</span><span class="p">)):</span> <span class="n">src</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/run"</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span> <span class="n">dst</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/new"</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span> <span class="n">os</span><span class="o">.</span><span class="n">rename</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">)</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Moved unfinished compose </span><span class="si">%s</span><span class="s2"> back to new state"</span><span class="p">,</span> <span class="n">src</span><span class="p">)</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="n">uuids</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/new"</span><span class="p">)),</span> <span class="n">key</span><span class="o">=</span><span class="n">queue_sort</span><span class="p">)</span> <span class="c1"># Pick the oldest and move it into ./run/</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">uuids</span><span class="p">:</span> <span class="c1"># No composes left to process, sleep for a bit</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">src</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/new"</span><span class="p">,</span> <span class="n">uuids</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="n">dst</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">composer_dir</span><span class="p">,</span> <span class="s2">"queue/run"</span><span class="p">,</span> <span class="n">uuids</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">try</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">rename</span><span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">dst</span><span class="p">)</span> <span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span> <span class="c1"># The symlink may vanish if uuid_cancel() has been called</span> <span class="k">continue</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Starting new compose: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">dst</span><span class="p">)</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="s2">"STATUS"</span><span class="p">),</span> <span class="s2">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"RUNNING</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">make_compose</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">dst</span><span class="p">))</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Finished building </span><span class="si">%s</span><span class="s2">, results are in </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">dst</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">dst</span><span class="p">))</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="s2">"STATUS"</span><span class="p">),</span> <span class="s2">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"FINISHED</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="n">write_timestamp</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">TS_FINISHED</span><span class="p">)</span> <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">traceback</span> <span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"traceback: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">())</span> <span class="c1"># TODO - Write the error message to an ERROR-LOG file to include with the status</span> <span class="c1"># log.error("Error running compose: %s", e)</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="s2">"STATUS"</span><span class="p">),</span> <span class="s2">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"FAILED</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="n">write_timestamp</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">TS_FINISHED</span><span class="p">)</span> <span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span></div> <div class="viewcode-block" id="make_compose"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.make_compose">[docs]</a><span class="k">def</span> <span class="nf">make_compose</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">results_dir</span><span class="p">):</span> <span class="sd">"""Run anaconda with the final-kickstart.ks from results_dir</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: DataHolder</span> <span class="sd"> :param results_dir: The directory containing the metadata and results for the build</span> <span class="sd"> :type results_dir: str</span> <span class="sd"> :returns: Nothing</span> <span class="sd"> :raises: May raise various exceptions</span> <span class="sd"> This takes the final-kickstart.ks, and the settings in config.toml and runs Anaconda</span> <span class="sd"> in no-virt mode (directly on the host operating system). Exceptions should be caught</span> <span class="sd"> at the higer level.</span> <span class="sd"> If there is a failure, the build artifacts will be cleaned up, and any logs will be</span> <span class="sd"> moved into logs/anaconda/ and their ownership will be set to the user from the cfg</span> <span class="sd"> object.</span> <span class="sd"> """</span> <span class="c1"># Check on the ks's presence</span> <span class="n">ks_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"final-kickstart.ks"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">ks_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing kickstart file at </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">ks_path</span><span class="p">)</span> <span class="c1"># The anaconda logs are copied into ./anaconda/ in this directory</span> <span class="n">log_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"logs/"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">log_dir</span><span class="p">):</span> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">log_dir</span><span class="p">)</span> <span class="c1"># Load the compose configuration</span> <span class="n">cfg_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"config.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing config.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">results_dir</span><span class="p">)</span> <span class="n">cfg_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="c1"># The keys in cfg_dict correspond to the arguments setup in livemedia-creator</span> <span class="c1"># keys that define what to build should be setup in compose_args, and keys with</span> <span class="c1"># defaults should be setup here.</span> <span class="c1"># Make sure that image_name contains no path components</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"image_name"</span><span class="p">]</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"image_name"</span><span class="p">])</span> <span class="c1"># Only support novirt installation, set some other defaults</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"no_virt"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"disk_image"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"fs_image"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"keep_image"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"domacboot"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"anaconda_args"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"proxy"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"armplatform"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">""</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"squashfs_args"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"lorax_templates"</span><span class="p">]</span> <span class="o">=</span> <span class="n">find_templates</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">share_dir</span><span class="p">)</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"tmp"</span><span class="p">]</span> <span class="o">=</span> <span class="n">cfg</span><span class="o">.</span><span class="n">tmp</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"dracut_args"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Use default args for dracut</span> <span class="c1"># TODO How to support other arches?</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"arch"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># Compose things in a temporary directory inside the results directory</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"result_dir"</span><span class="p">]</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"compose"</span><span class="p">)</span> <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"result_dir"</span><span class="p">])</span> <span class="n">install_cfg</span> <span class="o">=</span> <span class="n">DataHolder</span><span class="p">(</span><span class="o">**</span><span class="n">cfg_dict</span><span class="p">)</span> <span class="c1"># Some kludges for the 99-copy-logs %post, failure in it will crash the build</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">"/tmp/NOSAVE_INPUT_KS"</span><span class="p">,</span> <span class="s2">"/tmp/NOSAVE_LOGS"</span><span class="p">]:</span> <span class="nb">open</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="c1"># Placing a CANCEL file in the results directory will make execWithRedirect send anaconda a SIGTERM</span> <span class="k">def</span> <span class="nf">cancel_build</span><span class="p">():</span> <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"CANCEL"</span><span class="p">))</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"cfg = </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">install_cfg</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">test_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"TEST"</span><span class="p">)</span> <span class="n">write_timestamp</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="n">TS_STARTED</span><span class="p">)</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">test_path</span><span class="p">):</span> <span class="c1"># Pretend to run the compose</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">test_mode</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">test_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> <span class="n">test_mode</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">test_mode</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"TESTING FAILED compose"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="n">install_cfg</span><span class="o">.</span><span class="n">image_name</span><span class="p">),</span> <span class="s2">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"TEST IMAGE"</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">run_creator</span><span class="p">(</span><span class="n">install_cfg</span><span class="p">,</span> <span class="n">callback_func</span><span class="o">=</span><span class="n">cancel_build</span><span class="p">)</span> <span class="c1"># Extract the results of the compose into results_dir and cleanup the compose directory</span> <span class="n">move_compose_results</span><span class="p">(</span><span class="n">install_cfg</span><span class="p">,</span> <span class="n">results_dir</span><span class="p">)</span> <span class="k">finally</span><span class="p">:</span> <span class="c1"># Make sure any remaining temporary directories are removed (eg. if there was an exception)</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">tmp</span><span class="p">,</span> <span class="s2">"lmc-*"</span><span class="p">)):</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isdir</span><span class="p">(</span><span class="n">d</span><span class="p">):</span> <span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="k">elif</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">d</span><span class="p">):</span> <span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="c1"># Make sure that everything under the results directory is owned by the user</span> <span class="n">user</span> <span class="o">=</span> <span class="n">pwd</span><span class="o">.</span><span class="n">getpwuid</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">uid</span><span class="p">)</span><span class="o">.</span><span class="n">pw_name</span> <span class="n">group</span> <span class="o">=</span> <span class="n">grp</span><span class="o">.</span><span class="n">getgrgid</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">gid</span><span class="p">)</span><span class="o">.</span><span class="n">gr_name</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Install finished, chowning results to </span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="n">group</span><span class="p">)</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s2">"chown"</span><span class="p">,</span> <span class="s2">"-R"</span><span class="p">,</span> <span class="s2">"</span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">group</span><span class="p">),</span> <span class="n">results_dir</span><span class="p">])</span></div> <div class="viewcode-block" id="get_compose_type"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.get_compose_type">[docs]</a><span class="k">def</span> <span class="nf">get_compose_type</span><span class="p">(</span><span class="n">results_dir</span><span class="p">):</span> <span class="sd">"""Return the type of composition.</span> <span class="sd"> :param results_dir: The directory containing the metadata and results for the build</span> <span class="sd"> :type results_dir: str</span> <span class="sd"> :returns: The type of compose (eg. 'tar')</span> <span class="sd"> :rtype: str</span> <span class="sd"> :raises: RuntimeError if no kickstart template can be found.</span> <span class="sd"> """</span> <span class="c1"># Should only be 2 kickstarts, the final-kickstart.ks and the template</span> <span class="n">t</span> <span class="o">=</span> <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">ks</span><span class="p">)[:</span><span class="o">-</span><span class="mi">3</span><span class="p">]</span> <span class="k">for</span> <span class="n">ks</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"*.ks"</span><span class="p">))</span> <span class="k">if</span> <span class="s2">"final-kickstart"</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">ks</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Cannot find ks template for build </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">results_dir</span><span class="p">))</span> <span class="k">return</span> <span class="n">t</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span></div> <div class="viewcode-block" id="compose_detail"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.compose_detail">[docs]</a><span class="k">def</span> <span class="nf">compose_detail</span><span class="p">(</span><span class="n">results_dir</span><span class="p">):</span> <span class="sd">"""Return details about the build.</span> <span class="sd"> :param results_dir: The directory containing the metadata and results for the build</span> <span class="sd"> :type results_dir: str</span> <span class="sd"> :returns: A dictionary with details about the compose</span> <span class="sd"> :rtype: dict</span> <span class="sd"> :raises: IOError if it cannot read the directory, STATUS, or blueprint file.</span> <span class="sd"> The following details are included in the dict:</span> <span class="sd"> * id - The uuid of the comoposition</span> <span class="sd"> * queue_status - The final status of the composition (FINISHED or FAILED)</span> <span class="sd"> * compose_type - The type of output generated (tar, iso, etc.)</span> <span class="sd"> * blueprint - Blueprint name</span> <span class="sd"> * version - Blueprint version</span> <span class="sd"> * image_size - Size of the image, if finished. 0 otherwise.</span> <span class="sd"> Various timestamps are also included in the dict. These are all Unix UTC timestamps.</span> <span class="sd"> It is possible for these timestamps to not always exist, in which case they will be</span> <span class="sd"> None in Python (or null in JSON). The following timestamps are included:</span> <span class="sd"> * job_created - When the user submitted the compose</span> <span class="sd"> * job_started - Anaconda started running</span> <span class="sd"> * job_finished - Job entered FINISHED or FAILED state</span> <span class="sd"> """</span> <span class="n">build_id</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">results_dir</span><span class="p">))</span> <span class="n">status</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"STATUS"</span><span class="p">))</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="n">blueprint</span> <span class="o">=</span> <span class="n">recipe_from_file</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">results_dir</span><span class="p">,</span> <span class="s2">"blueprint.toml"</span><span class="p">))</span> <span class="n">compose_type</span> <span class="o">=</span> <span class="n">get_compose_type</span><span class="p">(</span><span class="n">results_dir</span><span class="p">)</span> <span class="n">image_path</span> <span class="o">=</span> <span class="n">get_image_name</span><span class="p">(</span><span class="n">results_dir</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">"FINISHED"</span> <span class="ow">and</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">image_path</span><span class="p">):</span> <span class="n">image_size</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span><span class="o">.</span><span class="n">st_size</span> <span class="k">else</span><span class="p">:</span> <span class="n">image_size</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">times</span> <span class="o">=</span> <span class="n">timestamp_dict</span><span class="p">(</span><span class="n">results_dir</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">build_id</span><span class="p">,</span> <span class="s2">"queue_status"</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span> <span class="s2">"job_created"</span><span class="p">:</span> <span class="n">times</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">TS_CREATED</span><span class="p">),</span> <span class="s2">"job_started"</span><span class="p">:</span> <span class="n">times</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">TS_STARTED</span><span class="p">),</span> <span class="s2">"job_finished"</span><span class="p">:</span> <span class="n">times</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">TS_FINISHED</span><span class="p">),</span> <span class="s2">"compose_type"</span><span class="p">:</span> <span class="n">compose_type</span><span class="p">,</span> <span class="s2">"blueprint"</span><span class="p">:</span> <span class="n">blueprint</span><span class="p">[</span><span class="s2">"name"</span><span class="p">],</span> <span class="s2">"version"</span><span class="p">:</span> <span class="n">blueprint</span><span class="p">[</span><span class="s2">"version"</span><span class="p">],</span> <span class="s2">"image_size"</span><span class="p">:</span> <span class="n">image_size</span> <span class="p">}</span></div> <div class="viewcode-block" id="queue_status"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.queue_status">[docs]</a><span class="k">def</span> <span class="nf">queue_status</span><span class="p">(</span><span class="n">cfg</span><span class="p">):</span> <span class="sd">"""Return details about what is in the queue.</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :returns: A list of the new composes, and a list of the running composes</span> <span class="sd"> :rtype: dict</span> <span class="sd"> This returns a dict with 2 lists. "new" is the list of uuids that are waiting to be built,</span> <span class="sd"> and "run" has the uuids that are being built (currently limited to 1 at a time).</span> <span class="sd"> """</span> <span class="n">queue_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"queue"</span><span class="p">)</span> <span class="n">new_queue</span> <span class="o">=</span> <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">queue_dir</span><span class="p">,</span> <span class="s2">"new/*"</span><span class="p">))]</span> <span class="n">run_queue</span> <span class="o">=</span> <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">queue_dir</span><span class="p">,</span> <span class="s2">"run/*"</span><span class="p">))]</span> <span class="n">new_details</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">new_queue</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">d</span> <span class="o">=</span> <span class="n">compose_detail</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span> <span class="k">continue</span> <span class="n">new_details</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="n">run_details</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">run_queue</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">d</span> <span class="o">=</span> <span class="n">compose_detail</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span> <span class="k">continue</span> <span class="n">run_details</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="k">return</span> <span class="p">{</span> <span class="s2">"new"</span><span class="p">:</span> <span class="n">new_details</span><span class="p">,</span> <span class="s2">"run"</span><span class="p">:</span> <span class="n">run_details</span> <span class="p">}</span></div> <div class="viewcode-block" id="uuid_status"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_status">[docs]</a><span class="k">def</span> <span class="nf">uuid_status</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Return the details of a specific UUID compose</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: Details about the build</span> <span class="sd"> :rtype: dict or None</span> <span class="sd"> Returns the same dict as `compose_details()`</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="k">return</span> <span class="n">compose_detail</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">)</span> <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span> <span class="k">return</span> <span class="kc">None</span></div> <div class="viewcode-block" id="build_status"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.build_status">[docs]</a><span class="k">def</span> <span class="nf">build_status</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">status_filter</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="sd">"""Return the details of finished or failed builds</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param status_filter: What builds to return. None == all, "FINISHED", or "FAILED"</span> <span class="sd"> :type status_filter: str</span> <span class="sd"> :returns: A list of the build details (from compose_details)</span> <span class="sd"> :rtype: list of dicts</span> <span class="sd"> This returns a list of build details for each of the matching builds on the</span> <span class="sd"> system. It does not return the status of builds that have not been finished.</span> <span class="sd"> Use queue_status() for those.</span> <span class="sd"> """</span> <span class="k">if</span> <span class="n">status_filter</span><span class="p">:</span> <span class="n">status_filter</span> <span class="o">=</span> <span class="p">[</span><span class="n">status_filter</span><span class="p">]</span> <span class="k">else</span><span class="p">:</span> <span class="n">status_filter</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"FINISHED"</span><span class="p">,</span> <span class="s2">"FAILED"</span><span class="p">]</span> <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">result_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">)</span> <span class="k">for</span> <span class="n">build</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">result_dir</span> <span class="o">+</span> <span class="s2">"/*"</span><span class="p">):</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Checking status of build </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">build</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">status</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">build</span><span class="p">,</span> <span class="s2">"STATUS"</span><span class="p">),</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">if</span> <span class="n">status</span> <span class="ow">in</span> <span class="n">status_filter</span><span class="p">:</span> <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">compose_detail</span><span class="p">(</span><span class="n">build</span><span class="p">))</span> <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span> <span class="k">pass</span> <span class="k">return</span> <span class="n">results</span></div> <div class="viewcode-block" id="uuid_cancel"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_cancel">[docs]</a><span class="k">def</span> <span class="nf">uuid_cancel</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Cancel a build and delete its results</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: True if it was canceled and deleted</span> <span class="sd"> :rtype: bool</span> <span class="sd"> Only call this if the build status is WAITING or RUNNING</span> <span class="sd"> """</span> <span class="c1"># This status can change (and probably will) while it is in the middle of doing this:</span> <span class="c1"># It can move from WAITING -> RUNNING or it can move from RUNNING -> FINISHED|FAILED</span> <span class="c1"># If it is in WAITING remove the symlink and then check to make sure it didn't show up</span> <span class="c1"># in RUNNING</span> <span class="n">queue_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"queue"</span><span class="p">)</span> <span class="n">uuid_new</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">queue_dir</span><span class="p">,</span> <span class="s2">"new"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_new</span><span class="p">):</span> <span class="k">try</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">unlink</span><span class="p">(</span><span class="n">uuid_new</span><span class="p">)</span> <span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span> <span class="c1"># The symlink may vanish if the queue monitor started the build</span> <span class="k">pass</span> <span class="n">uuid_run</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">queue_dir</span><span class="p">,</span> <span class="s2">"run"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_run</span><span class="p">):</span> <span class="c1"># Successfully removed it before the build started</span> <span class="k">return</span> <span class="n">uuid_delete</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="c1"># Tell the build to stop running</span> <span class="n">cancel_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="s2">"CANCEL"</span><span class="p">)</span> <span class="nb">open</span><span class="p">(</span><span class="n">cancel_path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Wait for status to move to FAILED</span> <span class="n">started</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span> <span class="n">status</span> <span class="o">=</span> <span class="n">uuid_status</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="n">status</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">status</span><span class="p">[</span><span class="s2">"queue_status"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"FAILED"</span><span class="p">:</span> <span class="k">break</span> <span class="c1"># Is this taking too long? Exit anyway and try to cleanup.</span> <span class="k">if</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">></span> <span class="n">started</span> <span class="o">+</span> <span class="p">(</span><span class="mi">10</span> <span class="o">*</span> <span class="mi">60</span><span class="p">):</span> <span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Failed to cancel the build of </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">break</span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># Remove the partial results</span> <span class="n">uuid_delete</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span></div> <div class="viewcode-block" id="uuid_delete"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_delete">[docs]</a><span class="k">def</span> <span class="nf">uuid_delete</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Delete all of the results from a compose</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: True if it was deleted</span> <span class="sd"> :rtype: bool</span> <span class="sd"> :raises: This will raise an error if the delete failed</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">uuid_dir</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">)</span> <span class="o"><</span> <span class="mi">10</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Directory length is too short: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid_dir</span><span class="p">)</span> <span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">)</span> <span class="k">return</span> <span class="kc">True</span></div> <div class="viewcode-block" id="uuid_info"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_info">[docs]</a><span class="k">def</span> <span class="nf">uuid_info</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Return information about the composition</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: dictionary of information about the composition or None</span> <span class="sd"> :rtype: dict</span> <span class="sd"> :raises: RuntimeError if there was a problem</span> <span class="sd"> This will return a dict with the following fields populated:</span> <span class="sd"> * id - The uuid of the comoposition</span> <span class="sd"> * config - containing the configuration settings used to run Anaconda</span> <span class="sd"> * blueprint - The depsolved blueprint used to generate the kickstart</span> <span class="sd"> * commit - The (local) git commit hash for the blueprint used</span> <span class="sd"> * deps - The NEVRA of all of the dependencies used in the composition</span> <span class="sd"> * compose_type - The type of output generated (tar, iso, etc.)</span> <span class="sd"> * queue_status - The final status of the composition (FINISHED or FAILED)</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">):</span> <span class="k">return</span> <span class="kc">None</span> <span class="c1"># Load the compose configuration</span> <span class="n">cfg_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"config.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing config.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">cfg_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">frozen_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"frozen.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">frozen_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing frozen.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">frozen_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">frozen_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">deps_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"deps.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">deps_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing deps.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">deps_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">deps_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">details</span> <span class="o">=</span> <span class="n">compose_detail</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">)</span> <span class="n">commit_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"COMMIT"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">commit_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing commit hash for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">commit_id</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">commit_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">return</span> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="n">uuid</span><span class="p">,</span> <span class="s2">"config"</span><span class="p">:</span> <span class="n">cfg_dict</span><span class="p">,</span> <span class="s2">"blueprint"</span><span class="p">:</span> <span class="n">frozen_dict</span><span class="p">,</span> <span class="s2">"commit"</span><span class="p">:</span> <span class="n">commit_id</span><span class="p">,</span> <span class="s2">"deps"</span><span class="p">:</span> <span class="n">deps_dict</span><span class="p">,</span> <span class="s2">"compose_type"</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">"compose_type"</span><span class="p">],</span> <span class="s2">"queue_status"</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">"queue_status"</span><span class="p">],</span> <span class="s2">"image_size"</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">"image_size"</span><span class="p">]</span> <span class="p">}</span></div> <div class="viewcode-block" id="uuid_tar"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_tar">[docs]</a><span class="k">def</span> <span class="nf">uuid_tar</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">metadata</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">logs</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span> <span class="sd">"""Return a tar of the build data</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :param metadata: Set to true to include all the metadata needed to reproduce the build</span> <span class="sd"> :type metadata: bool</span> <span class="sd"> :param image: Set to true to include the output image</span> <span class="sd"> :type image: bool</span> <span class="sd"> :param logs: Set to true to include the logs from the build</span> <span class="sd"> :type logs: bool</span> <span class="sd"> :returns: A stream of bytes from tar</span> <span class="sd"> :rtype: A generator</span> <span class="sd"> :raises: RuntimeError if there was a problem (eg. missing config file)</span> <span class="sd"> This yields an uncompressed tar's data to the caller. It includes</span> <span class="sd"> the selected data to the caller by returning the Popen stdout from the tar process.</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> is not a valid build_id"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="c1"># Load the compose configuration</span> <span class="n">cfg_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"config.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing config.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">cfg_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">image_name</span> <span class="o">=</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"image_name"</span><span class="p">]</span> <span class="k">def</span> <span class="nf">include_file</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s2">"/logs"</span><span class="p">):</span> <span class="k">return</span> <span class="n">logs</span> <span class="k">if</span> <span class="n">f</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="n">image_name</span><span class="p">):</span> <span class="k">return</span> <span class="n">image</span> <span class="k">return</span> <span class="n">metadata</span> <span class="n">filenames</span> <span class="o">=</span> <span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">glob</span><span class="p">(</span><span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"*"</span><span class="p">))</span> <span class="k">if</span> <span class="n">include_file</span><span class="p">(</span><span class="n">f</span><span class="p">)]</span> <span class="n">tar</span> <span class="o">=</span> <span class="n">Popen</span><span class="p">([</span><span class="s2">"tar"</span><span class="p">,</span> <span class="s2">"-C"</span><span class="p">,</span> <span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"-cf-"</span><span class="p">]</span> <span class="o">+</span> <span class="n">filenames</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">)</span> <span class="k">return</span> <span class="n">tar</span><span class="o">.</span><span class="n">stdout</span></div> <div class="viewcode-block" id="uuid_image"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_image">[docs]</a><span class="k">def</span> <span class="nf">uuid_image</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span> <span class="sd">"""Return the filename and full path of the build's image file</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: The image filename and full path</span> <span class="sd"> :rtype: tuple of strings</span> <span class="sd"> :raises: RuntimeError if there was a problem (eg. invalid uuid, missing config file)</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">return</span> <span class="n">get_image_name</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">)</span></div> <div class="viewcode-block" id="get_image_name"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.get_image_name">[docs]</a><span class="k">def</span> <span class="nf">get_image_name</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">):</span> <span class="sd">"""Return the filename and full path of the build's image file</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :returns: The image filename and full path</span> <span class="sd"> :rtype: tuple of strings</span> <span class="sd"> :raises: RuntimeError if there was a problem (eg. invalid uuid, missing config file)</span> <span class="sd"> """</span> <span class="n">uuid</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">))</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> is not a valid build_id"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="c1"># Load the compose configuration</span> <span class="n">cfg_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"config.toml"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Missing config.toml for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="n">cfg_dict</span> <span class="o">=</span> <span class="n">toml</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">cfg_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> <span class="n">image_name</span> <span class="o">=</span> <span class="n">cfg_dict</span><span class="p">[</span><span class="s2">"image_name"</span><span class="p">]</span> <span class="k">return</span> <span class="p">(</span><span class="n">image_name</span><span class="p">,</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="n">image_name</span><span class="p">))</span></div> <div class="viewcode-block" id="uuid_log"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.uuid_log">[docs]</a><span class="k">def</span> <span class="nf">uuid_log</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">1024</span><span class="p">):</span> <span class="sd">"""Return `size` kbytes from the end of the anaconda.log</span> <span class="sd"> :param cfg: Configuration settings</span> <span class="sd"> :type cfg: ComposerConfig</span> <span class="sd"> :param uuid: The UUID of the build</span> <span class="sd"> :type uuid: str</span> <span class="sd"> :param size: Number of kbytes to read. Default is 1024</span> <span class="sd"> :type size: int</span> <span class="sd"> :returns: Up to `size` kbytes from the end of the log</span> <span class="sd"> :rtype: str</span> <span class="sd"> :raises: RuntimeError if there was a problem (eg. no log file available)</span> <span class="sd"> This function tries to return lines from the end of the log, it will</span> <span class="sd"> attempt to start on a line boundry, and may return less than `size` kbytes.</span> <span class="sd"> """</span> <span class="n">uuid_dir</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">cfg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"composer"</span><span class="p">,</span> <span class="s2">"lib_dir"</span><span class="p">),</span> <span class="s2">"results"</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> is not a valid build_id"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="c1"># While a build is running the logs will be in /tmp/anaconda.log and when it</span> <span class="c1"># has finished they will be in the results directory</span> <span class="n">status</span> <span class="o">=</span> <span class="n">uuid_status</span><span class="p">(</span><span class="n">cfg</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="n">status</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"Status is missing for </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">uuid</span><span class="p">)</span> <span class="k">if</span> <span class="n">status</span><span class="p">[</span><span class="s2">"queue_status"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"RUNNING"</span><span class="p">:</span> <span class="n">log_path</span> <span class="o">=</span> <span class="s2">"/tmp/anaconda.log"</span> <span class="k">else</span><span class="p">:</span> <span class="n">log_path</span> <span class="o">=</span> <span class="n">joinpaths</span><span class="p">(</span><span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">"logs"</span><span class="p">,</span> <span class="s2">"anaconda"</span><span class="p">,</span> <span class="s2">"anaconda.log"</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">log_path</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"No anaconda.log available."</span><span class="p">)</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">log_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="n">end</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="k">if</span> <span class="n">end</span> <span class="o"><</span> <span class="mi">1024</span> <span class="o">*</span> <span class="n">size</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="p">(</span><span class="mi">1024</span> <span class="o">*</span> <span class="n">size</span><span class="p">))</span> <span class="c1"># Find the start of the next line and return the rest</span> <span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span> <span class="k">return</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span></div> </pre></div> </div> </div> <footer> <hr/> <div role="contentinfo"> <p> © Copyright 2018, Red Hat, Inc.. </p> </div> Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT:'../../../', VERSION:'29.11', LANGUAGE:'None', COLLAPSE_INDEX:false, FILE_SUFFIX:'.html', HAS_SOURCE: true, SOURCELINK_SUFFIX: '.txt' }; </script> <script type="text/javascript" src="../../../_static/jquery.js"></script> <script type="text/javascript" src="../../../_static/underscore.js"></script> <script type="text/javascript" src="../../../_static/doctools.js"></script> <script type="text/javascript" src="../../../_static/js/theme.js"></script> <script type="text/javascript"> jQuery(function () { SphinxRtdTheme.Navigation.enable(true); }); </script> </body> </html>