lorax/_modules/pylorax/api/queue.html
2019-06-18 15:08:20 -07:00

875 lines
100 KiB
HTML

<!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 &mdash; Lorax 31.7 documentation</title>
<script type="text/javascript" src="../../../_static/js/modernizr.min.js"></script>
<script type="text/javascript" id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></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/language_data.js"></script>
<script type="text/javascript" src="../../../_static/js/theme.js"></script>
<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" />
</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">
31.7
</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> &raquo;</li>
<li><a href="../../index.html">Module code</a> &raquo;</li>
<li><a href="../../pylorax.html">pylorax</a> &raquo;</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 &lt;http://www.gnu.org/licenses/&gt;.</span>
<span class="c1">#</span>
<span class="sd">&quot;&quot;&quot; Functions to monitor compose queue and run anaconda&quot;&quot;&quot;</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">&quot;pylorax&quot;</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">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">import</span> <span class="nn">pylorax.api.toml</span> <span class="k">as</span> <span class="nn">toml</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="check_queues"><a class="viewcode-back" href="../../../pylorax.api.html#pylorax.api.queue.check_queues">[docs]</a><span class="k">def</span> <span class="nf">check_queues</span><span class="p">(</span><span class="n">cfg</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Check to make sure the new and run queue symlinks are correct</span>
<span class="sd"> :param cfg: Configuration settings</span>
<span class="sd"> :type cfg: DataHolder</span>
<span class="sd"> Also check all of the existing results and make sure any with WAITING</span>
<span class="sd"> set in STATUS have a symlink in queue/new/</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># Remove broken symlinks from the new and run queues</span>
<span class="n">queue_symlinks</span> <span class="o">=</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">composer_dir</span><span class="p">,</span> <span class="s2">&quot;queue/new/*&quot;</span><span class="p">))</span> <span class="o">+</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">composer_dir</span><span class="p">,</span> <span class="s2">&quot;queue/run/*&quot;</span><span class="p">))</span>
<span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">queue_symlinks</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">isdir</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">link</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">&quot;Removing broken symlink </span><span class="si">%s</span><span class="s2">&quot;</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">unlink</span><span class="p">(</span><span class="n">link</span><span class="p">)</span>
<span class="c1"># Write FAILED to the STATUS of any run queue symlinks and remove them</span>
<span class="k">for</span> <span class="n">link</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">composer_dir</span><span class="p">,</span> <span class="s2">&quot;queue/run/*&quot;</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">&quot;Setting build </span><span class="si">%s</span><span class="s2"> to FAILED, and removing symlink from queue/run/&quot;</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">link</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">link</span><span class="p">,</span> <span class="s2">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;FAILED</span><span class="se">\n</span><span class="s2">&quot;</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">link</span><span class="p">)</span>
<span class="c1"># Check results STATUS messages</span>
<span class="c1"># - If STATUS is missing, set it to FAILED</span>
<span class="c1"># - RUNNING should be changed to FAILED</span>
<span class="c1"># - WAITING should have a symlink in the new queue</span>
<span class="k">for</span> <span class="n">link</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">composer_dir</span><span class="p">,</span> <span class="s2">&quot;results/*&quot;</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">joinpaths</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="s2">&quot;STATUS&quot;</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">link</span><span class="p">,</span> <span class="s2">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;FAILED</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">continue</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">link</span><span class="p">,</span> <span class="s2">&quot;STATUS&quot;</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="o">==</span> <span class="s2">&quot;RUNNING&quot;</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">&quot;Setting build </span><span class="si">%s</span><span class="s2"> to FAILED&quot;</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">link</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">link</span><span class="p">,</span> <span class="s2">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;FAILED</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;WAITING&quot;</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">islink</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">&quot;queue/new/&quot;</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">link</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">&quot;Creating missing symlink to new build </span><span class="si">%s</span><span class="s2">&quot;</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">link</span><span class="p">))</span>
<span class="n">os</span><span class="o">.</span><span class="n">symlink</span><span class="p">(</span><span class="n">link</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">&quot;queue/new/&quot;</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">link</span><span class="p">)))</span></div>
<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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;share_dir&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;tmp&quot;</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">&quot;&quot;&quot;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: WAITING, 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"> &quot;&quot;&quot;</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">&quot;&quot;&quot;Sort the queue entries by their mtime, not their names&quot;&quot;&quot;</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">&quot;queue/new&quot;</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="n">check_queues</span><span class="p">(</span><span class="n">cfg</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">&quot;queue/new&quot;</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">&quot;queue/new&quot;</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">&quot;queue/run&quot;</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">&quot;Starting new compose: </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;RUNNING</span><span class="se">\n</span><span class="s2">&quot;</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">&quot;Finished building </span><span class="si">%s</span><span class="s2">, results are in </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;FINISHED</span><span class="se">\n</span><span class="s2">&quot;</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">&quot;traceback: </span><span class="si">%s</span><span class="s2">&quot;</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(&quot;Error running compose: %s&quot;, 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">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;FAILED</span><span class="se">\n</span><span class="s2">&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</span>
<span class="c1"># Check on the ks&#39;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">&quot;final-kickstart.ks&quot;</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">&quot;Missing kickstart file at </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;logs/&quot;</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">&quot;config.toml&quot;</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">&quot;Missing config.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;image_name&quot;</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">&quot;image_name&quot;</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">&quot;no_virt&quot;</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">&quot;disk_image&quot;</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">&quot;fs_image&quot;</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">&quot;keep_image&quot;</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">&quot;domacboot&quot;</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">&quot;anaconda_args&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">cfg_dict</span><span class="p">[</span><span class="s2">&quot;proxy&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">cfg_dict</span><span class="p">[</span><span class="s2">&quot;armplatform&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">cfg_dict</span><span class="p">[</span><span class="s2">&quot;squashfs_args&quot;</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">&quot;lorax_templates&quot;</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">&quot;tmp&quot;</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">&quot;dracut_args&quot;</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">&quot;arch&quot;</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">&quot;result_dir&quot;</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">&quot;compose&quot;</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">&quot;result_dir&quot;</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">&quot;/tmp/NOSAVE_INPUT_KS&quot;</span><span class="p">,</span> <span class="s2">&quot;/tmp/NOSAVE_LOGS&quot;</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">&quot;w&quot;</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">&quot;CANCEL&quot;</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">&quot;cfg = </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;TEST&quot;</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">&quot;r&quot;</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">&quot;TESTING FAILED compose&quot;</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">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;TEST IMAGE&quot;</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">cancel_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">&quot;lmc-*&quot;</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">&quot;Install finished, chowning results to </span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">&quot;</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">&quot;chown&quot;</span><span class="p">,</span> <span class="s2">&quot;-R&quot;</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">&quot;</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">&quot;&quot;&quot;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. &#39;tar&#39;)</span>
<span class="sd"> :rtype: str</span>
<span class="sd"> :raises: RuntimeError if no kickstart template can be found.</span>
<span class="sd"> &quot;&quot;&quot;</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">&quot;*.ks&quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="s2">&quot;final-kickstart&quot;</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">&quot;Cannot find ks template for build </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;STATUS&quot;</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">&quot;blueprint.toml&quot;</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">&quot;FINISHED&quot;</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">&quot;id&quot;</span><span class="p">:</span> <span class="n">build_id</span><span class="p">,</span>
<span class="s2">&quot;queue_status&quot;</span><span class="p">:</span> <span class="n">status</span><span class="p">,</span>
<span class="s2">&quot;job_created&quot;</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">&quot;job_started&quot;</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">&quot;job_finished&quot;</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">&quot;compose_type&quot;</span><span class="p">:</span> <span class="n">compose_type</span><span class="p">,</span>
<span class="s2">&quot;blueprint&quot;</span><span class="p">:</span> <span class="n">blueprint</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span>
<span class="s2">&quot;version&quot;</span><span class="p">:</span> <span class="n">blueprint</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">],</span>
<span class="s2">&quot;image_size&quot;</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">&quot;&quot;&quot;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. &quot;new&quot; is the list of uuids that are waiting to be built,</span>
<span class="sd"> and &quot;run&quot; has the uuids that are being built (currently limited to 1 at a time).</span>
<span class="sd"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;queue&quot;</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">&quot;new/*&quot;</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">&quot;run/*&quot;</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">&quot;new&quot;</span><span class="p">:</span> <span class="n">new_details</span><span class="p">,</span>
<span class="s2">&quot;run&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;&quot;&quot;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, &quot;FINISHED&quot;, or &quot;FAILED&quot;</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"> &quot;&quot;&quot;</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">&quot;FINISHED&quot;</span><span class="p">,</span> <span class="s2">&quot;FAILED&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;/*&quot;</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">&quot;Checking status of build </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;STATUS&quot;</span><span class="p">),</span> <span class="s2">&quot;r&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</span><span class="p">,</span> <span class="n">uuid</span><span class="p">,</span> <span class="s2">&quot;CANCEL&quot;</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">cancel_path</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">&quot;Cancel has already been requested for </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">uuid</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</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 -&gt; RUNNING or it can move from RUNNING -&gt; FINISHED|FAILED</span>
<span class="c1"># If it is in WAITING remove the symlink and then check to make sure it didn&#39;t show up</span>
<span class="c1"># in the run queue</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;queue&quot;</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">&quot;new&quot;</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">&quot;run&quot;</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"># Make sure the build is still in the waiting state</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">&quot;queue_status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;WAITING&quot;</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"># At this point the build has probably started. Write to the CANCEL file.</span>
<span class="nb">open</span><span class="p">(</span><span class="n">cancel_path</span><span class="p">,</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="c1"># Wait for status to move to FAILED or FINISHED</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">&quot;queue_status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;FAILED&quot;</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">elif</span> <span class="n">status</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">status</span><span class="p">[</span><span class="s2">&quot;queue_status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;FINISHED&quot;</span><span class="p">:</span>
<span class="c1"># The build finished successfully, no point in deleting it now</span>
<span class="k">return</span> <span class="kc">False</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">&gt;</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">&quot;Failed to cancel the build of </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&lt;</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">&quot;Directory length is too short: </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;config.toml&quot;</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">&quot;Missing config.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;frozen.toml&quot;</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">&quot;Missing frozen.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;deps.toml&quot;</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">&quot;Missing deps.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;COMMIT&quot;</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">&quot;Missing commit hash for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;id&quot;</span><span class="p">:</span> <span class="n">uuid</span><span class="p">,</span>
<span class="s2">&quot;config&quot;</span><span class="p">:</span> <span class="n">cfg_dict</span><span class="p">,</span>
<span class="s2">&quot;blueprint&quot;</span><span class="p">:</span> <span class="n">frozen_dict</span><span class="p">,</span>
<span class="s2">&quot;commit&quot;</span><span class="p">:</span> <span class="n">commit_id</span><span class="p">,</span>
<span class="s2">&quot;deps&quot;</span><span class="p">:</span> <span class="n">deps_dict</span><span class="p">,</span>
<span class="s2">&quot;compose_type&quot;</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;compose_type&quot;</span><span class="p">],</span>
<span class="s2">&quot;queue_status&quot;</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;queue_status&quot;</span><span class="p">],</span>
<span class="s2">&quot;image_size&quot;</span><span class="p">:</span> <span class="n">details</span><span class="p">[</span><span class="s2">&quot;image_size&quot;</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">&quot;&quot;&quot;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&#39;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;</span><span class="si">%s</span><span class="s2"> is not a valid build_id&quot;</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">&quot;config.toml&quot;</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">&quot;Missing config.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;image_name&quot;</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">&quot;/logs&quot;</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">&quot;*&quot;</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">&quot;tar&quot;</span><span class="p">,</span> <span class="s2">&quot;-C&quot;</span><span class="p">,</span> <span class="n">uuid_dir</span><span class="p">,</span> <span class="s2">&quot;-cf-&quot;</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">&quot;&quot;&quot;Return the filename and full path of the build&#39;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;&quot;&quot;Return the filename and full path of the build&#39;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"> &quot;&quot;&quot;</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">&quot;</span><span class="si">%s</span><span class="s2"> is not a valid build_id&quot;</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">&quot;config.toml&quot;</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">&quot;Missing config.toml for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;r&quot;</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">&quot;image_name&quot;</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">&quot;&quot;&quot;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"> &quot;&quot;&quot;</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">&quot;composer&quot;</span><span class="p">,</span> <span class="s2">&quot;lib_dir&quot;</span><span class="p">),</span> <span class="s2">&quot;results&quot;</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">&quot;</span><span class="si">%s</span><span class="s2"> is not a valid build_id&quot;</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">&quot;Status is missing for </span><span class="si">%s</span><span class="s2">&quot;</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">&quot;queue_status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;RUNNING&quot;</span><span class="p">:</span>
<span class="n">log_path</span> <span class="o">=</span> <span class="s2">&quot;/tmp/anaconda.log&quot;</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">&quot;logs&quot;</span><span class="p">,</span> <span class="s2">&quot;anaconda&quot;</span><span class="p">,</span> <span class="s2">&quot;anaconda.log&quot;</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">&quot;No anaconda.log available.&quot;</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">&quot;r&quot;</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">&lt;</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>
&copy; 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">
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>