diff --git a/.buildinfo b/.buildinfo index c19f2a6e..b48190b2 100644 --- a/.buildinfo +++ b/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 976fdd7ad1c7255de97a1c91fa7bf7af +config: 98a432c0452272f3968f9d4d9720ed79 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/composer.cli.doctree b/.doctrees/composer.cli.doctree index 441cd54c..e7375591 100644 Binary files a/.doctrees/composer.cli.doctree and b/.doctrees/composer.cli.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle index 45b24fb1..c6c1215c 100644 Binary files a/.doctrees/environment.pickle and b/.doctrees/environment.pickle differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree index e70540ba..bb82811c 100644 Binary files a/.doctrees/index.doctree and b/.doctrees/index.doctree differ diff --git a/.doctrees/pylorax.api.doctree b/.doctrees/pylorax.api.doctree index aed81763..291dc23b 100644 Binary files a/.doctrees/pylorax.api.doctree and b/.doctrees/pylorax.api.doctree differ diff --git a/.doctrees/pylorax.doctree b/.doctrees/pylorax.doctree index d89912e7..05396f41 100644 Binary files a/.doctrees/pylorax.doctree and b/.doctrees/pylorax.doctree differ diff --git a/_modules/composer/cli.html b/_modules/composer/cli.html index 90cff51b..5ddfa492 100644 --- a/_modules/composer/cli.html +++ b/_modules/composer/cli.html @@ -8,7 +8,7 @@ - composer.cli — Lorax 31.4 documentation + composer.cli — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/blueprints.html b/_modules/composer/cli/blueprints.html index 6220c9f6..fe381784 100644 --- a/_modules/composer/cli/blueprints.html +++ b/_modules/composer/cli/blueprints.html @@ -8,7 +8,7 @@ - composer.cli.blueprints — Lorax 31.4 documentation + composer.cli.blueprints — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
@@ -345,62 +345,129 @@ return rc for diff in result["diff"]: - print(prettyDiffEntry(diff)) + print(pretty_diff_entry(diff)) return rc -
[docs]def prettyDiffEntry(diff): +
[docs]def pretty_dict(d): + """Return the dict as a human readable single line + + :param d: key/values + :type d: dict + :returns: String of the dict's keys and values + :rtype: str + + key="str", key="str1,str2", ... + """ + result = [] + for k in d: + if type(d[k]) == type(""): + result.append('%s="%s"' % (k, d[k])) + elif type(d[k]) == type([]) and type(d[k][0]) == type(""): + result.append('%s="%s"' % (k, ", ".join(d[k]))) + elif type(d[k]) == type([]) and type(d[k][0]) == type({}): + result.append('%s="%s"' % (k, pretty_dict(d[k]))) + return " ".join(result)
+ +
[docs]def dict_names(lst): + """Return comma-separated list of the dict's name/user fields + + :param d: key/values + :type d: dict + :returns: String of the dict's keys and values + :rtype: str + + root, norm + """ + if "user" in lst[0]: + field_name = "user" + elif "name" in lst[0]: + field_name = "name" + else: + # Use first fields in sorted keys + field_name = sorted(lst[0].keys())[0] + + return ", ".join(d[field_name] for d in lst)
+ +
[docs]def pretty_diff_entry(diff): """Generate nice diff entry string. :param diff: Difference entry dict :type diff: dict :returns: Nice string """ - def change(diff): - if diff["old"] and diff["new"]: - return "Changed" - elif diff["new"] and not diff["old"]: - return "Added" - elif diff["old"] and not diff["new"]: - return "Removed" - else: - return "Unknown" + if diff["old"] and diff["new"]: + change = "Changed" + elif diff["new"] and not diff["old"]: + change = "Added" + elif diff["old"] and not diff["new"]: + change = "Removed" + else: + change = "Unknown" - def name(diff): - if diff["old"]: - return list(diff["old"].keys())[0] - elif diff["new"]: - return list(diff["new"].keys())[0] - else: - return "Unknown" + if diff["old"]: + name = list(diff["old"].keys())[0] + elif diff["new"]: + name = list(diff["new"].keys())[0] + else: + name = "Unknown" def details(diff): - if change(diff) == "Changed": - if name(diff) == "Description": - return '"%s" -> "%s"' % (diff["old"][name(diff)], diff["new"][name(diff)]) - elif name(diff) == "Version": - return "%s -> %s" % (diff["old"][name(diff)], diff["new"][name(diff)]) - elif name(diff) in ["Module", "Package"]: - return "%s %s -> %s" % (diff["old"][name(diff)]["name"], diff["old"][name(diff)]["version"], - diff["new"][name(diff)]["version"]) + if change == "Changed": + if type(diff["old"][name]) == type(""): + if name == "Description" or " " in diff["old"][name]: + return '"%s" -> "%s"' % (diff["old"][name], diff["new"][name]) + else: + return "%s -> %s" % (diff["old"][name], diff["new"][name]) + elif name in ["Module", "Package"]: + return "%s %s -> %s" % (diff["old"][name]["name"], diff["old"][name]["version"], + diff["new"][name]["version"]) + elif type(diff["old"][name]) == type([]): + if type(diff["old"][name][0]) == type(""): + return "%s -> %s" % (" ".join(diff["old"][name]), " ".join(diff["new"][name])) + elif type(diff["old"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return "%s -> %s" % (dict_names(diff["old"][name]), dict_names(diff["new"][name])) + elif type(diff["old"][name]) == type({}): + return "%s -> %s" % (pretty_dict(diff["old"][name]), pretty_dict(diff["new"][name])) else: return "Unknown" - elif change(diff) == "Added": - if name(diff) in ["Module", "Package"]: - return "%s %s" % (diff["new"][name(diff)]["name"], diff["new"][name(diff)]["version"]) - elif name(diff) in ["Group"]: - return diff["new"][name(diff)]["name"] + elif change == "Added": + if name in ["Module", "Package"]: + return "%s %s" % (diff["new"][name]["name"], diff["new"][name]["version"]) + elif name in ["Group"]: + return diff["new"][name]["name"] + elif type(diff["new"][name]) == type(""): + return diff["new"][name] + elif type(diff["new"][name]) == type([]): + if type(diff["new"][name][0]) == type(""): + return " ".join(diff["new"][name]) + elif type(diff["new"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return dict_names(diff["new"][name]) + elif type(diff["new"][name]) == type({}): + return pretty_dict(diff["new"][name]) else: - return " ".join([diff["new"][k] for k in diff["new"]]) - elif change(diff) == "Removed": - if name(diff) in ["Module", "Package"]: - return "%s %s" % (diff["old"][name(diff)]["name"], diff["old"][name(diff)]["version"]) - elif name(diff) in ["Group"]: - return diff["old"][name(diff)]["name"] + return "unknown/todo: %s" % type(diff["new"][name]) + elif change == "Removed": + if name in ["Module", "Package"]: + return "%s %s" % (diff["old"][name]["name"], diff["old"][name]["version"]) + elif name in ["Group"]: + return diff["old"][name]["name"] + elif type(diff["old"][name]) == type(""): + return diff["old"][name] + elif type(diff["old"][name]) == type([]): + if type(diff["old"][name][0]) == type(""): + return " ".join(diff["old"][name]) + elif type(diff["old"][name][0]) == type({}): + # Lists of dicts are too long to display in detail, just show their names + return dict_names(diff["old"][name]) + elif type(diff["old"][name]) == type({}): + return pretty_dict(diff["old"][name]) else: - return " ".join([diff["old"][k] for k in diff["old"]]) + return "unknown/todo: %s" % type(diff["new"][name]) - return change(diff) + " " + name(diff) + " " + details(diff)
+ return change + " " + name + " " + details(diff)
[docs]def blueprints_save(socket_path, api_version, args, show_json=False): """Save the blueprint to a TOML file diff --git a/_modules/composer/cli/cmdline.html b/_modules/composer/cli/cmdline.html index ed5cb3ec..cf6697cb 100644 --- a/_modules/composer/cli/cmdline.html +++ b/_modules/composer/cli/cmdline.html @@ -8,7 +8,7 @@ - composer.cli.cmdline — Lorax 31.4 documentation + composer.cli.cmdline — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/compose.html b/_modules/composer/cli/compose.html index 05ae0a41..bc9d40e1 100644 --- a/_modules/composer/cli/compose.html +++ b/_modules/composer/cli/compose.html @@ -8,7 +8,7 @@ - composer.cli.compose — Lorax 31.4 documentation + composer.cli.compose — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/modules.html b/_modules/composer/cli/modules.html index 5049d4a5..b0a24cb1 100644 --- a/_modules/composer/cli/modules.html +++ b/_modules/composer/cli/modules.html @@ -8,7 +8,7 @@ - composer.cli.modules — Lorax 31.4 documentation + composer.cli.modules — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/projects.html b/_modules/composer/cli/projects.html index 1adc4c7c..685d2429 100644 --- a/_modules/composer/cli/projects.html +++ b/_modules/composer/cli/projects.html @@ -8,7 +8,7 @@ - composer.cli.projects — Lorax 31.4 documentation + composer.cli.projects — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/sources.html b/_modules/composer/cli/sources.html index e3dc53fc..00a859c6 100644 --- a/_modules/composer/cli/sources.html +++ b/_modules/composer/cli/sources.html @@ -8,7 +8,7 @@ - composer.cli.sources — Lorax 31.4 documentation + composer.cli.sources — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/status.html b/_modules/composer/cli/status.html index 0f6df1ec..47916949 100644 --- a/_modules/composer/cli/status.html +++ b/_modules/composer/cli/status.html @@ -8,7 +8,7 @@ - composer.cli.status — Lorax 31.4 documentation + composer.cli.status — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/cli/utilities.html b/_modules/composer/cli/utilities.html index ef187fab..444a9c47 100644 --- a/_modules/composer/cli/utilities.html +++ b/_modules/composer/cli/utilities.html @@ -8,7 +8,7 @@ - composer.cli.utilities — Lorax 31.4 documentation + composer.cli.utilities — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/http_client.html b/_modules/composer/http_client.html index 5ee4274b..fe5d2c2f 100644 --- a/_modules/composer/http_client.html +++ b/_modules/composer/http_client.html @@ -8,7 +8,7 @@ - composer.http_client — Lorax 31.4 documentation + composer.http_client — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/composer/unix_socket.html b/_modules/composer/unix_socket.html index ae8813cb..82b5ce57 100644 --- a/_modules/composer/unix_socket.html +++ b/_modules/composer/unix_socket.html @@ -8,7 +8,7 @@ - composer.unix_socket — Lorax 31.4 documentation + composer.unix_socket — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
diff --git a/_modules/index.html b/_modules/index.html index ae59ec97..27d09710 100644 --- a/_modules/index.html +++ b/_modules/index.html @@ -8,7 +8,7 @@ - Overview: module code — Lorax 31.4 documentation + Overview: module code — Lorax 31.7 documentation @@ -58,7 +58,7 @@
- 31.4 + 31.7
@@ -171,12 +171,14 @@
  • pylorax.api.config
  • pylorax.api.crossdomain
  • pylorax.api.dnfbase
  • +
  • pylorax.api.flask_blueprint
  • pylorax.api.gitrpm
  • pylorax.api.projects
  • pylorax.api.queue
  • pylorax.api.recipes
  • pylorax.api.server
  • pylorax.api.timestamp
  • +
  • pylorax.api.toml
  • pylorax.api.v0
  • pylorax.api.workspace
  • pylorax.base
  • diff --git a/_modules/pylorax.html b/_modules/pylorax.html index ee155b43..2de1ea99 100644 --- a/_modules/pylorax.html +++ b/_modules/pylorax.html @@ -8,7 +8,7 @@ - pylorax — Lorax 31.4 documentation + pylorax — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/bisect.html b/_modules/pylorax/api/bisect.html index 310e3c81..c3da94d4 100644 --- a/_modules/pylorax/api/bisect.html +++ b/_modules/pylorax/api/bisect.html @@ -8,7 +8,7 @@ - pylorax.api.bisect — Lorax 31.4 documentation + pylorax.api.bisect — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/checkparams.html b/_modules/pylorax/api/checkparams.html index 610654f5..c178c288 100644 --- a/_modules/pylorax/api/checkparams.html +++ b/_modules/pylorax/api/checkparams.html @@ -8,7 +8,7 @@ - pylorax.api.checkparams — Lorax 31.4 documentation + pylorax.api.checkparams — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/cmdline.html b/_modules/pylorax/api/cmdline.html index 9dfc16f4..28e246c3 100644 --- a/_modules/pylorax/api/cmdline.html +++ b/_modules/pylorax/api/cmdline.html @@ -8,7 +8,7 @@ - pylorax.api.cmdline — Lorax 31.4 documentation + pylorax.api.cmdline — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/compose.html b/_modules/pylorax/api/compose.html index bd5d9c5d..0263abb1 100644 --- a/_modules/pylorax/api/compose.html +++ b/_modules/pylorax/api/compose.html @@ -8,7 +8,7 @@ - pylorax.api.compose — Lorax 31.4 documentation + pylorax.api.compose — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -195,7 +195,6 @@ from glob import glob from io import StringIO from math import ceil -import pytoml as toml import shutil from uuid import uuid4 @@ -209,6 +208,7 @@ from pylorax.api.projects import ProjectsError from pylorax.api.recipes import read_recipe_and_id from pylorax.api.timestamp import TS_CREATED, write_timestamp +import pylorax.api.toml as toml from pylorax.base import DataHolder from pylorax.imgutils import default_image_name from pylorax.ltmpl import LiveTemplateRunner diff --git a/_modules/pylorax/api/config.html b/_modules/pylorax/api/config.html index 722eab20..9ce6db40 100644 --- a/_modules/pylorax/api/config.html +++ b/_modules/pylorax/api/config.html @@ -8,7 +8,7 @@ - pylorax.api.config — Lorax 31.4 documentation + pylorax.api.config — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/crossdomain.html b/_modules/pylorax/api/crossdomain.html index d34dad81..d8f653fe 100644 --- a/_modules/pylorax/api/crossdomain.html +++ b/_modules/pylorax/api/crossdomain.html @@ -8,7 +8,7 @@ - pylorax.api.crossdomain — Lorax 31.4 documentation + pylorax.api.crossdomain — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/dnfbase.html b/_modules/pylorax/api/dnfbase.html index 2ec9b5c0..9c845149 100644 --- a/_modules/pylorax/api/dnfbase.html +++ b/_modules/pylorax/api/dnfbase.html @@ -8,7 +8,7 @@ - pylorax.api.dnfbase — Lorax 31.4 documentation + pylorax.api.dnfbase — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/flask_blueprint.html b/_modules/pylorax/api/flask_blueprint.html new file mode 100644 index 00000000..dac7e472 --- /dev/null +++ b/_modules/pylorax/api/flask_blueprint.html @@ -0,0 +1,254 @@ + + + + + + + + + + + pylorax.api.flask_blueprint — Lorax 31.7 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.flask_blueprint

    +#
    +# Copyright (C) 2019 Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +""" Flask Blueprints that support skipping routes
    +
    +When using Blueprints for API versioning you will usually want to fall back
    +to the previous version's rules for routes that have no new behavior. To do
    +this we add a 'skip_rule' list to the Blueprint's options dictionary. It lists
    +all of the routes that you do not want to register.
    +
    +For example:
    +    from pylorax.api.v0 import v0
    +    from pylorax.api.v1 import v1
    +
    +    server.register_blueprint(v0, url_prefix="/api/v0/")
    +    server.register_blueprint(v0, url_prefix="/api/v1/", skip_rules=["/blueprints/list"]
    +    server.register_blueprint(v1, url_prefix="/api/v1/")
    +
    +This will register all of v0's routes under `/api/v0`, and all but `/blueprints/list` under /api/v1,
    +and then register v1's version of `/blueprints/list` under `/api/v1`
    +
    +"""
    +from flask import Blueprint
    +from flask.blueprints import BlueprintSetupState
    +
    +
    [docs]class BlueprintSetupStateSkip(BlueprintSetupState): + def __init__(self, blueprint, app, options, first_registration, skip_rules): + self._skip_rules = skip_rules + super(BlueprintSetupStateSkip, self).__init__(blueprint, app, options, first_registration) + +
    [docs] def add_url_rule(self, rule, endpoint=None, view_func=None, **options): + if rule not in self._skip_rules: + super(BlueprintSetupStateSkip, self).add_url_rule(rule, endpoint, view_func, **options)
    + +
    [docs]class BlueprintSkip(Blueprint): + def __init__(self, *args, **kwargs): + super(BlueprintSkip, self).__init__(*args, **kwargs) + +
    [docs] def make_setup_state(self, app, options, first_registration=False): + skip_rules = options.pop("skip_rules", []) + return BlueprintSetupStateSkip(self, app, options, first_registration, skip_rules)
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/pylorax/api/gitrpm.html b/_modules/pylorax/api/gitrpm.html index 6daedcd6..a38d2179 100644 --- a/_modules/pylorax/api/gitrpm.html +++ b/_modules/pylorax/api/gitrpm.html @@ -8,7 +8,7 @@ - pylorax.api.gitrpm — Lorax 31.4 documentation + pylorax.api.gitrpm — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/projects.html b/_modules/pylorax/api/projects.html index 6c74c6d5..dd023df5 100644 --- a/_modules/pylorax/api/projects.html +++ b/_modules/pylorax/api/projects.html @@ -8,7 +8,7 @@ - pylorax.api.projects — Lorax 31.4 documentation + pylorax.api.projects — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/api/queue.html b/_modules/pylorax/api/queue.html index fcb2361b..f23d4774 100644 --- a/_modules/pylorax/api/queue.html +++ b/_modules/pylorax/api/queue.html @@ -8,7 +8,7 @@ - pylorax.api.queue — Lorax 31.4 documentation + pylorax.api.queue — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -179,7 +179,6 @@ import grp from glob import glob import multiprocessing as mp -import pytoml as toml import pwd import shutil import subprocess @@ -190,6 +189,7 @@ from pylorax.api.compose import move_compose_results from pylorax.api.recipes import recipe_from_file from pylorax.api.timestamp import TS_CREATED, TS_STARTED, TS_FINISHED, write_timestamp, timestamp_dict +import pylorax.api.toml as toml from pylorax.base import DataHolder from pylorax.creator import run_creator from pylorax.sysutils import joinpaths diff --git a/_modules/pylorax/api/recipes.html b/_modules/pylorax/api/recipes.html index 9b5e3bb3..eeba82f8 100644 --- a/_modules/pylorax/api/recipes.html +++ b/_modules/pylorax/api/recipes.html @@ -8,7 +8,7 @@ - pylorax.api.recipes — Lorax 31.4 documentation + pylorax.api.recipes — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -180,12 +180,12 @@ from gi.repository import GLib import os -import pytoml as toml import semantic_version as semver from pylorax.api.projects import dep_evra from pylorax.base import DataHolder from pylorax.sysutils import joinpaths +import pylorax.api.toml as toml
    [docs]class CommitTimeValError(Exception): @@ -1077,25 +1077,78 @@ diff = Git.Diff.new_tree_to_tree(repo, parent.get_tree(), tree, diff_opts) return diff.get_num_deltas() > 0
    +
    [docs]def find_field_value(field, value, lst): + """Find a field matching value in the list of dicts. + + :param field: field to search for + :type field: str + :param value: value to match in the field + :type value: str + :param lst: List of dict's with field + :type lst: list of dict + :returns: First dict with matching field:value, or None + :rtype: dict or None + + Used to return a specific entry from a list that looks like this: + + [{"name": "one", "attr": "green"}, ...] + + find_field_value("name", "one", lst) will return the matching dict. + """ + for d in lst: + if d.get(field) and d.get(field) == value: + return d + return None
    +
    [docs]def find_name(name, lst): """Find the dict matching the name in a list and return it. :param name: Name to search for :type name: str :param lst: List of dict's with "name" field + :type lst: list of dict :returns: First dict with matching name, or None :rtype: dict or None - """ - for e in lst: - if e["name"] == name: - return e - return None
    -
    [docs]def diff_items(title, old_items, new_items): + This is just a wrapper for find_field_value with field set to "name" + """ + return find_field_value("name", name, lst)
    + +
    [docs]def find_recipe_obj(path, recipe, default=None): + """Find a recipe object + + :param path: A list of dict field names + :type path: list of str + :param recipe: The recipe to search + :type recipe: Recipe + :param default: The value to return if it is not found + :type default: Any + + Return the object found by applying the path to the dicts in the recipe, or + return the default if it doesn't exist. + + eg. {"customizations": {"hostname": "foo", "users": [...]}} + + find_recipe_obj(["customizations", "hostname"], recipe, "") + """ + o = recipe + try: + for p in path: + if not o.get(p): + return default + o = o.get(p) + except AttributeError: + return default + + return o
    + +
    [docs]def diff_lists(title, field, old_items, new_items): """Return the differences between two lists of dicts. :param title: Title of the entry :type title: str + :param field: Field to use as the key for comparisons + :type field: str :param old_items: List of item dicts with "name" field :type old_items: list(dict) :param new_items: List of item dicts with "name" field @@ -1104,35 +1157,80 @@ :rtype: list(dict) """ diffs = [] - old_names = set(m["name"] for m in old_items) - new_names = set(m["name"] for m in new_items) + old_fields= set(m[field] for m in old_items) + new_fields= set(m[field] for m in new_items) - added_items = new_names.difference(old_names) + added_items = new_fields.difference(old_fields) added_items = sorted(added_items, key=lambda n: n.lower()) - removed_items = old_names.difference(new_names) + removed_items = old_fields.difference(new_fields) removed_items = sorted(removed_items, key=lambda n: n.lower()) - same_items = old_names.intersection(new_names) + same_items = old_fields.intersection(new_fields) same_items = sorted(same_items, key=lambda n: n.lower()) - for name in added_items: + for v in added_items: diffs.append({"old":None, - "new":{title:find_name(name, new_items)}}) + "new":{title:find_field_value(field, v, new_items)}}) - for name in removed_items: - diffs.append({"old":{title:find_name(name, old_items)}, + for v in removed_items: + diffs.append({"old":{title:find_field_value(field, v, old_items)}, "new":None}) - for name in same_items: - old_item = find_name(name, old_items) - new_item = find_name(name, new_items) + for v in same_items: + old_item = find_field_value(field, v, old_items) + new_item = find_field_value(field, v, new_items) if old_item != new_item: diffs.append({"old":{title:old_item}, "new":{title:new_item}}) return diffs
    +
    [docs]def customizations_diff(old_recipe, new_recipe): + """Diff the customizations sections from two versions of a recipe + """ + diffs = [] + old_keys = set(old_recipe.get("customizations", {}).keys()) + new_keys = set(new_recipe.get("customizations", {}).keys()) + + added_keys = new_keys.difference(old_keys) + added_keys = sorted(added_keys, key=lambda n: n.lower()) + + removed_keys = old_keys.difference(new_keys) + removed_keys = sorted(removed_keys, key=lambda n: n.lower()) + + same_keys = old_keys.intersection(new_keys) + same_keys = sorted(same_keys, key=lambda n: n.lower()) + + for v in added_keys: + diffs.append({"old": None, + "new": {"Customizations."+v: new_recipe["customizations"][v]}}) + + for v in removed_keys: + diffs.append({"old": {"Customizations."+v: old_recipe["customizations"][v]}, + "new": None}) + + for v in same_keys: + if new_recipe["customizations"][v] == old_recipe["customizations"][v]: + continue + + if type(new_recipe["customizations"][v]) == type([]): + # Lists of dicts need to use diff_lists + # sshkey uses 'user', user and group use 'name' + if "user" in new_recipe["customizations"][v][0]: + field_name = "user" + elif "name" in new_recipe["customizations"][v][0]: + field_name = "name" + else: + raise RuntimeError("%s list has unrecognized key, not 'name' or 'user'" % "customizations."+v) + + diffs.extend(diff_lists("Customizations."+v, field_name, old_recipe["customizations"][v], new_recipe["customizations"][v])) + else: + diffs.append({"old": {"Customizations."+v: old_recipe["customizations"][v]}, + "new": {"Customizations."+v: new_recipe["customizations"][v]}}) + + return diffs
    +
    [docs]def recipe_diff(old_recipe, new_recipe): """Diff two versions of a recipe @@ -1152,9 +1250,18 @@ diffs.append({"old":{element.title():old_recipe[element]}, "new":{element.title():new_recipe[element]}}) - diffs.extend(diff_items("Module", old_recipe["modules"], new_recipe["modules"])) - diffs.extend(diff_items("Package", old_recipe["packages"], new_recipe["packages"])) - diffs.extend(diff_items("Group", old_recipe["groups"], new_recipe["groups"])) + # These lists always exist + diffs.extend(diff_lists("Module", "name", old_recipe["modules"], new_recipe["modules"])) + diffs.extend(diff_lists("Package", "name", old_recipe["packages"], new_recipe["packages"])) + diffs.extend(diff_lists("Group", "name", old_recipe["groups"], new_recipe["groups"])) + + # The customizations section can contain a number of different types + diffs.extend(customizations_diff(old_recipe, new_recipe)) + + # repos contains keys that are lists (eg. [[repos.git]]) + diffs.extend(diff_lists("Repos.git", "rpmname", + find_recipe_obj(["repos", "git"], old_recipe, []), + find_recipe_obj(["repos", "git"], new_recipe, []))) return diffs
    diff --git a/_modules/pylorax/api/server.html b/_modules/pylorax/api/server.html index 1bbcfa17..44fa94e0 100644 --- a/_modules/pylorax/api/server.html +++ b/_modules/pylorax/api/server.html @@ -8,7 +8,7 @@ - pylorax.api.server — Lorax 31.4 documentation + pylorax.api.server — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -157,7 +157,7 @@

    Source code for pylorax.api.server

     #
    -# Copyright (C) 2017  Red Hat, Inc.
    +# Copyright (C) 2017-2019 Red Hat, Inc.
     #
     # This program is free software; you can redistribute it and/or modify
     # it under the terms of the GNU General Public License as published by
    @@ -179,9 +179,10 @@
     from flask import Flask, jsonify, redirect, send_from_directory
     from glob import glob
     import os
    +import werkzeug
     
     from pylorax import vernum
    -from pylorax.api.crossdomain import crossdomain
    +from pylorax.api.errors import HTTP_ERROR
     from pylorax.api.v0 import v0_api
     from pylorax.sysutils import joinpaths
     
    @@ -210,7 +211,6 @@
         return send_from_directory(docs_path, path)
     
     @server.route("/api/status")
    -@crossdomain(origin="*")
     def v0_status():
         """
         `/api/v0/status`
    @@ -237,7 +237,12 @@
                        db_supported=True,
                        msgs=server.config["TEMPLATE_ERRORS"])
     
    -v0_api(server)
    +@server.errorhandler(werkzeug.exceptions.HTTPException)
    +def bad_request(error):
    +    return jsonify(status=False, errors=[{ "id": HTTP_ERROR, "code": error.code, "msg": error.name }]), error.code
    +
    +# Register the v0 API on /api/v0/
    +server.register_blueprint(v0_api, url_prefix="/api/v0/")
     
    diff --git a/_modules/pylorax/api/timestamp.html b/_modules/pylorax/api/timestamp.html index 90a6df4b..5ccc9314 100644 --- a/_modules/pylorax/api/timestamp.html +++ b/_modules/pylorax/api/timestamp.html @@ -8,7 +8,7 @@ - pylorax.api.timestamp — Lorax 31.4 documentation + pylorax.api.timestamp — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -173,10 +173,10 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import pytoml as toml import time from pylorax.sysutils import joinpaths +import pylorax.api.toml as toml TS_CREATED = "created" TS_STARTED = "started" diff --git a/_modules/pylorax/api/toml.html b/_modules/pylorax/api/toml.html new file mode 100644 index 00000000..b6537cc9 --- /dev/null +++ b/_modules/pylorax/api/toml.html @@ -0,0 +1,232 @@ + + + + + + + + + + + pylorax.api.toml — Lorax 31.7 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + + +
    + +
    + + + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    + +

    Source code for pylorax.api.toml

    +#
    +# Copyright (C) 2019  Red Hat, Inc.
    +#
    +# This program is free software; you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation; either version 2 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +#
    +
    +import toml
    +
    +
    [docs]class TomlError(toml.TomlDecodeError): + pass
    + +
    [docs]def loads(s): + if isinstance(s, bytes): + s = s.decode('utf-8') + try: + return toml.loads(s) + except toml.TomlDecodeError as e: + raise TomlError(e.msg, e.doc, e.pos)
    + +
    [docs]def dumps(o): + return toml.dumps(o, encoder=toml.TomlEncoder(dict))
    +
    + +
    + +
    + + +
    +
    + +
    + +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/pylorax/api/v0.html b/_modules/pylorax/api/v0.html index b0b384e3..f7f8adb2 100644 --- a/_modules/pylorax/api/v0.html +++ b/_modules/pylorax/api/v0.html @@ -8,7 +8,7 @@ - pylorax.api.v0 — Lorax 31.4 documentation + pylorax.api.v0 — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -157,7 +157,7 @@

    Source code for pylorax.api.v0

     #
    -# Copyright (C) 2017-2018  Red Hat, Inc.
    +# Copyright (C) 2017-2019  Red Hat, Inc.
     #
     # This program is free software; you can redistribute it and/or modify
     # it under the terms of the GNU General Public License as published by
    @@ -204,946 +204,6 @@
     used then the API will use the `master` branch for blueprints. If you want to create
     a new branch use the `new` or `workspace` routes with ?branch=<branch-name> to
     store the new blueprint on the new branch.
    -
    -`/api/v0/blueprints/list`
    -^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  List the available blueprints::
    -
    -      { "limit": 20,
    -        "offset": 0,
    -        "blueprints": [
    -          "atlas",
    -          "development",
    -          "glusterfs",
    -          "http-server",
    -          "jboss",
    -          "kubernetes" ],
    -        "total": 6 }
    -
    -`/api/v0/blueprints/info/<blueprint_names>[?format=<json|toml>]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the JSON representation of the blueprint. This includes 3 top level
    -  objects.  `changes` which lists whether or not the workspace is different from
    -  the most recent commit. `blueprints` which lists the JSON representation of the
    -  blueprint, and `errors` which will list any errors, like non-existant blueprints.
    -
    -  By default the response is JSON, but if `?format=toml` is included in the URL's
    -  arguments it will return the response as the blueprint's raw TOML content.
    -  *Unless* there is an error which will only return a 400 and a standard error
    -  `Status Response`_.
    -
    -  If there is an error when JSON is requested the successful blueprints and the
    -  errors will both be returned.
    -
    -  Example of json response::
    -
    -      {
    -        "changes": [
    -          {
    -            "changed": false,
    -            "name": "glusterfs"
    -          }
    -        ],
    -        "errors": [],
    -        "blueprints": [
    -          {
    -            "description": "An example GlusterFS server with samba",
    -            "modules": [
    -              {
    -                "name": "glusterfs",
    -                "version": "3.7.*"
    -              },
    -              {
    -                "name": "glusterfs-cli",
    -                "version": "3.7.*"
    -              }
    -            ],
    -            "name": "glusterfs",
    -            "packages": [
    -              {
    -                "name": "2ping",
    -                "version": "3.2.1"
    -              },
    -              {
    -                "name": "samba",
    -                "version": "4.2.*"
    -              }
    -            ],
    -            "version": "0.0.6"
    -          }
    -        ]
    -      }
    -
    -  Error example::
    -
    -      {
    -        "changes": [],
    -        "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"]
    -        "blueprints": []
    -      }
    -
    -`/api/v0/blueprints/changes/<blueprint_names>[?offset=0&limit=20]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the commits to a blueprint. By default it returns the first 20 commits, this
    -  can be changed by passing `offset` and/or `limit`. The response will include the
    -  commit hash, summary, timestamp, and optionally the revision number. The commit
    -  hash can be passed to `/api/v0/blueprints/diff/` to retrieve the exact changes.
    -
    -  Example::
    -
    -      {
    -        "errors": [],
    -        "limit": 20,
    -        "offset": 0,
    -        "blueprints": [
    -          {
    -            "changes": [
    -              {
    -                "commit": "e083921a7ed1cf2eec91ad12b9ad1e70ef3470be",
    -                "message": "blueprint glusterfs, version 0.0.6 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-23T00:18:13Z"
    -              },
    -              {
    -                "commit": "cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3",
    -                "message": "blueprint glusterfs, version 0.0.5 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-11T01:00:28Z"
    -              },
    -              {
    -                "commit": "29b492f26ed35d80800b536623bafc51e2f0eff2",
    -                "message": "blueprint glusterfs, version 0.0.4 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-11T00:28:30Z"
    -              },
    -              {
    -                "commit": "03374adbf080fe34f5c6c29f2e49cc2b86958bf2",
    -                "message": "blueprint glusterfs, version 0.0.3 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-10T23:15:52Z"
    -              },
    -              {
    -                "commit": "0e08ecbb708675bfabc82952599a1712a843779d",
    -                "message": "blueprint glusterfs, version 0.0.2 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-10T23:14:56Z"
    -              },
    -              {
    -                "commit": "3e11eb87a63d289662cba4b1804a0947a6843379",
    -                "message": "blueprint glusterfs, version 0.0.1 saved.",
    -                "revision": null,
    -                "timestamp": "2017-11-08T00:02:47Z"
    -              }
    -            ],
    -            "name": "glusterfs",
    -            "total": 6
    -          }
    -        ]
    -      }
    -
    -POST `/api/v0/blueprints/new`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML
    -  for the blueprint format. The blueprint should be in the body of the request with the
    -  `Content-Type` header set to either `application/json` or `text/x-toml`.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -DELETE `/api/v0/blueprints/delete/<blueprint_name>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Delete a blueprint. The blueprint is deleted from the branch, and will no longer
    -  be listed by the `list` route. A blueprint can be undeleted using the `undo` route
    -  to revert to a previous commit. This will also delete the workspace copy of the
    -  blueprint.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -POST `/api/v0/blueprints/workspace`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Write a blueprint to the temporary workspace. This works exactly the same as `new` except
    -  that it does not create a commit. JSON and TOML bodies are supported.
    -
    -  The workspace is meant to be used as a temporary blueprint storage for clients.
    -  It will be read by the `info` and `diff` routes if it is different from the
    -  most recent commit.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -DELETE `/api/v0/blueprints/workspace/<blueprint_name>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Remove the temporary workspace copy of a blueprint. The `info` route will now
    -  return the most recent commit of the blueprint. Any changes that were in the
    -  workspace will be lost.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -POST `/api/v0/blueprints/undo/<blueprint_name>/<commit>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  This will revert the blueprint to a previous commit. The commit hash from the `changes`
    -  route can be used in this request.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -POST `/api/v0/blueprints/tag/<blueprint_name>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Tag a blueprint as a new release. This uses git tags with a special format.
    -  `refs/tags/<branch>/<filename>/r<revision>`. Only the most recent blueprint commit
    -  can be tagged. Revisions start at 1 and increment for each new tag
    -  (per-blueprint). If the commit has already been tagged it will return false.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -`/api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the differences between two commits, or the workspace. The commit hash
    -  from the `changes` response can be used here, or several special strings:
    -
    -  - NEWEST will select the newest git commit. This works for `from_commit` or `to_commit`
    -  - WORKSPACE will select the workspace copy. This can only be used in `to_commit`
    -
    -  eg. `/api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE` will return the differences
    -  between the most recent git commit and the contents of the workspace.
    -
    -  Each entry in the response's diff object contains the old blueprint value and the new one.
    -  If old is null and new is set, then it was added.
    -  If new is null and old is set, then it was removed.
    -  If both are set, then it was changed.
    -
    -  The old/new entries will have the name of the blueprint field that was changed. This
    -  can be one of: Name, Description, Version, Module, or Package.
    -  The contents for these will be the old/new values for them.
    -
    -  In the example below the version was changed and the ping package was added.
    -
    -  Example::
    -
    -      {
    -        "diff": [
    -          {
    -            "new": {
    -              "Version": "0.0.6"
    -            },
    -            "old": {
    -              "Version": "0.0.5"
    -            }
    -          },
    -          {
    -            "new": {
    -              "Package": {
    -                "name": "ping",
    -                "version": "3.2.1"
    -              }
    -            },
    -            "old": null
    -          }
    -        ]
    -      }
    -
    -`/api/v0/blueprints/freeze/<blueprint_names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return a JSON representation of the blueprint with the package and module versions set
    -  to the exact versions chosen by depsolving the blueprint.
    -
    -  Example::
    -
    -      {
    -        "errors": [],
    -        "blueprints": [
    -          {
    -            "blueprint": {
    -              "description": "An example GlusterFS server with samba",
    -              "modules": [
    -                {
    -                  "name": "glusterfs",
    -                  "version": "3.8.4-18.4.el7.x86_64"
    -                },
    -                {
    -                  "name": "glusterfs-cli",
    -                  "version": "3.8.4-18.4.el7.x86_64"
    -                }
    -              ],
    -              "name": "glusterfs",
    -              "packages": [
    -                {
    -                  "name": "ping",
    -                  "version": "2:3.2.1-2.el7.noarch"
    -                },
    -                {
    -                  "name": "samba",
    -                  "version": "4.6.2-8.el7.x86_64"
    -                }
    -              ],
    -              "version": "0.0.6"
    -            }
    -          }
    -        ]
    -      }
    -
    -`/api/v0/blueprints/depsolve/<blueprint_names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages
    -  chosen to satisfy the blueprint's requirements. The response will include a list of results,
    -  with the full dependency list in `dependencies`, the NEVRAs for the blueprint's direct modules
    -  and packages in `modules`, and any error will be in `errors`.
    -
    -  Example::
    -
    -      {
    -        "errors": [],
    -        "blueprints": [
    -          {
    -            "dependencies": [
    -              {
    -                "arch": "noarch",
    -                "epoch": "0",
    -                "name": "2ping",
    -                "release": "2.el7",
    -                "version": "3.2.1"
    -              },
    -              {
    -                "arch": "x86_64",
    -                "epoch": "0",
    -                "name": "acl",
    -                "release": "12.el7",
    -                "version": "2.2.51"
    -              },
    -              {
    -                "arch": "x86_64",
    -                "epoch": "0",
    -                "name": "audit-libs",
    -                "release": "3.el7",
    -                "version": "2.7.6"
    -              },
    -              {
    -                "arch": "x86_64",
    -                "epoch": "0",
    -                "name": "avahi-libs",
    -                "release": "17.el7",
    -                "version": "0.6.31"
    -              },
    -              ...
    -            ],
    -            "modules": [
    -              {
    -                "arch": "noarch",
    -                "epoch": "0",
    -                "name": "2ping",
    -                "release": "2.el7",
    -                "version": "3.2.1"
    -              },
    -              {
    -                "arch": "x86_64",
    -                "epoch": "0",
    -                "name": "glusterfs",
    -                "release": "18.4.el7",
    -                "version": "3.8.4"
    -              },
    -              ...
    -            ],
    -            "blueprint": {
    -              "description": "An example GlusterFS server with samba",
    -              "modules": [
    -                {
    -                  "name": "glusterfs",
    -                  "version": "3.7.*"
    -                },
    -             ...
    -            }
    -          }
    -        ]
    -      }
    -
    -`/api/v0/projects/list[?offset=0&limit=20]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  List all of the available projects. By default this returns the first 20 items,
    -  but this can be changed by setting the `offset` and `limit` arguments.
    -
    -  Example::
    -
    -      {
    -        "limit": 20,
    -        "offset": 0,
    -        "projects": [
    -          {
    -            "description": "0 A.D. (pronounced \"zero ey-dee\") is a ...",
    -            "homepage": "http://play0ad.com",
    -            "name": "0ad",
    -            "summary": "Cross-Platform RTS Game of Ancient Warfare",
    -            "upstream_vcs": "UPSTREAM_VCS"
    -          },
    -          ...
    -        ],
    -        "total": 21770
    -      }
    -
    -`/api/v0/projects/info/<project_names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return information about the comma-separated list of projects. It includes the description
    -  of the package along with the list of available builds.
    -
    -  Example::
    -
    -      {
    -        "projects": [
    -          {
    -            "builds": [
    -              {
    -                "arch": "x86_64",
    -                "build_config_ref": "BUILD_CONFIG_REF",
    -                "build_env_ref": "BUILD_ENV_REF",
    -                "build_time": "2017-03-01T08:39:23",
    -                "changelog": "- restore incremental backups correctly, files ...",
    -                "epoch": "2",
    -                "metadata": {},
    -                "release": "32.el7",
    -                "source": {
    -                  "license": "GPLv3+",
    -                  "metadata": {},
    -                  "source_ref": "SOURCE_REF",
    -                  "version": "1.26"
    -                }
    -              }
    -            ],
    -            "description": "The GNU tar program saves many ...",
    -            "homepage": "http://www.gnu.org/software/tar/",
    -            "name": "tar",
    -            "summary": "A GNU file archiving program",
    -            "upstream_vcs": "UPSTREAM_VCS"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/projects/depsolve/<project_names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Depsolve the comma-separated list of projects and return the list of NEVRAs needed
    -  to satisfy the request.
    -
    -  Example::
    -
    -      {
    -        "projects": [
    -          {
    -            "arch": "noarch",
    -            "epoch": "0",
    -            "name": "basesystem",
    -            "release": "7.el7",
    -            "version": "10.0"
    -          },
    -          {
    -            "arch": "x86_64",
    -            "epoch": "0",
    -            "name": "bash",
    -            "release": "28.el7",
    -            "version": "4.2.46"
    -          },
    -          {
    -            "arch": "x86_64",
    -            "epoch": "0",
    -            "name": "filesystem",
    -            "release": "21.el7",
    -            "version": "3.2"
    -          },
    -          ...
    -        ]
    -      }
    -
    -`/api/v0/projects/source/list`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the list of repositories used for depsolving and installing packages.
    -
    -  Example::
    -
    -      {
    -        "sources": [
    -          "fedora",
    -          "fedora-cisco-openh264",
    -          "fedora-updates-testing",
    -          "fedora-updates"
    -        ]
    -      }
    -
    -`/api/v0/projects/source/info/<source-names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return information about the comma-separated list of source names. Or all of the
    -  sources if '*' is passed. Note that general globbing is not supported, only '*'.
    -
    -  immutable system sources will have the "system" field set to true. User added sources
    -  will have it set to false. System sources cannot be changed or deleted.
    -
    -  Example::
    -
    -      {
    -        "errors": [],
    -        "sources": {
    -          "fedora": {
    -            "check_gpg": true,
    -            "check_ssl": true,
    -            "gpgkey_urls": [
    -              "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64"
    -            ],
    -            "name": "fedora",
    -            "proxy": "http://proxy.brianlane.com:8123",
    -            "system": true,
    -            "type": "yum-metalink",
    -            "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64"
    -          }
    -        }
    -      }
    -
    -POST `/api/v0/projects/source/new`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Add (or change) a source for use when depsolving blueprints and composing images.
    -
    -  The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported
    -  types for the urls are:
    -
    -  * ``yum-baseurl`` is a URL to a yum repository.
    -  * ``yum-mirrorlist`` is a URL for a mirrorlist.
    -  * ``yum-metalink`` is a URL for a metalink.
    -
    -  If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set
    -  this to false, or add your Certificate Authority to the host system.
    -
    -  If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls``
    -  should point to it.
    -
    -  You can edit an existing source (other than system sources), by doing a POST
    -  of the new version of the source. It will overwrite the previous one.
    -
    -  Example::
    -
    -      {
    -          "name": "custom-source-1",
    -          "url": "https://url/path/to/repository/",
    -          "type": "yum-baseurl",
    -          "check_ssl": true,
    -          "check_gpg": true,
    -          "gpgkey_urls": [
    -              "https://url/path/to/gpg-key"
    -          ]
    -      }
    -
    -DELETE `/api/v0/projects/source/delete/<source-name>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Delete a user added source. This will fail if a system source is passed to
    -  it.
    -
    -  The response will be a status response with `status` set to true, or an
    -  error response with it set to false and an error message included.
    -
    -`/api/v0/modules/list[?offset=0&limit=20]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return a list of all of the available modules. This includes the name and the
    -  group_type, which is always "rpm" for lorax-composer. By default this returns
    -  the first 20 items. This can be changed by setting the `offset` and `limit`
    -  arguments.
    -
    -  Example::
    -
    -      {
    -        "limit": 20,
    -        "modules": [
    -          {
    -            "group_type": "rpm",
    -            "name": "0ad"
    -          },
    -          {
    -            "group_type": "rpm",
    -            "name": "0ad-data"
    -          },
    -          {
    -            "group_type": "rpm",
    -            "name": "0install"
    -          },
    -          {
    -            "group_type": "rpm",
    -            "name": "2048-cli"
    -          },
    -          ...
    -        ]
    -        "total": 21770
    -      }
    -
    -`/api/v0/modules/list/<module_names>[?offset=0&limit=20]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the list of comma-separated modules. Output is the same as `/modules/list`
    -
    -  Example::
    -
    -      {
    -        "limit": 20,
    -        "modules": [
    -          {
    -            "group_type": "rpm",
    -            "name": "tar"
    -          }
    -        ],
    -        "offset": 0,
    -        "total": 1
    -      }
    -
    -`/api/v0/modules/info/<module_names>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the module's dependencies, and the information about the module.
    -
    -  Example::
    -
    -      {
    -        "modules": [
    -          {
    -            "dependencies": [
    -              {
    -                "arch": "noarch",
    -                "epoch": "0",
    -                "name": "basesystem",
    -                "release": "7.el7",
    -                "version": "10.0"
    -              },
    -              {
    -                "arch": "x86_64",
    -                "epoch": "0",
    -                "name": "bash",
    -                "release": "28.el7",
    -                "version": "4.2.46"
    -              },
    -              ...
    -            ],
    -            "description": "The GNU tar program saves ...",
    -            "homepage": "http://www.gnu.org/software/tar/",
    -            "name": "tar",
    -            "summary": "A GNU file archiving program",
    -            "upstream_vcs": "UPSTREAM_VCS"
    -          }
    -        ]
    -      }
    -
    -POST `/api/v0/compose`
    -^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Start a compose. The content type should be 'application/json' and the body of the POST
    -  should look like this
    -  
    -  Example::
    -
    -      {
    -        "blueprint_name": "http-server",
    -        "compose_type": "tar",
    -        "branch": "master"
    -      }
    -
    -  Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the
    -  blueprint branch to use. 'branch' is optional and will default to master. It will create a new
    -  build and add it to the queue. It returns the build uuid and a status if it succeeds
    -
    -  Example::
    -  
    -      {
    -        "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf",
    -        "status": true
    -      }
    -
    -`/api/v0/compose/types`
    -^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns the list of supported output types that are valid for use with 'POST /api/v0/compose'
    -
    -  Example::
    -
    -      {
    -        "types": [
    -          {
    -            "enabled": true,
    -            "name": "tar"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/compose/queue`
    -^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the status of the build queue. It includes information about the builds waiting,
    -  and the build that is running.
    -
    -  Example::
    -
    -      {
    -        "new": [
    -          {
    -            "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
    -            "blueprint": "glusterfs",
    -            "queue_status": "WAITING",
    -            "job_created": 1517362647.4570868,
    -            "version": "0.0.6"
    -          },
    -          {
    -            "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73",
    -            "blueprint": "kubernetes",
    -            "queue_status": "WAITING",
    -            "job_created": 1517362659.0034983,
    -            "version": "0.0.1"
    -          }
    -        ],
    -        "run": [
    -          {
    -            "id": "745712b2-96db-44c0-8014-fe925c35e795",
    -            "blueprint": "glusterfs",
    -            "queue_status": "RUNNING",
    -            "job_created": 1517362633.7965999,
    -            "job_started": 1517362633.8001345,
    -            "version": "0.0.6"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/compose/finished`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the details on all of the finished composes on the system.
    -
    -  Example::
    -
    -      {
    -        "finished": [
    -          {
    -            "id": "70b84195-9817-4b8a-af92-45e380f39894",
    -            "blueprint": "glusterfs",
    -            "queue_status": "FINISHED",
    -            "job_created": 1517351003.8210032,
    -            "job_started": 1517351003.8230415,
    -            "job_finished": 1517359234.1003145,
    -            "version": "0.0.6"
    -          },
    -          {
    -            "id": "e695affd-397f-4af9-9022-add2636e7459",
    -            "blueprint": "glusterfs",
    -            "queue_status": "FINISHED",
    -            "job_created": 1517362289.7193348,
    -            "job_started": 1517362289.9751132,
    -            "job_finished": 1517363500.1234567,
    -            "version": "0.0.6"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/compose/failed`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the details on all of the failed composes on the system.
    -
    -  Example::
    -
    -      {
    -        "failed": [
    -           {
    -            "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
    -            "blueprint": "http-server",
    -            "queue_status": "FAILED",
    -            "job_created": 1517523249.9301329,
    -            "job_started": 1517523249.9314211,
    -            "job_finished": 1517523255.5623411,
    -            "version": "0.0.2"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Return the details for each of the comma-separated list of uuids. A uuid of '*' will return
    -  details for all composes.
    -
    -  Example::
    -
    -      {
    -        "uuids": [
    -          {
    -            "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
    -            "blueprint": "http-server",
    -            "queue_status": "FINISHED",
    -            "job_created": 1517523644.2384307,
    -            "job_started": 1517523644.2551234,
    -            "job_finished": 1517523689.9864314,
    -            "version": "0.0.2"
    -          },
    -          {
    -            "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
    -            "blueprint": "glusterfs",
    -            "queue_status": "FINISHED",
    -            "job_created": 1517363442.188399,
    -            "job_started": 1517363442.325324,
    -            "job_finished": 1517363451.653621,
    -            "version": "0.0.6"
    -          }
    -        ]
    -      }
    -
    -DELETE `/api/v0/compose/cancel/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Cancel the build, if it is not finished, and delete the results. It will return a
    -  status of True if it is successful.
    -
    -  Example::
    -
    -      {
    -        "status": true,
    -        "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5"
    -      }
    -
    -DELETE `/api/v0/compose/delete/<uuids>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Delete the list of comma-separated uuids from the compose results.
    -
    -  Example::
    -
    -      {
    -        "errors": [],
    -        "uuids": [
    -          {
    -            "status": true,
    -            "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0"
    -          }
    -        ]
    -      }
    -
    -`/api/v0/compose/info/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Get detailed information about the compose. The returned JSON string will
    -  contain the following information:
    -
    -    * id - The uuid of the comoposition
    -    * config - containing the configuration settings used to run Anaconda
    -    * blueprint - The depsolved blueprint used to generate the kickstart
    -    * commit - The (local) git commit hash for the blueprint used
    -    * deps - The NEVRA of all of the dependencies used in the composition
    -    * compose_type - The type of output generated (tar, iso, etc.)
    -    * queue_status - The final status of the composition (FINISHED or FAILED)
    -
    -  Example::
    -
    -      {
    -        "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d",
    -        "compose_type": "tar",
    -        "config": {
    -          "anaconda_args": "",
    -          "armplatform": "",
    -          "compress_args": [],
    -          "compression": "xz",
    -          "image_name": "root.tar.xz",
    -          ...
    -        },
    -        "deps": {
    -          "packages": [
    -            {
    -              "arch": "x86_64",
    -              "epoch": "0",
    -              "name": "acl",
    -              "release": "14.el7",
    -              "version": "2.2.51"
    -            }
    -          ]
    -        },
    -        "id": "c30b7d80-523b-4a23-ad52-61b799739ce8",
    -        "queue_status": "FINISHED",
    -        "blueprint": {
    -          "description": "An example kubernetes master",
    -          ...
    -        }
    -      }
    -
    -`/api/v0/compose/metadata/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns a .tar of the metadata used for the build. This includes all the
    -  information needed to reproduce the build, including the final kickstart
    -  populated with repository and package NEVRA.
    -
    -  The mime type is set to 'application/x-tar' and the filename is set to
    -  UUID-metadata.tar
    -
    -  The .tar is uncompressed, but is not large.
    -
    -`/api/v0/compose/results/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns a .tar of the metadata, logs, and output image of the build. This
    -  includes all the information needed to reproduce the build, including the
    -  final kickstart populated with repository and package NEVRA. The output image
    -  is already in compressed form so the returned tar is not compressed.
    -
    -  The mime type is set to 'application/x-tar' and the filename is set to
    -  UUID.tar
    -
    -`/api/v0/compose/logs/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns a .tar of the anaconda build logs. The tar is not compressed, but is
    -  not large.
    -
    -  The mime type is set to 'application/x-tar' and the filename is set to
    -  UUID-logs.tar
    -
    -`/api/v0/compose/image/<uuid>`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns the output image from the build. The filename is set to the filename
    -  from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso.
    -
    -`/api/v0/compose/log/<uuid>[?size=kbytes]`
    -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    -
    -  Returns the end of the anaconda.log. The size parameter is optional and defaults to 1Mbytes
    -  if it is not included. The returned data is raw text from the end of the logfile, starting on
    -  a line boundry.
    -
    -  Example::
    -
    -      12:59:24,222 INFO anaconda: Running Thread: AnaConfigurationThread (140629395244800)
    -      12:59:24,223 INFO anaconda: Configuring installed system
    -      12:59:24,912 INFO anaconda: Configuring installed system
    -      12:59:24,912 INFO anaconda: Creating users
    -      12:59:24,913 INFO anaconda: Clearing libuser.conf at /tmp/libuser.Dyy8Gj
    -      12:59:25,154 INFO anaconda: Creating users
    -      12:59:25,155 INFO anaconda: Configuring addons
    -      12:59:25,155 INFO anaconda: Configuring addons
    -      12:59:25,155 INFO anaconda: Generating initramfs
    -      12:59:49,467 INFO anaconda: Generating initramfs
    -      12:59:49,467 INFO anaconda: Running post-installation scripts
    -      12:59:49,467 INFO anaconda: Running kickstart %%post script(s)
    -      12:59:50,782 INFO anaconda: All kickstart %%post script(s) have been run
    -      12:59:50,782 INFO anaconda: Running post-installation scripts
    -      12:59:50,784 INFO anaconda: Thread Done: AnaConfigurationThread (140629395244800)
    -
     """
     
     import logging
    @@ -1151,13 +211,13 @@
     
     import os
     from flask import jsonify, request, Response, send_file
    -import pytoml as toml
    +from flask import current_app as api
     
     from pylorax.sysutils import joinpaths
     from pylorax.api.checkparams import checkparams
     from pylorax.api.compose import start_build, compose_types
    -from pylorax.api.crossdomain import crossdomain
     from pylorax.api.errors import *                               # pylint: disable=wildcard-import
    +from pylorax.api.flask_blueprint import BlueprintSkip
     from pylorax.api.projects import projects_list, projects_info, projects_depsolve
     from pylorax.api.projects import modules_list, modules_info, ProjectsError, repo_to_source
     from pylorax.api.projects import get_repo_sources, delete_repo_source, source_to_repo, dnf_repo_to_file_repo
    @@ -1167,6 +227,7 @@
     from pylorax.api.recipes import recipe_from_dict, recipe_from_toml, commit_recipe, delete_recipe, revert_recipe
     from pylorax.api.recipes import tag_recipe_commit, recipe_diff, RecipeFileError
     from pylorax.api.regexes import VALID_API_STRING
    +import pylorax.api.toml as toml
     from pylorax.api.workspace import workspace_read, workspace_write, workspace_delete
     
     # The API functions don't actually get called by any code here
    @@ -1185,7 +246,7 @@
         """
         return iterable[offset:][:limit]
    -
    [docs]def blueprint_exists(api, branch, blueprint_name): +
    [docs]def blueprint_exists(branch, blueprint_name): """Return True if the blueprint exists :param api: flask object @@ -1203,1045 +264,1949 @@ except (RecipeError, RecipeFileError): return False
    -
    [docs]def v0_api(api): - # Note that Sphinx will not generate documentations for any of these. - @api.route("/api/v0/blueprints/list") - @crossdomain(origin="*") - def v0_blueprints_list(): - """List the available blueprints on a branch.""" - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 +# Create the v0 routes Blueprint with skip_routes support +v0_api = BlueprintSkip("v0_routes", __name__) +
    [docs]@v0_api.route("/blueprints/list") +def v0_blueprints_list(): + """List the available blueprints on a branch. + + **/api/v0/blueprints/list** + + List the available blueprints:: + + { "limit": 20, + "offset": 0, + "blueprints": [ + "atlas", + "development", + "glusterfs", + "http-server", + "jboss", + "kubernetes" ], + "total": 6 } + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + with api.config["GITLOCK"].lock: + blueprints = [f[:-5] for f in list_branch_files(api.config["GITLOCK"].repo, branch)] + limited_blueprints = take_limits(blueprints, offset, limit) + return jsonify(blueprints=limited_blueprints, limit=limit, offset=offset, total=len(blueprints))
    + +
    [docs]@v0_api.route("/blueprints/info", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/info/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_info(blueprint_names): + """Return the contents of the blueprint, or a list of blueprints + + **/api/v0/blueprints/info/<blueprint_names>[?format=<json|toml>]** + + Return the JSON representation of the blueprint. This includes 3 top level + objects. `changes` which lists whether or not the workspace is different from + the most recent commit. `blueprints` which lists the JSON representation of the + blueprint, and `errors` which will list any errors, like non-existant blueprints. + + By default the response is JSON, but if `?format=toml` is included in the URL's + arguments it will return the response as the blueprint's raw TOML content. + *Unless* there is an error which will only return a 400 and a standard error + `Status Responses`_. + + If there is an error when JSON is requested the successful blueprints and the + errors will both be returned. + + Example of json response:: + + { + "changes": [ + { + "changed": false, + "name": "glusterfs" + } + ], + "errors": [], + "blueprints": [ + { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + { + "name": "glusterfs-cli", + "version": "3.7.*" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "2ping", + "version": "3.2.1" + }, + { + "name": "samba", + "version": "4.2.*" + } + ], + "version": "0.0.6" + } + ] + } + + Error example:: + + { + "changes": [], + "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"] + "blueprints": [] + } + """ + if VALID_API_STRING.match(blueprint_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + blueprints = [] + changes = [] + errors = [] + for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: + exceptions = [] + # Get the workspace version (if it exists) try: - limit = int(request.args.get("limit", "20")) - offset = int(request.args.get("offset", "0")) - except ValueError as e: - return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + with api.config["GITLOCK"].lock: + ws_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + ws_blueprint = None + exceptions.append(str(e)) + log.error("(v0_blueprints_info) %s", str(e)) + + # Get the git version (if it exists) + try: + with api.config["GITLOCK"].lock: + git_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # Adding an exception would be redundant, skip it + git_blueprint = None + log.error("(v0_blueprints_info) %s", str(e)) + except Exception as e: + git_blueprint = None + exceptions.append(str(e)) + log.error("(v0_blueprints_info) %s", str(e)) + + if not ws_blueprint and not git_blueprint: + # Neither blueprint, return an error + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: %s" % (blueprint_name, ", ".join(exceptions))}) + elif ws_blueprint and not git_blueprint: + # No git blueprint, return the workspace blueprint + changes.append({"name":blueprint_name, "changed":True}) + blueprints.append(ws_blueprint) + elif not ws_blueprint and git_blueprint: + # No workspace blueprint, no change, return the git blueprint + changes.append({"name":blueprint_name, "changed":False}) + blueprints.append(git_blueprint) + else: + # Both exist, maybe changed, return the workspace blueprint + changes.append({"name":blueprint_name, "changed":ws_blueprint != git_blueprint}) + blueprints.append(ws_blueprint) + + # Sort all the results by case-insensitive blueprint name + changes = sorted(changes, key=lambda c: c["name"].lower()) + blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) + + if out_fmt == "toml": + if errors: + # If there are errors they need to be reported, use JSON and 400 for this + return jsonify(status=False, errors=errors), 400 + else: + # With TOML output we just want to dump the raw blueprint, skipping the rest. + return "\n\n".join([r.toml() for r in blueprints]) + else: + return jsonify(changes=changes, blueprints=blueprints, errors=errors)
    + +
    [docs]@v0_api.route("/blueprints/changes", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/changes/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_changes(blueprint_names): + """Return the changes to a blueprint or list of blueprints + + **/api/v0/blueprints/changes/<blueprint_names>[?offset=0&limit=20]** + + Return the commits to a blueprint. By default it returns the first 20 commits, this + can be changed by passing `offset` and/or `limit`. The response will include the + commit hash, summary, timestamp, and optionally the revision number. The commit + hash can be passed to `/api/v0/blueprints/diff/` to retrieve the exact changes. + + Example:: + + { + "errors": [], + "limit": 20, + "offset": 0, + "blueprints": [ + { + "changes": [ + { + "commit": "e083921a7ed1cf2eec91ad12b9ad1e70ef3470be", + "message": "blueprint glusterfs, version 0.0.6 saved.", + "revision": null, + "timestamp": "2017-11-23T00:18:13Z" + }, + { + "commit": "cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3", + "message": "blueprint glusterfs, version 0.0.5 saved.", + "revision": null, + "timestamp": "2017-11-11T01:00:28Z" + }, + { + "commit": "29b492f26ed35d80800b536623bafc51e2f0eff2", + "message": "blueprint glusterfs, version 0.0.4 saved.", + "revision": null, + "timestamp": "2017-11-11T00:28:30Z" + }, + { + "commit": "03374adbf080fe34f5c6c29f2e49cc2b86958bf2", + "message": "blueprint glusterfs, version 0.0.3 saved.", + "revision": null, + "timestamp": "2017-11-10T23:15:52Z" + }, + { + "commit": "0e08ecbb708675bfabc82952599a1712a843779d", + "message": "blueprint glusterfs, version 0.0.2 saved.", + "revision": null, + "timestamp": "2017-11-10T23:14:56Z" + }, + { + "commit": "3e11eb87a63d289662cba4b1804a0947a6843379", + "message": "blueprint glusterfs, version 0.0.1 saved.", + "revision": null, + "timestamp": "2017-11-08T00:02:47Z" + } + ], + "name": "glusterfs", + "total": 6 + } + ] + } + """ + if VALID_API_STRING.match(blueprint_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: + filename = recipe_filename(blueprint_name) + try: + with api.config["GITLOCK"].lock: + commits = list_commits(api.config["GITLOCK"].repo, branch, filename) + except Exception as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_changes) %s", str(e)) + else: + if commits: + limited_commits = take_limits(commits, offset, limit) + blueprints.append({"name":blueprint_name, "changes":limited_commits, "total":len(commits)}) + else: + # no commits means there is no blueprint in the branch + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s" % blueprint_name}) + + blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) + + return jsonify(blueprints=blueprints, errors=errors, offset=offset, limit=limit)
    + +
    [docs]@v0_api.route("/blueprints/new", methods=["POST"]) +def v0_blueprints_new(): + """Commit a new blueprint + + **POST /api/v0/blueprints/new** + + Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML + for the blueprint format. The blueprint should be in the body of the request with the + `Content-Type` header set to either `application/json` or `text/x-toml`. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + if request.headers['Content-Type'] == "text/x-toml": + blueprint = recipe_from_toml(request.data) + else: + blueprint = recipe_from_dict(request.get_json(cache=False)) + + if VALID_API_STRING.match(blueprint["name"]) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 with api.config["GITLOCK"].lock: - blueprints = [f[:-5] for f in list_branch_files(api.config["GITLOCK"].repo, branch)] - limited_blueprints = take_limits(blueprints, offset, limit) - return jsonify(blueprints=limited_blueprints, limit=limit, offset=offset, total=len(blueprints)) + commit_recipe(api.config["GITLOCK"].repo, branch, blueprint) - @api.route("/api/v0/blueprints/info", defaults={'blueprint_names': ""}) - @api.route("/api/v0/blueprints/info/<blueprint_names>") - @crossdomain(origin="*") - @checkparams([("blueprint_names", "", "no blueprint names given")]) - def v0_blueprints_info(blueprint_names): - """Return the contents of the blueprint, or a list of blueprints""" - if VALID_API_STRING.match(blueprint_names) is None: + # Read the blueprint with new version and write it to the workspace + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint["name"]) + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_new) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/delete", defaults={'blueprint_name': ""}, methods=["DELETE"]) +@v0_api.route("/blueprints/delete/<blueprint_name>", methods=["DELETE"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_delete(blueprint_name): + """Delete a blueprint from git + + **DELETE /api/v0/blueprints/delete/<blueprint_name>** + + Delete a blueprint. The blueprint is deleted from the branch, and will no longer + be listed by the `list` route. A blueprint can be undeleted using the `undo` route + to revert to a previous commit. This will also delete the workspace copy of the + blueprint. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) + delete_recipe(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + log.error("(v0_blueprints_delete) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/workspace", methods=["POST"]) +def v0_blueprints_workspace(): + """Write a blueprint to the workspace + + **POST /api/v0/blueprints/workspace** + + Write a blueprint to the temporary workspace. This works exactly the same as `new` except + that it does not create a commit. JSON and TOML bodies are supported. + + The workspace is meant to be used as a temporary blueprint storage for clients. + It will be read by the `info` and `diff` routes if it is different from the + most recent commit. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + if request.headers['Content-Type'] == "text/x-toml": + blueprint = recipe_from_toml(request.data) + else: + blueprint = recipe_from_dict(request.get_json(cache=False)) + + if VALID_API_STRING.match(blueprint["name"]) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + with api.config["GITLOCK"].lock: + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_workspace) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    - out_fmt = request.args.get("format", "json") - if VALID_API_STRING.match(out_fmt) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 +
    [docs]@v0_api.route("/blueprints/workspace", defaults={'blueprint_name': ""}, methods=["DELETE"]) +@v0_api.route("/blueprints/workspace/<blueprint_name>", methods=["DELETE"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_delete_workspace(blueprint_name): + """Delete a blueprint from the workspace - blueprints = [] - changes = [] - errors = [] - for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: - exceptions = [] - # Get the workspace version (if it exists) - try: - with api.config["GITLOCK"].lock: - ws_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) - except Exception as e: - ws_blueprint = None - exceptions.append(str(e)) - log.error("(v0_blueprints_info) %s", str(e)) + **DELETE /api/v0/blueprints/workspace/<blueprint_name>** - # Get the git version (if it exists) - try: - with api.config["GITLOCK"].lock: - git_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - except RecipeFileError as e: - # Adding an exception would be redundant, skip it - git_blueprint = None - log.error("(v0_blueprints_info) %s", str(e)) - except Exception as e: - git_blueprint = None - exceptions.append(str(e)) - log.error("(v0_blueprints_info) %s", str(e)) + Remove the temporary workspace copy of a blueprint. The `info` route will now + return the most recent commit of the blueprint. Any changes that were in the + workspace will be lost. - if not ws_blueprint and not git_blueprint: - # Neither blueprint, return an error - errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: %s" % (blueprint_name, ", ".join(exceptions))}) - elif ws_blueprint and not git_blueprint: - # No git blueprint, return the workspace blueprint - changes.append({"name":blueprint_name, "changed":True}) - blueprints.append(ws_blueprint) - elif not ws_blueprint and git_blueprint: - # No workspace blueprint, no change, return the git blueprint - changes.append({"name":blueprint_name, "changed":False}) - blueprints.append(git_blueprint) - else: - # Both exist, maybe changed, return the workspace blueprint - changes.append({"name":blueprint_name, "changed":ws_blueprint != git_blueprint}) - blueprints.append(ws_blueprint) + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - # Sort all the results by case-insensitive blueprint name - changes = sorted(changes, key=lambda c: c["name"].lower()) - blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - if out_fmt == "toml": - if errors: - # If there are errors they need to be reported, use JSON and 400 for this - return jsonify(status=False, errors=errors), 400 - else: - # With TOML output we just want to dump the raw blueprint, skipping the rest. - return "\n\n".join([r.toml() for r in blueprints]) - else: - return jsonify(changes=changes, blueprints=blueprints, errors=errors) + try: + with api.config["GITLOCK"].lock: + workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception as e: + log.error("(v0_blueprints_delete_workspace) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    - @api.route("/api/v0/blueprints/changes", defaults={'blueprint_names': ""}) - @api.route("/api/v0/blueprints/changes/<blueprint_names>") - @crossdomain(origin="*") - @checkparams([("blueprint_names", "", "no blueprint names given")]) - def v0_blueprints_changes(blueprint_names): - """Return the changes to a blueprint or list of blueprints""" - if VALID_API_STRING.match(blueprint_names) is None: +
    [docs]@v0_api.route("/blueprints/undo", defaults={'blueprint_name': "", 'commit': ""}, methods=["POST"]) +@v0_api.route("/blueprints/undo/<blueprint_name>", defaults={'commit': ""}, methods=["POST"]) +@v0_api.route("/blueprints/undo/<blueprint_name>/<commit>", methods=["POST"]) +@checkparams([("blueprint_name", "", "no blueprint name given"), + ("commit", "", "no commit ID given")]) +def v0_blueprints_undo(blueprint_name, commit): + """Undo changes to a blueprint by reverting to a previous commit. + + **POST /api/v0/blueprints/undo/<blueprint_name>/<commit>** + + This will revert the blueprint to a previous commit. The commit hash from the `changes` + route can be used in this request. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + revert_recipe(api.config["GITLOCK"].repo, branch, blueprint_name, commit) + + # Read the new recipe and write it to the workspace + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + workspace_write(api.config["GITLOCK"].repo, branch, blueprint) + except Exception as e: + log.error("(v0_blueprints_undo) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/tag", defaults={'blueprint_name': ""}, methods=["POST"]) +@v0_api.route("/blueprints/tag/<blueprint_name>", methods=["POST"]) +@checkparams([("blueprint_name", "", "no blueprint name given")]) +def v0_blueprints_tag(blueprint_name): + """Tag a blueprint's latest blueprint commit as a 'revision' + + **POST /api/v0/blueprints/tag/<blueprint_name>** + + Tag a blueprint as a new release. This uses git tags with a special format. + `refs/tags/<branch>/<filename>/r<revision>`. Only the most recent blueprint commit + can be tagged. Revisions start at 1 and increment for each new tag + (per-blueprint). If the commit has already been tagged it will return false. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(blueprint_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + try: + with api.config["GITLOCK"].lock: + tag_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + log.error("(v0_blueprints_tag) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": str(e)}]), 400 + except Exception as e: + log.error("(v0_blueprints_tag) %s", str(e)) + return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + else: + return jsonify(status=True)
    + +
    [docs]@v0_api.route("/blueprints/diff", defaults={'blueprint_name': "", 'from_commit': "", 'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>", defaults={'from_commit': "", 'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>/<from_commit>", defaults={'to_commit': ""}) +@v0_api.route("/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>") +@checkparams([("blueprint_name", "", "no blueprint name given"), + ("from_commit", "", "no from commit ID given"), + ("to_commit", "", "no to commit ID given")]) +def v0_blueprints_diff(blueprint_name, from_commit, to_commit): + """Return the differences between two commits of a blueprint + + **/api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>** + + Return the differences between two commits, or the workspace. The commit hash + from the `changes` response can be used here, or several special strings: + + - NEWEST will select the newest git commit. This works for `from_commit` or `to_commit` + - WORKSPACE will select the workspace copy. This can only be used in `to_commit` + + eg. `/api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE` will return the differences + between the most recent git commit and the contents of the workspace. + + Each entry in the response's diff object contains the old blueprint value and the new one. + If old is null and new is set, then it was added. + If new is null and old is set, then it was removed. + If both are set, then it was changed. + + The old/new entries will have the name of the blueprint field that was changed. This + can be one of: Name, Description, Version, Module, or Package. + The contents for these will be the old/new values for them. + + In the example below the version was changed and the ping package was added. + + Example:: + + { + "diff": [ + { + "new": { + "Version": "0.0.6" + }, + "old": { + "Version": "0.0.5" + } + }, + { + "new": { + "Package": { + "name": "ping", + "version": "3.2.1" + } + }, + "old": null + } + ] + } + """ + for s in [blueprint_name, from_commit, to_commit]: + if VALID_API_STRING.match(s) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - try: - limit = int(request.args.get("limit", "20")) - offset = int(request.args.get("offset", "0")) - except ValueError as e: - return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 - - blueprints = [] - errors = [] - for blueprint_name in [n.strip() for n in blueprint_names.split(",")]: - filename = recipe_filename(blueprint_name) - try: - with api.config["GITLOCK"].lock: - commits = list_commits(api.config["GITLOCK"].repo, branch, filename) - except Exception as e: - errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) - log.error("(v0_blueprints_changes) %s", str(e)) - else: - if commits: - limited_commits = take_limits(commits, offset, limit) - blueprints.append({"name":blueprint_name, "changes":limited_commits, "total":len(commits)}) - else: - # no commits means there is no blueprint in the branch - errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s" % blueprint_name}) - - blueprints = sorted(blueprints, key=lambda r: r["name"].lower()) - - return jsonify(blueprints=blueprints, errors=errors, offset=offset, limit=limit) - - @api.route("/api/v0/blueprints/new", methods=["POST"]) - @crossdomain(origin="*") - def v0_blueprints_new(): - """Commit a new blueprint""" - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: - if request.headers['Content-Type'] == "text/x-toml": - blueprint = recipe_from_toml(request.data) - else: - blueprint = recipe_from_dict(request.get_json(cache=False)) - - if VALID_API_STRING.match(blueprint["name"]) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + if not blueprint_exists(branch, blueprint_name): + return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}]) + try: + if from_commit == "NEWEST": with api.config["GITLOCK"].lock: - commit_recipe(api.config["GITLOCK"].repo, branch, blueprint) - - # Read the blueprint with new version and write it to the workspace - blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint["name"]) - workspace_write(api.config["GITLOCK"].repo, branch, blueprint) - except Exception as e: - log.error("(v0_blueprints_new) %s", str(e)) - return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 + old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/delete", defaults={'blueprint_name': ""}, methods=["DELETE"]) - @api.route("/api/v0/blueprints/delete/<blueprint_name>", methods=["DELETE"]) - @crossdomain(origin="*") - @checkparams([("blueprint_name", "", "no blueprint name given")]) - def v0_blueprints_delete(blueprint_name): - """Delete a blueprint from git""" - if VALID_API_STRING.match(blueprint_name) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: with api.config["GITLOCK"].lock: - workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) - delete_recipe(api.config["GITLOCK"].repo, branch, blueprint_name) - except Exception as e: - log.error("(v0_blueprints_delete) %s", str(e)) - return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 - else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/workspace", methods=["POST"]) - @crossdomain(origin="*") - def v0_blueprints_workspace(): - """Write a blueprint to the workspace""" - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: - if request.headers['Content-Type'] == "text/x-toml": - blueprint = recipe_from_toml(request.data) - else: - blueprint = recipe_from_dict(request.get_json(cache=False)) - - if VALID_API_STRING.match(blueprint["name"]) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, from_commit) + except Exception as e: + log.error("(v0_blueprints_diff) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + try: + if to_commit == "WORKSPACE": with api.config["GITLOCK"].lock: - workspace_write(api.config["GITLOCK"].repo, branch, blueprint) - except Exception as e: - log.error("(v0_blueprints_workspace) %s", str(e)) - return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 - else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/workspace", defaults={'blueprint_name': ""}, methods=["DELETE"]) - @api.route("/api/v0/blueprints/workspace/<blueprint_name>", methods=["DELETE"]) - @crossdomain(origin="*") - @checkparams([("blueprint_name", "", "no blueprint name given")]) - def v0_blueprints_delete_workspace(blueprint_name): - """Delete a blueprint from the workspace""" - if VALID_API_STRING.match(blueprint_name) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: - with api.config["GITLOCK"].lock: - workspace_delete(api.config["GITLOCK"].repo, branch, blueprint_name) - except Exception as e: - log.error("(v0_blueprints_delete_workspace) %s", str(e)) - return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 - else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/undo", defaults={'blueprint_name': "", 'commit': ""}, methods=["POST"]) - @api.route("/api/v0/blueprints/undo/<blueprint_name>", defaults={'commit': ""}, methods=["POST"]) - @api.route("/api/v0/blueprints/undo/<blueprint_name>/<commit>", methods=["POST"]) - @crossdomain(origin="*") - @checkparams([("blueprint_name", "", "no blueprint name given"), - ("commit", "", "no commit ID given")]) - def v0_blueprints_undo(blueprint_name, commit): - """Undo changes to a blueprint by reverting to a previous commit.""" - if VALID_API_STRING.match(blueprint_name) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: - with api.config["GITLOCK"].lock: - revert_recipe(api.config["GITLOCK"].repo, branch, blueprint_name, commit) - - # Read the new recipe and write it to the workspace - blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - workspace_write(api.config["GITLOCK"].repo, branch, blueprint) - except Exception as e: - log.error("(v0_blueprints_undo) %s", str(e)) - return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 - else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/tag", defaults={'blueprint_name': ""}, methods=["POST"]) - @api.route("/api/v0/blueprints/tag/<blueprint_name>", methods=["POST"]) - @crossdomain(origin="*") - @checkparams([("blueprint_name", "", "no blueprint name given")]) - def v0_blueprints_tag(blueprint_name): - """Tag a blueprint's latest blueprint commit as a 'revision'""" - if VALID_API_STRING.match(blueprint_name) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - try: - with api.config["GITLOCK"].lock: - tag_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - except RecipeFileError as e: - log.error("(v0_blueprints_tag) %s", str(e)) - return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": str(e)}]), 400 - except Exception as e: - log.error("(v0_blueprints_tag) %s", str(e)) - return jsonify(status=False, errors=[{"id": BLUEPRINTS_ERROR, "msg": str(e)}]), 400 - else: - return jsonify(status=True) - - @api.route("/api/v0/blueprints/diff", defaults={'blueprint_name': "", 'from_commit': "", 'to_commit': ""}) - @api.route("/api/v0/blueprints/diff/<blueprint_name>", defaults={'from_commit': "", 'to_commit': ""}) - @api.route("/api/v0/blueprints/diff/<blueprint_name>/<from_commit>", defaults={'to_commit': ""}) - @api.route("/api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>") - @crossdomain(origin="*") - @checkparams([("blueprint_name", "", "no blueprint name given"), - ("from_commit", "", "no from commit ID given"), - ("to_commit", "", "no to commit ID given")]) - def v0_blueprints_diff(blueprint_name, from_commit, to_commit): - """Return the differences between two commits of a blueprint""" - for s in [blueprint_name, from_commit, to_commit]: - if VALID_API_STRING.match(s) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 - - if not blueprint_exists(api, branch, blueprint_name): - return jsonify(status=False, errors=[{"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}]) - - try: - if from_commit == "NEWEST": - with api.config["GITLOCK"].lock: - old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - else: - with api.config["GITLOCK"].lock: - old_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, from_commit) - except Exception as e: - log.error("(v0_blueprints_diff) %s", str(e)) - return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 - - try: - if to_commit == "WORKSPACE": - with api.config["GITLOCK"].lock: - new_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) - # If there is no workspace, use the newest commit instead - if not new_blueprint: - with api.config["GITLOCK"].lock: - new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - elif to_commit == "NEWEST": + new_blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + # If there is no workspace, use the newest commit instead + if not new_blueprint: with api.config["GITLOCK"].lock: new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - else: - with api.config["GITLOCK"].lock: - new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, to_commit) - except Exception as e: - log.error("(v0_blueprints_diff) %s", str(e)) - return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 + elif to_commit == "NEWEST": + with api.config["GITLOCK"].lock: + new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + else: + with api.config["GITLOCK"].lock: + new_blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name, to_commit) + except Exception as e: + log.error("(v0_blueprints_diff) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_COMMIT, "msg": str(e)}]), 400 - diff = recipe_diff(old_blueprint, new_blueprint) - return jsonify(diff=diff) + diff = recipe_diff(old_blueprint, new_blueprint) + return jsonify(diff=diff)
    - @api.route("/api/v0/blueprints/freeze", defaults={'blueprint_names': ""}) - @api.route("/api/v0/blueprints/freeze/<blueprint_names>") - @crossdomain(origin="*") - @checkparams([("blueprint_names", "", "no blueprint names given")]) - def v0_blueprints_freeze(blueprint_names): - """Return the blueprint with the exact modules and packages selected by depsolve""" - if VALID_API_STRING.match(blueprint_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 +
    [docs]@v0_api.route("/blueprints/freeze", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/freeze/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_freeze(blueprint_names): + """Return the blueprint with the exact modules and packages selected by depsolve - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + **/api/v0/blueprints/freeze/<blueprint_names>** - out_fmt = request.args.get("format", "json") - if VALID_API_STRING.match(out_fmt) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + Return a JSON representation of the blueprint with the package and module versions set + to the exact versions chosen by depsolving the blueprint. - blueprints = [] - errors = [] - for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: - # get the blueprint - # Get the workspace version (if it exists) - blueprint = None + Example:: + + { + "errors": [], + "blueprints": [ + { + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.8.4-18.4.el7.x86_64" + }, + { + "name": "glusterfs-cli", + "version": "3.8.4-18.4.el7.x86_64" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "ping", + "version": "2:3.2.1-2.el7.noarch" + }, + { + "name": "samba", + "version": "4.6.2-8.el7.x86_64" + } + ], + "version": "0.0.6" + } + } + ] + } + """ + if VALID_API_STRING.match(blueprint_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: + # get the blueprint + # Get the workspace version (if it exists) + blueprint = None + try: + with api.config["GITLOCK"].lock: + blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception: + pass + + if not blueprint: + # No workspace version, get the git version (if it exists) try: with api.config["GITLOCK"].lock: - blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) - except Exception: - pass - - if not blueprint: - # No workspace version, get the git version (if it exists) - try: - with api.config["GITLOCK"].lock: - blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - except RecipeFileError as e: - # adding an error here would be redundant, skip it - log.error("(v0_blueprints_freeze) %s", str(e)) - except Exception as e: - errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) - log.error("(v0_blueprints_freeze) %s", str(e)) - - # No blueprint found, skip it. - if not blueprint: - errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint_not_found" % blueprint_name}) - continue - - # Combine modules and packages and depsolve the list - # TODO include the version/glob in the depsolving - module_nver = blueprint.module_nver - package_nver = blueprint.package_nver - projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) - deps = [] - try: - with api.config["DNFLOCK"].lock: - deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) - except ProjectsError as e: + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # adding an error here would be redundant, skip it + log.error("(v0_blueprints_freeze) %s", str(e)) + except Exception as e: errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) log.error("(v0_blueprints_freeze) %s", str(e)) - blueprints.append({"blueprint": blueprint.freeze(deps)}) + # No blueprint found, skip it. + if not blueprint: + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint_not_found" % blueprint_name}) + continue - if out_fmt == "toml": - # With TOML output we just want to dump the raw blueprint, skipping the rest. - return "\n\n".join([e["blueprint"].toml() for e in blueprints]) - else: - return jsonify(blueprints=blueprints, errors=errors) + # Combine modules and packages and depsolve the list + # TODO include the version/glob in the depsolving + module_nver = blueprint.module_nver + package_nver = blueprint.package_nver + projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) + deps = [] + try: + with api.config["DNFLOCK"].lock: + deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) + except ProjectsError as e: + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_freeze) %s", str(e)) - @api.route("/api/v0/blueprints/depsolve", defaults={'blueprint_names': ""}) - @api.route("/api/v0/blueprints/depsolve/<blueprint_names>") - @crossdomain(origin="*") - @checkparams([("blueprint_names", "", "no blueprint names given")]) - def v0_blueprints_depsolve(blueprint_names): - """Return the dependencies for a blueprint""" - if VALID_API_STRING.match(blueprint_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + blueprints.append({"blueprint": blueprint.freeze(deps)}) - branch = request.args.get("branch", "master") - if VALID_API_STRING.match(branch) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + if out_fmt == "toml": + # With TOML output we just want to dump the raw blueprint, skipping the rest. + return "\n\n".join([e["blueprint"].toml() for e in blueprints]) + else: + return jsonify(blueprints=blueprints, errors=errors)
    - blueprints = [] - errors = [] - for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: - # get the blueprint - # Get the workspace version (if it exists) - blueprint = None +
    [docs]@v0_api.route("/blueprints/depsolve", defaults={'blueprint_names': ""}) +@v0_api.route("/blueprints/depsolve/<blueprint_names>") +@checkparams([("blueprint_names", "", "no blueprint names given")]) +def v0_blueprints_depsolve(blueprint_names): + """Return the dependencies for a blueprint + + **/api/v0/blueprints/depsolve/<blueprint_names>** + + Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages + chosen to satisfy the blueprint's requirements. The response will include a list of results, + with the full dependency list in `dependencies`, the NEVRAs for the blueprint's direct modules + and packages in `modules`, and any error will be in `errors`. + + Example:: + + { + "errors": [], + "blueprints": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "12.el7", + "version": "2.2.51" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "audit-libs", + "release": "3.el7", + "version": "2.7.6" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "avahi-libs", + "release": "17.el7", + "version": "0.6.31" + }, + ... + ], + "modules": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "glusterfs", + "release": "18.4.el7", + "version": "3.8.4" + }, + ... + ], + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + ... + } + } + ] + } + """ + if VALID_API_STRING.match(blueprint_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + branch = request.args.get("branch", "master") + if VALID_API_STRING.match(branch) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 + + blueprints = [] + errors = [] + for blueprint_name in [n.strip() for n in sorted(blueprint_names.split(","), key=lambda n: n.lower())]: + # get the blueprint + # Get the workspace version (if it exists) + blueprint = None + try: + with api.config["GITLOCK"].lock: + blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) + except Exception: + pass + + if not blueprint: + # No workspace version, get the git version (if it exists) try: with api.config["GITLOCK"].lock: - blueprint = workspace_read(api.config["GITLOCK"].repo, branch, blueprint_name) - except Exception: - pass - - if not blueprint: - # No workspace version, get the git version (if it exists) - try: - with api.config["GITLOCK"].lock: - blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) - except RecipeFileError as e: - # adding an error here would be redundant, skip it - log.error("(v0_blueprints_depsolve) %s", str(e)) - except Exception as e: - errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) - log.error("(v0_blueprints_depsolve) %s", str(e)) - - # No blueprint found, skip it. - if not blueprint: - errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint not found" % blueprint_name}) - continue - - # Combine modules and packages and depsolve the list - # TODO include the version/glob in the depsolving - module_nver = blueprint.module_nver - package_nver = blueprint.package_nver - projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) - deps = [] - try: - with api.config["DNFLOCK"].lock: - deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) - except ProjectsError as e: + blueprint = read_recipe_commit(api.config["GITLOCK"].repo, branch, blueprint_name) + except RecipeFileError as e: + # adding an error here would be redundant, skip it + log.error("(v0_blueprints_depsolve) %s", str(e)) + except Exception as e: errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) log.error("(v0_blueprints_depsolve) %s", str(e)) - # Get the NEVRA's of the modules and projects, add as "modules" - modules = [] - for dep in deps: - if dep["name"] in projects: - modules.append(dep) - modules = sorted(modules, key=lambda m: m["name"].lower()) - - blueprints.append({"blueprint":blueprint, "dependencies":deps, "modules":modules}) - - return jsonify(blueprints=blueprints, errors=errors) - - @api.route("/api/v0/projects/list") - @crossdomain(origin="*") - def v0_projects_list(): - """List all of the available projects/packages""" - try: - limit = int(request.args.get("limit", "20")) - offset = int(request.args.get("offset", "0")) - except ValueError as e: - return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + # No blueprint found, skip it. + if not blueprint: + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "%s: blueprint not found" % blueprint_name}) + continue + # Combine modules and packages and depsolve the list + # TODO include the version/glob in the depsolving + module_nver = blueprint.module_nver + package_nver = blueprint.package_nver + projects = sorted(set(module_nver+package_nver), key=lambda p: p[0].lower()) + deps = [] try: with api.config["DNFLOCK"].lock: - available = projects_list(api.config["DNFLOCK"].dbo) + deps = projects_depsolve(api.config["DNFLOCK"].dbo, projects, blueprint.group_names) except ProjectsError as e: - log.error("(v0_projects_list) %s", str(e)) - return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + errors.append({"id": BLUEPRINTS_ERROR, "msg": "%s: %s" % (blueprint_name, str(e))}) + log.error("(v0_blueprints_depsolve) %s", str(e)) - projects = take_limits(available, offset, limit) - return jsonify(projects=projects, offset=offset, limit=limit, total=len(available)) + # Get the NEVRA's of the modules and projects, add as "modules" + modules = [] + for dep in deps: + if dep["name"] in projects: + modules.append(dep) + modules = sorted(modules, key=lambda m: m["name"].lower()) - @api.route("/api/v0/projects/info", defaults={'project_names': ""}) - @api.route("/api/v0/projects/info/<project_names>") - @crossdomain(origin="*") - @checkparams([("project_names", "", "no project names given")]) - def v0_projects_info(project_names): - """Return detailed information about the listed projects""" - if VALID_API_STRING.match(project_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + blueprints.append({"blueprint":blueprint, "dependencies":deps, "modules":modules}) - try: - with api.config["DNFLOCK"].lock: - projects = projects_info(api.config["DNFLOCK"].dbo, project_names.split(",")) - except ProjectsError as e: - log.error("(v0_projects_info) %s", str(e)) - return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + return jsonify(blueprints=blueprints, errors=errors)
    - if not projects: - msg = "one of the requested projects does not exist: %s" % project_names - log.error("(v0_projects_info) %s", msg) - return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 +
    [docs]@v0_api.route("/projects/list") +def v0_projects_list(): + """List all of the available projects/packages - return jsonify(projects=projects) + **/api/v0/projects/list[?offset=0&limit=20]** - @api.route("/api/v0/projects/depsolve", defaults={'project_names': ""}) - @api.route("/api/v0/projects/depsolve/<project_names>") - @crossdomain(origin="*") - @checkparams([("project_names", "", "no project names given")]) - def v0_projects_depsolve(project_names): - """Return detailed information about the listed projects""" - if VALID_API_STRING.match(project_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + List all of the available projects. By default this returns the first 20 items, + but this can be changed by setting the `offset` and `limit` arguments. - try: - with api.config["DNFLOCK"].lock: - deps = projects_depsolve(api.config["DNFLOCK"].dbo, [(n, "*") for n in project_names.split(",")], []) - except ProjectsError as e: - log.error("(v0_projects_depsolve) %s", str(e)) - return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + Example:: - if not deps: - msg = "one of the requested projects does not exist: %s" % project_names - log.error("(v0_projects_depsolve) %s", msg) - return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 + { + "limit": 20, + "offset": 0, + "projects": [ + { + "description": "0 A.D. (pronounced \"zero ey-dee\") is a ...", + "homepage": "http://play0ad.com", + "name": "0ad", + "summary": "Cross-Platform RTS Game of Ancient Warfare", + "upstream_vcs": "UPSTREAM_VCS" + }, + ... + ], + "total": 21770 + } + """ + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 - return jsonify(projects=deps) - - @api.route("/api/v0/projects/source/list") - @crossdomain(origin="*") - def v0_projects_source_list(): - """Return the list of source names""" + try: with api.config["DNFLOCK"].lock: - repos = list(api.config["DNFLOCK"].dbo.repos.iter_enabled()) - sources = sorted([r.id for r in repos]) - return jsonify(sources=sources) + available = projects_list(api.config["DNFLOCK"].dbo) + except ProjectsError as e: + log.error("(v0_projects_list) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 - @api.route("/api/v0/projects/source/info", defaults={'source_names': ""}) - @api.route("/api/v0/projects/source/info/<source_names>") - @crossdomain(origin="*") - @checkparams([("source_names", "", "no source names given")]) - def v0_projects_source_info(source_names): - """Return detailed info about the list of sources""" - if VALID_API_STRING.match(source_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + projects = take_limits(available, offset, limit) + return jsonify(projects=projects, offset=offset, limit=limit, total=len(available))
    - out_fmt = request.args.get("format", "json") - if VALID_API_STRING.match(out_fmt) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 +
    [docs]@v0_api.route("/projects/info", defaults={'project_names': ""}) +@v0_api.route("/projects/info/<project_names>") +@checkparams([("project_names", "", "no project names given")]) +def v0_projects_info(project_names): + """Return detailed information about the listed projects - # Return info on all of the sources - if source_names == "*": - with api.config["DNFLOCK"].lock: - source_names = ",".join(r.id for r in api.config["DNFLOCK"].dbo.repos.iter_enabled()) + **/api/v0/projects/info/<project_names>** - sources = {} - errors = [] - system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") - for source in source_names.split(","): - with api.config["DNFLOCK"].lock: - repo = api.config["DNFLOCK"].dbo.repos.get(source, None) - if not repo: - errors.append({"id": UNKNOWN_SOURCE, "msg": "%s is not a valid source" % source}) - continue - sources[repo.id] = repo_to_source(repo, repo.id in system_sources) + Return information about the comma-separated list of projects. It includes the description + of the package along with the list of available builds. - if out_fmt == "toml" and not errors: - # With TOML output we just want to dump the raw sources, skipping the errors - return toml.dumps(sources) - elif out_fmt == "toml" and errors: - # TOML requested, but there was an error - return jsonify(status=False, errors=errors), 400 - else: - return jsonify(sources=sources, errors=errors) + Example:: - @api.route("/api/v0/projects/source/new", methods=["POST"]) - @crossdomain(origin="*") - def v0_projects_source_new(): - """Add a new package source. Or change an existing one""" - if request.headers['Content-Type'] == "text/x-toml": - source = toml.loads(request.data) - else: - source = request.get_json(cache=False) + { + "projects": [ + { + "builds": [ + { + "arch": "x86_64", + "build_config_ref": "BUILD_CONFIG_REF", + "build_env_ref": "BUILD_ENV_REF", + "build_time": "2017-03-01T08:39:23", + "changelog": "- restore incremental backups correctly, files ...", + "epoch": "2", + "metadata": {}, + "release": "32.el7", + "source": { + "license": "GPLv3+", + "metadata": {}, + "source_ref": "SOURCE_REF", + "version": "1.26" + } + } + ], + "description": "The GNU tar program saves many ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ + if VALID_API_STRING.match(project_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") - if source["name"] in system_sources: - return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["name"]}]), 400 + try: + with api.config["DNFLOCK"].lock: + projects = projects_info(api.config["DNFLOCK"].dbo, project_names.split(",")) + except ProjectsError as e: + log.error("(v0_projects_info) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + if not projects: + msg = "one of the requested projects does not exist: %s" % project_names + log.error("(v0_projects_info) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 + + return jsonify(projects=projects)
    + +
    [docs]@v0_api.route("/projects/depsolve", defaults={'project_names': ""}) +@v0_api.route("/projects/depsolve/<project_names>") +@checkparams([("project_names", "", "no project names given")]) +def v0_projects_depsolve(project_names): + """Return detailed information about the listed projects + + **/api/v0/projects/depsolve/<project_names>** + + Depsolve the comma-separated list of projects and return the list of NEVRAs needed + to satisfy the request. + + Example:: + + { + "projects": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "filesystem", + "release": "21.el7", + "version": "3.2" + }, + ... + ] + } + """ + if VALID_API_STRING.match(project_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + with api.config["DNFLOCK"].lock: + deps = projects_depsolve(api.config["DNFLOCK"].dbo, [(n, "*") for n in project_names.split(",")], []) + except ProjectsError as e: + log.error("(v0_projects_depsolve) %s", str(e)) + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + + if not deps: + msg = "one of the requested projects does not exist: %s" % project_names + log.error("(v0_projects_depsolve) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_PROJECT, "msg": msg}]), 400 + + return jsonify(projects=deps)
    + +
    [docs]@v0_api.route("/projects/source/list") +def v0_projects_source_list(): + """Return the list of source names + + **/api/v0/projects/source/list** + + Return the list of repositories used for depsolving and installing packages. + + Example:: + + { + "sources": [ + "fedora", + "fedora-cisco-openh264", + "fedora-updates-testing", + "fedora-updates" + ] + } + """ + with api.config["DNFLOCK"].lock: + repos = list(api.config["DNFLOCK"].dbo.repos.iter_enabled()) + sources = sorted([r.id for r in repos]) + return jsonify(sources=sources)
    + +
    [docs]@v0_api.route("/projects/source/info", defaults={'source_names': ""}) +@v0_api.route("/projects/source/info/<source_names>") +@checkparams([("source_names", "", "no source names given")]) +def v0_projects_source_info(source_names): + """Return detailed info about the list of sources + + **/api/v0/projects/source/info/<source-names>** + + Return information about the comma-separated list of source names. Or all of the + sources if '*' is passed. Note that general globbing is not supported, only '*'. + + immutable system sources will have the "system" field set to true. User added sources + will have it set to false. System sources cannot be changed or deleted. + + Example:: + + { + "errors": [], + "sources": { + "fedora": { + "check_gpg": true, + "check_ssl": true, + "gpgkey_urls": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "name": "fedora", + "proxy": "http://proxy.brianlane.com:8123", + "system": true, + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + } + } + """ + if VALID_API_STRING.match(source_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + out_fmt = request.args.get("format", "json") + if VALID_API_STRING.match(out_fmt) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in format argument"}]), 400 + + # Return info on all of the sources + if source_names == "*": + with api.config["DNFLOCK"].lock: + source_names = ",".join(r.id for r in api.config["DNFLOCK"].dbo.repos.iter_enabled()) + + sources = {} + errors = [] + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + for source in source_names.split(","): + with api.config["DNFLOCK"].lock: + repo = api.config["DNFLOCK"].dbo.repos.get(source, None) + if not repo: + errors.append({"id": UNKNOWN_SOURCE, "msg": "%s is not a valid source" % source}) + continue + sources[repo.id] = repo_to_source(repo, repo.id in system_sources) + + if out_fmt == "toml" and not errors: + # With TOML output we just want to dump the raw sources, skipping the errors + return toml.dumps(sources) + elif out_fmt == "toml" and errors: + # TOML requested, but there was an error + return jsonify(status=False, errors=errors), 400 + else: + return jsonify(sources=sources, errors=errors)
    + +
    [docs]@v0_api.route("/projects/source/new", methods=["POST"]) +def v0_projects_source_new(): + """Add a new package source. Or change an existing one + + **POST /api/v0/projects/source/new** + + Add (or change) a source for use when depsolving blueprints and composing images. + + The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported + types for the urls are: + + * ``yum-baseurl`` is a URL to a yum repository. + * ``yum-mirrorlist`` is a URL for a mirrorlist. + * ``yum-metalink`` is a URL for a metalink. + + If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set + this to false, or add your Certificate Authority to the host system. + + If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` + should point to it. + + You can edit an existing source (other than system sources), by doing a POST + of the new version of the source. It will overwrite the previous one. + + Example:: + + { + "name": "custom-source-1", + "url": "https://url/path/to/repository/", + "type": "yum-baseurl", + "check_ssl": true, + "check_gpg": true, + "gpgkey_urls": [ + "https://url/path/to/gpg-key" + ] + } + + + """ + if request.headers['Content-Type'] == "text/x-toml": + source = toml.loads(request.data) + else: + source = request.get_json(cache=False) + + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + if source["name"] in system_sources: + return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["name"]}]), 400 + + try: + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + with api.config["DNFLOCK"].lock: + dbo = api.config["DNFLOCK"].dbo + # If this repo already exists, delete it and replace it with the new one + repos = list(r.id for r in dbo.repos.iter_enabled()) + if source["name"] in repos: + del dbo.repos[source["name"]] + + repo = source_to_repo(source, dbo.conf) + dbo.repos.add(repo) + + log.info("Updating repository metadata after adding %s", source["name"]) + dbo.fill_sack(load_system_repo=False) + dbo.read_comps() + + # Write the new repo to disk, replacing any existing ones + repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + + # Remove any previous sources with this name, ignore it if it isn't found try: - # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + delete_repo_source(joinpaths(repo_dir, "*.repo"), source["name"]) + except ProjectsError: + pass + + # Make sure the source name can't contain a path traversal by taking the basename + source_path = joinpaths(repo_dir, os.path.basename("%s.repo" % source["name"])) + with open(source_path, "w") as f: + f.write(dnf_repo_to_file_repo(repo)) + except Exception as e: + log.error("(v0_projects_source_add) adding %s failed: %s", source["name"], str(e)) + + # Cleanup the mess, if loading it failed we don't want to leave it in memory + repos = list(r.id for r in dbo.repos.iter_enabled()) + if source["name"] in repos: with api.config["DNFLOCK"].lock: dbo = api.config["DNFLOCK"].dbo - # If this repo already exists, delete it and replace it with the new one - repos = list(r.id for r in dbo.repos.iter_enabled()) - if source["name"] in repos: - del dbo.repos[source["name"]] + del dbo.repos[source["name"]] - repo = source_to_repo(source, dbo.conf) - dbo.repos.add(repo) - - log.info("Updating repository metadata after adding %s", source["name"]) + log.info("Updating repository metadata after adding %s failed", source["name"]) dbo.fill_sack(load_system_repo=False) dbo.read_comps() - # Write the new repo to disk, replacing any existing ones - repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 - # Remove any previous sources with this name, ignore it if it isn't found - try: - delete_repo_source(joinpaths(repo_dir, "*.repo"), source["name"]) - except ProjectsError: - pass + return jsonify(status=True)
    - # Make sure the source name can't contain a path traversal by taking the basename - source_path = joinpaths(repo_dir, os.path.basename("%s.repo" % source["name"])) - with open(source_path, "w") as f: - f.write(dnf_repo_to_file_repo(repo)) - except Exception as e: - log.error("(v0_projects_source_add) adding %s failed: %s", source["name"], str(e)) +
    [docs]@v0_api.route("/projects/source/delete", defaults={'source_name': ""}, methods=["DELETE"]) +@v0_api.route("/projects/source/delete/<source_name>", methods=["DELETE"]) +@checkparams([("source_name", "", "no source name given")]) +def v0_projects_source_delete(source_name): + """Delete the named source and return a status response - # Cleanup the mess, if loading it failed we don't want to leave it in memory - repos = list(r.id for r in dbo.repos.iter_enabled()) - if source["name"] in repos: - with api.config["DNFLOCK"].lock: - dbo = api.config["DNFLOCK"].dbo - del dbo.repos[source["name"]] + **DELETE /api/v0/projects/source/delete/<source-name>** - log.info("Updating repository metadata after adding %s failed", source["name"]) - dbo.fill_sack(load_system_repo=False) - dbo.read_comps() + Delete a user added source. This will fail if a system source is passed to + it. - return jsonify(status=False, errors=[{"id": PROJECTS_ERROR, "msg": str(e)}]), 400 + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ + if VALID_API_STRING.match(source_name) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - return jsonify(status=True) + system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") + if source_name in system_sources: + return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be deleted." % source_name}]), 400 + share_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") + try: + # Remove the file entry for the source + delete_repo_source(joinpaths(share_dir, "*.repo"), source_name) - @api.route("/api/v0/projects/source/delete", defaults={'source_name': ""}, methods=["DELETE"]) - @api.route("/api/v0/projects/source/delete/<source_name>", methods=["DELETE"]) - @crossdomain(origin="*") - @checkparams([("source_name", "", "no source name given")]) - def v0_projects_source_delete(source_name): - """Delete the named source and return a status response""" - if VALID_API_STRING.match(source_name) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) + with api.config["DNFLOCK"].lock: + if source_name in api.config["DNFLOCK"].dbo.repos: + del api.config["DNFLOCK"].dbo.repos[source_name] + log.info("Updating repository metadata after removing %s", source_name) + api.config["DNFLOCK"].dbo.fill_sack(load_system_repo=False) + api.config["DNFLOCK"].dbo.read_comps() - system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") - if source_name in system_sources: - return jsonify(status=False, errors=[{"id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be deleted." % source_name}]), 400 - share_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") - try: - # Remove the file entry for the source - delete_repo_source(joinpaths(share_dir, "*.repo"), source_name) + except ProjectsError as e: + log.error("(v0_projects_source_delete) %s", str(e)) + return jsonify(status=False, errors=[{"id": UNKNOWN_SOURCE, "msg": str(e)}]), 400 - # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) - with api.config["DNFLOCK"].lock: - if source_name in api.config["DNFLOCK"].dbo.repos: - del api.config["DNFLOCK"].dbo.repos[source_name] - log.info("Updating repository metadata after removing %s", source_name) - api.config["DNFLOCK"].dbo.fill_sack(load_system_repo=False) - api.config["DNFLOCK"].dbo.read_comps() + return jsonify(status=True)
    - except ProjectsError as e: - log.error("(v0_projects_source_delete) %s", str(e)) - return jsonify(status=False, errors=[{"id": UNKNOWN_SOURCE, "msg": str(e)}]), 400 +
    [docs]@v0_api.route("/modules/list") +@v0_api.route("/modules/list/<module_names>") +def v0_modules_list(module_names=None): + """List available modules, filtering by module_names - return jsonify(status=True) + **/api/v0/modules/list[?offset=0&limit=20]** - @api.route("/api/v0/modules/list") - @api.route("/api/v0/modules/list/<module_names>") - @crossdomain(origin="*") - def v0_modules_list(module_names=None): - """List available modules, filtering by module_names""" - if module_names and VALID_API_STRING.match(module_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + Return a list of all of the available modules. This includes the name and the + group_type, which is always "rpm" for lorax-composer. By default this returns + the first 20 items. This can be changed by setting the `offset` and `limit` + arguments. - try: - limit = int(request.args.get("limit", "20")) - offset = int(request.args.get("offset", "0")) - except ValueError as e: - return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 + Example:: - if module_names: - module_names = module_names.split(",") + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "0ad" + }, + { + "group_type": "rpm", + "name": "0ad-data" + }, + { + "group_type": "rpm", + "name": "0install" + }, + { + "group_type": "rpm", + "name": "2048-cli" + }, + ... + ] + "total": 21770 + } - try: - with api.config["DNFLOCK"].lock: - available = modules_list(api.config["DNFLOCK"].dbo, module_names) - except ProjectsError as e: - log.error("(v0_modules_list) %s", str(e)) - return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 + **/api/v0/modules/list/<module_names>[?offset=0&limit=20]** - if module_names and not available: - msg = "one of the requested modules does not exist: %s" % module_names - log.error("(v0_modules_list) %s", msg) - return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 + Return the list of comma-separated modules. Output is the same as `/modules/list` - modules = take_limits(available, offset, limit) - return jsonify(modules=modules, offset=offset, limit=limit, total=len(available)) + Example:: - @api.route("/api/v0/modules/info", defaults={'module_names': ""}) - @api.route("/api/v0/modules/info/<module_names>") - @crossdomain(origin="*") - @checkparams([("module_names", "", "no module names given")]) - def v0_modules_info(module_names): - """Return detailed information about the listed modules""" - if VALID_API_STRING.match(module_names) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - try: - with api.config["DNFLOCK"].lock: - modules = modules_info(api.config["DNFLOCK"].dbo, module_names.split(",")) - except ProjectsError as e: - log.error("(v0_modules_info) %s", str(e)) - return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "tar" + } + ], + "offset": 0, + "total": 1 + } + """ + if module_names and VALID_API_STRING.match(module_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - if not modules: - msg = "one of the requested modules does not exist: %s" % module_names - log.error("(v0_modules_info) %s", msg) - return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 + try: + limit = int(request.args.get("limit", "20")) + offset = int(request.args.get("offset", "0")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": BAD_LIMIT_OR_OFFSET, "msg": str(e)}]), 400 - return jsonify(modules=modules) + if module_names: + module_names = module_names.split(",") - @api.route("/api/v0/compose", methods=["POST"]) - @crossdomain(origin="*") - def v0_compose_start(): - """Start a compose + try: + with api.config["DNFLOCK"].lock: + available = modules_list(api.config["DNFLOCK"].dbo, module_names) + except ProjectsError as e: + log.error("(v0_modules_list) %s", str(e)) + return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 - The body of the post should have these fields: - blueprint_name - The blueprint name from /blueprints/list/ - compose_type - The type of output to create, from /compose/types - branch - Optional, defaults to master, selects the git branch to use for the blueprint. - """ - # Passing ?test=1 will generate a fake FAILED compose. - # Passing ?test=2 will generate a fake FINISHED compose. - try: - test_mode = int(request.args.get("test", "0")) - except ValueError: - test_mode = 0 + if module_names and not available: + msg = "one of the requested modules does not exist: %s" % module_names + log.error("(v0_modules_list) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 - compose = request.get_json(cache=False) + modules = take_limits(available, offset, limit) + return jsonify(modules=modules, offset=offset, limit=limit, total=len(available))
    - errors = [] - if not compose: - return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 +
    [docs]@v0_api.route("/modules/info", defaults={'module_names': ""}) +@v0_api.route("/modules/info/<module_names>") +@checkparams([("module_names", "", "no module names given")]) +def v0_modules_info(module_names): + """Return detailed information about the listed modules - if "blueprint_name" not in compose: - errors.append({"id": UNKNOWN_BLUEPRINT,"msg": "No 'blueprint_name' in the JSON request"}) + **/api/v0/modules/info/<module_names>** + + Return the module's dependencies, and the information about the module. + + Example:: + + { + "modules": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + ... + ], + "description": "The GNU tar program saves ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ + if VALID_API_STRING.match(module_names) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + try: + with api.config["DNFLOCK"].lock: + modules = modules_info(api.config["DNFLOCK"].dbo, module_names.split(",")) + except ProjectsError as e: + log.error("(v0_modules_info) %s", str(e)) + return jsonify(status=False, errors=[{"id": MODULES_ERROR, "msg": str(e)}]), 400 + + if not modules: + msg = "one of the requested modules does not exist: %s" % module_names + log.error("(v0_modules_info) %s", msg) + return jsonify(status=False, errors=[{"id": UNKNOWN_MODULE, "msg": msg}]), 400 + + return jsonify(modules=modules)
    + +
    [docs]@v0_api.route("/compose", methods=["POST"]) +def v0_compose_start(): + """Start a compose + + The body of the post should have these fields: + blueprint_name - The blueprint name from /blueprints/list/ + compose_type - The type of output to create, from /compose/types + branch - Optional, defaults to master, selects the git branch to use for the blueprint. + + **POST /api/v0/compose** + + Start a compose. The content type should be 'application/json' and the body of the POST + should look like this + + Example:: + + { + "blueprint_name": "http-server", + "compose_type": "tar", + "branch": "master" + } + + Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the + blueprint branch to use. 'branch' is optional and will default to master. It will create a new + build and add it to the queue. It returns the build uuid and a status if it succeeds + + Example:: + + { + "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", + "status": true + } + """ + # Passing ?test=1 will generate a fake FAILED compose. + # Passing ?test=2 will generate a fake FINISHED compose. + try: + test_mode = int(request.args.get("test", "0")) + except ValueError: + test_mode = 0 + + compose = request.get_json(cache=False) + + errors = [] + if not compose: + return jsonify(status=False, errors=[{"id": MISSING_POST, "msg": "Missing POST body"}]), 400 + + if "blueprint_name" not in compose: + errors.append({"id": UNKNOWN_BLUEPRINT,"msg": "No 'blueprint_name' in the JSON request"}) + else: + blueprint_name = compose["blueprint_name"] + + if "branch" not in compose or not compose["branch"]: + branch = "master" + else: + branch = compose["branch"] + + if "compose_type" not in compose: + errors.append({"id": BAD_COMPOSE_TYPE, "msg": "No 'compose_type' in the JSON request"}) + else: + compose_type = compose["compose_type"] + + if VALID_API_STRING.match(blueprint_name) is None: + errors.append({"id": INVALID_CHARS, "msg": "Invalid characters in API path"}) + + if not blueprint_exists(branch, blueprint_name): + errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}) + + if errors: + return jsonify(status=False, errors=errors), 400 + + try: + build_id = start_build(api.config["COMPOSER_CFG"], api.config["DNFLOCK"], api.config["GITLOCK"], + branch, blueprint_name, compose_type, test_mode) + except Exception as e: + if "Invalid compose type" in str(e): + return jsonify(status=False, errors=[{"id": BAD_COMPOSE_TYPE, "msg": str(e)}]), 400 else: - blueprint_name = compose["blueprint_name"] + return jsonify(status=False, errors=[{"id": BUILD_FAILED, "msg": str(e)}]), 400 - if "branch" not in compose or not compose["branch"]: - branch = "master" - else: - branch = compose["branch"] + return jsonify(status=True, build_id=build_id)
    - if "compose_type" not in compose: - errors.append({"id": BAD_COMPOSE_TYPE, "msg": "No 'compose_type' in the JSON request"}) - else: - compose_type = compose["compose_type"] +
    [docs]@v0_api.route("/compose/types") +def v0_compose_types(): + """Return the list of enabled output types - if VALID_API_STRING.match(blueprint_name) is None: - errors.append({"id": INVALID_CHARS, "msg": "Invalid characters in API path"}) + (only enabled types are returned) - if not blueprint_exists(api, branch, blueprint_name): - errors.append({"id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name}) + **/api/v0/compose/types** - if errors: - return jsonify(status=False, errors=errors), 400 + Returns the list of supported output types that are valid for use with 'POST /api/v0/compose' - try: - build_id = start_build(api.config["COMPOSER_CFG"], api.config["DNFLOCK"], api.config["GITLOCK"], - branch, blueprint_name, compose_type, test_mode) - except Exception as e: - if "Invalid compose type" in str(e): - return jsonify(status=False, errors=[{"id": BAD_COMPOSE_TYPE, "msg": str(e)}]), 400 - else: - return jsonify(status=False, errors=[{"id": BUILD_FAILED, "msg": str(e)}]), 400 + Example:: - return jsonify(status=True, build_id=build_id) + { + "types": [ + { + "enabled": true, + "name": "tar" + } + ] + } + """ + share_dir = api.config["COMPOSER_CFG"].get("composer", "share_dir") + return jsonify(types=[{"name": k, "enabled": True} for k in compose_types(share_dir)])
    - @api.route("/api/v0/compose/types") - @crossdomain(origin="*") - def v0_compose_types(): - """Return the list of enabled output types +
    [docs]@v0_api.route("/compose/queue") +def v0_compose_queue(): + """Return the status of the new and running queues - (only enabled types are returned) - """ - share_dir = api.config["COMPOSER_CFG"].get("composer", "share_dir") - return jsonify(types=[{"name": k, "enabled": True} for k in compose_types(share_dir)]) + **/api/v0/compose/queue** - @api.route("/api/v0/compose/queue") - @crossdomain(origin="*") - def v0_compose_queue(): - """Return the status of the new and running queues""" - return jsonify(queue_status(api.config["COMPOSER_CFG"])) + Return the status of the build queue. It includes information about the builds waiting, + and the build that is running. - @api.route("/api/v0/compose/finished") - @crossdomain(origin="*") - def v0_compose_finished(): - """Return the list of finished composes""" - return jsonify(finished=build_status(api.config["COMPOSER_CFG"], "FINISHED")) + Example:: - @api.route("/api/v0/compose/failed") - @crossdomain(origin="*") - def v0_compose_failed(): - """Return the list of failed composes""" - return jsonify(failed=build_status(api.config["COMPOSER_CFG"], "FAILED")) + { + "new": [ + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "WAITING", + "job_created": 1517362647.4570868, + "version": "0.0.6" + }, + { + "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73", + "blueprint": "kubernetes", + "queue_status": "WAITING", + "job_created": 1517362659.0034983, + "version": "0.0.1" + } + ], + "run": [ + { + "id": "745712b2-96db-44c0-8014-fe925c35e795", + "blueprint": "glusterfs", + "queue_status": "RUNNING", + "job_created": 1517362633.7965999, + "job_started": 1517362633.8001345, + "version": "0.0.6" + } + ] + } + """ + return jsonify(queue_status(api.config["COMPOSER_CFG"]))
    - @api.route("/api/v0/compose/status", defaults={'uuids': ""}) - @api.route("/api/v0/compose/status/<uuids>") - @crossdomain(origin="*") - @checkparams([("uuids", "", "no UUIDs given")]) - def v0_compose_status(uuids): - """Return the status of the listed uuids""" - if VALID_API_STRING.match(uuids) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 +
    [docs]@v0_api.route("/compose/finished") +def v0_compose_finished(): + """Return the list of finished composes - blueprint = request.args.get("blueprint", None) - status = request.args.get("status", None) - compose_type = request.args.get("type", None) + **/api/v0/compose/finished** - results = [] - errors = [] + Return the details on all of the finished composes on the system. - if uuids.strip() == '*': - queue_status_dict = queue_status(api.config["COMPOSER_CFG"]) - queue_new = queue_status_dict["new"] - queue_running = queue_status_dict["run"] - candidates = queue_new + queue_running + build_status(api.config["COMPOSER_CFG"]) - else: - candidates = [] - for uuid in [n.strip().lower() for n in uuids.split(",")]: - details = uuid_status(api.config["COMPOSER_CFG"], uuid) - if details is None: - errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) - else: - candidates.append(details) + Example:: - for details in candidates: - if blueprint is not None and details['blueprint'] != blueprint: - continue + { + "finished": [ + { + "id": "70b84195-9817-4b8a-af92-45e380f39894", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517351003.8210032, + "job_started": 1517351003.8230415, + "job_finished": 1517359234.1003145, + "version": "0.0.6" + }, + { + "id": "e695affd-397f-4af9-9022-add2636e7459", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517362289.7193348, + "job_started": 1517362289.9751132, + "job_finished": 1517363500.1234567, + "version": "0.0.6" + } + ] + } + """ + return jsonify(finished=build_status(api.config["COMPOSER_CFG"], "FINISHED"))
    - if status is not None and details['queue_status'] != status: - continue +
    [docs]@v0_api.route("/compose/failed") +def v0_compose_failed(): + """Return the list of failed composes - if compose_type is not None and details['compose_type'] != compose_type: - continue + **/api/v0/compose/failed** - results.append(details) + Return the details on all of the failed composes on the system. - return jsonify(uuids=results, errors=errors) + Example:: - @api.route("/api/v0/compose/cancel", defaults={'uuid': ""}, methods=["DELETE"]) - @api.route("/api/v0/compose/cancel/<uuid>", methods=["DELETE"]) - @crossdomain(origin="*") - @checkparams([("uuid", "", "no UUID given")]) - def v0_compose_cancel(uuid): - """Cancel a running compose and delete its results directory""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + { + "failed": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FAILED", + "job_created": 1517523249.9301329, + "job_started": 1517523249.9314211, + "job_finished": 1517523255.5623411, + "version": "0.0.2" + } + ] + } + """ + return jsonify(failed=build_status(api.config["COMPOSER_CFG"], "FAILED"))
    - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 +
    [docs]@v0_api.route("/compose/status", defaults={'uuids': ""}) +@v0_api.route("/compose/status/<uuids>") +@checkparams([("uuids", "", "no UUIDs given")]) +def v0_compose_status(uuids): + """Return the status of the listed uuids - if status["queue_status"] not in ["WAITING", "RUNNING"]: - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in WAITING or RUNNING." % uuid}]) + **/api/v0/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]** - try: - uuid_cancel(api.config["COMPOSER_CFG"], uuid) - except Exception as e: - return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}]),400 - else: - return jsonify(status=True, uuid=uuid) + Return the details for each of the comma-separated list of uuids. A uuid of '*' will return + details for all composes. - @api.route("/api/v0/compose/delete", defaults={'uuids': ""}, methods=["DELETE"]) - @api.route("/api/v0/compose/delete/<uuids>", methods=["DELETE"]) - @crossdomain(origin="*") - @checkparams([("uuids", "", "no UUIDs given")]) - def v0_compose_delete(uuids): - """Delete the compose results for the listed uuids""" - if VALID_API_STRING.match(uuids) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + Example:: - results = [] - errors = [] + { + "uuids": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FINISHED", + "job_created": 1517523644.2384307, + "job_started": 1517523644.2551234, + "job_finished": 1517523689.9864314, + "version": "0.0.2" + }, + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517363442.188399, + "job_started": 1517363442.325324, + "job_finished": 1517363451.653621, + "version": "0.0.6" + } + ] + } + """ + if VALID_API_STRING.match(uuids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + blueprint = request.args.get("blueprint", None) + status = request.args.get("status", None) + compose_type = request.args.get("type", None) + + results = [] + errors = [] + + if uuids.strip() == '*': + queue_status_dict = queue_status(api.config["COMPOSER_CFG"]) + queue_new = queue_status_dict["new"] + queue_running = queue_status_dict["run"] + candidates = queue_new + queue_running + build_status(api.config["COMPOSER_CFG"]) + else: + candidates = [] for uuid in [n.strip().lower() for n in uuids.split(",")]: - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: + details = uuid_status(api.config["COMPOSER_CFG"], uuid) + if details is None: errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) - elif status["queue_status"] not in ["FINISHED", "FAILED"]: - errors.append({"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in FINISHED or FAILED." % uuid}) else: - try: - uuid_delete(api.config["COMPOSER_CFG"], uuid) - except Exception as e: - errors.append({"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}) - else: - results.append({"uuid":uuid, "status":True}) - return jsonify(uuids=results, errors=errors) + candidates.append(details) - @api.route("/api/v0/compose/info", defaults={'uuid': ""}) - @api.route("/api/v0/compose/info/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid", "", "no UUID given")]) - def v0_compose_info(uuid): - """Return detailed info about a compose""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + for details in candidates: + if blueprint is not None and details['blueprint'] != blueprint: + continue - try: - info = uuid_info(api.config["COMPOSER_CFG"], uuid) - except Exception as e: - return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + if status is not None and details['queue_status'] != status: + continue - if info is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 - else: - return jsonify(**info) + if compose_type is not None and details['compose_type'] != compose_type: + continue - @api.route("/api/v0/compose/metadata", defaults={'uuid': ""}) - @api.route("/api/v0/compose/metadata/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid","", "no UUID given")]) - def v0_compose_metadata(uuid): - """Return a tar of the metadata for the build""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + results.append(details) + return jsonify(uuids=results, errors=errors)
    + +
    [docs]@v0_api.route("/compose/cancel", defaults={'uuid': ""}, methods=["DELETE"]) +@v0_api.route("/compose/cancel/<uuid>", methods=["DELETE"]) +@checkparams([("uuid", "", "no UUID given")]) +def v0_compose_cancel(uuid): + """Cancel a running compose and delete its results directory + + **DELETE /api/v0/compose/cancel/<uuid>** + + Cancel the build, if it is not finished, and delete the results. It will return a + status of True if it is successful. + + Example:: + + { + "status": true, + "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5" + } + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + + if status["queue_status"] not in ["WAITING", "RUNNING"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in WAITING or RUNNING." % uuid}]) + + try: + uuid_cancel(api.config["COMPOSER_CFG"], uuid) + except Exception as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}]),400 + else: + return jsonify(status=True, uuid=uuid)
    + +
    [docs]@v0_api.route("/compose/delete", defaults={'uuids': ""}, methods=["DELETE"]) +@v0_api.route("/compose/delete/<uuids>", methods=["DELETE"]) +@checkparams([("uuids", "", "no UUIDs given")]) +def v0_compose_delete(uuids): + """Delete the compose results for the listed uuids + + **DELETE /api/v0/compose/delete/<uuids>** + + Delete the list of comma-separated uuids from the compose results. + + Example:: + + { + "errors": [], + "uuids": [ + { + "status": true, + "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0" + } + ] + } + """ + if VALID_API_STRING.match(uuids) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + results = [] + errors = [] + for uuid in [n.strip().lower() for n in uuids.split(",")]: status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 - if status["queue_status"] not in ["FINISHED", "FAILED"]: - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 - else: - return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=False, logs=False), - mimetype="application/x-tar", - headers=[("Content-Disposition", "attachment; filename=%s-metadata.tar;" % uuid)], - direct_passthrough=True) - - @api.route("/api/v0/compose/results", defaults={'uuid': ""}) - @api.route("/api/v0/compose/results/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid","", "no UUID given")]) - def v0_compose_results(uuid): - """Return a tar of the metadata and the results for the build""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) elif status["queue_status"] not in ["FINISHED", "FAILED"]: - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + errors.append({"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in FINISHED or FAILED." % uuid}) else: - return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=True, logs=True), - mimetype="application/x-tar", - headers=[("Content-Disposition", "attachment; filename=%s.tar;" % uuid)], - direct_passthrough=True) + try: + uuid_delete(api.config["COMPOSER_CFG"], uuid) + except Exception as e: + errors.append({"id": COMPOSE_ERROR, "msg": "%s: %s" % (uuid, str(e))}) + else: + results.append({"uuid":uuid, "status":True}) + return jsonify(uuids=results, errors=errors)
    - @api.route("/api/v0/compose/logs", defaults={'uuid': ""}) - @api.route("/api/v0/compose/logs/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid","", "no UUID given")]) - def v0_compose_logs(uuid): - """Return a tar of the metadata for the build""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 +
    [docs]@v0_api.route("/compose/info", defaults={'uuid': ""}) +@v0_api.route("/compose/info/<uuid>") +@checkparams([("uuid", "", "no UUID given")]) +def v0_compose_info(uuid): + """Return detailed info about a compose - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 - elif status["queue_status"] not in ["FINISHED", "FAILED"]: - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 - else: - return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=False, image=False, logs=True), - mimetype="application/x-tar", - headers=[("Content-Disposition", "attachment; filename=%s-logs.tar;" % uuid)], - direct_passthrough=True) + **/api/v0/compose/info/<uuid>** - @api.route("/api/v0/compose/image", defaults={'uuid': ""}) - @api.route("/api/v0/compose/image/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid","", "no UUID given")]) - def v0_compose_image(uuid): - """Return the output image for the build""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + Get detailed information about the compose. The returned JSON string will + contain the following information: - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 - elif status["queue_status"] not in ["FINISHED", "FAILED"]: - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 - else: - image_name, image_path = uuid_image(api.config["COMPOSER_CFG"], uuid) + * id - The uuid of the comoposition + * config - containing the configuration settings used to run Anaconda + * blueprint - The depsolved blueprint used to generate the kickstart + * commit - The (local) git commit hash for the blueprint used + * deps - The NEVRA of all of the dependencies used in the composition + * compose_type - The type of output generated (tar, iso, etc.) + * queue_status - The final status of the composition (FINISHED or FAILED) - # Make sure it really exists - if not os.path.exists(image_path): - return jsonify(status=False, errors=[{"id": BUILD_MISSING_FILE, "msg": "Build %s is missing image file %s" % (uuid, image_name)}]), 400 + Example:: - # Make the image name unique - image_name = uuid + "-" + image_name - # XXX - Will mime type guessing work for all our output? - return send_file(image_path, as_attachment=True, attachment_filename=image_name, add_etags=False) + { + "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d", + "compose_type": "tar", + "config": { + "anaconda_args": "", + "armplatform": "", + "compress_args": [], + "compression": "xz", + "image_name": "root.tar.xz", + ... + }, + "deps": { + "packages": [ + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "14.el7", + "version": "2.2.51" + } + ] + }, + "id": "c30b7d80-523b-4a23-ad52-61b799739ce8", + "queue_status": "FINISHED", + "blueprint": { + "description": "An example kubernetes master", + ... + } + } + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 - @api.route("/api/v0/compose/log", defaults={'uuid': ""}) - @api.route("/api/v0/compose/log/<uuid>") - @crossdomain(origin="*") - @checkparams([("uuid","", "no UUID given")]) - def v0_compose_log_tail(uuid): - """Return the end of the main anaconda.log, defaults to 1Mbytes""" - if VALID_API_STRING.match(uuid) is None: - return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + try: + info = uuid_info(api.config["COMPOSER_CFG"], uuid) + except Exception as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 - try: - size = int(request.args.get("size", "1024")) - except ValueError as e: - return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + if info is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + else: + return jsonify(**info)
    - status = uuid_status(api.config["COMPOSER_CFG"], uuid) - if status is None: - return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 - elif status["queue_status"] == "WAITING": - return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s has not started yet. No logs to view" % uuid}]) - try: - return Response(uuid_log(api.config["COMPOSER_CFG"], uuid, size), direct_passthrough=True) - except RuntimeError as e: - return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400
    +
    [docs]@v0_api.route("/compose/metadata", defaults={'uuid': ""}) +@v0_api.route("/compose/metadata/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_metadata(uuid): + """Return a tar of the metadata for the build + + **/api/v0/compose/metadata/<uuid>** + + Returns a .tar of the metadata used for the build. This includes all the + information needed to reproduce the build, including the final kickstart + populated with repository and package NEVRA. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-metadata.tar + + The .tar is uncompressed, but is not large. + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + if status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=False, logs=False), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s-metadata.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/results", defaults={'uuid': ""}) +@v0_api.route("/compose/results/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_results(uuid): + """Return a tar of the metadata and the results for the build + + **/api/v0/compose/results/<uuid>** + + Returns a .tar of the metadata, logs, and output image of the build. This + includes all the information needed to reproduce the build, including the + final kickstart populated with repository and package NEVRA. The output image + is already in compressed form so the returned tar is not compressed. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID.tar + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=True, image=True, logs=True), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/logs", defaults={'uuid': ""}) +@v0_api.route("/compose/logs/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_logs(uuid): + """Return a tar of the metadata for the build + + **/api/v0/compose/logs/<uuid>** + + Returns a .tar of the anaconda build logs. The tar is not compressed, but is + not large. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-logs.tar + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + return Response(uuid_tar(api.config["COMPOSER_CFG"], uuid, metadata=False, image=False, logs=True), + mimetype="application/x-tar", + headers=[("Content-Disposition", "attachment; filename=%s-logs.tar;" % uuid)], + direct_passthrough=True)
    + +
    [docs]@v0_api.route("/compose/image", defaults={'uuid': ""}) +@v0_api.route("/compose/image/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_image(uuid): + """Return the output image for the build + + **/api/v0/compose/image/<uuid>** + + Returns the output image from the build. The filename is set to the filename + from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso. + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] not in ["FINISHED", "FAILED"]: + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 + else: + image_name, image_path = uuid_image(api.config["COMPOSER_CFG"], uuid) + + # Make sure it really exists + if not os.path.exists(image_path): + return jsonify(status=False, errors=[{"id": BUILD_MISSING_FILE, "msg": "Build %s is missing image file %s" % (uuid, image_name)}]), 400 + + # Make the image name unique + image_name = uuid + "-" + image_name + # XXX - Will mime type guessing work for all our output? + return send_file(image_path, as_attachment=True, attachment_filename=image_name, add_etags=False)
    + +
    [docs]@v0_api.route("/compose/log", defaults={'uuid': ""}) +@v0_api.route("/compose/log/<uuid>") +@checkparams([("uuid","", "no UUID given")]) +def v0_compose_log_tail(uuid): + """Return the end of the main anaconda.log, defaults to 1Mbytes + + **/api/v0/compose/log/<uuid>[?size=kbytes]** + + Returns the end of the anaconda.log. The size parameter is optional and defaults to 1Mbytes + if it is not included. The returned data is raw text from the end of the logfile, starting on + a line boundry. + + Example:: + + 12:59:24,222 INFO anaconda: Running Thread: AnaConfigurationThread (140629395244800) + 12:59:24,223 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Creating users + 12:59:24,913 INFO anaconda: Clearing libuser.conf at /tmp/libuser.Dyy8Gj + 12:59:25,154 INFO anaconda: Creating users + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Running post-installation scripts + 12:59:49,467 INFO anaconda: Running kickstart %%post script(s) + 12:59:50,782 INFO anaconda: All kickstart %%post script(s) have been run + 12:59:50,782 INFO anaconda: Running post-installation scripts + 12:59:50,784 INFO anaconda: Thread Done: AnaConfigurationThread (140629395244800) + """ + if VALID_API_STRING.match(uuid) is None: + return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 + + try: + size = int(request.args.get("size", "1024")) + except ValueError as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400 + + status = uuid_status(api.config["COMPOSER_CFG"], uuid) + if status is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + elif status["queue_status"] == "WAITING": + return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s has not started yet. No logs to view" % uuid}]) + try: + return Response(uuid_log(api.config["COMPOSER_CFG"], uuid, size), direct_passthrough=True) + except RuntimeError as e: + return jsonify(status=False, errors=[{"id": COMPOSE_ERROR, "msg": str(e)}]), 400
    diff --git a/_modules/pylorax/api/workspace.html b/_modules/pylorax/api/workspace.html index 1508e823..aafb695e 100644 --- a/_modules/pylorax/api/workspace.html +++ b/_modules/pylorax/api/workspace.html @@ -8,7 +8,7 @@ - pylorax.api.workspace — Lorax 31.4 documentation + pylorax.api.workspace — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/base.html b/_modules/pylorax/base.html index 88da3aaf..fd52cdb6 100644 --- a/_modules/pylorax/base.html +++ b/_modules/pylorax/base.html @@ -8,7 +8,7 @@ - pylorax.base — Lorax 31.4 documentation + pylorax.base — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/buildstamp.html b/_modules/pylorax/buildstamp.html index c8053596..83d3291f 100644 --- a/_modules/pylorax/buildstamp.html +++ b/_modules/pylorax/buildstamp.html @@ -8,7 +8,7 @@ - pylorax.buildstamp — Lorax 31.4 documentation + pylorax.buildstamp — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/cmdline.html b/_modules/pylorax/cmdline.html index c820d244..4eddcd80 100644 --- a/_modules/pylorax/cmdline.html +++ b/_modules/pylorax/cmdline.html @@ -8,7 +8,7 @@ - pylorax.cmdline — Lorax 31.4 documentation + pylorax.cmdline — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/creator.html b/_modules/pylorax/creator.html index 53723869..1f1f040d 100644 --- a/_modules/pylorax/creator.html +++ b/_modules/pylorax/creator.html @@ -8,7 +8,7 @@ - pylorax.creator — Lorax 31.4 documentation + pylorax.creator — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/decorators.html b/_modules/pylorax/decorators.html index 585a636b..8a38c35c 100644 --- a/_modules/pylorax/decorators.html +++ b/_modules/pylorax/decorators.html @@ -8,7 +8,7 @@ - pylorax.decorators — Lorax 31.4 documentation + pylorax.decorators — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/discinfo.html b/_modules/pylorax/discinfo.html index eb0856a5..01ae6c20 100644 --- a/_modules/pylorax/discinfo.html +++ b/_modules/pylorax/discinfo.html @@ -8,7 +8,7 @@ - pylorax.discinfo — Lorax 31.4 documentation + pylorax.discinfo — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/dnfbase.html b/_modules/pylorax/dnfbase.html index 7662369a..d9b611c6 100644 --- a/_modules/pylorax/dnfbase.html +++ b/_modules/pylorax/dnfbase.html @@ -8,7 +8,7 @@ - pylorax.dnfbase — Lorax 31.4 documentation + pylorax.dnfbase — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/dnfhelper.html b/_modules/pylorax/dnfhelper.html index 3a30c527..ccd3c52b 100644 --- a/_modules/pylorax/dnfhelper.html +++ b/_modules/pylorax/dnfhelper.html @@ -8,7 +8,7 @@ - pylorax.dnfhelper — Lorax 31.4 documentation + pylorax.dnfhelper — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/executils.html b/_modules/pylorax/executils.html index 67b91a09..432997f1 100644 --- a/_modules/pylorax/executils.html +++ b/_modules/pylorax/executils.html @@ -8,7 +8,7 @@ - pylorax.executils — Lorax 31.4 documentation + pylorax.executils — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/imgutils.html b/_modules/pylorax/imgutils.html index 6f5cfbb3..cc23d3fd 100644 --- a/_modules/pylorax/imgutils.html +++ b/_modules/pylorax/imgutils.html @@ -8,7 +8,7 @@ - pylorax.imgutils — Lorax 31.4 documentation + pylorax.imgutils — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/installer.html b/_modules/pylorax/installer.html index 561f6dea..d357cf20 100644 --- a/_modules/pylorax/installer.html +++ b/_modules/pylorax/installer.html @@ -8,7 +8,7 @@ - pylorax.installer — Lorax 31.4 documentation + pylorax.installer — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/ltmpl.html b/_modules/pylorax/ltmpl.html index 05188250..c295fc9d 100644 --- a/_modules/pylorax/ltmpl.html +++ b/_modules/pylorax/ltmpl.html @@ -8,7 +8,7 @@ - pylorax.ltmpl — Lorax 31.4 documentation + pylorax.ltmpl — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -274,6 +274,7 @@ # install a bunch of packages runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) runner.run("install-packages.ltmpl") + NOTES: * Parsing procedure is roughly: diff --git a/_modules/pylorax/monitor.html b/_modules/pylorax/monitor.html index c27e0cf4..0798fe6e 100644 --- a/_modules/pylorax/monitor.html +++ b/_modules/pylorax/monitor.html @@ -8,7 +8,7 @@ - pylorax.monitor — Lorax 31.4 documentation + pylorax.monitor — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/mount.html b/_modules/pylorax/mount.html index 57763e68..ae4c9d9b 100644 --- a/_modules/pylorax/mount.html +++ b/_modules/pylorax/mount.html @@ -8,7 +8,7 @@ - pylorax.mount — Lorax 31.4 documentation + pylorax.mount — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    @@ -179,9 +179,10 @@ log = logging.getLogger("livemedia-creator") import os +import pycdlib +from pycdlib.pycdlibexception import PyCdlibException from pylorax.imgutils import mount, umount -from pylorax.executils import execWithCapture
    [docs]class IsoMountpoint(object): """ @@ -252,12 +253,12 @@ Sets self.label if one is found """ - isoinfo_output = execWithCapture("isoinfo", ["-d", "-i", self.iso_path]) - log.debug(isoinfo_output) - for line in isoinfo_output.splitlines(): - if line.startswith("Volume id: "): - self.label = line[11:] - return
    + try: + iso = pycdlib.PyCdlib() + iso.open(self.iso_path) + self.label = iso.pvd.volume_identifier.decode("UTF-8").strip() + except PyCdlibException as e: + log.error("Problem reading label from %s: %s", self.iso_path, e) diff --git a/_modules/pylorax/sysutils.html b/_modules/pylorax/sysutils.html index 526ffb94..dd91d76e 100644 --- a/_modules/pylorax/sysutils.html +++ b/_modules/pylorax/sysutils.html @@ -8,7 +8,7 @@ - pylorax.sysutils — Lorax 31.4 documentation + pylorax.sysutils — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/treebuilder.html b/_modules/pylorax/treebuilder.html index 1274548b..f8809561 100644 --- a/_modules/pylorax/treebuilder.html +++ b/_modules/pylorax/treebuilder.html @@ -8,7 +8,7 @@ - pylorax.treebuilder — Lorax 31.4 documentation + pylorax.treebuilder — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_modules/pylorax/treeinfo.html b/_modules/pylorax/treeinfo.html index 6fe28e93..2be5067e 100644 --- a/_modules/pylorax/treeinfo.html +++ b/_modules/pylorax/treeinfo.html @@ -8,7 +8,7 @@ - pylorax.treeinfo — Lorax 31.4 documentation + pylorax.treeinfo — Lorax 31.7 documentation @@ -58,7 +58,7 @@
    - 31.4 + 31.7
    diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt index 40acd5a6..c19a1fe9 100644 --- a/_sources/index.rst.txt +++ b/_sources/index.rst.txt @@ -22,6 +22,8 @@ Contents: Documentation for other Lorax Branches ====================================== +* `Fedora 30 `_ +* `Fedora 29 `_ * `Fedora 28 `_ * `RHEL7 lorax-composer `_ diff --git a/_sources/pylorax.api.rst.txt b/_sources/pylorax.api.rst.txt index 4428d012..2891c82e 100644 --- a/_sources/pylorax.api.rst.txt +++ b/_sources/pylorax.api.rst.txt @@ -44,14 +44,6 @@ pylorax.api.config module :undoc-members: :show-inheritance: -pylorax.api.crossdomain module ------------------------------- - -.. automodule:: pylorax.api.crossdomain - :members: - :undoc-members: - :show-inheritance: - pylorax.api.dnfbase module -------------------------- @@ -68,6 +60,14 @@ pylorax.api.errors module :undoc-members: :show-inheritance: +pylorax.api.flask\_blueprint module +----------------------------------- + +.. automodule:: pylorax.api.flask_blueprint + :members: + :undoc-members: + :show-inheritance: + pylorax.api.gitrpm module ------------------------- @@ -124,6 +124,14 @@ pylorax.api.timestamp module :undoc-members: :show-inheritance: +pylorax.api.toml module +----------------------- + +.. automodule:: pylorax.api.toml + :members: + :undoc-members: + :show-inheritance: + pylorax.api.v0 module --------------------- diff --git a/_static/documentation_options.js b/_static/documentation_options.js index b919ed66..576d0398 100644 --- a/_static/documentation_options.js +++ b/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '31.4', + VERSION: '31.7', LANGUAGE: 'None', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', diff --git a/composer-cli.html b/composer-cli.html index 367eea1e..afde4f23 100644 --- a/composer-cli.html +++ b/composer-cli.html @@ -8,7 +8,7 @@ - composer-cli — Lorax 31.4 documentation + composer-cli — Lorax 31.7 documentation @@ -60,7 +60,7 @@
    - 31.4 + 31.7
    diff --git a/composer.cli.html b/composer.cli.html index 35f1ed83..53bef7a5 100644 --- a/composer.cli.html +++ b/composer.cli.html @@ -8,7 +8,7 @@ - composer.cli package — Lorax 31.4 documentation + composer.cli package — Lorax 31.7 documentation @@ -60,7 +60,7 @@
    - 31.4 + 31.7
    @@ -445,6 +445,24 @@ blueprints freeze save <blueprint,...> Save the frozen blueprint to a file

    blueprints workspace <blueprint> Push the blueprint TOML to the temporary workspace storage.

    +
    +
    +composer.cli.blueprints.dict_names(lst)[source]¶
    +

    Return comma-separated list of the dict's name/user fields

    +
    +
    Parameters
    +

    d (dict) -- key/values

    +
    +
    Returns
    +

    String of the dict's keys and values

    +
    +
    Return type
    +

    str

    +
    +
    +

    root, norm

    +
    +
    composer.cli.blueprints.prettyCommitDetails(change, indent=4)[source]¶
    @@ -460,8 +478,26 @@ blueprints freeze save <blueprint,...> Save the frozen blueprint to a file
    -
    -composer.cli.blueprints.prettyDiffEntry(diff)[source]¶
    +
    +composer.cli.blueprints.pretty_dict(d)[source]¶
    +

    Return the dict as a human readable single line

    +
    +
    Parameters
    +

    d (dict) -- key/values

    +
    +
    Returns
    +

    String of the dict's keys and values

    +
    +
    Return type
    +

    str

    +
    +
    +

    key="str", key="str1,str2", ...

    +
    + +
    +
    +composer.cli.blueprints.pretty_diff_entry(diff)[source]¶

    Generate nice diff entry string.

    Parameters
    diff --git a/composer.html b/composer.html index 5c8b0c3e..25dacabb 100644 --- a/composer.html +++ b/composer.html @@ -8,7 +8,7 @@ - composer package — Lorax 31.4 documentation + composer package — Lorax 31.7 documentation @@ -60,7 +60,7 @@
    - 31.4 + 31.7
    diff --git a/genindex.html b/genindex.html index 24593b68..c2f82d74 100644 --- a/genindex.html +++ b/genindex.html @@ -9,7 +9,7 @@ - Index — Lorax 31.4 documentation + Index — Lorax 31.7 documentation @@ -59,7 +59,7 @@
    - 31.4 + 31.7
    @@ -191,6 +191,8 @@
  • add_git_tarball() (pylorax.api.gitrpm.GitRpmBuild method)
  • add_section() (pylorax.treeinfo.TreeInfo method) +
  • +
  • add_url_rule() (pylorax.api.flask_blueprint.BlueprintSetupStateSkip method)
  • anaconda_cleanup() (in module pylorax.installer)
  • @@ -244,10 +246,10 @@
  • blueprints_list() (in module composer.cli.blueprints)
  • - - + @@ -436,7 +438,9 @@
  • dep_nevra() (in module pylorax.api.projects)
  • -
  • diff_items() (in module pylorax.api.recipes) +
  • dict_names() (in module composer.cli.blueprints) +
  • +
  • diff_lists() (in module pylorax.api.recipes)
  • @@ -497,6 +503,8 @@
  • filename (pylorax.api.recipes.Recipe attribute)
  • find_commit_tag() (in module pylorax.api.recipes) +
  • +
  • find_field_value() (in module pylorax.api.recipes)
  • find_free_port() (in module pylorax.installer)
  • @@ -506,6 +514,8 @@ - +
    • timezone_cmd() (in module pylorax.api.compose)
    • toml() (pylorax.api.recipes.Recipe method)
    • toml_filename() (in module composer.cli.utilities) +
    • +
    • TomlError
    • touch() (in module pylorax.sysutils)
    • @@ -1256,10 +1276,78 @@

      V

      - - - + + + + + +
          pylorax.api.config
          - pylorax.api.crossdomain -
          @@ -298,6 +293,11 @@     pylorax.api.errors
          + pylorax.api.flask_blueprint +
          @@ -333,6 +333,11 @@     pylorax.api.timestamp
          + pylorax.api.toml +
          diff --git a/pylorax.api.html b/pylorax.api.html index b626891c..a73768d1 100644 --- a/pylorax.api.html +++ b/pylorax.api.html @@ -8,7 +8,7 @@ - pylorax.api package — Lorax 31.4 documentation + pylorax.api package — Lorax 31.7 documentation @@ -59,7 +59,7 @@
      - 31.4 + 31.7
      @@ -773,14 +773,6 @@ with whatever options are relevant.

      - -
      -

      pylorax.api.crossdomain module¶

      -
      -
      -pylorax.api.crossdomain.crossdomain(origin, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True)[source]¶
      -
      -

      pylorax.api.dnfbase module¶

      @@ -829,6 +821,52 @@ metadata.

      pylorax.api.errors module¶

      +
      +
      +

      pylorax.api.flask_blueprint module¶

      +

      Flask Blueprints that support skipping routes

      +

      When using Blueprints for API versioning you will usually want to fall back +to the previous version's rules for routes that have no new behavior. To do +this we add a 'skip_rule' list to the Blueprint's options dictionary. It lists +all of the routes that you do not want to register.

      +
      +
      For example:

      from pylorax.api.v0 import v0 +from pylorax.api.v1 import v1

      +

      server.register_blueprint(v0, url_prefix="/api/v0/") +server.register_blueprint(v0, url_prefix="/api/v1/", skip_rules=["/blueprints/list"] +server.register_blueprint(v1, url_prefix="/api/v1/")

      +
      +
      +

      This will register all of v0's routes under /api/v0, and all but /blueprints/list under /api/v1, +and then register v1's version of /blueprints/list under /api/v1

      +
      +
      +class pylorax.api.flask_blueprint.BlueprintSetupStateSkip(blueprint, app, options, first_registration, skip_rules)[source]¶
      +

      Bases: flask.blueprints.BlueprintSetupState

      +
      +
      +add_url_rule(rule, endpoint=None, view_func=None, **options)[source]¶
      +

      A helper method to register a rule (and optionally a view function) +to the application. The endpoint is automatically prefixed with the +blueprint's name.

      +
      + +
      + +
      +
      +class pylorax.api.flask_blueprint.BlueprintSkip(*args, **kwargs)[source]¶
      +

      Bases: flask.blueprints.Blueprint

      +
      +
      +make_setup_state(app, options, first_registration=False)[source]¶
      +

      Creates an instance of BlueprintSetupState() +object that is later passed to the register callback functions. +Subclasses can override this to return a subclass of the setup state.

      +
      + +
      +

      pylorax.api.gitrpm module¶

      @@ -2057,6 +2095,12 @@ be tried.

      +
      +
      +pylorax.api.recipes.customizations_diff(old_recipe, new_recipe)[source]¶
      +

      Diff the customizations sections from two versions of a recipe

      +
      +
      pylorax.api.recipes.delete_file(repo, branch, filename)[source]¶
      @@ -2106,13 +2150,14 @@ be tried.

      -
      -pylorax.api.recipes.diff_items(title, old_items, new_items)[source]¶
      +
      +pylorax.api.recipes.diff_lists(title, field, old_items, new_items)[source]¶

      Return the differences between two lists of dicts.

      Parameters
      • title (str) -- Title of the entry

      • +
      • field (str) -- Field to use as the key for comparisons

      • old_items (list(dict)) -- List of item dicts with "name" field

      • new_items (list(dict)) -- List of item dicts with "name" field

      @@ -2151,6 +2196,30 @@ be a tag at all.

      The tag will look like: 'refs/tags/<branch>/<filename>/r<revision>'

      +
      +
      +pylorax.api.recipes.find_field_value(field, value, lst)[source]¶
      +

      Find a field matching value in the list of dicts.

      +
      +
      Parameters
      +
        +
      • field (str) -- field to search for

      • +
      • value (str) -- value to match in the field

      • +
      • lst (list of dict) -- List of dict's with field

      • +
      +
      +
      Returns
      +

      First dict with matching field:value, or None

      +
      +
      Return type
      +

      dict or None

      +
      +
      +

      Used to return a specific entry from a list that looks like this:

      +

      [{"name": "one", "attr": "green"}, ...]

      +

      find_field_value("name", "one", lst) will return the matching dict.

      +
      +
      pylorax.api.recipes.find_name(name, lst)[source]¶
      @@ -2159,7 +2228,7 @@ be a tag at all.

      Parameters
      • name (str) -- Name to search for

      • -
      • lst -- List of dict's with "name" field

      • +
      • lst (list of dict) -- List of dict's with "name" field

      Returns
      @@ -2169,6 +2238,26 @@ be a tag at all.

      dict or None

      +

      This is just a wrapper for find_field_value with field set to "name"

      +
      + +
      +
      +pylorax.api.recipes.find_recipe_obj(path, recipe, default=None)[source]¶
      +

      Find a recipe object

      +
      +
      Parameters
      +
        +
      • path (list of str) -- A list of dict field names

      • +
      • recipe (Recipe) -- The recipe to search

      • +
      • default (Any) -- The value to return if it is not found

      • +
      +
      +
      +

      Return the object found by applying the path to the dicts in the recipe, or +return the default if it doesn't exist.

      +

      eg. {"customizations": {"hostname": "foo", "users": [...]}}

      +

      find_recipe_obj(["customizations", "hostname"], recipe, "")

      @@ -2784,6 +2873,25 @@ If the commit has already been tagged it will return false.

      pylorax.api.timestamp.write_timestamp(destdir, ty)[source]¶
      +
      +
      +

      pylorax.api.toml module¶

      +
      +
      +exception pylorax.api.toml.TomlError(msg, doc, pos)[source]¶
      +

      Bases: toml.decoder.TomlDecodeError

      +
      + +
      +
      +pylorax.api.toml.dumps(o)[source]¶
      +
      + +
      +
      +pylorax.api.toml.loads(s)[source]¶
      +
      +

      pylorax.api.v0 module¶

      @@ -2816,88 +2924,44 @@ error response with it set to false and an error message included.

      used then the API will use the master branch for blueprints. If you want to create a new branch use the new or workspace routes with ?branch=<branch-name> to store the new blueprint on the new branch.

      -
      -

      /api/v0/blueprints/list¶

      -
      -

      List the available blueprints:

      -
      { "limit": 20,
      -  "offset": 0,
      -  "blueprints": [
      -    "atlas",
      -    "development",
      -    "glusterfs",
      -    "http-server",
      -    "jboss",
      -    "kubernetes" ],
      -  "total": 6 }
      -
      -
      -
      -
      -
      -

      /api/v0/blueprints/info/<blueprint_names>[?format=<json|toml>]¶

      -
      -

      Return the JSON representation of the blueprint. This includes 3 top level -objects. changes which lists whether or not the workspace is different from -the most recent commit. blueprints which lists the JSON representation of the -blueprint, and errors which will list any errors, like non-existant blueprints.

      -

      By default the response is JSON, but if ?format=toml is included in the URL's -arguments it will return the response as the blueprint's raw TOML content. -Unless there is an error which will only return a 400 and a standard error -`Status Response`_.

      -

      If there is an error when JSON is requested the successful blueprints and the -errors will both be returned.

      -

      Example of json response:

      -
      {
      -  "changes": [
      -    {
      -      "changed": false,
      -      "name": "glusterfs"
      -    }
      -  ],
      -  "errors": [],
      -  "blueprints": [
      -    {
      -      "description": "An example GlusterFS server with samba",
      -      "modules": [
      -        {
      -          "name": "glusterfs",
      -          "version": "3.7.*"
      -        },
      -        {
      -          "name": "glusterfs-cli",
      -          "version": "3.7.*"
      -        }
      -      ],
      -      "name": "glusterfs",
      -      "packages": [
      -        {
      -          "name": "2ping",
      -          "version": "3.2.1"
      -        },
      -        {
      -          "name": "samba",
      -          "version": "4.2.*"
      -        }
      -      ],
      -      "version": "0.0.6"
      -    }
      -  ]
      -}
      -
      -
      -

      Error example:

      -
      {
      -  "changes": [],
      -  "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"]
      -  "blueprints": []
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/blueprints/changes/<blueprint_names>[?offset=0&limit=20]¶

      +
      +
      +pylorax.api.v0.blueprint_exists(branch, blueprint_name)[source]¶
      +

      Return True if the blueprint exists

      +
      +
      Parameters
      +
        +
      • api (Flask) -- flask object

      • +
      • branch (str) -- Branch name

      • +
      • recipe_name (str) -- Recipe name to read

      • +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.take_limits(iterable, offset, limit)[source]¶
      +

      Apply offset and limit to an iterable object

      +
      +
      Parameters
      +
        +
      • iterable (iter) -- The object to limit

      • +
      • offset (int) -- The number of items to skip

      • +
      • limit (int) -- The total number of items to return

      • +
      +
      +
      Returns
      +

      A subset of the iterable

      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_blueprints_changes(blueprint_names)[source]¶
      +

      Return the changes to a blueprint or list of blueprints

      +

      /api/v0/blueprints/changes/<blueprint_names>[?offset=0&limit=20]

      Return the commits to a blueprint. By default it returns the first 20 commits, this can be changed by passing offset and/or limit. The response will include the @@ -2956,19 +3020,13 @@ hash can be passed to /api/v0/blueprints/diff/ to retrieve the exac

      - -
      -

      POST /api/v0/blueprints/new¶

      -
      -

      Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML -for the blueprint format. The blueprint should be in the body of the request with the -Content-Type header set to either application/json or text/x-toml.

      -

      The response will be a status response with status set to true, or an -error response with it set to false and an error message included.

      -
      -
      -
      -

      DELETE /api/v0/blueprints/delete/<blueprint_name>¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_delete(blueprint_name)[source]¶
      +

      Delete a blueprint from git

      +

      DELETE /api/v0/blueprints/delete/<blueprint_name>

      Delete a blueprint. The blueprint is deleted from the branch, and will no longer be listed by the list route. A blueprint can be undeleted using the undo route @@ -2977,21 +3035,13 @@ blueprint.

      The response will be a status response with status set to true, or an error response with it set to false and an error message included.

      -
      -
      -

      POST /api/v0/blueprints/workspace¶

      -
      -

      Write a blueprint to the temporary workspace. This works exactly the same as new except -that it does not create a commit. JSON and TOML bodies are supported.

      -

      The workspace is meant to be used as a temporary blueprint storage for clients. -It will be read by the info and diff routes if it is different from the -most recent commit.

      -

      The response will be a status response with status set to true, or an -error response with it set to false and an error message included.

      -
      -
      -
      -

      DELETE /api/v0/blueprints/workspace/<blueprint_name>¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_delete_workspace(blueprint_name)[source]¶
      +

      Delete a blueprint from the workspace

      +

      DELETE /api/v0/blueprints/workspace/<blueprint_name>

      Remove the temporary workspace copy of a blueprint. The info route will now return the most recent commit of the blueprint. Any changes that were in the @@ -2999,116 +3049,13 @@ workspace will be lost.

      The response will be a status response with status set to true, or an error response with it set to false and an error message included.

      -
      -
      -

      POST /api/v0/blueprints/undo/<blueprint_name>/<commit>¶

      -
      -

      This will revert the blueprint to a previous commit. The commit hash from the changes -route can be used in this request.

      -

      The response will be a status response with status set to true, or an -error response with it set to false and an error message included.

      -
      -
      -
      -

      POST /api/v0/blueprints/tag/<blueprint_name>¶

      -
      -

      Tag a blueprint as a new release. This uses git tags with a special format. -refs/tags/<branch>/<filename>/r<revision>. Only the most recent blueprint commit -can be tagged. Revisions start at 1 and increment for each new tag -(per-blueprint). If the commit has already been tagged it will return false.

      -

      The response will be a status response with status set to true, or an -error response with it set to false and an error message included.

      -
      -
      -
      -

      /api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>¶

      -
      -

      Return the differences between two commits, or the workspace. The commit hash -from the changes response can be used here, or several special strings:

      -
        -
      • NEWEST will select the newest git commit. This works for from_commit or to_commit

      • -
      • WORKSPACE will select the workspace copy. This can only be used in to_commit

      • -
      -

      eg. /api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE will return the differences -between the most recent git commit and the contents of the workspace.

      -

      Each entry in the response's diff object contains the old blueprint value and the new one. -If old is null and new is set, then it was added. -If new is null and old is set, then it was removed. -If both are set, then it was changed.

      -

      The old/new entries will have the name of the blueprint field that was changed. This -can be one of: Name, Description, Version, Module, or Package. -The contents for these will be the old/new values for them.

      -

      In the example below the version was changed and the ping package was added.

      -

      Example:

      -
      {
      -  "diff": [
      -    {
      -      "new": {
      -        "Version": "0.0.6"
      -      },
      -      "old": {
      -        "Version": "0.0.5"
      -      }
      -    },
      -    {
      -      "new": {
      -        "Package": {
      -          "name": "ping",
      -          "version": "3.2.1"
      -        }
      -      },
      -      "old": null
      -    }
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/blueprints/freeze/<blueprint_names>¶

      -
      -

      Return a JSON representation of the blueprint with the package and module versions set -to the exact versions chosen by depsolving the blueprint.

      -

      Example:

      -
      {
      -  "errors": [],
      -  "blueprints": [
      -    {
      -      "blueprint": {
      -        "description": "An example GlusterFS server with samba",
      -        "modules": [
      -          {
      -            "name": "glusterfs",
      -            "version": "3.8.4-18.4.el7.x86_64"
      -          },
      -          {
      -            "name": "glusterfs-cli",
      -            "version": "3.8.4-18.4.el7.x86_64"
      -          }
      -        ],
      -        "name": "glusterfs",
      -        "packages": [
      -          {
      -            "name": "ping",
      -            "version": "2:3.2.1-2.el7.noarch"
      -          },
      -          {
      -            "name": "samba",
      -            "version": "4.6.2-8.el7.x86_64"
      -          }
      -        ],
      -        "version": "0.0.6"
      -      }
      -    }
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/blueprints/depsolve/<blueprint_names>¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_depsolve(blueprint_names)[source]¶
      +

      Return the dependencies for a blueprint

      +

      /api/v0/blueprints/depsolve/<blueprint_names>

      Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages chosen to satisfy the blueprint's requirements. The response will include a list of results, @@ -3182,368 +3129,320 @@ and packages in modules, and any error will be in errors

      - -
      -

      /api/v0/projects/list[?offset=0&limit=20]¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_diff(blueprint_name, from_commit, to_commit)[source]¶
      +

      Return the differences between two commits of a blueprint

      +

      /api/v0/blueprints/diff/<blueprint_name>/<from_commit>/<to_commit>

      -

      List all of the available projects. By default this returns the first 20 items, -but this can be changed by setting the offset and limit arguments.

      +

      Return the differences between two commits, or the workspace. The commit hash +from the changes response can be used here, or several special strings:

      +
        +
      • NEWEST will select the newest git commit. This works for from_commit or to_commit

      • +
      • WORKSPACE will select the workspace copy. This can only be used in to_commit

      • +
      +

      eg. /api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE will return the differences +between the most recent git commit and the contents of the workspace.

      +

      Each entry in the response's diff object contains the old blueprint value and the new one. +If old is null and new is set, then it was added. +If new is null and old is set, then it was removed. +If both are set, then it was changed.

      +

      The old/new entries will have the name of the blueprint field that was changed. This +can be one of: Name, Description, Version, Module, or Package. +The contents for these will be the old/new values for them.

      +

      In the example below the version was changed and the ping package was added.

      Example:

      {
      -  "limit": 20,
      -  "offset": 0,
      -  "projects": [
      +  "diff": [
           {
      -      "description": "0 A.D. (pronounced "zero ey-dee") is a ...",
      -      "homepage": "http://play0ad.com",
      -      "name": "0ad",
      -      "summary": "Cross-Platform RTS Game of Ancient Warfare",
      -      "upstream_vcs": "UPSTREAM_VCS"
      +      "new": {
      +        "Version": "0.0.6"
      +      },
      +      "old": {
      +        "Version": "0.0.5"
      +      }
           },
      -    ...
      -  ],
      -  "total": 21770
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/projects/info/<project_names>¶

      -
      -

      Return information about the comma-separated list of projects. It includes the description -of the package along with the list of available builds.

      -

      Example:

      -
      {
      -  "projects": [
           {
      -      "builds": [
      -        {
      -          "arch": "x86_64",
      -          "build_config_ref": "BUILD_CONFIG_REF",
      -          "build_env_ref": "BUILD_ENV_REF",
      -          "build_time": "2017-03-01T08:39:23",
      -          "changelog": "- restore incremental backups correctly, files ...",
      -          "epoch": "2",
      -          "metadata": {},
      -          "release": "32.el7",
      -          "source": {
      -            "license": "GPLv3+",
      -            "metadata": {},
      -            "source_ref": "SOURCE_REF",
      -            "version": "1.26"
      -          }
      +      "new": {
      +        "Package": {
      +          "name": "ping",
      +          "version": "3.2.1"
               }
      -      ],
      -      "description": "The GNU tar program saves many ...",
      -      "homepage": "http://www.gnu.org/software/tar/",
      -      "name": "tar",
      -      "summary": "A GNU file archiving program",
      -      "upstream_vcs": "UPSTREAM_VCS"
      +      },
      +      "old": null
           }
         ]
       }
       
      -
      -
      -

      /api/v0/projects/depsolve/<project_names>¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_freeze(blueprint_names)[source]¶
      +

      Return the blueprint with the exact modules and packages selected by depsolve

      +

      /api/v0/blueprints/freeze/<blueprint_names>

      -

      Depsolve the comma-separated list of projects and return the list of NEVRAs needed -to satisfy the request.

      -

      Example:

      -
      {
      -  "projects": [
      -    {
      -      "arch": "noarch",
      -      "epoch": "0",
      -      "name": "basesystem",
      -      "release": "7.el7",
      -      "version": "10.0"
      -    },
      -    {
      -      "arch": "x86_64",
      -      "epoch": "0",
      -      "name": "bash",
      -      "release": "28.el7",
      -      "version": "4.2.46"
      -    },
      -    {
      -      "arch": "x86_64",
      -      "epoch": "0",
      -      "name": "filesystem",
      -      "release": "21.el7",
      -      "version": "3.2"
      -    },
      -    ...
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/projects/source/list¶

      -
      -

      Return the list of repositories used for depsolving and installing packages.

      -

      Example:

      -
      {
      -  "sources": [
      -    "fedora",
      -    "fedora-cisco-openh264",
      -    "fedora-updates-testing",
      -    "fedora-updates"
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/projects/source/info/<source-names>¶

      -
      -

      Return information about the comma-separated list of source names. Or all of the -sources if '*' is passed. Note that general globbing is not supported, only '*'.

      -

      immutable system sources will have the "system" field set to true. User added sources -will have it set to false. System sources cannot be changed or deleted.

      +

      Return a JSON representation of the blueprint with the package and module versions set +to the exact versions chosen by depsolving the blueprint.

      Example:

      {
         "errors": [],
      -  "sources": {
      -    "fedora": {
      -      "check_gpg": true,
      -      "check_ssl": true,
      -      "gpgkey_urls": [
      -        "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64"
      -      ],
      -      "name": "fedora",
      -      "proxy": "http://proxy.brianlane.com:8123",
      -      "system": true,
      -      "type": "yum-metalink",
      -      "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64"
      +  "blueprints": [
      +    {
      +      "blueprint": {
      +        "description": "An example GlusterFS server with samba",
      +        "modules": [
      +          {
      +            "name": "glusterfs",
      +            "version": "3.8.4-18.4.el7.x86_64"
      +          },
      +          {
      +            "name": "glusterfs-cli",
      +            "version": "3.8.4-18.4.el7.x86_64"
      +          }
      +        ],
      +        "name": "glusterfs",
      +        "packages": [
      +          {
      +            "name": "ping",
      +            "version": "2:3.2.1-2.el7.noarch"
      +          },
      +          {
      +            "name": "samba",
      +            "version": "4.6.2-8.el7.x86_64"
      +          }
      +        ],
      +        "version": "0.0.6"
      +      }
           }
      -  }
      +  ]
       }
       
      -
      -
      -

      POST /api/v0/projects/source/new¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_info(blueprint_names)[source]¶
      +

      Return the contents of the blueprint, or a list of blueprints

      +

      /api/v0/blueprints/info/<blueprint_names>[?format=<json|toml>]

      -

      Add (or change) a source for use when depsolving blueprints and composing images.

      -

      The proxy and gpgkey_urls entries are optional. All of the others are required. The supported -types for the urls are:

      -
        -
      • yum-baseurl is a URL to a yum repository.

      • -
      • yum-mirrorlist is a URL for a mirrorlist.

      • -
      • yum-metalink is a URL for a metalink.

      • -
      -

      If check_ssl is true the https certificates must be valid. If they are self-signed you can either set -this to false, or add your Certificate Authority to the host system.

      -

      If check_gpg is true the GPG key must either be installed on the host system, or gpgkey_urls -should point to it.

      -

      You can edit an existing source (other than system sources), by doing a POST -of the new version of the source. It will overwrite the previous one.

      -

      Example:

      +

      Return the JSON representation of the blueprint. This includes 3 top level +objects. changes which lists whether or not the workspace is different from +the most recent commit. blueprints which lists the JSON representation of the +blueprint, and errors which will list any errors, like non-existant blueprints.

      +

      By default the response is JSON, but if ?format=toml is included in the URL's +arguments it will return the response as the blueprint's raw TOML content. +Unless there is an error which will only return a 400 and a standard error +Status Responses.

      +

      If there is an error when JSON is requested the successful blueprints and the +errors will both be returned.

      +

      Example of json response:

      {
      -    "name": "custom-source-1",
      -    "url": "https://url/path/to/repository/",
      -    "type": "yum-baseurl",
      -    "check_ssl": true,
      -    "check_gpg": true,
      -    "gpgkey_urls": [
      -        "https://url/path/to/gpg-key"
      -    ]
      +  "changes": [
      +    {
      +      "changed": false,
      +      "name": "glusterfs"
      +    }
      +  ],
      +  "errors": [],
      +  "blueprints": [
      +    {
      +      "description": "An example GlusterFS server with samba",
      +      "modules": [
      +        {
      +          "name": "glusterfs",
      +          "version": "3.7.*"
      +        },
      +        {
      +          "name": "glusterfs-cli",
      +          "version": "3.7.*"
      +        }
      +      ],
      +      "name": "glusterfs",
      +      "packages": [
      +        {
      +          "name": "2ping",
      +          "version": "3.2.1"
      +        },
      +        {
      +          "name": "samba",
      +          "version": "4.2.*"
      +        }
      +      ],
      +      "version": "0.0.6"
      +    }
      +  ]
      +}
      +
      +
      +

      Error example:

      +
      {
      +  "changes": [],
      +  "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"]
      +  "blueprints": []
       }
       
      -
      -
      -

      DELETE /api/v0/projects/source/delete/<source-name>¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_list()[source]¶
      +

      List the available blueprints on a branch.

      +

      /api/v0/blueprints/list

      -

      Delete a user added source. This will fail if a system source is passed to -it.

      +

      List the available blueprints:

      +
      { "limit": 20,
      +  "offset": 0,
      +  "blueprints": [
      +    "atlas",
      +    "development",
      +    "glusterfs",
      +    "http-server",
      +    "jboss",
      +    "kubernetes" ],
      +  "total": 6 }
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_blueprints_new()[source]¶
      +

      Commit a new blueprint

      +

      POST /api/v0/blueprints/new

      +
      +

      Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML +for the blueprint format. The blueprint should be in the body of the request with the +Content-Type header set to either application/json or text/x-toml.

      The response will be a status response with status set to true, or an error response with it set to false and an error message included.

      -
      -
      -

      /api/v0/modules/list[?offset=0&limit=20]¶

      + + +
      +
      +pylorax.api.v0.v0_blueprints_tag(blueprint_name)[source]¶
      +

      Tag a blueprint's latest blueprint commit as a 'revision'

      +

      POST /api/v0/blueprints/tag/<blueprint_name>

      -

      Return a list of all of the available modules. This includes the name and the -group_type, which is always "rpm" for lorax-composer. By default this returns -the first 20 items. This can be changed by setting the offset and limit -arguments.

      +

      Tag a blueprint as a new release. This uses git tags with a special format. +refs/tags/<branch>/<filename>/r<revision>. Only the most recent blueprint commit +can be tagged. Revisions start at 1 and increment for each new tag +(per-blueprint). If the commit has already been tagged it will return false.

      +

      The response will be a status response with status set to true, or an +error response with it set to false and an error message included.

      +
      +
      + +
      +
      +pylorax.api.v0.v0_blueprints_undo(blueprint_name, commit)[source]¶
      +

      Undo changes to a blueprint by reverting to a previous commit.

      +

      POST /api/v0/blueprints/undo/<blueprint_name>/<commit>

      +
      +

      This will revert the blueprint to a previous commit. The commit hash from the changes +route can be used in this request.

      +

      The response will be a status response with status set to true, or an +error response with it set to false and an error message included.

      +
      +
      + +
      +
      +pylorax.api.v0.v0_blueprints_workspace()[source]¶
      +

      Write a blueprint to the workspace

      +

      POST /api/v0/blueprints/workspace

      +
      +

      Write a blueprint to the temporary workspace. This works exactly the same as new except +that it does not create a commit. JSON and TOML bodies are supported.

      +

      The workspace is meant to be used as a temporary blueprint storage for clients. +It will be read by the info and diff routes if it is different from the +most recent commit.

      +

      The response will be a status response with status set to true, or an +error response with it set to false and an error message included.

      +
      +
      + +
      +
      +pylorax.api.v0.v0_compose_cancel(uuid)[source]¶
      +

      Cancel a running compose and delete its results directory

      +

      DELETE /api/v0/compose/cancel/<uuid>

      +
      +

      Cancel the build, if it is not finished, and delete the results. It will return a +status of True if it is successful.

      Example:

      {
      -  "limit": 20,
      -  "modules": [
      -    {
      -      "group_type": "rpm",
      -      "name": "0ad"
      -    },
      -    {
      -      "group_type": "rpm",
      -      "name": "0ad-data"
      -    },
      -    {
      -      "group_type": "rpm",
      -      "name": "0install"
      -    },
      -    {
      -      "group_type": "rpm",
      -      "name": "2048-cli"
      -    },
      -    ...
      -  ]
      -  "total": 21770
      +  "status": true,
      +  "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5"
       }
       
      -
      -
      -

      /api/v0/modules/list/<module_names>[?offset=0&limit=20]¶

      + + +
      +
      +pylorax.api.v0.v0_compose_delete(uuids)[source]¶
      +

      Delete the compose results for the listed uuids

      +

      DELETE /api/v0/compose/delete/<uuids>

      -

      Return the list of comma-separated modules. Output is the same as /modules/list

      +

      Delete the list of comma-separated uuids from the compose results.

      Example:

      {
      -  "limit": 20,
      -  "modules": [
      +  "errors": [],
      +  "uuids": [
           {
      -      "group_type": "rpm",
      -      "name": "tar"
      -    }
      -  ],
      -  "offset": 0,
      -  "total": 1
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/modules/info/<module_names>¶

      -
      -

      Return the module's dependencies, and the information about the module.

      -

      Example:

      -
      {
      -  "modules": [
      -    {
      -      "dependencies": [
      -        {
      -          "arch": "noarch",
      -          "epoch": "0",
      -          "name": "basesystem",
      -          "release": "7.el7",
      -          "version": "10.0"
      -        },
      -        {
      -          "arch": "x86_64",
      -          "epoch": "0",
      -          "name": "bash",
      -          "release": "28.el7",
      -          "version": "4.2.46"
      -        },
      -        ...
      -      ],
      -      "description": "The GNU tar program saves ...",
      -      "homepage": "http://www.gnu.org/software/tar/",
      -      "name": "tar",
      -      "summary": "A GNU file archiving program",
      -      "upstream_vcs": "UPSTREAM_VCS"
      +      "status": true,
      +      "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0"
           }
         ]
       }
       
      -
      -
      -

      POST /api/v0/compose¶

      + + +
      +
      +pylorax.api.v0.v0_compose_failed()[source]¶
      +

      Return the list of failed composes

      +

      /api/v0/compose/failed

      -

      Start a compose. The content type should be 'application/json' and the body of the POST -should look like this

      +

      Return the details on all of the failed composes on the system.

      Example:

      {
      -  "blueprint_name": "http-server",
      -  "compose_type": "tar",
      -  "branch": "master"
      -}
      -
      -
      -

      Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the -blueprint branch to use. 'branch' is optional and will default to master. It will create a new -build and add it to the queue. It returns the build uuid and a status if it succeeds

      -

      Example:

      -
      {
      -  "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf",
      -  "status": true
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/compose/types¶

      -
      -

      Returns the list of supported output types that are valid for use with 'POST /api/v0/compose'

      -

      Example:

      -
      {
      -  "types": [
      -    {
      -      "enabled": true,
      -      "name": "tar"
      +  "failed": [
      +     {
      +      "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
      +      "blueprint": "http-server",
      +      "queue_status": "FAILED",
      +      "job_created": 1517523249.9301329,
      +      "job_started": 1517523249.9314211,
      +      "job_finished": 1517523255.5623411,
      +      "version": "0.0.2"
           }
         ]
       }
       
      -
      -
      -

      /api/v0/compose/queue¶

      -
      -

      Return the status of the build queue. It includes information about the builds waiting, -and the build that is running.

      -

      Example:

      -
      {
      -  "new": [
      -    {
      -      "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
      -      "blueprint": "glusterfs",
      -      "queue_status": "WAITING",
      -      "job_created": 1517362647.4570868,
      -      "version": "0.0.6"
      -    },
      -    {
      -      "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73",
      -      "blueprint": "kubernetes",
      -      "queue_status": "WAITING",
      -      "job_created": 1517362659.0034983,
      -      "version": "0.0.1"
      -    }
      -  ],
      -  "run": [
      -    {
      -      "id": "745712b2-96db-44c0-8014-fe925c35e795",
      -      "blueprint": "glusterfs",
      -      "queue_status": "RUNNING",
      -      "job_created": 1517362633.7965999,
      -      "job_started": 1517362633.8001345,
      -      "version": "0.0.6"
      -    }
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/compose/finished¶

      + + +
      +
      +pylorax.api.v0.v0_compose_finished()[source]¶
      +

      Return the list of finished composes

      +

      /api/v0/compose/finished

      Return the details on all of the finished composes on the system.

      Example:

      @@ -3572,95 +3471,24 @@ and the build that is running.

      - -
      -

      /api/v0/compose/failed¶

      + + +
      +
      +pylorax.api.v0.v0_compose_image(uuid)[source]¶
      +

      Return the output image for the build

      +

      /api/v0/compose/image/<uuid>

      -

      Return the details on all of the failed composes on the system.

      -

      Example:

      -
      {
      -  "failed": [
      -     {
      -      "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
      -      "blueprint": "http-server",
      -      "queue_status": "FAILED",
      -      "job_created": 1517523249.9301329,
      -      "job_started": 1517523249.9314211,
      -      "job_finished": 1517523255.5623411,
      -      "version": "0.0.2"
      -    }
      -  ]
      -}
      -
      -
      +

      Returns the output image from the build. The filename is set to the filename +from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso.

      -
      -
      -

      /api/v0/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]¶

      -
      -

      Return the details for each of the comma-separated list of uuids. A uuid of '*' will return -details for all composes.

      -

      Example:

      -
      {
      -  "uuids": [
      -    {
      -      "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
      -      "blueprint": "http-server",
      -      "queue_status": "FINISHED",
      -      "job_created": 1517523644.2384307,
      -      "job_started": 1517523644.2551234,
      -      "job_finished": 1517523689.9864314,
      -      "version": "0.0.2"
      -    },
      -    {
      -      "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
      -      "blueprint": "glusterfs",
      -      "queue_status": "FINISHED",
      -      "job_created": 1517363442.188399,
      -      "job_started": 1517363442.325324,
      -      "job_finished": 1517363451.653621,
      -      "version": "0.0.6"
      -    }
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      DELETE /api/v0/compose/cancel/<uuid>¶

      -
      -

      Cancel the build, if it is not finished, and delete the results. It will return a -status of True if it is successful.

      -

      Example:

      -
      {
      -  "status": true,
      -  "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5"
      -}
      -
      -
      -
      -
      -
      -

      DELETE /api/v0/compose/delete/<uuids>¶

      -
      -

      Delete the list of comma-separated uuids from the compose results.

      -

      Example:

      -
      {
      -  "errors": [],
      -  "uuids": [
      -    {
      -      "status": true,
      -      "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0"
      -    }
      -  ]
      -}
      -
      -
      -
      -
      -
      -

      /api/v0/compose/info/<uuid>¶

      + + +
      +
      +pylorax.api.v0.v0_compose_info(uuid)[source]¶
      +

      Return detailed info about a compose

      +

      /api/v0/compose/info/<uuid>

      Get detailed information about the compose. The returned JSON string will contain the following information:

      @@ -3708,47 +3536,13 @@ contain the following information:

      - -
      -

      /api/v0/compose/metadata/<uuid>¶

      -
      -

      Returns a .tar of the metadata used for the build. This includes all the -information needed to reproduce the build, including the final kickstart -populated with repository and package NEVRA.

      -

      The mime type is set to 'application/x-tar' and the filename is set to -UUID-metadata.tar

      -

      The .tar is uncompressed, but is not large.

      -
      -
      -
      -

      /api/v0/compose/results/<uuid>¶

      -
      -

      Returns a .tar of the metadata, logs, and output image of the build. This -includes all the information needed to reproduce the build, including the -final kickstart populated with repository and package NEVRA. The output image -is already in compressed form so the returned tar is not compressed.

      -

      The mime type is set to 'application/x-tar' and the filename is set to -UUID.tar

      -
      -
      -
      -

      /api/v0/compose/logs/<uuid>¶

      -
      -

      Returns a .tar of the anaconda build logs. The tar is not compressed, but is -not large.

      -

      The mime type is set to 'application/x-tar' and the filename is set to -UUID-logs.tar

      -
      -
      -
      -

      /api/v0/compose/image/<uuid>¶

      -
      -

      Returns the output image from the build. The filename is set to the filename -from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso.

      -
      -
      -
      -

      /api/v0/compose/log/<uuid>[?size=kbytes]¶

      + + +
      +
      +pylorax.api.v0.v0_compose_log_tail(uuid)[source]¶
      +

      Return the end of the main anaconda.log, defaults to 1Mbytes

      +

      /api/v0/compose/log/<uuid>[?size=kbytes]

      Returns the end of the anaconda.log. The size parameter is optional and defaults to 1Mbytes if it is not included. The returned data is raw text from the end of the logfile, starting on @@ -3772,45 +3566,499 @@ a line boundry.

      -
      -
      -pylorax.api.v0.blueprint_exists(api, branch, blueprint_name)[source]¶
      -

      Return True if the blueprint exists

      -
      -
      Parameters
      -
        -
      • api (Flask) -- flask object

      • -
      • branch (str) -- Branch name

      • -
      • recipe_name (str) -- Recipe name to read

      • -
      -
      -
      -
      -pylorax.api.v0.take_limits(iterable, offset, limit)[source]¶
      -

      Apply offset and limit to an iterable object

      -
      -
      Parameters
      -
        -
      • iterable (iter) -- The object to limit

      • -
      • offset (int) -- The number of items to skip

      • -
      • limit (int) -- The total number of items to return

      • -
      -
      -
      Returns
      -

      A subset of the iterable

      -
      -
      +
      +pylorax.api.v0.v0_compose_logs(uuid)[source]¶
      +

      Return a tar of the metadata for the build

      +

      /api/v0/compose/logs/<uuid>

      +
      +

      Returns a .tar of the anaconda build logs. The tar is not compressed, but is +not large.

      +

      The mime type is set to 'application/x-tar' and the filename is set to +UUID-logs.tar

      +
      -
      -pylorax.api.v0.v0_api(api)[source]¶
      -
      +
      +pylorax.api.v0.v0_compose_metadata(uuid)[source]¶
      +

      Return a tar of the metadata for the build

      +

      /api/v0/compose/metadata/<uuid>

      +
      +

      Returns a .tar of the metadata used for the build. This includes all the +information needed to reproduce the build, including the final kickstart +populated with repository and package NEVRA.

      +

      The mime type is set to 'application/x-tar' and the filename is set to +UUID-metadata.tar

      +

      The .tar is uncompressed, but is not large.

      +
      +
      +
      +
      +pylorax.api.v0.v0_compose_queue()[source]¶
      +

      Return the status of the new and running queues

      +

      /api/v0/compose/queue

      +
      +

      Return the status of the build queue. It includes information about the builds waiting, +and the build that is running.

      +

      Example:

      +
      {
      +  "new": [
      +    {
      +      "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
      +      "blueprint": "glusterfs",
      +      "queue_status": "WAITING",
      +      "job_created": 1517362647.4570868,
      +      "version": "0.0.6"
      +    },
      +    {
      +      "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73",
      +      "blueprint": "kubernetes",
      +      "queue_status": "WAITING",
      +      "job_created": 1517362659.0034983,
      +      "version": "0.0.1"
      +    }
      +  ],
      +  "run": [
      +    {
      +      "id": "745712b2-96db-44c0-8014-fe925c35e795",
      +      "blueprint": "glusterfs",
      +      "queue_status": "RUNNING",
      +      "job_created": 1517362633.7965999,
      +      "job_started": 1517362633.8001345,
      +      "version": "0.0.6"
      +    }
      +  ]
      +}
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_compose_results(uuid)[source]¶
      +

      Return a tar of the metadata and the results for the build

      +

      /api/v0/compose/results/<uuid>

      +
      +

      Returns a .tar of the metadata, logs, and output image of the build. This +includes all the information needed to reproduce the build, including the +final kickstart populated with repository and package NEVRA. The output image +is already in compressed form so the returned tar is not compressed.

      +

      The mime type is set to 'application/x-tar' and the filename is set to +UUID.tar

      +
      +
      + +
      +
      +pylorax.api.v0.v0_compose_start()[source]¶
      +

      Start a compose

      +
      +
      The body of the post should have these fields:

      blueprint_name - The blueprint name from /blueprints/list/ +compose_type - The type of output to create, from /compose/types +branch - Optional, defaults to master, selects the git branch to use for the blueprint.

      +
      +
      +

      POST /api/v0/compose

      +
      +

      Start a compose. The content type should be 'application/json' and the body of the POST +should look like this

      +

      Example:

      +
      {
      +  "blueprint_name": "http-server",
      +  "compose_type": "tar",
      +  "branch": "master"
      +}
      +
      +
      +

      Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the +blueprint branch to use. 'branch' is optional and will default to master. It will create a new +build and add it to the queue. It returns the build uuid and a status if it succeeds

      +

      Example:

      +
      {
      +  "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf",
      +  "status": true
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_compose_status(uuids)[source]¶
      +

      Return the status of the listed uuids

      +

      /api/v0/compose/status/<uuids>[?blueprint=<blueprint_name>&status=<compose_status>&type=<compose_type>]

      +
      +

      Return the details for each of the comma-separated list of uuids. A uuid of '*' will return +details for all composes.

      +

      Example:

      +
      {
      +  "uuids": [
      +    {
      +      "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a",
      +      "blueprint": "http-server",
      +      "queue_status": "FINISHED",
      +      "job_created": 1517523644.2384307,
      +      "job_started": 1517523644.2551234,
      +      "job_finished": 1517523689.9864314,
      +      "version": "0.0.2"
      +    },
      +    {
      +      "id": "45502a6d-06e8-48a5-a215-2b4174b3614b",
      +      "blueprint": "glusterfs",
      +      "queue_status": "FINISHED",
      +      "job_created": 1517363442.188399,
      +      "job_started": 1517363442.325324,
      +      "job_finished": 1517363451.653621,
      +      "version": "0.0.6"
      +    }
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_compose_types()[source]¶
      +

      Return the list of enabled output types

      +

      (only enabled types are returned)

      +

      /api/v0/compose/types

      +
      +

      Returns the list of supported output types that are valid for use with 'POST /api/v0/compose'

      +

      Example:

      +
      {
      +  "types": [
      +    {
      +      "enabled": true,
      +      "name": "tar"
      +    }
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_modules_info(module_names)[source]¶
      +

      Return detailed information about the listed modules

      +

      /api/v0/modules/info/<module_names>

      +
      +

      Return the module's dependencies, and the information about the module.

      +

      Example:

      +
      {
      +  "modules": [
      +    {
      +      "dependencies": [
      +        {
      +          "arch": "noarch",
      +          "epoch": "0",
      +          "name": "basesystem",
      +          "release": "7.el7",
      +          "version": "10.0"
      +        },
      +        {
      +          "arch": "x86_64",
      +          "epoch": "0",
      +          "name": "bash",
      +          "release": "28.el7",
      +          "version": "4.2.46"
      +        },
      +        ...
      +      ],
      +      "description": "The GNU tar program saves ...",
      +      "homepage": "http://www.gnu.org/software/tar/",
      +      "name": "tar",
      +      "summary": "A GNU file archiving program",
      +      "upstream_vcs": "UPSTREAM_VCS"
      +    }
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_modules_list(module_names=None)[source]¶
      +

      List available modules, filtering by module_names

      +

      /api/v0/modules/list[?offset=0&limit=20]

      +
      +

      Return a list of all of the available modules. This includes the name and the +group_type, which is always "rpm" for lorax-composer. By default this returns +the first 20 items. This can be changed by setting the offset and limit +arguments.

      +

      Example:

      +
      {
      +  "limit": 20,
      +  "modules": [
      +    {
      +      "group_type": "rpm",
      +      "name": "0ad"
      +    },
      +    {
      +      "group_type": "rpm",
      +      "name": "0ad-data"
      +    },
      +    {
      +      "group_type": "rpm",
      +      "name": "0install"
      +    },
      +    {
      +      "group_type": "rpm",
      +      "name": "2048-cli"
      +    },
      +    ...
      +  ]
      +  "total": 21770
      +}
      +
      +
      +
      +

      /api/v0/modules/list/<module_names>[?offset=0&limit=20]

      +
      +

      Return the list of comma-separated modules. Output is the same as /modules/list

      +

      Example:

      +
      {
      +  "limit": 20,
      +  "modules": [
      +    {
      +      "group_type": "rpm",
      +      "name": "tar"
      +    }
      +  ],
      +  "offset": 0,
      +  "total": 1
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_depsolve(project_names)[source]¶
      +

      Return detailed information about the listed projects

      +

      /api/v0/projects/depsolve/<project_names>

      +
      +

      Depsolve the comma-separated list of projects and return the list of NEVRAs needed +to satisfy the request.

      +

      Example:

      +
      {
      +  "projects": [
      +    {
      +      "arch": "noarch",
      +      "epoch": "0",
      +      "name": "basesystem",
      +      "release": "7.el7",
      +      "version": "10.0"
      +    },
      +    {
      +      "arch": "x86_64",
      +      "epoch": "0",
      +      "name": "bash",
      +      "release": "28.el7",
      +      "version": "4.2.46"
      +    },
      +    {
      +      "arch": "x86_64",
      +      "epoch": "0",
      +      "name": "filesystem",
      +      "release": "21.el7",
      +      "version": "3.2"
      +    },
      +    ...
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_info(project_names)[source]¶
      +

      Return detailed information about the listed projects

      +

      /api/v0/projects/info/<project_names>

      +
      +

      Return information about the comma-separated list of projects. It includes the description +of the package along with the list of available builds.

      +

      Example:

      +
      {
      +  "projects": [
      +    {
      +      "builds": [
      +        {
      +          "arch": "x86_64",
      +          "build_config_ref": "BUILD_CONFIG_REF",
      +          "build_env_ref": "BUILD_ENV_REF",
      +          "build_time": "2017-03-01T08:39:23",
      +          "changelog": "- restore incremental backups correctly, files ...",
      +          "epoch": "2",
      +          "metadata": {},
      +          "release": "32.el7",
      +          "source": {
      +            "license": "GPLv3+",
      +            "metadata": {},
      +            "source_ref": "SOURCE_REF",
      +            "version": "1.26"
      +          }
      +        }
      +      ],
      +      "description": "The GNU tar program saves many ...",
      +      "homepage": "http://www.gnu.org/software/tar/",
      +      "name": "tar",
      +      "summary": "A GNU file archiving program",
      +      "upstream_vcs": "UPSTREAM_VCS"
      +    }
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_list()[source]¶
      +

      List all of the available projects/packages

      +

      /api/v0/projects/list[?offset=0&limit=20]

      +
      +

      List all of the available projects. By default this returns the first 20 items, +but this can be changed by setting the offset and limit arguments.

      +

      Example:

      +
      {
      +  "limit": 20,
      +  "offset": 0,
      +  "projects": [
      +    {
      +      "description": "0 A.D. (pronounced "zero ey-dee") is a ...",
      +      "homepage": "http://play0ad.com",
      +      "name": "0ad",
      +      "summary": "Cross-Platform RTS Game of Ancient Warfare",
      +      "upstream_vcs": "UPSTREAM_VCS"
      +    },
      +    ...
      +  ],
      +  "total": 21770
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_source_delete(source_name)[source]¶
      +

      Delete the named source and return a status response

      +

      DELETE /api/v0/projects/source/delete/<source-name>

      +
      +

      Delete a user added source. This will fail if a system source is passed to +it.

      +

      The response will be a status response with status set to true, or an +error response with it set to false and an error message included.

      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_source_info(source_names)[source]¶
      +

      Return detailed info about the list of sources

      +

      /api/v0/projects/source/info/<source-names>

      +
      +

      Return information about the comma-separated list of source names. Or all of the +sources if '*' is passed. Note that general globbing is not supported, only '*'.

      +

      immutable system sources will have the "system" field set to true. User added sources +will have it set to false. System sources cannot be changed or deleted.

      +

      Example:

      +
      {
      +  "errors": [],
      +  "sources": {
      +    "fedora": {
      +      "check_gpg": true,
      +      "check_ssl": true,
      +      "gpgkey_urls": [
      +        "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64"
      +      ],
      +      "name": "fedora",
      +      "proxy": "http://proxy.brianlane.com:8123",
      +      "system": true,
      +      "type": "yum-metalink",
      +      "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64"
      +    }
      +  }
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_source_list()[source]¶
      +

      Return the list of source names

      +

      /api/v0/projects/source/list

      +
      +

      Return the list of repositories used for depsolving and installing packages.

      +

      Example:

      +
      {
      +  "sources": [
      +    "fedora",
      +    "fedora-cisco-openh264",
      +    "fedora-updates-testing",
      +    "fedora-updates"
      +  ]
      +}
      +
      +
      +
      +
      + +
      +
      +pylorax.api.v0.v0_projects_source_new()[source]¶
      +

      Add a new package source. Or change an existing one

      +

      POST /api/v0/projects/source/new

      +
      +

      Add (or change) a source for use when depsolving blueprints and composing images.

      +

      The proxy and gpgkey_urls entries are optional. All of the others are required. The supported +types for the urls are:

      +
        +
      • yum-baseurl is a URL to a yum repository.

      • +
      • yum-mirrorlist is a URL for a mirrorlist.

      • +
      • yum-metalink is a URL for a metalink.

      • +
      +

      If check_ssl is true the https certificates must be valid. If they are self-signed you can either set +this to false, or add your Certificate Authority to the host system.

      +

      If check_gpg is true the GPG key must either be installed on the host system, or gpgkey_urls +should point to it.

      +

      You can edit an existing source (other than system sources), by doing a POST +of the new version of the source. It will overwrite the previous one.

      +

      Example:

      +
      {
      +    "name": "custom-source-1",
      +    "url": "https://url/path/to/repository/",
      +    "type": "yum-baseurl",
      +    "check_ssl": true,
      +    "check_gpg": true,
      +    "gpgkey_urls": [
      +        "https://url/path/to/gpg-key"
      +    ]
      +}
      +
      +
      +
      +
      +
      @@ -3904,11 +4152,6 @@ a line boundry.

      Module contents¶

      -
      -
      -pylorax.api.crossdomain(origin, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True)[source]¶
      -
      -
      diff --git a/pylorax.html b/pylorax.html index bee594ff..19909fa2 100644 --- a/pylorax.html +++ b/pylorax.html @@ -8,7 +8,7 @@ - pylorax package — Lorax 31.4 documentation + pylorax package — Lorax 31.7 documentation @@ -60,7 +60,7 @@
      - 31.4 + 31.7
      @@ -205,9 +205,9 @@
    • pylorax.api.config module
    • -
    • pylorax.api.crossdomain module
    • pylorax.api.dnfbase module
    • pylorax.api.errors module
    • +
    • pylorax.api.flask_blueprint module
    • pylorax.api.gitrpm module
    • pylorax.api.projects module
    • pylorax.api.queue module
    • @@ -215,47 +215,10 @@
    • pylorax.api.regexes module
    • pylorax.api.server module
    • pylorax.api.timestamp module
    • +
    • pylorax.api.toml module
    • pylorax.api.v0 module
    • pylorax.api.workspace module
    • diff --git a/search.html b/search.html index 449ee2b7..01f966a8 100644 --- a/search.html +++ b/search.html @@ -8,7 +8,7 @@ - Search — Lorax 31.4 documentation + Search — Lorax 31.7 documentation @@ -59,7 +59,7 @@
      - 31.4 + 31.7
      diff --git a/searchindex.js b/searchindex.js index 56da47a4..fb4d74b9 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["composer","composer-cli","composer.cli","index","intro","livemedia-creator","lorax","lorax-composer","modules","product-images","pylorax","pylorax.api"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["composer.rst","composer-cli.rst","composer.cli.rst","index.rst","intro.rst","livemedia-creator.rst","lorax.rst","lorax-composer.rst","modules.rst","product-images.rst","pylorax.rst","pylorax.api.rst"],objects:{"":{composer:[0,0,0,"-"],pylorax:[10,0,0,"-"]},"composer.cli":{blueprints:[2,0,0,"-"],cmdline:[2,0,0,"-"],compose:[2,0,0,"-"],help:[2,0,0,"-"],main:[2,1,1,""],modules:[2,0,0,"-"],projects:[2,0,0,"-"],sources:[2,0,0,"-"],status:[2,0,0,"-"],utilities:[2,0,0,"-"]},"composer.cli.blueprints":{blueprints_changes:[2,1,1,""],blueprints_cmd:[2,1,1,""],blueprints_delete:[2,1,1,""],blueprints_depsolve:[2,1,1,""],blueprints_diff:[2,1,1,""],blueprints_freeze:[2,1,1,""],blueprints_freeze_save:[2,1,1,""],blueprints_freeze_show:[2,1,1,""],blueprints_list:[2,1,1,""],blueprints_push:[2,1,1,""],blueprints_save:[2,1,1,""],blueprints_show:[2,1,1,""],blueprints_tag:[2,1,1,""],blueprints_undo:[2,1,1,""],blueprints_workspace:[2,1,1,""],prettyCommitDetails:[2,1,1,""],prettyDiffEntry:[2,1,1,""]},"composer.cli.cmdline":{composer_cli_parser:[2,1,1,""]},"composer.cli.compose":{compose_cancel:[2,1,1,""],compose_cmd:[2,1,1,""],compose_delete:[2,1,1,""],compose_image:[2,1,1,""],compose_info:[2,1,1,""],compose_list:[2,1,1,""],compose_log:[2,1,1,""],compose_logs:[2,1,1,""],compose_metadata:[2,1,1,""],compose_results:[2,1,1,""],compose_start:[2,1,1,""],compose_status:[2,1,1,""],compose_types:[2,1,1,""]},"composer.cli.modules":{modules_cmd:[2,1,1,""]},"composer.cli.projects":{projects_cmd:[2,1,1,""],projects_info:[2,1,1,""],projects_list:[2,1,1,""]},"composer.cli.sources":{sources_add:[2,1,1,""],sources_cmd:[2,1,1,""],sources_delete:[2,1,1,""],sources_info:[2,1,1,""],sources_list:[2,1,1,""]},"composer.cli.status":{status_cmd:[2,1,1,""]},"composer.cli.utilities":{argify:[2,1,1,""],frozen_toml_filename:[2,1,1,""],handle_api_result:[2,1,1,""],packageNEVRA:[2,1,1,""],toml_filename:[2,1,1,""]},"composer.http_client":{api_url:[0,1,1,""],append_query:[0,1,1,""],delete_url_json:[0,1,1,""],download_file:[0,1,1,""],get_filename:[0,1,1,""],get_url_json:[0,1,1,""],get_url_json_unlimited:[0,1,1,""],get_url_raw:[0,1,1,""],post_url:[0,1,1,""],post_url_json:[0,1,1,""],post_url_toml:[0,1,1,""]},"composer.unix_socket":{UnixHTTPConnection:[0,2,1,""],UnixHTTPConnectionPool:[0,2,1,""]},"composer.unix_socket.UnixHTTPConnection":{connect:[0,3,1,""]},"pylorax.ArchData":{bcj_arch:[10,4,1,""],lib64_arches:[10,4,1,""]},"pylorax.Lorax":{configure:[10,3,1,""],init_file_logging:[10,3,1,""],init_stream_logging:[10,3,1,""],run:[10,3,1,""],templatedir:[10,4,1,""]},"pylorax.api":{bisect:[11,0,0,"-"],checkparams:[11,0,0,"-"],cmdline:[11,0,0,"-"],compose:[11,0,0,"-"],config:[11,0,0,"-"],crossdomain:[11,0,0,"-"],dnfbase:[11,0,0,"-"],errors:[11,0,0,"-"],gitrpm:[11,0,0,"-"],projects:[11,0,0,"-"],queue:[11,0,0,"-"],recipes:[11,0,0,"-"],regexes:[11,0,0,"-"],server:[11,0,0,"-"],timestamp:[11,0,0,"-"],v0:[11,0,0,"-"],workspace:[11,0,0,"-"]},"pylorax.api.bisect":{insort_left:[11,1,1,""]},"pylorax.api.checkparams":{checkparams:[11,1,1,""]},"pylorax.api.cmdline":{lorax_composer_parser:[11,1,1,""]},"pylorax.api.compose":{add_customizations:[11,1,1,""],bootloader_append:[11,1,1,""],compose_args:[11,1,1,""],compose_types:[11,1,1,""],customize_ks_template:[11,1,1,""],firewall_cmd:[11,1,1,""],get_default_services:[11,1,1,""],get_extra_pkgs:[11,1,1,""],get_firewall_settings:[11,1,1,""],get_kernel_append:[11,1,1,""],get_keyboard_layout:[11,1,1,""],get_languages:[11,1,1,""],get_services:[11,1,1,""],get_timezone_settings:[11,1,1,""],keyboard_cmd:[11,1,1,""],lang_cmd:[11,1,1,""],move_compose_results:[11,1,1,""],repo_to_ks:[11,1,1,""],services_cmd:[11,1,1,""],start_build:[11,1,1,""],test_templates:[11,1,1,""],timezone_cmd:[11,1,1,""],write_ks_group:[11,1,1,""],write_ks_root:[11,1,1,""],write_ks_user:[11,1,1,""]},"pylorax.api.config":{ComposerConfig:[11,2,1,""],configure:[11,1,1,""],make_dnf_dirs:[11,1,1,""],make_owned_dir:[11,1,1,""],make_queue_dirs:[11,1,1,""]},"pylorax.api.config.ComposerConfig":{get_default:[11,3,1,""]},"pylorax.api.crossdomain":{crossdomain:[11,1,1,""]},"pylorax.api.dnfbase":{DNFLock:[11,2,1,""],get_base_object:[11,1,1,""]},"pylorax.api.dnfbase.DNFLock":{lock:[11,4,1,""],lock_check:[11,4,1,""]},"pylorax.api.gitrpm":{GitArchiveTarball:[11,2,1,""],GitRpmBuild:[11,2,1,""],create_gitrpm_repo:[11,1,1,""],get_repo_description:[11,1,1,""],make_git_rpm:[11,1,1,""]},"pylorax.api.gitrpm.GitArchiveTarball":{write_file:[11,3,1,""]},"pylorax.api.gitrpm.GitRpmBuild":{add_git_tarball:[11,3,1,""],check:[11,3,1,""],clean:[11,3,1,""],cleanup_tmpdir:[11,3,1,""],get_base_dir:[11,3,1,""]},"pylorax.api.projects":{ProjectsError:[11,5,1,""],api_changelog:[11,1,1,""],api_time:[11,1,1,""],delete_repo_source:[11,1,1,""],dep_evra:[11,1,1,""],dep_nevra:[11,1,1,""],dnf_repo_to_file_repo:[11,1,1,""],estimate_size:[11,1,1,""],get_repo_sources:[11,1,1,""],get_source_ids:[11,1,1,""],modules_info:[11,1,1,""],modules_list:[11,1,1,""],pkg_to_build:[11,1,1,""],pkg_to_dep:[11,1,1,""],pkg_to_project:[11,1,1,""],pkg_to_project_info:[11,1,1,""],proj_to_module:[11,1,1,""],projects_depsolve:[11,1,1,""],projects_depsolve_with_size:[11,1,1,""],projects_info:[11,1,1,""],projects_list:[11,1,1,""],repo_to_source:[11,1,1,""],source_to_repo:[11,1,1,""]},"pylorax.api.queue":{build_status:[11,1,1,""],check_queues:[11,1,1,""],compose_detail:[11,1,1,""],get_compose_type:[11,1,1,""],get_image_name:[11,1,1,""],make_compose:[11,1,1,""],monitor:[11,1,1,""],queue_status:[11,1,1,""],start_queue_monitor:[11,1,1,""],uuid_cancel:[11,1,1,""],uuid_delete:[11,1,1,""],uuid_image:[11,1,1,""],uuid_info:[11,1,1,""],uuid_log:[11,1,1,""],uuid_status:[11,1,1,""],uuid_tar:[11,1,1,""]},"pylorax.api.recipes":{CommitDetails:[11,2,1,""],CommitTimeValError:[11,5,1,""],NewRecipeGit:[11,1,1,""],Recipe:[11,2,1,""],RecipeError:[11,5,1,""],RecipeFileError:[11,5,1,""],RecipeGit:[11,2,1,""],RecipeGroup:[11,2,1,""],RecipeModule:[11,2,1,""],RecipePackage:[11,2,1,""],commit_recipe:[11,1,1,""],commit_recipe_directory:[11,1,1,""],commit_recipe_file:[11,1,1,""],delete_file:[11,1,1,""],delete_recipe:[11,1,1,""],diff_items:[11,1,1,""],find_commit_tag:[11,1,1,""],find_name:[11,1,1,""],get_commit_details:[11,1,1,""],get_revision_from_tag:[11,1,1,""],gfile:[11,1,1,""],head_commit:[11,1,1,""],is_commit_tag:[11,1,1,""],is_parent_diff:[11,1,1,""],list_branch_files:[11,1,1,""],list_commit_files:[11,1,1,""],list_commits:[11,1,1,""],open_or_create_repo:[11,1,1,""],prepare_commit:[11,1,1,""],read_commit:[11,1,1,""],read_commit_spec:[11,1,1,""],read_recipe_and_id:[11,1,1,""],read_recipe_commit:[11,1,1,""],recipe_diff:[11,1,1,""],recipe_filename:[11,1,1,""],recipe_from_dict:[11,1,1,""],recipe_from_file:[11,1,1,""],recipe_from_toml:[11,1,1,""],repo_file_exists:[11,1,1,""],revert_file:[11,1,1,""],revert_recipe:[11,1,1,""],tag_file_commit:[11,1,1,""],tag_recipe_commit:[11,1,1,""],write_commit:[11,1,1,""]},"pylorax.api.recipes.Recipe":{bump_version:[11,3,1,""],filename:[11,4,1,""],freeze:[11,3,1,""],group_names:[11,4,1,""],module_names:[11,4,1,""],module_nver:[11,4,1,""],package_names:[11,4,1,""],package_nver:[11,4,1,""],toml:[11,3,1,""]},"pylorax.api.server":{GitLock:[11,2,1,""]},"pylorax.api.server.GitLock":{dir:[11,4,1,""],lock:[11,4,1,""],repo:[11,4,1,""]},"pylorax.api.timestamp":{timestamp_dict:[11,1,1,""],write_timestamp:[11,1,1,""]},"pylorax.api.v0":{blueprint_exists:[11,1,1,""],take_limits:[11,1,1,""],v0_api:[11,1,1,""]},"pylorax.api.workspace":{workspace_delete:[11,1,1,""],workspace_dir:[11,1,1,""],workspace_read:[11,1,1,""],workspace_write:[11,1,1,""]},"pylorax.base":{BaseLoraxClass:[10,2,1,""],DataHolder:[10,2,1,""]},"pylorax.base.BaseLoraxClass":{pcritical:[10,3,1,""],pdebug:[10,3,1,""],perror:[10,3,1,""],pinfo:[10,3,1,""],pwarning:[10,3,1,""]},"pylorax.base.DataHolder":{copy:[10,3,1,""]},"pylorax.buildstamp":{BuildStamp:[10,2,1,""]},"pylorax.buildstamp.BuildStamp":{write:[10,3,1,""]},"pylorax.cmdline":{lmc_parser:[10,1,1,""],lorax_parser:[10,1,1,""]},"pylorax.creator":{FakeDNF:[10,2,1,""],calculate_disk_size:[10,1,1,""],check_kickstart:[10,1,1,""],create_pxe_config:[10,1,1,""],find_ostree_root:[10,1,1,""],get_arch:[10,1,1,""],is_image_mounted:[10,1,1,""],make_appliance:[10,1,1,""],make_image:[10,1,1,""],make_live_images:[10,1,1,""],make_livecd:[10,1,1,""],make_runtime:[10,1,1,""],make_squashfs:[10,1,1,""],mount_boot_part_over_root:[10,1,1,""],rebuild_initrds_for_live:[10,1,1,""],run_creator:[10,1,1,""],squashfs_args:[10,1,1,""]},"pylorax.creator.FakeDNF":{reset:[10,3,1,""]},"pylorax.decorators":{singleton:[10,1,1,""]},"pylorax.discinfo":{DiscInfo:[10,2,1,""]},"pylorax.discinfo.DiscInfo":{write:[10,3,1,""]},"pylorax.dnfbase":{get_dnf_base_object:[10,1,1,""]},"pylorax.dnfhelper":{LoraxDownloadCallback:[10,2,1,""],LoraxRpmCallback:[10,2,1,""]},"pylorax.dnfhelper.LoraxDownloadCallback":{end:[10,3,1,""],progress:[10,3,1,""],start:[10,3,1,""]},"pylorax.dnfhelper.LoraxRpmCallback":{error:[10,3,1,""],progress:[10,3,1,""]},"pylorax.executils":{ExecProduct:[10,2,1,""],augmentEnv:[10,1,1,""],execReadlines:[10,1,1,""],execWithCapture:[10,1,1,""],execWithRedirect:[10,1,1,""],runcmd:[10,1,1,""],runcmd_output:[10,1,1,""],setenv:[10,1,1,""],startProgram:[10,1,1,""]},"pylorax.imgutils":{DMDev:[10,2,1,""],LoopDev:[10,2,1,""],Mount:[10,2,1,""],PartitionMount:[10,2,1,""],compress:[10,1,1,""],copytree:[10,1,1,""],default_image_name:[10,1,1,""],dm_attach:[10,1,1,""],dm_detach:[10,1,1,""],do_grafts:[10,1,1,""],estimate_size:[10,1,1,""],get_loop_name:[10,1,1,""],kpartx_disk_img:[10,1,1,""],loop_attach:[10,1,1,""],loop_detach:[10,1,1,""],loop_waitfor:[10,1,1,""],mkbtrfsimg:[10,1,1,""],mkcpio:[10,1,1,""],mkdosimg:[10,1,1,""],mkext4img:[10,1,1,""],mkfsimage:[10,1,1,""],mkfsimage_from_disk:[10,1,1,""],mkhfsimg:[10,1,1,""],mkqcow2:[10,1,1,""],mkqemu_img:[10,1,1,""],mkrootfsimg:[10,1,1,""],mksparse:[10,1,1,""],mksquashfs:[10,1,1,""],mktar:[10,1,1,""],mount:[10,1,1,""],round_to_blocks:[10,1,1,""],umount:[10,1,1,""]},"pylorax.installer":{InstallError:[10,5,1,""],QEMUInstall:[10,2,1,""],anaconda_cleanup:[10,1,1,""],append_initrd:[10,1,1,""],create_vagrant_metadata:[10,1,1,""],find_free_port:[10,1,1,""],novirt_cancel_check:[10,1,1,""],novirt_install:[10,1,1,""],update_vagrant_metadata:[10,1,1,""],virt_install:[10,1,1,""]},"pylorax.installer.QEMUInstall":{QEMU_CMDS:[10,4,1,""]},"pylorax.ltmpl":{LiveTemplateRunner:[10,2,1,""],LoraxTemplate:[10,2,1,""],LoraxTemplateRunner:[10,2,1,""],TemplateRunner:[10,2,1,""],brace_expand:[10,1,1,""],rexists:[10,1,1,""],rglob:[10,1,1,""],split_and_expand:[10,1,1,""]},"pylorax.ltmpl.LiveTemplateRunner":{installpkg:[10,3,1,""]},"pylorax.ltmpl.LoraxTemplate":{parse:[10,3,1,""]},"pylorax.ltmpl.LoraxTemplateRunner":{append:[10,3,1,""],chmod:[10,3,1,""],copy:[10,3,1,""],createaddrsize:[10,3,1,""],hardlink:[10,3,1,""],install:[10,3,1,""],installimg:[10,3,1,""],installinitrd:[10,3,1,""],installkernel:[10,3,1,""],installpkg:[10,3,1,""],installupgradeinitrd:[10,3,1,""],log:[10,3,1,""],mkdir:[10,3,1,""],move:[10,3,1,""],remove:[10,3,1,""],removefrom:[10,3,1,""],removekmod:[10,3,1,""],removepkg:[10,3,1,""],replace:[10,3,1,""],run_pkg_transaction:[10,3,1,""],runcmd:[10,3,1,""],symlink:[10,3,1,""],systemctl:[10,3,1,""],treeinfo:[10,3,1,""]},"pylorax.ltmpl.TemplateRunner":{run:[10,3,1,""]},"pylorax.monitor":{LogMonitor:[10,2,1,""],LogRequestHandler:[10,2,1,""],LogServer:[10,2,1,""]},"pylorax.monitor.LogMonitor":{shutdown:[10,3,1,""]},"pylorax.monitor.LogRequestHandler":{finish:[10,3,1,""],handle:[10,3,1,""],iserror:[10,3,1,""],re_tests:[10,4,1,""],setup:[10,3,1,""],simple_tests:[10,4,1,""]},"pylorax.monitor.LogServer":{log_check:[10,3,1,""],timeout:[10,4,1,""]},"pylorax.mount":{IsoMountpoint:[10,2,1,""]},"pylorax.mount.IsoMountpoint":{get_iso_label:[10,3,1,""],umount:[10,3,1,""]},"pylorax.sysutils":{chmod_:[10,1,1,""],chown_:[10,1,1,""],joinpaths:[10,1,1,""],linktree:[10,1,1,""],remove:[10,1,1,""],replace:[10,1,1,""],touch:[10,1,1,""]},"pylorax.treebuilder":{RuntimeBuilder:[10,2,1,""],TreeBuilder:[10,2,1,""],findkernels:[10,1,1,""],generate_module_info:[10,1,1,""],string_lower:[10,1,1,""],udev_escape:[10,1,1,""]},"pylorax.treebuilder.RuntimeBuilder":{cleanup:[10,3,1,""],create_ext4_runtime:[10,3,1,""],create_squashfs_runtime:[10,3,1,""],finished:[10,3,1,""],generate_module_data:[10,3,1,""],install:[10,3,1,""],postinstall:[10,3,1,""],verify:[10,3,1,""],writepkglists:[10,3,1,""],writepkgsizes:[10,3,1,""]},"pylorax.treebuilder.TreeBuilder":{build:[10,3,1,""],copy_dracut_hooks:[10,3,1,""],dracut_hooks_path:[10,4,1,""],implantisomd5:[10,3,1,""],kernels:[10,4,1,""],rebuild_initrds:[10,3,1,""]},"pylorax.treeinfo":{TreeInfo:[10,2,1,""]},"pylorax.treeinfo.TreeInfo":{add_section:[10,3,1,""],write:[10,3,1,""]},composer:{cli:[2,0,0,"-"],http_client:[0,0,0,"-"],unix_socket:[0,0,0,"-"]},pylorax:{ArchData:[10,2,1,""],Lorax:[10,2,1,""],api:[11,0,0,"-"],base:[10,0,0,"-"],buildstamp:[10,0,0,"-"],cmdline:[10,0,0,"-"],creator:[10,0,0,"-"],decorators:[10,0,0,"-"],discinfo:[10,0,0,"-"],dnfbase:[10,0,0,"-"],dnfhelper:[10,0,0,"-"],executils:[10,0,0,"-"],find_templates:[10,1,1,""],get_buildarch:[10,1,1,""],imgutils:[10,0,0,"-"],installer:[10,0,0,"-"],log_selinux_state:[10,1,1,""],ltmpl:[10,0,0,"-"],monitor:[10,0,0,"-"],mount:[10,0,0,"-"],output:[10,0,0,"-"],setup_logging:[10,1,1,""],sysutils:[10,0,0,"-"],treebuilder:[10,0,0,"-"],treeinfo:[10,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:method","4":"py:attribute","5":"py:exception"},terms:{"01t08":11,"03374adbf080fe34f5c6c29f2e49cc2b86958bf2":11,"03397f8d":11,"06e8":11,"08t00":11,"0ad":11,"0e08ecbb708675bfabc82952599a1712a843779d":11,"0instal":11,"10t23":11,"11t00":11,"11t01":11,"13z":11,"1kb":2,"1mbyte":11,"23t00":11,"28z":11,"29b492f26ed35d80800b536623bafc51e2f0eff2":11,"2b4174b3614b":11,"2ping":11,"30z":11,"3700mib":10,"3726a1093fd0":11,"397f":11,"3e11eb87a63d289662cba4b1804a0947a6843379":11,"3rn8evie2t50lmvybyihtgvrhcaecmeck31l":7,"41ef9c3e4b73":11,"44c0":11,"45502a6d":11,"45e380f39894":11,"47z":11,"48a5":11,"4a23":11,"4af9":11,"4b70":11,"4b8a":11,"4c68":11,"4c9f":11,"4cdb":11,"523b":11,"52z":11,"56z":11,"61b799739ce8":11,"6d292bd0":11,"7078e521a54b12eae31c3fd028680da7a0815a4d":11,"70b84195":11,"745712b2":11,"7f16":11,"870f":11,"8c8435ef":11,"8d7d":11,"96db":11,"99anaconda":10,"9bf1":11,"9c81":11,"byte":11,"case":[7,11],"catch":[5,10],"char":10,"class":[0,9,10,11],"default":[1,5,6,7,10,11],"final":[1,4,5,6,7,9,10,11],"function":[2,7,10,11],"import":[5,10],"int":[2,10,11],"new":[0,1,2,4,5,6,7,10],"null":[5,11],"public":[5,7],"return":[0,1,2,7,10,11],"short":7,"switch":5,"true":[0,2,5,6,7,10,11],"try":[5,10,11],"var":[5,6,7,10],"while":[7,9,10,11],ADDING:10,Adding:10,And:[5,7],But:[5,7],For:[0,5,7,10],Its:[4,6],NOT:11,Not:10,One:[5,7],RTS:11,The:[0,1,2,4,5,7,9,10,11],There:[5,7,10,11],These:[7,9,11],Use:[5,6,10,11],Used:[5,10],Uses:11,Using:11,Will:10,Yes:10,__init__:0,_io:10,_map:7,a215:11,a2ef832e6b1a:11,a697ca405cdf:11,aarch64:[6,9,10],abbrevi:5,abl:[6,7],abort:5,about:[1,2,5,11],abov:5,absolut:10,accept:7,access:[5,7,11],accomplish:5,account:[7,10],acff:11,acl:[10,11],action:10,activ:[5,7],actual:[10,11],ad52:11,add2636e7459:11,add:[0,1,2,5,6,9,10,11],add_arch_templ:[6,10],add_arch_template_var:[6,10],add_arg:10,add_custom:11,add_git_tarbal:11,add_sect:10,add_templ:[6,10],add_template_var:[6,10],added:[5,7,10,11],adding:[7,10],addit:[2,5,6,7,10,11],addon:11,addr:10,addrsiz:10,admin:7,administr:7,ae1bf7e3:11,af92:11,afford:5,after:[5,6,10,11],against:5,alia:11,alibaba:1,align:5,all:[0,1,2,4,5,6,7,9,10,11],allbut:[6,10],alloc:5,allow:[5,6,7],allow_no_valu:11,almost:4,along:[6,11],alreadi:[7,10,11],also:[1,5,6,7,10,11],alwai:[5,7,11],amazon:5,america:7,ami:[1,7],amount:7,anaconda:[1,4,6,7,9,10,11],anaconda_arg:[5,11],anaconda_cleanup:10,anaconfigurationthread:11,ancient:11,ani:[0,1,2,5,7,10,11],anoth:[5,6,10],anyth:[9,11],anywher:10,api:[0,1,2,7,8,10],api_changelog:11,api_tim:11,api_url:0,api_vers:[0,2],apiv:1,app:5,app_fil:5,app_nam:5,app_templ:5,appear:10,append:[0,2,5,6,7,10,11],append_initrd:10,append_queri:0,appli:[1,10,11],applianc:10,applic:[7,11],appropri:[5,10],arbitrari:[6,7],arch:[2,4,5,6,10,11],archdata:10,architectur:[4,5,6,10],archiv:[5,7,9,10,11],aren:[6,11],arg:[1,2,5,6,10,11],argifi:2,argpars:[2,10],argument:[0,2,10,11],argumentpars:[2,10,11],argv:10,arm:[5,10],armhfp:10,armplatform:[5,11],around:5,artifact:[5,11],assembl:11,associ:10,assum:[10,11],atla:11,attach:10,attach_to_al:11,attempt:[4,10,11],attribut:[5,11],audit:11,augmentenv:10,authent:11,author:[1,5,6,7,11],authorized_kei:7,automat:[7,10],automatic_opt:11,avahi:11,avail:[1,2,5,7,11],awar:7,b36e:11,back:[1,10],backup:[10,11],bare:[5,11],base:[0,5,6,7,8,11],basearch:10,baseimag:7,baseloraxclass:10,basenam:10,baserequesthandl:10,basesystem:11,baseurl:[5,7,11],bash:[4,5,7,11],basic:[1,6],bcj_arch:10,bcl:[1,5,6,7],bd31:11,bdc:7,bec7:11,becaus:[5,6,7,11],becom:[5,7],been:[5,10,11],befor:[3,5,6,7,10],behind:[7,10],being:[5,6,7,11],below:[5,6,11],best:[5,6,7,11],better:10,between:[1,2,7,10,11],big:10,bin:[5,7,10],binari:[5,10],binary_output:10,bind:5,bind_mount_opt:5,bio:5,bisect:[8,10],bit:7,blob:11,block:[6,7,10,11],block_siz:11,blocksiz:10,blog:7,blueprint:[0,8,10],blueprint_exist:11,blueprint_nam:[2,10],blueprints_chang:2,blueprints_cmd:2,blueprints_delet:2,blueprints_depsolv:2,blueprints_diff:2,blueprints_freez:2,blueprints_freeze_sav:2,blueprints_freeze_show:2,blueprints_list:2,blueprints_push:2,blueprints_sav:2,blueprints_show:2,blueprints_tag:2,blueprints_undo:2,blueprints_workspac:2,bodi:[0,11],bool:[2,10,11],boot:[1,4,6,7,9,10,11],boot_uefi:10,bootabl:5,bootdir:10,bootload:[5,7,11],bootloader_append:11,bootproto:5,both:[5,7,11],bound:11,boundri:11,box:5,brace:10,brace_expand:10,branch:[5,7,11],brian:[1,5,6,7],brianlan:11,browser:7,bug:[5,6,7],bugurl:[6,10],bugzilla:5,build:[2,4,5,6,7,9,10,11],build_config_ref:11,build_env_ref:11,build_id:11,build_statu:11,build_tim:11,buildarch:[6,10],builder:[5,11],buildinstal:4,buildsi:5,buildstamp:8,built:[6,10,11],builtin:10,bump:[7,11],bump_vers:11,bunch:10,bundl:5,bzip2:[5,10],c30b7d80:11,cach:[5,6,7,10],cachedir:[6,10],calcul:10,calculate_disk_s:10,call:[4,5,10,11],callback:10,calledprocesserror:10,caller:11,can:[1,2,5,6,7,9,10,11],cancel:[1,2,5,10],cancel_func:10,cannot:[0,5,6,7,11],captur:10,care:[10,11],cat:5,categor:7,caught:[5,11],caus:[7,10],cdboot:7,cdlabel:10,cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3:11,central:4,cert:10,certif:[6,7,11],cfg:[10,11],chang:[1,2,5,6,7,10],changelog:[1,11],charact:[7,10],check:[7,10,11],check_gpg:[7,11],check_kickstart:10,check_queu:11,check_ssl:[7,11],checkparam:[8,10],checksum:5,checksum_typ:5,child:10,chmod:[6,10],chmod_:10,cho2:7,choos:5,chosen:[5,10,11],chown_:10,chronyd:7,chroot:[5,6,9,10],chroot_setup_cmd:5,chvt:5,cisco:11,clean:[4,5,7,11],cleanup:[5,10,11],cleanup_tmpdir:11,clear:[4,7,11],clearpart:5,cli:[0,3,7,8,11],client:[0,5,11],client_address:10,clone:[7,11],close:10,cloud:[5,7],cls:10,cmd:[7,10],cmdline:[0,8],cmdlist:10,cockpit:7,code:[6,7,10,11],collect:11,com:[1,5,6,7,11],combin:[2,5],come:11,comma:[2,10,11],command:[0,1,2,4,5,6,7,9,10,11],commandlin:[1,7,10],comment_prefix:11,commit:[1,2,7,10],commit_id:11,commit_recip:11,commit_recipe_directori:11,commit_recipe_fil:11,commitdetail:11,committimevalerror:11,common:[5,6],commonli:7,commun:[0,2,7],comoposit:11,compar:11,compat:7,complet:[4,7,10,11],compon:5,compos:[3,8,10],compose_arg:[7,11],compose_cancel:2,compose_cmd:2,compose_delet:2,compose_detail:11,compose_imag:2,compose_info:2,compose_list:2,compose_log:2,compose_metadata:2,compose_result:2,compose_start:2,compose_statu:[2,10],compose_typ:[2,7,10],composer_cli_pars:2,composerconfig:11,composerpars:11,composit:11,compress:[5,9,10,11],compress_arg:[5,11],compressarg:10,compressopt:10,comput:10,conf:[4,6,7,10,11],conf_fil:[10,11],config:[5,6,7,8,10],config_opt:5,configfil:6,configpars:11,configur:[4,5,6,7,10,11],conflict:[6,7],connect:0,connectionpool:0,consist:[1,4],consol:7,construct:[7,10],constructor:11,contain:[4,6,7,9,10,11],content:[3,6,7,8,9],context:10,continu:[2,10],control:[4,7,10,11],convent:5,convert:[2,5,7,10,11],copi:[1,4,5,6,7,9,10,11],copy_dracut_hook:10,copyin:5,copytre:10,core:5,correct:[2,4,5,7,10,11],correctli:[5,7,10,11],correspond:10,could:[5,7],count:11,coupl:5,cpio:10,cpu:10,crash:10,creat:[1,4,6,7,9,10,11],create_ext4_runtim:10,create_gitrpm_repo:11,create_pxe_config:10,create_squashfs_runtim:10,create_vagrant_metadata:10,createaddrs:10,createrepo:5,createrepo_c:11,creation:[4,9,10,11],creator:[3,7,8,11],cross:11,crossdomain:[8,10],current:[1,4,5,7,10,11],custom:[4,5,9,11],customize_ks_templ:11,cwd:0,d6bd:11,data:[0,4,5,10,11],datahold:[10,11],dbo:[10,11],debug:[7,10],decod:10,decor:8,dee:11,default_image_nam:10,default_sect:11,defin:[5,7,11],delai:[7,10],delet:[0,1,2,5,6,7,10],delete_fil:11,delete_recip:11,delete_repo_sourc:11,delete_url_json:0,delimit:11,denial:[5,7],dep:11,dep_evra:11,dep_nevra:11,depend:[1,2,5,6,9,11],deploy:[7,10,11],depmod:10,depsolv:[1,2,7,10],describ:[5,7,11],descript:[1,5,7,10,11],desir:11,desktop:5,dest:[10,11],destdir:11,destfil:10,destin:[6,7,10,11],detach:10,detail:[1,2,7,11],detect:[5,10],dev:[5,6,10],devel:5,develop:[5,7,11],devic:[5,6,10],devicemapp:10,dhcp:[5,7],dialog:5,dict:[0,2,10,11],dict_typ:11,dictionari:11,didn:5,died:5,diff:[1,2,10],diff_item:11,differ:[1,2,5,7,10,11],difficult:11,dir:[5,6,10,11],direcori:10,direct:11,directli:[2,5,7,11],directori:[1,5,6,7,9,10,11],dirinstall_path:10,disabl:[6,7,10,11],disablerepo:[6,10],discinfo:[6,8],disk:[1,10],disk_imag:5,disk_img:10,disk_info:5,disk_siz:10,diskimag:10,dispatch:2,displai:[1,2,5,7],disposit:0,distribut:[6,7],dm_attach:10,dm_detach:10,dmdev:10,dmsetup:10,dnf:[6,7,10,11],dnf_conf:11,dnf_obj:10,dnf_repo_to_file_repo:11,dnfbase:8,dnfhelper:8,dnflock:11,dnfplugin:[6,10],do_graft:10,doc:[5,7],document:[5,6,7],doe:[2,5,6,7,10,11],doesn:[2,5,7,10,11],doing:[5,7,11],domacboot:10,domain:7,don:[5,10,11],done:[1,10,11],doupgrad:10,down:11,download:[0,2,6,10,11],download_fil:0,downloadprogress:10,dracut:10,dracut_arg:[5,6],dracut_default:10,dracut_hook:10,dracut_hooks_path:10,drawback:5,drive:6,driven:4,driver:[4,10],drop:[7,9],dst:10,due:5,dump:11,dure:2,dyy8gj:11,e083921a7ed1cf2eec91ad12b9ad1e70ef3470b:11,e695affd:11,e6fa6db4:11,each:[1,2,5,6,7,10,11],easi:10,easier:5,eastern:7,ec2:5,echo:5,edit:[7,11],edk2:5,effect:7,efi:[5,7],either:[5,7,10,11],el7:11,els:10,emit:10,empti:[6,7,10,11],empty_lines_in_valu:11,en_u:7,enabl:[5,6,7,10,11],enablerepo:[6,10],encod:10,encount:[5,11],encrypt:7,end:[1,5,6,7,10,11],endfor:10,endif:6,enforc:[5,7,11],enhanc:5,enough:10,ensur:[10,11],enter:11,entir:7,entri:[2,5,7,10,11],env_add:10,env_prun:10,environ:[5,6,7,10],epoch:[2,11],equival:10,err:10,error:[2,5,7,8,10],escap:10,especi:7,estim:11,estimate_s:[10,11],etc:[5,6,7,10,11],even:[5,6,11],ever:0,everi:11,everyth:[5,6,10],exact:[7,11],exactli:[7,11],examin:5,exampl:[1,2,5,9,10,11],except:[5,6,7,10,11],exclud:10,excludepkg:[6,10],exec:5,execproduct:10,execreadlin:10,execut:[2,4,7,10],executil:8,execwithcaptur:10,execwithredirect:10,exist:[0,1,4,5,6,7,10,11],exit:[1,2,5,6,7,10],expand:10,expans:10,expect:[5,7,10],experi:10,expir:11,expire_sec:11,explicitli:7,explor:1,exract:11,ext4:[1,6,7,10],extend:7,extens:[1,6],extern:10,extra:[2,5,7,11],extra_boot_arg:[5,10],extract:[10,11],f15:5,f16:5,f629b7a948f5:11,fail:[1,2,7,10],failur:[10,11],fairli:6,fakednf:10,fals:[1,2,5,6,7,10,11],far:5,fatal:[5,10],fatalerror:10,fe925c35e795:11,featur:5,fedora:[3,5,6,7,10,11],fedoraproject:[5,6,11],feedback:5,fetch:[0,10],few:[5,6],field:[7,11],figur:4,fila:11,file:[0,1,2,4,6,7,9,10,11],fileglob:10,filenam:[0,1,2,10,11],filesystem:[1,7,9,10,11],fill:11,filter:10,filter_stderr:10,find:[0,4,5,10,11],find_commit_tag:11,find_free_port:10,find_nam:11,find_ostree_root:10,find_templ:10,findkernel:10,fine:7,finish:[1,2,6,7,10],firewal:11,firewall_cmd:11,firewalld:7,firmwar:5,first:[4,5,7,10,11],fit:5,five:2,fix:10,flag:10,flask:11,flatten:5,flexibl:4,fmt:10,fname:10,fobj:10,follow:[2,5,10,11],forc:[6,7,10,11],form:[0,6,11],format:[1,2,5,7,10],found:[5,7,10,11],four:2,free:[6,10],freez:[1,2,10],from:[0,1,2,4,5,6,7,9,10,11],from_commit:10,frozen:[1,2],frozen_toml_filenam:2,fs_imag:5,fs_label:5,fsck:10,fsimag:[5,10],fstab:5,fstype:[5,10],ftp:7,ftruncat:10,full:[0,7,10,11],further:10,futur:7,game:11,gener:[2,4,5,6,10,11],generate_module_data:10,generate_module_info:10,get:[0,5,7,10,11],get_arch:10,get_base_dir:11,get_base_object:11,get_buildarch:10,get_commit_detail:11,get_compose_typ:11,get_default:11,get_default_servic:11,get_dnf_base_object:10,get_extra_pkg:11,get_filenam:0,get_firewall_set:11,get_image_nam:11,get_iso_label:10,get_kernel_append:11,get_keyboard_layout:11,get_languag:11,get_loop_nam:10,get_repo_descript:11,get_repo_sourc:11,get_revision_from_tag:11,get_servic:11,get_source_id:11,get_timezone_set:11,get_url_json:0,get_url_json_unlimit:0,get_url_raw:0,gfile:11,ggit:11,gib:[5,6,10],gid:[7,11],git:[5,11],gitarchivetarbal:11,github:5,gitlock:11,gitrepo:11,gitrpm:[8,10],gitrpmbuild:11,given:[0,10,11],glanc:5,glob:[6,7,10,11],glusterf:11,gnome:5,gnu:11,goe:[4,6,10],going:5,good:[5,10],googl:[1,7],gpg:[7,11],gpgcheck:7,gpgkei:[7,11],gpgkey_url:[7,11],gplv3:11,graft:10,group:[1,5,10,11],group_nam:11,group_typ:11,grow:5,growpart:5,grub2:[5,7],grub:10,gui:7,gzip:[5,10],had:5,handl:[2,5,6,7,10],handle_api_result:2,handler:10,happen:[5,6,10],hard:11,hardlink:10,has:[2,5,7,9,10,11],hash:[1,2,7,11],have:[2,5,6,7,10,11],haven:5,hawkei:11,hda:1,head:[7,11],head_commit:11,header:[0,7,11],hello:5,help:[0,5,8,10],here:[4,5,6,7,9,11],higer:11,highbank:5,higher:6,histori:[7,11],hold:11,home:[5,7],homepag:11,hook:10,host:[0,5,6,7,10,11],hostnam:7,how:[4,10],howev:7,http:[0,1,2,5,6,7,10,11],http_client:8,httpconnect:0,httpconnectionpool:0,httpd:7,human:2,hw_random:10,hwmon:10,hyper:1,i386:10,ia64:10,id_rsa:7,idea:[4,5],ideal:10,identifi:[2,6],ids:11,ignor:10,imag:[2,3,4,6,10],image_nam:[5,7,11],image_s:11,image_size_align:5,image_typ:[5,10],images_dir:10,imap:7,img:[5,6,9,10],img_mount:10,img_siz:10,imgutil:8,immedi:7,immut:[7,11],implantisomd5:10,implement:[9,10],includ:[0,2,5,7,9,11],inclus:11,incom:10,increment:11,indent:2,index:[3,11],indic:10,individu:2,info:[1,2,7,10],inform:[1,2,4,6,7,11],init:[5,7,10],init_file_log:10,init_stream_log:10,initi:10,initramf:[5,6,10,11],initrd:[5,6,10],initrd_address:10,initrd_path:10,inject:7,inline_comment_prefix:11,input:[5,10],inroot:10,insecur:5,insert:11,insid:[5,10,11],insort_left:11,instal:[1,2,4,8,9,11],install_log:10,installclass:9,installerror:10,installimg:[9,10],installinitrd:10,installkernel:10,installpkg:[6,9,10,11],installroot:[6,10],installtre:10,installupgradeinitrd:10,instanc:[5,11],instead:[1,2,5,6,7,11],instroot:4,instruct:5,insuffici:10,integ:11,interact:1,interfac:7,interfer:6,intermedi:1,interpol:11,intrd:10,introduct:3,invalid:11,ioerror:11,is_commit_tag:11,is_image_mount:10,is_parent_diff:11,iserror:10,isfin:[6,10],isn:[5,10,11],iso:[1,4,10,11],iso_nam:5,iso_path:10,isoinfo:10,isolabel:10,isolinux:10,isomountpoint:10,issu:7,item:[2,10,11],iter:[10,11],its:[5,10,11],itself:7,jboss:11,job:11,job_creat:11,job_finish:11,job_start:11,joinpath:10,json:[0,1,2,5,7,10],just:[9,10],kbyte:10,kdir:10,keep:[1,5,10,11],keepglob:10,kei:[7,10,11],kernel:[5,6,10,11],kernel_append:11,kernel_arg:[5,10],keyboard:[7,11],keyboard_cmd:11,keymap:7,kickstart:[7,10,11],kickstartpars:10,kill:[5,10],knowledg:4,known:2,kpartx:[5,10],kpartx_disk_img:10,ks_path:10,ks_templat:11,ksflatten:5,kubernet:11,kvm:[1,5],kwarg:[10,11],label:[5,10],lambda:10,lane:[1,5,6,7],lang:11,lang_cmd:11,languag:[7,11],larg:[7,11],last:[1,2,10,11],later:[6,10],latest:5,launch:7,layout:11,lazi:10,lead:[0,10],least:[5,10],leav:[7,10,11],left:[7,10,11],leftmost:11,leftov:[5,10],len:11,less:11,level:[5,6,7,10,11],lib64_arch:10,lib:[7,10,11],librari:4,libus:11,libvirt:5,licens:11,light:6,like:[1,5,6,7,9,10,11],limit:[0,5,7,10],line:[4,7,10,11],link:10,linktre:10,linux:[5,6,10],list:[1,2,4,5,6,7,10],list_branch_fil:11,list_commit:11,list_commit_fil:11,listen:[1,7,10],live:[1,4,7,10,11],live_image_nam:10,live_rootfs_s:5,livecd:10,livemedia:[3,7,10,11],liveo:[6,10],livesi:5,livetemplaterunn:10,lmc:[5,10],lmc_parser:10,load:10,local:[1,5,10,11],localectl:7,localhost:10,locat:[5,6],lock:[7,11],lock_check:11,log:[1,2,5,6,10],log_check:10,log_error:10,log_output:10,log_path:10,log_request_handler_class:10,log_selinux_st:10,logdir:10,logfil:[1,5,6,7,10,11],logger:10,logic:6,logmonitor:10,lognam:10,logrequesthandl:10,logserv:10,longer:[7,11],look:[4,5,7,9,11],loop:[5,6,10],loop_attach:10,loop_detach:10,loop_dev:10,loop_waitfor:10,loopdev:10,loopx:10,loopxpn:10,lorax:[1,5,9,10,11],lorax_composer_pars:11,lorax_pars:10,lorax_templ:5,loraxdir:10,loraxdownloadcallback:10,loraxrpmcallback:10,loraxtempl:10,loraxtemplaterunn:[6,10],lose:5,losetup:10,lost:11,low:10,lowercas:10,lowest:10,lpar:10,lst:11,ltmpl:[6,8],lvm2:10,lzma:[5,10],macboot:[5,6],made:[7,10],mai:[5,6,7,10,11],mail:5,main:2,maintain:4,make:[5,6,7,10,11],make_:7,make_appli:10,make_compos:11,make_disk:7,make_dnf_dir:11,make_git_rpm:11,make_imag:10,make_live_imag:10,make_livecd:10,make_owned_dir:11,make_queue_dir:11,make_runtim:10,make_squashf:10,make_tar_disk:10,makestamp:4,maketreeinfo:4,mako:[4,5,6,10],manag:1,mandatori:[7,11],mani:11,manual:11,map:2,mask:10,master:11,match:[5,7,10,11],max_ag:11,maximum:11,maxretri:10,mbr:5,meant:[10,11],mechan:7,media:[5,10],megabyt:5,member:[1,5],memlimit:10,memori:[5,10],memtest86:5,mention:10,messag:[7,10,11],metadata:[1,2,5,6,7,10],metalink:[7,11],method:[5,7,10,11],mib:[5,10],mime:11,mind:[5,11],minim:[5,7,10],minimum:[5,11],minut:5,mirror:[5,10,11],mirrorlist:[6,7,10,11],mirrormanag:5,miss:[10,11],mix:4,mkbtrfsimg:10,mkcpio:10,mkdir:[5,6,10],mkdosimg:10,mkext4img:10,mkf:10,mkfsarg:10,mkfsimag:10,mkfsimage_from_disk:10,mkhfsimg:10,mknod:5,mkqcow2:10,mkqemu_img:10,mkrootfsimg:10,mkspars:10,mksquashf:10,mktar:10,mnt:[7,10],mock:[1,7],mockfil:7,moddir:10,mode:[1,5,6,10,11],modeless:10,modifi:[5,10,11],modul:[1,3,4,6,8],module_nam:10,module_nv:11,modules_cmd:2,modules_info:11,modules_list:11,monitor:[5,8,11],more:[4,5,7,10],most:[1,2,5,7,11],mount:[5,7,8],mount_boot_part_over_root:10,mount_dir:10,mount_ok:10,mountarg:10,mountpoint:[5,10],move:[6,7,10,11],move_compose_result:[7,11],msg:10,much:10,multi:5,multipl:[2,5,6,7,10,11],must:[5,6,7,9,10,11],mvebu:5,myconfig:10,name:[2,10],namespac:2,need:[1,2,5,6,7,10,11],neither:11,network:[5,7,10],never:10,nevra:[2,11],new_item:11,new_recip:11,newer:5,newest:[1,2,11],newli:10,newlin:10,newrecipegit:11,newrun:10,next:[10,11],nice:2,noarch:[7,11],node:[5,6],nomacboot:[5,6],non:[7,10,11],none:[0,5,7,10,11],nop:10,normal:[1,5,6,9],north:7,nosmt:7,nosuchpackag:10,note:[5,6,10,11],noth:[2,10,11],noupgrad:6,noverifi:6,noverifyssl:[6,10],novirt:5,novirt_cancel_check:10,novirt_instal:[7,10,11],now:[5,6,9,10,11],nspawn:[5,6],ntp:7,ntpserver:[7,11],number:[1,2,5,6,7,10,11],numer:7,nvr:6,object:[0,10,11],observ:5,occas:10,occur:10,oci_config:5,oci_runtim:5,octalmod:10,off:7,offset:[0,10],oid:11,old:[5,6,10,11],old_item:11,old_recip:11,old_vers:11,older:5,omap:5,omit:7,onc:[1,5,6,7],one:[1,2,5,6,7,9,10,11],ones:[6,7,10,11],onli:[2,5,6,7,10,11],onto:6,open:[7,11],open_or_create_repo:11,openh264:11,openstack:[1,7],oper:[4,5,7,11],opt:[2,7,10,11],option:[4,5,6,7,10,11],order:[4,6,7,11],ordereddict:11,org:[5,6,7,11],origin:[0,5,7,11],ostre:[5,10],other:[4,5,6,7,10,11],otherwis:[7,10,11],ouput:11,out:[1,4,7,10,11],outfil:10,output:[1,2,5,6,8],outputdir:[6,10],outroot:10,outsid:10,over:[7,9],overhead:10,overrid:[5,6,7,10,11],overridden:7,overwrit:[7,11],overwritten:10,ovmf:5,ovmf_path:[5,10],own:[5,6,7,11],owner:[7,11],ownership:[7,11],p_dir:11,pacag:10,packag:[1,4,5,6,8,9],package_nam:11,package_nv:11,packagedir:10,packagenevra:2,page:3,param1:0,param2:0,param:[10,11],paramat:9,paramet:[0,2,10,11],parent:11,pars:[10,11],parser:10,part:[2,5,9,10,11],particular:10,partit:[1,5,10],partitin:5,partitionmount:10,pass:[1,5,6,7,9,10,11],passwd:5,password:[5,7,11],pat:10,patch:[7,11],path:[0,1,2,5,6,7,10,11],pathnam:10,pattern:10,payload:10,pcritic:10,pdebug:10,per:[10,11],permiss:[7,11],perror:10,phys_root:10,physic:10,pick:[1,10],pid:5,pinfo:10,ping:11,pivot:10,pkg:[2,10,11],pkg_to_build:11,pkg_to_dep:11,pkg_to_project:11,pkg_to_project_info:11,pkgglob:10,pkglistdir:10,pkgname:9,pkgsizefil:10,pki:11,place:[5,6,9,10,11],plain:[6,7,10,11],plan:7,platform:[5,11],play0ad:11,pleas:10,plugin:6,plugin_conf:5,point:[4,5,7,10,11],pool:7,popen:[10,11],popul:[10,11],port:[0,5,6,7,10,11],posit:11,possibl:[2,5,7,10,11],post:[0,5,7,10],post_url:0,post_url_json:0,post_url_toml:0,postfix:7,postinstal:10,postun:10,powerpc:10,ppc64:10,ppc64le:[9,10],ppc:9,pre:[5,7,10],precaut:1,preexec_fn:10,prefix:[5,7,10,11],prepar:11,prepare_commit:11,prepend:11,present:[4,5],preserv:10,pretti:[7,10],prettycommitdetail:2,prettydiffentri:2,preun:10,prevent:11,previou:[7,10,11],previous:[4,5],primari:[5,7],primarili:7,print:[1,2],privileg:7,probabl:6,problem:[4,10,11],proc:10,procedur:10,process:[2,4,5,6,7,9,10,11],produc:[4,5,7,11],product:[3,6,10],program:[1,2,5,6,7,10,11],progress:[0,2,10],proj:11,proj_to_modul:11,project:[0,1,5,7,8,10],project_info:11,project_nam:10,projects_cmd:2,projects_depsolv:11,projects_depsolve_with_s:11,projects_info:[2,11],projects_list:[2,11],projectserror:11,pronounc:11,properti:11,protocol:7,provid:[4,5,6,10,11],proxi:[6,7,10,11],pub:[5,6,7],pubkei:5,pull:[4,5,6],pungi:4,purpos:[5,7],push:[1,2],put:[7,9,10,11],pwarn:10,pxe:10,pxeboot:6,pyanaconda:9,pykickstart:[10,11],pylorax:[4,6,7,8,9],pyo:10,python:[4,6,10,11],pythonpath:5,qcow2:[1,5,10],qemu:[1,10],qemu_arg:5,qemu_cmd:10,qemuinstal:10,queri:[0,2],queue:[2,7,8,10],queue_statu:11,quot:10,race:10,rais:[0,10,11],raise_err:10,ram:[5,10],random:[5,10],rang:10,rare:10,raw:[0,1,2,5,11],rawhid:[5,6],rdo:5,re_test:10,react:7,read:[4,5,10,11],read_commit:11,read_commit_spec:11,read_recipe_and_id:11,read_recipe_commit:11,readabl:2,readi:[10,11],readm:11,real:[5,7,10],realli:[5,6,10],reason:[5,10],reboot:7,rebuild:[5,6,10],rebuild_initrd:10,rebuild_initrds_for_l:10,recent:[1,2,11],recip:[8,10],recipe_dict:11,recipe_diff:11,recipe_filenam:11,recipe_from_dict:11,recipe_from_fil:11,recipe_from_toml:11,recipe_nam:11,recipe_path:11,recipe_str:11,recipeerror:11,recipefileerror:11,recipegit:11,recipegroup:11,recipemodul:11,recipepackag:11,recommend:[5,7],recurs:10,redhat:[1,5,6,7],redirect:[5,10],reduc:7,ref:[7,11],refer:[7,11],referenc:7,refus:5,regex:[8,10],rel:10,relat:[7,11],releas:[1,2,4,5,6,7,10,11],releasev:[5,7,10],relev:11,reli:4,reliabl:5,remain:[2,6,7],remaind:11,rememb:7,remov:[4,5,6,7,10,11],remove_temp:10,removefrom:[6,10],removekmod:[6,10],removepkg:[6,10],renam:[5,10],repl:10,replac:[4,5,6,7,9,10,11],repo1:5,repo2:5,repo:[4,6,10,11],repo_file_exist:11,repo_to_k:11,repo_to_sourc:11,repo_url:5,repodata:[5,11],repodict:11,report:[5,6,7,11],repositori:[6,7,10,11],represent:11,reproduc:11,reqpart:[5,10],request:[0,7,10,11],requir:[1,5,7,10,11],rerun:11,rescu:5,reserv:5,reset:10,reset_handl:10,reset_lang:10,resolv:10,resort:10,respond:7,respons:[0,1,10],rest:[7,10],restart:[7,11],restor:11,result:[0,1,2,5,6,7,10],result_dir:5,resultdir:5,results_dir:[10,11],retain:7,reticul:10,retriev:[7,11],retrysleep:10,retun:11,returncod:10,revert:[1,2,11],revert_fil:11,revert_recip:11,revis:11,revisor:4,revpars:11,rexist:10,rglob:10,rhel7:[3,5,11],rhel:5,rng:5,root:[1,4,5,6,7,10,11],root_dir:11,rootdir:10,rootf:[5,6,10],rootfs_imag:10,rootfs_siz:6,rootm:5,rootpw:[5,11],roughli:10,round:[10,11],round_to_block:10,rout:[0,7,10],rpm:[4,5,7,10,11],rpmbuild:11,rpmfluff:11,rpmname:[7,11],rpmreleas:[7,11],rpmversion:[7,11],rtype:11,run:[1,2,5,7,9,10,11],run_creat:10,run_pkg_transact:[6,10],runcmd:[6,10],runcmd_output:10,rundir:10,runner:10,runtim:[5,9,10],runtimebuild:[9,10],runtimeerror:[0,10,11],rxxx:11,s390x:10,safe:[7,10],samba:11,same:[5,6,7,10,11],sampl:10,satisfi:11,save:[0,1,2,6,7,10,11],sbin:[5,10],scene:7,scm:7,script:[4,5,10,11],scriptlet:10,search:[3,10,11],second:[5,11],secondari:7,section:[5,7,10,11],secur:1,see:[5,10,11],seem:10,select:[1,2,5,6,7,10,11],self:[7,10,11],selinux:[5,7,10],semver:[7,11],send:[0,1],separ:[2,10,11],sequenc:10,server:[0,1,2,7,8,10],servic:[6,10,11],services_cmd:11,set:[2,4,5,6,7,10,11],setenforc:6,setenv:10,setup:[5,6,7,10,11],setup_log:10,sever:[5,9,11],sha256:5,shallow:10,share:[5,6,7,9,10,11],share_dir:11,sharedir:[6,7,10],shell:7,ship:6,shlex:10,shortnam:10,should:[0,5,6,7,10,11],should_exit_now:2,show:[1,2,5,6,7,10],show_json:2,shutdown:[5,10],sig:11,sig_dfl:10,sig_ign:10,sign:[7,10,11],signal:10,signific:7,similar:[6,7],simpl:[2,6,7],simple_test:10,simplerpmbuild:11,simpli:7,simul:2,sinc:[5,7,11],singl:5,singleton:10,site:5,situat:7,size:[1,2,5,6,10],skip:[5,10,11],slice:11,slightli:5,slow:5,small:10,smp:5,socket:[0,1,2,7],socket_path:[0,2],socketserv:10,softwar:11,solut:5,solv:11,some:[0,4,5,6,7,10,11],someplac:7,someth:[4,5,7,10,11],sometim:5,sort:[6,11],sound:[6,10],sourc:[0,1,6,8,10],source_glob:11,source_nam:11,source_path:11,source_ref:11,source_to_repo:11,sources_add:2,sources_cmd:2,sources_delet:2,sources_info:2,sources_list:2,sourcesdir:11,space:[2,6,7,10,11],sparingli:11,spars:[5,10],speak:[4,6],spec:11,special:[6,11],specif:[5,6,7,9,10,11],specifi:[0,5,7,10,11],speed:5,spin:5,spline:10,split:10,split_and_expand:10,squashf:[5,10],squashfs_arg:[5,10],squashfs_onli:10,src:[3,5,10],srcdir:10,srcglob:10,srv:7,ssh:[5,7,11],sshd:[5,7],sshkei:11,ssl:[6,10],sslverifi:10,stage2:10,stage:[4,5],standard:[10,11],start:[1,2,5,6,7,10,11],start_build:11,start_queue_monitor:11,startprogram:10,startup:7,state:[1,5,7,10,11],statement:10,statu:[0,7,8,10],status_cmd:2,status_filt:11,stderr:10,stdin:10,stdout:[10,11],step:[4,5],stick:7,still:[5,7,10],stop:[5,7],storag:[1,2,5,7,10,11],store:[5,6,7,10,11],str:[0,2,10,11],strang:5,stream:11,strict:11,strictli:6,string:[0,2,7,10,11],string_low:10,stuck:5,stuff:5,style:10,sub:10,subclass:11,subdirectori:11,submit:11,submodul:8,submount:10,subpackag:8,subprocess:10,subset:11,substitut:[5,6],succe:11,success:[10,11],sudo:[5,7],suffix:10,suit:[1,7],suitabl:[10,11],summari:[7,11],support:[1,2,4,5,6,9,11],sure:[5,7,10,11],suspect:5,swap:5,symlink:[6,10,11],sys:[2,10],sys_root_dir:10,sysimag:10,syslinux:5,sysroot:10,system:[1,5,6,7,10,11],system_sourc:11,systemctl:[6,7,10],systemd:[5,6,7,10],sysutil:8,tag:[1,2,6,7,10],tag_file_commit:11,tag_recipe_commit:11,take:[2,5,7,9,10,11],take_limit:11,talk:[0,2],tar:[1,2,7,11],tar_disk_nam:5,tar_img:10,tarbal:10,tarfil:[5,10],target:[5,6,10],tcp:[7,10],tcpserver:10,tear:11,tegra:5,tell:6,telnet:7,telnetd:7,tempdir:10,templat:[4,5,7,9,10,11],template_fil:10,templatedir:10,templatefil:10,templaterunn:10,temporari:[1,2,4,5,6,7,10,11],termin:[5,10],test:[1,5,7,11],test_config:11,test_mod:11,test_templ:11,testmod:[1,2],text:[6,7,11],textiowrapp:10,than:[5,7,10,11],thei:[1,5,6,7,11],thelogg:10,them:[4,6,7,10,11],therefor:7,thi:[0,1,2,5,6,7,9,10,11],thing:[4,5,10,11],those:[4,9,11],though:[4,11],thread:[5,7,10,11],three:[2,7],thu:10,ti_don:10,ti_tot:10,time:[5,6,7,9,10,11],timedatectl:7,timeout:[0,5,10],timestamp:[8,10],timestamp_dict:11,timezon:11,timezone_cmd:11,titl:[5,10,11],tmp:[5,6,7,10,11],tmpdir:[10,11],tmpl:[9,10,11],to_commit:10,token:10,told:6,toml:[0,1,2,7,10],toml_dict:11,toml_filenam:2,tomlerror:11,tool:[1,4,5,6],top:[5,6,7,9,10,11],total:[5,11],total_drpm:10,total_fil:10,total_fn:0,total_s:10,touch:10,trace:10,traceback:10,track:[1,11],trail:11,transact:10,transactionprogress:10,transmogrifi:10,trash:5,treat:[7,10],tree:[4,5,6,9,10,11],treebuild:[8,9,11],treeinfo:[6,8],tri:[5,10,11],truckin:10,ts_done:10,ts_total:10,tty1:5,tty3:5,tui:5,tupl:[2,10,11],turn:4,two:[2,11],type:[0,1,2,5,10],typic:10,udev_escap:10,udp:7,uid:[7,11],umask:10,umount:[5,7,10],uncompress:11,undelet:11,under:[5,6,7,10,11],understand:7,undo:[1,2,10],unicodedecodeerror:10,uniqu:11,unit:[7,10],unix:[0,2,7,11],unix_socket:8,unixhttpconnect:0,unixhttpconnectionpool:0,unknown:10,unless:11,unmaintain:4,unmount:[5,10],unneed:[4,6,7,10,11],unpack:4,unpartit:10,until:[7,10],untouch:10,unus:[2,5],upd:4,updat:[2,3,5,6,7,10,11],update_vagrant_metadata:10,upgrad:10,upload:[5,7],upstream:11,upstream_vc:11,url:[0,5,6,7,10,11],urllib3:0,usabl:5,usag:[1,5,6,7,10],usbutil:10,use:[0,1,2,5,6,7,10,11],used:[1,2,4,5,6,7,10,11],useful:[5,10],user:[1,10,11],user_dracut_arg:10,useradd:7,uses:[5,6,7,10,11],using:[1,2,5,6,7,9,10,11],usr:[5,6,7,9,10,11],usual:[5,7],utc:[7,11],utf:[7,10],util:[0,5,8],uuid:[1,2,7,10],uuid_cancel:11,uuid_delet:11,uuid_dir:11,uuid_imag:11,uuid_info:11,uuid_log:11,uuid_statu:11,uuid_tar:11,v0_api:11,vagrant:10,vagrant_metadata:5,vagrantfil:5,valid:[7,10,11],valu:[2,5,7,10,11],valueerror:11,valuetok:10,variabl:[5,6,10],variant:[6,10],variou:[10,11],vcpu:[5,10],verbatim:5,veri:5,verifi:[1,6,10],version:[0,1,2,4,5,6,7,10,11],vhd:1,via:[5,6,7],video:10,view:1,virt:[10,11],virt_instal:10,virtio:10,virtio_consol:10,virtio_host:10,virtio_port:10,virtual:[5,10],vmdk:1,vmlinuz:[5,10],vnc:[5,10],volid:[5,6,10],volum:[5,6],wai:[2,5,7,11],wait:[1,10,11],want:[5,7,11],warfar:11,warn:[10,11],wasn:5,watch:5,web:[5,7],websit:5,weight:6,welcom:5,welder:7,weldr:[1,7,11],well:[5,6,7,11],were:[10,11],what:[0,4,5,6,7,10,11],whatev:11,wheel:[5,7],when:[5,6,7,10,11],whenev:10,where:[1,5,6,7,10,11],whether:[2,10,11],which:[1,2,4,5,6,7,9,10,11],whitespac:10,who:5,whole:10,widest:7,widget:7,wildcard:7,winnt:10,with_cor:11,with_rng:5,without:[5,6,7,11],word:10,work:[10,11],work_dir:10,workdir:[6,10],workflow:4,workspac:[1,2,8,10],workspace_delet:11,workspace_dir:11,workspace_read:11,workspace_writ:11,world:5,would:[5,7,9,10],write:[4,10,11],write_commit:11,write_fil:11,write_ks_group:11,write_ks_root:11,write_ks_us:11,write_timestamp:11,writepkglist:10,writepkgs:10,written:[4,5,7,10],wrong:10,wrote:11,wwood:10,www:11,x86:[6,9,10,11],x86_64:[5,6,10,11],xattr:10,xfce:5,xfsprog:10,xml:5,xorrisof:6,xxxx:5,xxxxx:5,yield:11,you:[1,5,6,7,9,10,11],your:[5,6,7,9,11],yourdomain:5,yum:[4,5,7,11],yumbas:11,yumlock:11,zero:[10,11],zerombr:5},titles:["composer package","composer-cli","composer.cli package","Welcome to Lorax's documentation!","Introduction to Lorax","livemedia-creator","Lorax","lorax-composer","src","Product and Updates Images","pylorax package","pylorax.api package"],titleterms:{"import":7,"new":11,Adding:[7,11],The:6,Using:5,add:7,ami:5,anaconda:5,api:11,applianc:5,argument:[1,5,6,7],atom:5,base:10,befor:4,bisect:11,blueprint:[1,2,7,11],blueprint_nam:11,boot:5,branch:3,build:1,buildstamp:10,cancel:11,chang:11,checkparam:11,cleanup:6,cli:[1,2],cmdline:[1,2,5,6,7,10,11],commit:11,compos:[0,1,2,7,11],compose_statu:11,compose_typ:11,config:11,contain:5,content:[0,2,10,11],creat:5,creation:[5,6],creator:[5,10],crossdomain:11,custom:[6,7],debug:5,decor:10,delet:11,depsolv:11,diff:11,discinfo:10,disk:[5,7],dnfbase:[10,11],dnfhelper:10,docker:5,document:3,download:1,dracut:[5,6],dvd:7,edit:1,error:11,exampl:7,executil:10,fail:11,file:5,filesystem:[5,6],finish:11,firewal:7,format:11,freez:11,from_commit:11,git:7,gitrpm:11,group:7,hack:5,help:2,how:[5,6,7],http_client:0,imag:[1,5,7,9,11],imgutil:10,indic:3,info:11,initi:5,insid:6,instal:[5,6,7,10],introduct:4,iso:[5,6,7],json:11,kbyte:11,kernel:7,kickstart:5,limit:11,list:11,live:5,livemedia:5,local:7,log:[7,11],lorax:[3,4,6,7],ltmpl:10,metadata:11,mock:[5,6],modul:[0,2,7,10,11],module_nam:11,monitor:[1,10],mount:10,name:[1,5,6,7,11],note:7,oci:5,offset:11,open:5,openstack:5,other:3,output:[7,10,11],packag:[0,2,7,10,11],partit:7,posit:[1,6,7],post:11,postinstal:6,problem:5,product:9,project:[2,11],project_nam:11,proxi:5,pxe:5,pylorax:[10,11],qemu:5,queue:11,quickstart:[5,6,7],recip:11,regex:11,repo:[5,7],repositori:5,requir:6,respons:11,result:11,rout:11,run:6,runtim:6,secur:7,server:11,servic:7,size:11,sourc:[2,7,11],squashf:6,src:8,sshkei:7,statu:[1,2,11],submodul:[0,2,10,11],subpackag:[0,10],support:7,sysutil:10,tabl:3,tag:11,tar:5,templat:6,thing:7,timestamp:11,timezon:7,tmpl:6,to_commit:11,toml:11,treebuild:10,treeinfo:10,type:[7,11],uefi:5,undo:11,unix_socket:0,updat:9,user:[5,7],util:2,uuid:11,vagrant:5,virt:5,welcom:3,work:[5,6,7],workspac:11}}) \ No newline at end of file +Search.setIndex({docnames:["composer","composer-cli","composer.cli","index","intro","livemedia-creator","lorax","lorax-composer","modules","product-images","pylorax","pylorax.api"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["composer.rst","composer-cli.rst","composer.cli.rst","index.rst","intro.rst","livemedia-creator.rst","lorax.rst","lorax-composer.rst","modules.rst","product-images.rst","pylorax.rst","pylorax.api.rst"],objects:{"":{composer:[0,0,0,"-"],pylorax:[10,0,0,"-"]},"composer.cli":{blueprints:[2,0,0,"-"],cmdline:[2,0,0,"-"],compose:[2,0,0,"-"],help:[2,0,0,"-"],main:[2,1,1,""],modules:[2,0,0,"-"],projects:[2,0,0,"-"],sources:[2,0,0,"-"],status:[2,0,0,"-"],utilities:[2,0,0,"-"]},"composer.cli.blueprints":{blueprints_changes:[2,1,1,""],blueprints_cmd:[2,1,1,""],blueprints_delete:[2,1,1,""],blueprints_depsolve:[2,1,1,""],blueprints_diff:[2,1,1,""],blueprints_freeze:[2,1,1,""],blueprints_freeze_save:[2,1,1,""],blueprints_freeze_show:[2,1,1,""],blueprints_list:[2,1,1,""],blueprints_push:[2,1,1,""],blueprints_save:[2,1,1,""],blueprints_show:[2,1,1,""],blueprints_tag:[2,1,1,""],blueprints_undo:[2,1,1,""],blueprints_workspace:[2,1,1,""],dict_names:[2,1,1,""],prettyCommitDetails:[2,1,1,""],pretty_dict:[2,1,1,""],pretty_diff_entry:[2,1,1,""]},"composer.cli.cmdline":{composer_cli_parser:[2,1,1,""]},"composer.cli.compose":{compose_cancel:[2,1,1,""],compose_cmd:[2,1,1,""],compose_delete:[2,1,1,""],compose_image:[2,1,1,""],compose_info:[2,1,1,""],compose_list:[2,1,1,""],compose_log:[2,1,1,""],compose_logs:[2,1,1,""],compose_metadata:[2,1,1,""],compose_results:[2,1,1,""],compose_start:[2,1,1,""],compose_status:[2,1,1,""],compose_types:[2,1,1,""]},"composer.cli.modules":{modules_cmd:[2,1,1,""]},"composer.cli.projects":{projects_cmd:[2,1,1,""],projects_info:[2,1,1,""],projects_list:[2,1,1,""]},"composer.cli.sources":{sources_add:[2,1,1,""],sources_cmd:[2,1,1,""],sources_delete:[2,1,1,""],sources_info:[2,1,1,""],sources_list:[2,1,1,""]},"composer.cli.status":{status_cmd:[2,1,1,""]},"composer.cli.utilities":{argify:[2,1,1,""],frozen_toml_filename:[2,1,1,""],handle_api_result:[2,1,1,""],packageNEVRA:[2,1,1,""],toml_filename:[2,1,1,""]},"composer.http_client":{api_url:[0,1,1,""],append_query:[0,1,1,""],delete_url_json:[0,1,1,""],download_file:[0,1,1,""],get_filename:[0,1,1,""],get_url_json:[0,1,1,""],get_url_json_unlimited:[0,1,1,""],get_url_raw:[0,1,1,""],post_url:[0,1,1,""],post_url_json:[0,1,1,""],post_url_toml:[0,1,1,""]},"composer.unix_socket":{UnixHTTPConnection:[0,2,1,""],UnixHTTPConnectionPool:[0,2,1,""]},"composer.unix_socket.UnixHTTPConnection":{connect:[0,3,1,""]},"pylorax.ArchData":{bcj_arch:[10,4,1,""],lib64_arches:[10,4,1,""]},"pylorax.Lorax":{configure:[10,3,1,""],init_file_logging:[10,3,1,""],init_stream_logging:[10,3,1,""],run:[10,3,1,""],templatedir:[10,4,1,""]},"pylorax.api":{bisect:[11,0,0,"-"],checkparams:[11,0,0,"-"],cmdline:[11,0,0,"-"],compose:[11,0,0,"-"],config:[11,0,0,"-"],dnfbase:[11,0,0,"-"],errors:[11,0,0,"-"],flask_blueprint:[11,0,0,"-"],gitrpm:[11,0,0,"-"],projects:[11,0,0,"-"],queue:[11,0,0,"-"],recipes:[11,0,0,"-"],regexes:[11,0,0,"-"],server:[11,0,0,"-"],timestamp:[11,0,0,"-"],toml:[11,0,0,"-"],v0:[11,0,0,"-"],workspace:[11,0,0,"-"]},"pylorax.api.bisect":{insort_left:[11,1,1,""]},"pylorax.api.checkparams":{checkparams:[11,1,1,""]},"pylorax.api.cmdline":{lorax_composer_parser:[11,1,1,""]},"pylorax.api.compose":{add_customizations:[11,1,1,""],bootloader_append:[11,1,1,""],compose_args:[11,1,1,""],compose_types:[11,1,1,""],customize_ks_template:[11,1,1,""],firewall_cmd:[11,1,1,""],get_default_services:[11,1,1,""],get_extra_pkgs:[11,1,1,""],get_firewall_settings:[11,1,1,""],get_kernel_append:[11,1,1,""],get_keyboard_layout:[11,1,1,""],get_languages:[11,1,1,""],get_services:[11,1,1,""],get_timezone_settings:[11,1,1,""],keyboard_cmd:[11,1,1,""],lang_cmd:[11,1,1,""],move_compose_results:[11,1,1,""],repo_to_ks:[11,1,1,""],services_cmd:[11,1,1,""],start_build:[11,1,1,""],test_templates:[11,1,1,""],timezone_cmd:[11,1,1,""],write_ks_group:[11,1,1,""],write_ks_root:[11,1,1,""],write_ks_user:[11,1,1,""]},"pylorax.api.config":{ComposerConfig:[11,2,1,""],configure:[11,1,1,""],make_dnf_dirs:[11,1,1,""],make_owned_dir:[11,1,1,""],make_queue_dirs:[11,1,1,""]},"pylorax.api.config.ComposerConfig":{get_default:[11,3,1,""]},"pylorax.api.dnfbase":{DNFLock:[11,2,1,""],get_base_object:[11,1,1,""]},"pylorax.api.dnfbase.DNFLock":{lock:[11,4,1,""],lock_check:[11,4,1,""]},"pylorax.api.flask_blueprint":{BlueprintSetupStateSkip:[11,2,1,""],BlueprintSkip:[11,2,1,""]},"pylorax.api.flask_blueprint.BlueprintSetupStateSkip":{add_url_rule:[11,3,1,""]},"pylorax.api.flask_blueprint.BlueprintSkip":{make_setup_state:[11,3,1,""]},"pylorax.api.gitrpm":{GitArchiveTarball:[11,2,1,""],GitRpmBuild:[11,2,1,""],create_gitrpm_repo:[11,1,1,""],get_repo_description:[11,1,1,""],make_git_rpm:[11,1,1,""]},"pylorax.api.gitrpm.GitArchiveTarball":{write_file:[11,3,1,""]},"pylorax.api.gitrpm.GitRpmBuild":{add_git_tarball:[11,3,1,""],check:[11,3,1,""],clean:[11,3,1,""],cleanup_tmpdir:[11,3,1,""],get_base_dir:[11,3,1,""]},"pylorax.api.projects":{ProjectsError:[11,5,1,""],api_changelog:[11,1,1,""],api_time:[11,1,1,""],delete_repo_source:[11,1,1,""],dep_evra:[11,1,1,""],dep_nevra:[11,1,1,""],dnf_repo_to_file_repo:[11,1,1,""],estimate_size:[11,1,1,""],get_repo_sources:[11,1,1,""],get_source_ids:[11,1,1,""],modules_info:[11,1,1,""],modules_list:[11,1,1,""],pkg_to_build:[11,1,1,""],pkg_to_dep:[11,1,1,""],pkg_to_project:[11,1,1,""],pkg_to_project_info:[11,1,1,""],proj_to_module:[11,1,1,""],projects_depsolve:[11,1,1,""],projects_depsolve_with_size:[11,1,1,""],projects_info:[11,1,1,""],projects_list:[11,1,1,""],repo_to_source:[11,1,1,""],source_to_repo:[11,1,1,""]},"pylorax.api.queue":{build_status:[11,1,1,""],check_queues:[11,1,1,""],compose_detail:[11,1,1,""],get_compose_type:[11,1,1,""],get_image_name:[11,1,1,""],make_compose:[11,1,1,""],monitor:[11,1,1,""],queue_status:[11,1,1,""],start_queue_monitor:[11,1,1,""],uuid_cancel:[11,1,1,""],uuid_delete:[11,1,1,""],uuid_image:[11,1,1,""],uuid_info:[11,1,1,""],uuid_log:[11,1,1,""],uuid_status:[11,1,1,""],uuid_tar:[11,1,1,""]},"pylorax.api.recipes":{CommitDetails:[11,2,1,""],CommitTimeValError:[11,5,1,""],NewRecipeGit:[11,1,1,""],Recipe:[11,2,1,""],RecipeError:[11,5,1,""],RecipeFileError:[11,5,1,""],RecipeGit:[11,2,1,""],RecipeGroup:[11,2,1,""],RecipeModule:[11,2,1,""],RecipePackage:[11,2,1,""],commit_recipe:[11,1,1,""],commit_recipe_directory:[11,1,1,""],commit_recipe_file:[11,1,1,""],customizations_diff:[11,1,1,""],delete_file:[11,1,1,""],delete_recipe:[11,1,1,""],diff_lists:[11,1,1,""],find_commit_tag:[11,1,1,""],find_field_value:[11,1,1,""],find_name:[11,1,1,""],find_recipe_obj:[11,1,1,""],get_commit_details:[11,1,1,""],get_revision_from_tag:[11,1,1,""],gfile:[11,1,1,""],head_commit:[11,1,1,""],is_commit_tag:[11,1,1,""],is_parent_diff:[11,1,1,""],list_branch_files:[11,1,1,""],list_commit_files:[11,1,1,""],list_commits:[11,1,1,""],open_or_create_repo:[11,1,1,""],prepare_commit:[11,1,1,""],read_commit:[11,1,1,""],read_commit_spec:[11,1,1,""],read_recipe_and_id:[11,1,1,""],read_recipe_commit:[11,1,1,""],recipe_diff:[11,1,1,""],recipe_filename:[11,1,1,""],recipe_from_dict:[11,1,1,""],recipe_from_file:[11,1,1,""],recipe_from_toml:[11,1,1,""],repo_file_exists:[11,1,1,""],revert_file:[11,1,1,""],revert_recipe:[11,1,1,""],tag_file_commit:[11,1,1,""],tag_recipe_commit:[11,1,1,""],write_commit:[11,1,1,""]},"pylorax.api.recipes.Recipe":{bump_version:[11,3,1,""],filename:[11,4,1,""],freeze:[11,3,1,""],group_names:[11,4,1,""],module_names:[11,4,1,""],module_nver:[11,4,1,""],package_names:[11,4,1,""],package_nver:[11,4,1,""],toml:[11,3,1,""]},"pylorax.api.server":{GitLock:[11,2,1,""]},"pylorax.api.server.GitLock":{dir:[11,4,1,""],lock:[11,4,1,""],repo:[11,4,1,""]},"pylorax.api.timestamp":{timestamp_dict:[11,1,1,""],write_timestamp:[11,1,1,""]},"pylorax.api.toml":{TomlError:[11,5,1,""],dumps:[11,1,1,""],loads:[11,1,1,""]},"pylorax.api.v0":{blueprint_exists:[11,1,1,""],take_limits:[11,1,1,""],v0_blueprints_changes:[11,1,1,""],v0_blueprints_delete:[11,1,1,""],v0_blueprints_delete_workspace:[11,1,1,""],v0_blueprints_depsolve:[11,1,1,""],v0_blueprints_diff:[11,1,1,""],v0_blueprints_freeze:[11,1,1,""],v0_blueprints_info:[11,1,1,""],v0_blueprints_list:[11,1,1,""],v0_blueprints_new:[11,1,1,""],v0_blueprints_tag:[11,1,1,""],v0_blueprints_undo:[11,1,1,""],v0_blueprints_workspace:[11,1,1,""],v0_compose_cancel:[11,1,1,""],v0_compose_delete:[11,1,1,""],v0_compose_failed:[11,1,1,""],v0_compose_finished:[11,1,1,""],v0_compose_image:[11,1,1,""],v0_compose_info:[11,1,1,""],v0_compose_log_tail:[11,1,1,""],v0_compose_logs:[11,1,1,""],v0_compose_metadata:[11,1,1,""],v0_compose_queue:[11,1,1,""],v0_compose_results:[11,1,1,""],v0_compose_start:[11,1,1,""],v0_compose_status:[11,1,1,""],v0_compose_types:[11,1,1,""],v0_modules_info:[11,1,1,""],v0_modules_list:[11,1,1,""],v0_projects_depsolve:[11,1,1,""],v0_projects_info:[11,1,1,""],v0_projects_list:[11,1,1,""],v0_projects_source_delete:[11,1,1,""],v0_projects_source_info:[11,1,1,""],v0_projects_source_list:[11,1,1,""],v0_projects_source_new:[11,1,1,""]},"pylorax.api.workspace":{workspace_delete:[11,1,1,""],workspace_dir:[11,1,1,""],workspace_read:[11,1,1,""],workspace_write:[11,1,1,""]},"pylorax.base":{BaseLoraxClass:[10,2,1,""],DataHolder:[10,2,1,""]},"pylorax.base.BaseLoraxClass":{pcritical:[10,3,1,""],pdebug:[10,3,1,""],perror:[10,3,1,""],pinfo:[10,3,1,""],pwarning:[10,3,1,""]},"pylorax.base.DataHolder":{copy:[10,3,1,""]},"pylorax.buildstamp":{BuildStamp:[10,2,1,""]},"pylorax.buildstamp.BuildStamp":{write:[10,3,1,""]},"pylorax.cmdline":{lmc_parser:[10,1,1,""],lorax_parser:[10,1,1,""]},"pylorax.creator":{FakeDNF:[10,2,1,""],calculate_disk_size:[10,1,1,""],check_kickstart:[10,1,1,""],create_pxe_config:[10,1,1,""],find_ostree_root:[10,1,1,""],get_arch:[10,1,1,""],is_image_mounted:[10,1,1,""],make_appliance:[10,1,1,""],make_image:[10,1,1,""],make_live_images:[10,1,1,""],make_livecd:[10,1,1,""],make_runtime:[10,1,1,""],make_squashfs:[10,1,1,""],mount_boot_part_over_root:[10,1,1,""],rebuild_initrds_for_live:[10,1,1,""],run_creator:[10,1,1,""],squashfs_args:[10,1,1,""]},"pylorax.creator.FakeDNF":{reset:[10,3,1,""]},"pylorax.decorators":{singleton:[10,1,1,""]},"pylorax.discinfo":{DiscInfo:[10,2,1,""]},"pylorax.discinfo.DiscInfo":{write:[10,3,1,""]},"pylorax.dnfbase":{get_dnf_base_object:[10,1,1,""]},"pylorax.dnfhelper":{LoraxDownloadCallback:[10,2,1,""],LoraxRpmCallback:[10,2,1,""]},"pylorax.dnfhelper.LoraxDownloadCallback":{end:[10,3,1,""],progress:[10,3,1,""],start:[10,3,1,""]},"pylorax.dnfhelper.LoraxRpmCallback":{error:[10,3,1,""],progress:[10,3,1,""]},"pylorax.executils":{ExecProduct:[10,2,1,""],augmentEnv:[10,1,1,""],execReadlines:[10,1,1,""],execWithCapture:[10,1,1,""],execWithRedirect:[10,1,1,""],runcmd:[10,1,1,""],runcmd_output:[10,1,1,""],setenv:[10,1,1,""],startProgram:[10,1,1,""]},"pylorax.imgutils":{DMDev:[10,2,1,""],LoopDev:[10,2,1,""],Mount:[10,2,1,""],PartitionMount:[10,2,1,""],compress:[10,1,1,""],copytree:[10,1,1,""],default_image_name:[10,1,1,""],dm_attach:[10,1,1,""],dm_detach:[10,1,1,""],do_grafts:[10,1,1,""],estimate_size:[10,1,1,""],get_loop_name:[10,1,1,""],kpartx_disk_img:[10,1,1,""],loop_attach:[10,1,1,""],loop_detach:[10,1,1,""],loop_waitfor:[10,1,1,""],mkbtrfsimg:[10,1,1,""],mkcpio:[10,1,1,""],mkdosimg:[10,1,1,""],mkext4img:[10,1,1,""],mkfsimage:[10,1,1,""],mkfsimage_from_disk:[10,1,1,""],mkhfsimg:[10,1,1,""],mkqcow2:[10,1,1,""],mkqemu_img:[10,1,1,""],mkrootfsimg:[10,1,1,""],mksparse:[10,1,1,""],mksquashfs:[10,1,1,""],mktar:[10,1,1,""],mount:[10,1,1,""],round_to_blocks:[10,1,1,""],umount:[10,1,1,""]},"pylorax.installer":{InstallError:[10,5,1,""],QEMUInstall:[10,2,1,""],anaconda_cleanup:[10,1,1,""],append_initrd:[10,1,1,""],create_vagrant_metadata:[10,1,1,""],find_free_port:[10,1,1,""],novirt_cancel_check:[10,1,1,""],novirt_install:[10,1,1,""],update_vagrant_metadata:[10,1,1,""],virt_install:[10,1,1,""]},"pylorax.installer.QEMUInstall":{QEMU_CMDS:[10,4,1,""]},"pylorax.ltmpl":{LiveTemplateRunner:[10,2,1,""],LoraxTemplate:[10,2,1,""],LoraxTemplateRunner:[10,2,1,""],TemplateRunner:[10,2,1,""],brace_expand:[10,1,1,""],rexists:[10,1,1,""],rglob:[10,1,1,""],split_and_expand:[10,1,1,""]},"pylorax.ltmpl.LiveTemplateRunner":{installpkg:[10,3,1,""]},"pylorax.ltmpl.LoraxTemplate":{parse:[10,3,1,""]},"pylorax.ltmpl.LoraxTemplateRunner":{append:[10,3,1,""],chmod:[10,3,1,""],copy:[10,3,1,""],createaddrsize:[10,3,1,""],hardlink:[10,3,1,""],install:[10,3,1,""],installimg:[10,3,1,""],installinitrd:[10,3,1,""],installkernel:[10,3,1,""],installpkg:[10,3,1,""],installupgradeinitrd:[10,3,1,""],log:[10,3,1,""],mkdir:[10,3,1,""],move:[10,3,1,""],remove:[10,3,1,""],removefrom:[10,3,1,""],removekmod:[10,3,1,""],removepkg:[10,3,1,""],replace:[10,3,1,""],run_pkg_transaction:[10,3,1,""],runcmd:[10,3,1,""],symlink:[10,3,1,""],systemctl:[10,3,1,""],treeinfo:[10,3,1,""]},"pylorax.ltmpl.TemplateRunner":{run:[10,3,1,""]},"pylorax.monitor":{LogMonitor:[10,2,1,""],LogRequestHandler:[10,2,1,""],LogServer:[10,2,1,""]},"pylorax.monitor.LogMonitor":{shutdown:[10,3,1,""]},"pylorax.monitor.LogRequestHandler":{finish:[10,3,1,""],handle:[10,3,1,""],iserror:[10,3,1,""],re_tests:[10,4,1,""],setup:[10,3,1,""],simple_tests:[10,4,1,""]},"pylorax.monitor.LogServer":{log_check:[10,3,1,""],timeout:[10,4,1,""]},"pylorax.mount":{IsoMountpoint:[10,2,1,""]},"pylorax.mount.IsoMountpoint":{get_iso_label:[10,3,1,""],umount:[10,3,1,""]},"pylorax.sysutils":{chmod_:[10,1,1,""],chown_:[10,1,1,""],joinpaths:[10,1,1,""],linktree:[10,1,1,""],remove:[10,1,1,""],replace:[10,1,1,""],touch:[10,1,1,""]},"pylorax.treebuilder":{RuntimeBuilder:[10,2,1,""],TreeBuilder:[10,2,1,""],findkernels:[10,1,1,""],generate_module_info:[10,1,1,""],string_lower:[10,1,1,""],udev_escape:[10,1,1,""]},"pylorax.treebuilder.RuntimeBuilder":{cleanup:[10,3,1,""],create_ext4_runtime:[10,3,1,""],create_squashfs_runtime:[10,3,1,""],finished:[10,3,1,""],generate_module_data:[10,3,1,""],install:[10,3,1,""],postinstall:[10,3,1,""],verify:[10,3,1,""],writepkglists:[10,3,1,""],writepkgsizes:[10,3,1,""]},"pylorax.treebuilder.TreeBuilder":{build:[10,3,1,""],copy_dracut_hooks:[10,3,1,""],dracut_hooks_path:[10,4,1,""],implantisomd5:[10,3,1,""],kernels:[10,4,1,""],rebuild_initrds:[10,3,1,""]},"pylorax.treeinfo":{TreeInfo:[10,2,1,""]},"pylorax.treeinfo.TreeInfo":{add_section:[10,3,1,""],write:[10,3,1,""]},composer:{cli:[2,0,0,"-"],http_client:[0,0,0,"-"],unix_socket:[0,0,0,"-"]},pylorax:{ArchData:[10,2,1,""],Lorax:[10,2,1,""],api:[11,0,0,"-"],base:[10,0,0,"-"],buildstamp:[10,0,0,"-"],cmdline:[10,0,0,"-"],creator:[10,0,0,"-"],decorators:[10,0,0,"-"],discinfo:[10,0,0,"-"],dnfbase:[10,0,0,"-"],dnfhelper:[10,0,0,"-"],executils:[10,0,0,"-"],find_templates:[10,1,1,""],get_buildarch:[10,1,1,""],imgutils:[10,0,0,"-"],installer:[10,0,0,"-"],log_selinux_state:[10,1,1,""],ltmpl:[10,0,0,"-"],monitor:[10,0,0,"-"],mount:[10,0,0,"-"],output:[10,0,0,"-"],setup_logging:[10,1,1,""],sysutils:[10,0,0,"-"],treebuilder:[10,0,0,"-"],treeinfo:[10,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:method","4":"py:attribute","5":"py:exception"},terms:{"01t08":11,"03374adbf080fe34f5c6c29f2e49cc2b86958bf2":11,"03397f8d":11,"06e8":11,"08t00":11,"0ad":11,"0e08ecbb708675bfabc82952599a1712a843779d":11,"0instal":11,"10t23":11,"11t00":11,"11t01":11,"13z":11,"1kb":2,"1mbyte":11,"23t00":11,"28z":11,"29b492f26ed35d80800b536623bafc51e2f0eff2":11,"2b4174b3614b":11,"2ping":11,"30z":11,"3700mib":10,"3726a1093fd0":11,"397f":11,"3e11eb87a63d289662cba4b1804a0947a6843379":11,"3rn8evie2t50lmvybyihtgvrhcaecmeck31l":7,"41ef9c3e4b73":11,"44c0":11,"45502a6d":11,"45e380f39894":11,"47z":11,"48a5":11,"4a23":11,"4af9":11,"4b70":11,"4b8a":11,"4c68":11,"4c9f":11,"4cdb":11,"523b":11,"52z":11,"56z":11,"61b799739ce8":11,"6d292bd0":11,"7078e521a54b12eae31c3fd028680da7a0815a4d":11,"70b84195":11,"745712b2":11,"7f16":11,"870f":11,"8c8435ef":11,"8d7d":11,"96db":11,"99anaconda":10,"9bf1":11,"9c81":11,"byte":11,"case":[7,11],"catch":[5,10],"char":10,"class":[0,9,10,11],"default":[1,5,6,7,10,11],"final":[1,4,5,6,7,9,10,11],"function":[2,7,10,11],"import":[5,10,11],"int":[2,10,11],"new":[0,1,2,4,5,6,7,10],"null":[5,11],"public":[5,7],"return":[0,1,2,7,10,11],"short":7,"switch":5,"true":[0,2,5,6,7,10,11],"try":[5,10,11],"var":[5,6,7,10],"while":[7,9,10,11],ADDING:10,Adding:10,And:[5,7],But:[5,7],For:[0,5,7,10,11],Its:[4,6],NOT:11,Not:10,One:[5,7],RTS:11,The:[0,1,2,4,5,7,9,10,11],There:[5,7,10,11],These:[7,9,11],Use:[5,6,10,11],Used:[5,10,11],Uses:11,Using:11,Will:10,Yes:10,__init__:0,_io:10,_map:7,a215:11,a2ef832e6b1a:11,a697ca405cdf:11,aarch64:[6,9,10],abbrevi:5,abl:[6,7],abort:5,about:[1,2,5,11],abov:5,absolut:10,accept:7,access:[5,7,11],accomplish:5,account:[7,10],acff:11,acl:[10,11],action:10,activ:[5,7],actual:[10,11],ad52:11,add2636e7459:11,add:[0,1,2,5,6,9,10,11],add_arch_templ:[6,10],add_arch_template_var:[6,10],add_arg:10,add_custom:11,add_git_tarbal:11,add_sect:10,add_templ:[6,10],add_template_var:[6,10],add_url_rul:11,added:[5,7,10,11],adding:[7,10],addit:[2,5,6,7,10,11],addon:11,addr:10,addrsiz:10,admin:7,administr:7,ae1bf7e3:11,af92:11,afford:5,after:[5,6,10,11],against:5,alia:11,alibaba:1,align:5,all:[0,1,2,4,5,6,7,9,10,11],allbut:[6,10],alloc:5,allow:[5,6,7],allow_no_valu:11,almost:4,along:[6,11],alreadi:[7,10,11],also:[1,5,6,7,10,11],alwai:[5,7,11],amazon:5,america:7,ami:[1,7],amount:7,anaconda:[1,4,6,7,9,10,11],anaconda_arg:[5,11],anaconda_cleanup:10,anaconfigurationthread:11,ancient:11,ani:[0,1,2,5,7,10,11],anoth:[5,6,10],anyth:[9,11],anywher:10,api:[0,1,2,7,8,10],api_changelog:11,api_tim:11,api_url:0,api_vers:[0,2],apiv:1,app:[5,11],app_fil:5,app_nam:5,app_templ:5,appear:10,append:[0,2,5,6,7,10,11],append_initrd:10,append_queri:0,appli:[1,10,11],applianc:10,applic:[7,11],appropri:[5,10],arbitrari:[6,7],arch:[2,4,5,6,10,11],archdata:10,architectur:[4,5,6,10],archiv:[5,7,9,10,11],aren:[6,11],arg:[1,2,5,6,10,11],argifi:2,argpars:[2,10],argument:[0,2,10,11],argumentpars:[2,10,11],argv:10,arm:[5,10],armhfp:10,armplatform:[5,11],around:5,artifact:[5,11],assembl:11,associ:10,assum:[10,11],atla:11,attach:10,attach_to_al:[],attempt:[4,10,11],attr:11,attribut:[5,11],audit:11,augmentenv:10,authent:11,author:[1,5,6,7,11],authorized_kei:7,automat:[7,10,11],automatic_opt:[],avahi:11,avail:[1,2,5,7,11],awar:7,b36e:11,back:[1,10,11],backup:[10,11],bare:[5,11],base:[0,5,6,7,8,11],basearch:10,baseimag:7,baseloraxclass:10,basenam:10,baserequesthandl:10,basesystem:11,baseurl:[5,7,11],bash:[4,5,7,11],basic:[1,6],bcj_arch:10,bcl:[1,5,6,7],bd31:11,bdc:7,bec7:11,becaus:[5,6,7,11],becom:[5,7],been:[5,10,11],befor:[3,5,6,7,10],behavior:11,behind:[7,10],being:[5,6,7,11],below:[5,6,11],best:[5,6,7,11],better:10,between:[1,2,7,10,11],big:10,bin:[5,7,10],binari:[5,10],binary_output:10,bind:5,bind_mount_opt:5,bio:5,bisect:[8,10],bit:7,blob:11,block:[6,7,10,11],block_siz:11,blocksiz:10,blog:7,blueprint:[0,8,11],blueprint_exist:11,blueprint_nam:[2,11],blueprints_chang:2,blueprints_cmd:2,blueprints_delet:2,blueprints_depsolv:2,blueprints_diff:2,blueprints_freez:2,blueprints_freeze_sav:2,blueprints_freeze_show:2,blueprints_list:2,blueprints_push:2,blueprints_sav:2,blueprints_show:2,blueprints_tag:2,blueprints_undo:2,blueprints_workspac:2,blueprintsetupst:11,blueprintsetupstateskip:11,blueprintskip:11,bodi:[0,11],bool:[2,10,11],boot:[1,4,6,7,9,10,11],boot_uefi:10,bootabl:5,bootdir:10,bootload:[5,7,11],bootloader_append:11,bootproto:5,both:[5,7,11],bound:11,boundri:11,box:5,brace:10,brace_expand:10,branch:[5,7,11],brian:[1,5,6,7],brianlan:11,browser:7,bug:[5,6,7],bugurl:[6,10],bugzilla:5,build:[2,4,5,6,7,9,10,11],build_config_ref:11,build_env_ref:11,build_id:11,build_statu:11,build_tim:11,buildarch:[6,10],builder:[5,11],buildinstal:4,buildsi:5,buildstamp:8,built:[6,10,11],builtin:10,bump:[7,11],bump_vers:11,bunch:10,bundl:5,bzip2:[5,10],c30b7d80:11,cach:[5,6,7,10],cachedir:[6,10],calcul:10,calculate_disk_s:10,call:[4,5,10,11],callback:[10,11],calledprocesserror:10,caller:11,can:[1,2,5,6,7,9,10,11],cancel:[1,2,5,10,11],cancel_func:10,cannot:[0,5,6,7,11],captur:10,care:[10,11],cat:5,categor:7,caught:[5,11],caus:[7,10],cdboot:7,cdlabel:10,cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3:11,central:4,cert:10,certif:[6,7,11],cfg:[10,11],chang:[1,2,5,6,7,10,11],changelog:[1,11],charact:[7,10],check:[7,10,11],check_gpg:[7,11],check_kickstart:10,check_queu:11,check_ssl:[7,11],checkparam:[8,10],checksum:5,checksum_typ:5,child:10,chmod:[6,10],chmod_:10,cho2:7,choos:5,chosen:[5,10,11],chown_:10,chronyd:7,chroot:[5,6,9,10],chroot_setup_cmd:5,chvt:5,cisco:11,clean:[4,5,7,11],cleanup:[5,10,11],cleanup_tmpdir:11,clear:[4,7,11],clearpart:5,cli:[0,3,7,8,11],client:[0,5,11],client_address:10,clone:[7,11],close:10,cloud:[5,7],cls:10,cmd:[7,10],cmdline:[0,8],cmdlist:10,cockpit:7,code:[6,7,10,11],collect:11,com:[1,5,6,7,11],combin:[2,5],come:11,comma:[2,10,11],command:[0,1,2,4,5,6,7,9,10,11],commandlin:[1,7,10],comment_prefix:11,commit:[1,2,7,11],commit_id:11,commit_recip:11,commit_recipe_directori:11,commit_recipe_fil:11,commitdetail:11,committimevalerror:11,common:[5,6],commonli:7,commun:[0,2,7],comoposit:11,compar:11,comparison:11,compat:7,complet:[4,7,10,11],compon:5,compos:[3,8,10],compose_arg:[7,11],compose_cancel:2,compose_cmd:2,compose_delet:2,compose_detail:11,compose_imag:2,compose_info:2,compose_list:2,compose_log:2,compose_metadata:2,compose_result:2,compose_start:2,compose_statu:[2,11],compose_typ:[2,7,11],composer_cli_pars:2,composerconfig:11,composerpars:11,composit:11,compress:[5,9,10,11],compress_arg:[5,11],compressarg:10,compressopt:10,comput:10,conf:[4,6,7,10,11],conf_fil:[10,11],config:[5,6,7,8,10],config_opt:5,configfil:6,configpars:11,configur:[4,5,6,7,10,11],conflict:[6,7],connect:0,connectionpool:0,consist:[1,4],consol:7,construct:[7,10],constructor:11,contain:[4,6,7,9,10,11],content:[3,6,7,8,9],context:10,continu:[2,10],control:[4,7,10,11],convent:5,convert:[2,5,7,10,11],copi:[1,4,5,6,7,9,10,11],copy_dracut_hook:10,copyin:5,copytre:10,core:5,correct:[2,4,5,7,10,11],correctli:[5,7,10,11],correspond:10,could:[5,7],count:11,coupl:5,cpio:10,cpu:10,crash:10,creat:[1,4,6,7,9,10,11],create_ext4_runtim:10,create_gitrpm_repo:11,create_pxe_config:10,create_squashfs_runtim:10,create_vagrant_metadata:10,createaddrs:10,createrepo:5,createrepo_c:11,creation:[4,9,10,11],creator:[3,7,8,11],cross:11,crossdomain:[],current:[1,4,5,7,10,11],custom:[4,5,9,11],customizations_diff:11,customize_ks_templ:11,cwd:0,d6bd:11,data:[0,4,5,10,11],datahold:[10,11],dbo:[10,11],debug:[7,10],decod:[10,11],decor:8,dee:11,default_image_nam:10,default_sect:11,defin:[5,7,11],delai:[7,10],delet:[0,1,2,5,6,7,10,11],delete_fil:11,delete_recip:11,delete_repo_sourc:11,delete_url_json:0,delimit:11,denial:[5,7],dep:11,dep_evra:11,dep_nevra:11,depend:[1,2,5,6,9,11],deploy:[7,10,11],depmod:10,depsolv:[1,2,7,11],describ:[5,7,11],descript:[1,5,7,10,11],desir:11,desktop:5,dest:[10,11],destdir:11,destfil:10,destin:[6,7,10,11],detach:10,detail:[1,2,7,11],detect:[5,10],dev:[5,6,10],devel:5,develop:[5,7,11],devic:[5,6,10],devicemapp:10,dhcp:[5,7],dialog:5,dict:[0,2,10,11],dict_nam:2,dict_typ:11,dictionari:11,didn:5,died:5,diff:[1,2,11],diff_item:[],diff_list:11,differ:[1,2,5,7,10,11],difficult:11,dir:[5,6,10,11],direcori:10,direct:11,directli:[2,5,7,11],directori:[1,5,6,7,9,10,11],dirinstall_path:10,disabl:[6,7,10,11],disablerepo:[6,10],discinfo:[6,8],disk:[1,10],disk_imag:5,disk_img:10,disk_info:5,disk_siz:10,diskimag:10,dispatch:2,displai:[1,2,5,7],disposit:0,distribut:[6,7],dm_attach:10,dm_detach:10,dmdev:10,dmsetup:10,dnf:[6,7,10,11],dnf_conf:11,dnf_obj:10,dnf_repo_to_file_repo:11,dnfbase:8,dnfhelper:8,dnflock:11,dnfplugin:[6,10],do_graft:10,doc:[5,7,11],document:[5,6,7],doe:[2,5,6,7,10,11],doesn:[2,5,7,10,11],doing:[5,7,11],domacboot:10,domain:7,don:[5,10,11],done:[1,10,11],doupgrad:10,down:11,download:[0,2,6,10,11],download_fil:0,downloadprogress:10,dracut:10,dracut_arg:[5,6],dracut_default:10,dracut_hook:10,dracut_hooks_path:10,drawback:5,drive:6,driven:4,driver:[4,10],drop:[7,9],dst:10,due:5,dump:11,dure:2,dyy8gj:11,e083921a7ed1cf2eec91ad12b9ad1e70ef3470b:11,e695affd:11,e6fa6db4:11,each:[1,2,5,6,7,10,11],easi:10,easier:5,eastern:7,ec2:5,echo:5,edit:[7,11],edk2:5,effect:7,efi:[5,7],either:[5,7,10,11],el7:11,els:10,emit:10,empti:[6,7,10,11],empty_lines_in_valu:11,en_u:7,enabl:[5,6,7,10,11],enablerepo:[6,10],encod:10,encount:[5,11],encrypt:7,end:[1,5,6,7,10,11],endfor:10,endif:6,endpoint:11,enforc:[5,7,11],enhanc:5,enough:10,ensur:[10,11],enter:11,entir:7,entri:[2,5,7,10,11],env_add:10,env_prun:10,environ:[5,6,7,10],epoch:[2,11],equival:10,err:10,error:[2,5,7,8,10],escap:10,especi:7,estim:11,estimate_s:[10,11],etc:[5,6,7,10,11],even:[5,6,11],ever:0,everi:11,everyth:[5,6,10],exact:[7,11],exactli:[7,11],examin:5,exampl:[1,2,5,9,10,11],except:[5,6,7,10,11],exclud:10,excludepkg:[6,10],exec:5,execproduct:10,execreadlin:10,execut:[2,4,7,10],executil:8,execwithcaptur:10,execwithredirect:10,exist:[0,1,4,5,6,7,10,11],exit:[1,2,5,6,7,10],expand:10,expans:10,expect:[5,7,10],experi:10,expir:11,expire_sec:11,explicitli:7,explor:1,exract:11,ext4:[1,6,7,10],extend:7,extens:[1,6],extern:10,extra:[2,5,7,11],extra_boot_arg:[5,10],extract:[10,11],f15:5,f16:5,f629b7a948f5:11,fail:[1,2,7,10,11],failur:[10,11],fairli:6,fakednf:10,fall:11,fals:[1,2,5,6,7,10,11],far:5,fatal:[5,10],fatalerror:10,fe925c35e795:11,featur:5,fedora:[3,5,6,7,10,11],fedoraproject:[5,6,11],feedback:5,fetch:[0,10],few:[5,6],field:[2,7,11],figur:4,fila:11,file:[0,1,2,4,6,7,9,10,11],fileglob:10,filenam:[0,1,2,10,11],filesystem:[1,7,9,10,11],fill:11,filter:[10,11],filter_stderr:10,find:[0,4,5,10,11],find_commit_tag:11,find_field_valu:11,find_free_port:10,find_nam:11,find_ostree_root:10,find_recipe_obj:11,find_templ:10,findkernel:10,fine:7,finish:[1,2,6,7,10,11],firewal:11,firewall_cmd:11,firewalld:7,firmwar:5,first:[4,5,7,10,11],first_registr:11,fit:5,five:2,fix:10,flag:10,flask:11,flask_blueprint:[8,10],flatten:5,flexibl:4,fmt:10,fname:10,fobj:10,follow:[2,5,10,11],foo:11,forc:[6,7,10,11],form:[0,6,11],format:[1,2,5,7,10,11],found:[5,7,10,11],four:2,free:[6,10],freez:[1,2,11],from:[0,1,2,4,5,6,7,9,10,11],from_commit:11,frozen:[1,2],frozen_toml_filenam:2,fs_imag:5,fs_label:5,fsck:10,fsimag:[5,10],fstab:5,fstype:[5,10],ftp:7,ftruncat:10,full:[0,7,10,11],further:10,futur:7,game:11,gener:[2,4,5,6,10,11],generate_module_data:10,generate_module_info:10,get:[0,5,7,10,11],get_arch:10,get_base_dir:11,get_base_object:11,get_buildarch:10,get_commit_detail:11,get_compose_typ:11,get_default:11,get_default_servic:11,get_dnf_base_object:10,get_extra_pkg:11,get_filenam:0,get_firewall_set:11,get_image_nam:11,get_iso_label:10,get_kernel_append:11,get_keyboard_layout:11,get_languag:11,get_loop_nam:10,get_repo_descript:11,get_repo_sourc:11,get_revision_from_tag:11,get_servic:11,get_source_id:11,get_timezone_set:11,get_url_json:0,get_url_json_unlimit:0,get_url_raw:0,gfile:11,ggit:11,gib:[5,6,10],gid:[7,11],git:[5,11],gitarchivetarbal:11,github:5,gitlock:11,gitrepo:11,gitrpm:[8,10],gitrpmbuild:11,given:[0,10,11],glanc:5,glob:[6,7,10,11],glusterf:11,gnome:5,gnu:11,goe:[4,6,10],going:5,good:[5,10],googl:[1,7],gpg:[7,11],gpgcheck:7,gpgkei:[7,11],gpgkey_url:[7,11],gplv3:11,graft:10,green:11,group:[1,5,10,11],group_nam:11,group_typ:11,grow:5,growpart:5,grub2:[5,7],grub:10,gui:7,gzip:[5,10],had:5,handl:[2,5,6,7,10],handle_api_result:2,handler:10,happen:[5,6,10],hard:11,hardlink:10,has:[2,5,7,9,10,11],hash:[1,2,7,11],have:[2,5,6,7,10,11],haven:5,hawkei:11,hda:1,head:[7,11],head_commit:11,header:[0,7,11],hello:5,help:[0,5,8,10],helper:11,here:[4,5,6,7,9,11],higer:11,highbank:5,higher:6,histori:[7,11],hold:11,home:[5,7],homepag:11,hook:10,host:[0,5,6,7,10,11],hostnam:[7,11],how:[4,10],howev:7,http:[0,1,2,5,6,7,10,11],http_client:8,httpconnect:0,httpconnectionpool:0,httpd:7,human:2,hw_random:10,hwmon:10,hyper:1,i386:10,ia64:10,id_rsa:7,idea:[4,5],ideal:10,identifi:[2,6],ids:11,ignor:10,imag:[2,3,4,6,10,11],image_nam:[5,7,11],image_s:11,image_size_align:5,image_typ:[5,10],images_dir:10,imap:7,img:[5,6,9,10],img_mount:10,img_siz:10,imgutil:8,immedi:7,immut:[7,11],implantisomd5:10,implement:[9,10],includ:[0,2,5,7,9,11],inclus:11,incom:10,increment:11,indent:2,index:[3,11],indic:10,individu:2,info:[1,2,7,11],inform:[1,2,4,6,7,11],init:[5,7,10],init_file_log:10,init_stream_log:10,initi:10,initramf:[5,6,10,11],initrd:[5,6,10],initrd_address:10,initrd_path:10,inject:7,inline_comment_prefix:11,input:[5,10],inroot:10,insecur:5,insert:11,insid:[5,10,11],insort_left:11,instal:[1,2,4,8,9,11],install_log:10,installclass:9,installerror:10,installimg:[9,10],installinitrd:10,installkernel:10,installpkg:[6,9,10,11],installroot:[6,10],installtre:10,installupgradeinitrd:10,instanc:[5,11],instead:[1,2,5,6,7,11],instroot:4,instruct:5,insuffici:10,integ:11,interact:1,interfac:7,interfer:6,intermedi:1,interpol:11,intrd:10,introduct:3,invalid:11,ioerror:11,is_commit_tag:11,is_image_mount:10,is_parent_diff:11,iserror:10,isfin:[6,10],isn:[5,10,11],iso:[1,4,10,11],iso_nam:5,iso_path:10,isoinfo:10,isolabel:10,isolinux:10,isomountpoint:10,issu:7,item:[2,10,11],iter:[10,11],its:[5,10,11],itself:7,jboss:11,job:11,job_creat:11,job_finish:11,job_start:11,joinpath:10,json:[0,1,2,5,7,10,11],just:[9,10,11],kbyte:11,kdir:10,keep:[1,5,10,11],keepglob:10,kei:[2,7,10,11],kernel:[5,6,10,11],kernel_append:11,kernel_arg:[5,10],keyboard:[7,11],keyboard_cmd:11,keymap:7,kickstart:[7,10,11],kickstartpars:10,kill:[5,10],knowledg:4,known:2,kpartx:[5,10],kpartx_disk_img:10,ks_path:10,ks_templat:11,ksflatten:5,kubernet:11,kvm:[1,5],kwarg:[10,11],label:[5,10],lambda:10,lane:[1,5,6,7],lang:11,lang_cmd:11,languag:[7,11],larg:[7,11],last:[1,2,10,11],later:[6,10,11],latest:[5,11],launch:7,layout:11,lazi:10,lead:[0,10],least:[5,10],leav:[7,10,11],left:[7,10,11],leftmost:11,leftov:[5,10],len:11,less:11,level:[5,6,7,10,11],lib64_arch:10,lib:[7,10,11],librari:4,libus:11,libvirt:5,licens:11,light:6,like:[1,5,6,7,9,10,11],limit:[0,5,7,10,11],line:[2,4,7,10,11],link:10,linktre:10,linux:[5,6,10],list:[1,2,4,5,6,7,10,11],list_branch_fil:11,list_commit:11,list_commit_fil:11,listen:[1,7,10],live:[1,4,7,10,11],live_image_nam:10,live_rootfs_s:5,livecd:10,livemedia:[3,7,10,11],liveo:[6,10],livesi:5,livetemplaterunn:10,lmc:[5,10],lmc_parser:10,load:[10,11],local:[1,5,10,11],localectl:7,localhost:10,locat:[5,6],lock:[7,11],lock_check:11,log:[1,2,5,6,10,11],log_check:10,log_error:10,log_output:10,log_path:10,log_request_handler_class:10,log_selinux_st:10,logdir:10,logfil:[1,5,6,7,10,11],logger:10,logic:6,logmonitor:10,lognam:10,logrequesthandl:10,logserv:10,longer:[7,11],look:[4,5,7,9,11],loop:[5,6,10],loop_attach:10,loop_detach:10,loop_dev:10,loop_waitfor:10,loopdev:10,loopx:10,loopxpn:10,lorax:[1,5,9,10,11],lorax_composer_pars:11,lorax_pars:10,lorax_templ:5,loraxdir:10,loraxdownloadcallback:10,loraxrpmcallback:10,loraxtempl:10,loraxtemplaterunn:[6,10],lose:5,losetup:10,lost:11,low:10,lowercas:10,lowest:10,lpar:10,lst:[2,11],ltmpl:[6,8],lvm2:10,lzma:[5,10],macboot:[5,6],made:[7,10],mai:[5,6,7,10,11],mail:5,main:[2,11],maintain:4,make:[5,6,7,10,11],make_:7,make_appli:10,make_compos:11,make_disk:7,make_dnf_dir:11,make_git_rpm:11,make_imag:10,make_live_imag:10,make_livecd:10,make_owned_dir:11,make_queue_dir:11,make_runtim:10,make_setup_st:11,make_squashf:10,make_tar_disk:10,makestamp:4,maketreeinfo:4,mako:[4,5,6,10],manag:1,mandatori:[7,11],mani:11,manual:11,map:2,mask:10,master:11,match:[5,7,10,11],max_ag:[],maximum:11,maxretri:10,mbr:5,meant:[10,11],mechan:7,media:[5,10],megabyt:5,member:[1,5],memlimit:10,memori:[5,10],memtest86:5,mention:10,messag:[7,10,11],metadata:[1,2,5,6,7,10,11],metalink:[7,11],method:[5,7,10,11],mib:[5,10],mime:11,mind:[5,11],minim:[5,7,10],minimum:[5,11],minut:5,mirror:[5,10,11],mirrorlist:[6,7,10,11],mirrormanag:5,miss:[10,11],mix:4,mkbtrfsimg:10,mkcpio:10,mkdir:[5,6,10],mkdosimg:10,mkext4img:10,mkf:10,mkfsarg:10,mkfsimag:10,mkfsimage_from_disk:10,mkhfsimg:10,mknod:5,mkqcow2:10,mkqemu_img:10,mkrootfsimg:10,mkspars:10,mksquashf:10,mktar:10,mnt:[7,10],mock:[1,7],mockfil:7,moddir:10,mode:[1,5,6,10,11],modeless:10,modifi:[5,10,11],modul:[1,3,4,6,8],module_nam:11,module_nv:11,modules_cmd:2,modules_info:11,modules_list:11,monitor:[5,8,11],more:[4,5,7,10],most:[1,2,5,7,11],mount:[5,7,8],mount_boot_part_over_root:10,mount_dir:10,mount_ok:10,mountarg:10,mountpoint:[5,10],move:[6,7,10,11],move_compose_result:[7,11],msg:[10,11],much:10,multi:5,multipl:[2,5,6,7,10,11],must:[5,6,7,9,10,11],mvebu:5,myconfig:10,name:[2,10,11],namespac:2,need:[1,2,5,6,7,10,11],neither:11,network:[5,7,10],never:10,nevra:[2,11],new_item:11,new_recip:11,newer:5,newest:[1,2,11],newli:10,newlin:10,newrecipegit:11,newrun:10,next:[10,11],nice:2,noarch:[7,11],node:[5,6],nomacboot:[5,6],non:[7,10,11],none:[0,5,7,10,11],nop:10,norm:2,normal:[1,5,6,9],north:7,nosmt:7,nosuchpackag:10,note:[5,6,10,11],noth:[2,10,11],noupgrad:6,noverifi:6,noverifyssl:[6,10],novirt:5,novirt_cancel_check:10,novirt_instal:[7,10,11],now:[5,6,9,10,11],nspawn:[5,6],ntp:7,ntpserver:[7,11],number:[1,2,5,6,7,10,11],numer:7,nvr:6,object:[0,10,11],observ:5,occas:10,occur:10,oci_config:5,oci_runtim:5,octalmod:10,off:7,offset:[0,11],oid:11,old:[5,6,10,11],old_item:11,old_recip:11,old_vers:11,older:5,omap:5,omit:7,onc:[1,5,6,7],one:[1,2,5,6,7,9,10,11],ones:[6,7,10,11],onli:[2,5,6,7,10,11],onto:6,open:[7,11],open_or_create_repo:11,openh264:11,openstack:[1,7],oper:[4,5,7,11],opt:[2,7,10,11],option:[4,5,6,7,10,11],order:[4,6,7,11],ordereddict:11,org:[5,6,7,11],origin:[0,5,7,11],ostre:[5,10],other:[4,5,6,7,10,11],otherwis:[7,10,11],ouput:11,out:[1,4,7,10,11],outfil:10,output:[1,2,5,6,8],outputdir:[6,10],outroot:10,outsid:10,over:[7,9],overhead:10,overrid:[5,6,7,10,11],overridden:7,overwrit:[7,11],overwritten:10,ovmf:5,ovmf_path:[5,10],own:[5,6,7,11],owner:[7,11],ownership:[7,11],p_dir:11,pacag:10,packag:[1,4,5,6,8,9],package_nam:11,package_nv:11,packagedir:10,packagenevra:2,page:3,param1:0,param2:0,param:[10,11],paramat:9,paramet:[0,2,10,11],parent:11,pars:[10,11],parser:10,part:[2,5,9,10,11],particular:10,partit:[1,5,10],partitin:5,partitionmount:10,pass:[1,5,6,7,9,10,11],passwd:5,password:[5,7,11],pat:10,patch:[7,11],path:[0,1,2,5,6,7,10,11],pathnam:10,pattern:10,payload:10,pcritic:10,pdebug:10,per:[10,11],permiss:[7,11],perror:10,phys_root:10,physic:10,pick:[1,10],pid:5,pinfo:10,ping:11,pivot:10,pkg:[2,10,11],pkg_to_build:11,pkg_to_dep:11,pkg_to_project:11,pkg_to_project_info:11,pkgglob:10,pkglistdir:10,pkgname:9,pkgsizefil:10,pki:11,place:[5,6,9,10,11],plain:[6,7,10,11],plan:7,platform:[5,11],play0ad:11,pleas:10,plugin:6,plugin_conf:5,point:[4,5,7,10,11],pool:7,popen:[10,11],popul:[10,11],port:[0,5,6,7,10,11],pos:11,posit:11,possibl:[2,5,7,10,11],post:[0,5,7,10,11],post_url:0,post_url_json:0,post_url_toml:0,postfix:7,postinstal:10,postun:10,powerpc:10,ppc64:10,ppc64le:[9,10],ppc:9,pre:[5,7,10],precaut:1,preexec_fn:10,prefix:[5,7,10,11],prepar:11,prepare_commit:11,prepend:11,present:[4,5],preserv:10,pretti:[7,10],pretty_dict:2,pretty_diff_entri:2,prettycommitdetail:2,prettydiffentri:[],preun:10,prevent:11,previou:[7,10,11],previous:[4,5],primari:[5,7],primarili:7,print:[1,2],privileg:7,probabl:6,problem:[4,10,11],proc:10,procedur:10,process:[2,4,5,6,7,9,10,11],produc:[4,5,7,11],product:[3,6,10],program:[1,2,5,6,7,10,11],progress:[0,2,10],proj:11,proj_to_modul:11,project:[0,1,5,7,8,10],project_info:11,project_nam:11,projects_cmd:2,projects_depsolv:11,projects_depsolve_with_s:11,projects_info:[2,11],projects_list:[2,11],projectserror:11,pronounc:11,properti:11,protocol:7,provid:[4,5,6,10,11],proxi:[6,7,10,11],pub:[5,6,7],pubkei:5,pull:[4,5,6],pungi:4,purpos:[5,7],push:[1,2],put:[7,9,10,11],pwarn:10,pxe:10,pxeboot:6,pyanaconda:9,pykickstart:[10,11],pylorax:[4,6,7,8,9],pyo:10,python:[4,6,10,11],pythonpath:5,qcow2:[1,5,10],qemu:[1,10],qemu_arg:5,qemu_cmd:10,qemuinstal:10,queri:[0,2],queue:[2,7,8,10],queue_statu:11,quot:10,race:10,rais:[0,10,11],raise_err:10,ram:[5,10],random:[5,10],rang:10,rare:10,raw:[0,1,2,5,11],rawhid:[5,6],rdo:5,re_test:10,react:7,read:[4,5,10,11],read_commit:11,read_commit_spec:11,read_recipe_and_id:11,read_recipe_commit:11,readabl:2,readi:[10,11],readm:11,real:[5,7,10],realli:[5,6,10],reason:[5,10],reboot:7,rebuild:[5,6,10],rebuild_initrd:10,rebuild_initrds_for_l:10,recent:[1,2,11],recip:[8,10],recipe_dict:11,recipe_diff:11,recipe_filenam:11,recipe_from_dict:11,recipe_from_fil:11,recipe_from_toml:11,recipe_nam:11,recipe_path:11,recipe_str:11,recipeerror:11,recipefileerror:11,recipegit:11,recipegroup:11,recipemodul:11,recipepackag:11,recommend:[5,7],recurs:10,redhat:[1,5,6,7],redirect:[5,10],reduc:7,ref:[7,11],refer:[7,11],referenc:7,refus:5,regex:[8,10],regist:11,register_blueprint:11,rel:10,relat:[7,11],releas:[1,2,4,5,6,7,10,11],releasev:[5,7,10],relev:11,reli:4,reliabl:5,remain:[2,6,7],remaind:11,rememb:7,remov:[4,5,6,7,10,11],remove_temp:10,removefrom:[6,10],removekmod:[6,10],removepkg:[6,10],renam:[5,10],repl:10,replac:[4,5,6,7,9,10,11],repo1:5,repo2:5,repo:[4,6,10,11],repo_file_exist:11,repo_to_k:11,repo_to_sourc:11,repo_url:5,repodata:[5,11],repodict:11,report:[5,6,7,11],repositori:[6,7,10,11],represent:11,reproduc:11,reqpart:[5,10],request:[0,7,10,11],requir:[1,5,7,10,11],rerun:11,rescu:5,reserv:5,reset:10,reset_handl:10,reset_lang:10,resolv:10,resort:10,respond:7,respons:[0,1,10],rest:[7,10],restart:[7,11],restor:11,result:[0,1,2,5,6,7,10,11],result_dir:5,resultdir:5,results_dir:[10,11],retain:7,reticul:10,retriev:[7,11],retrysleep:10,retun:11,returncod:10,revert:[1,2,11],revert_fil:11,revert_recip:11,revis:11,revisor:4,revpars:11,rexist:10,rglob:10,rhel7:[3,5,11],rhel:5,rng:5,root:[1,2,4,5,6,7,10,11],root_dir:11,rootdir:10,rootf:[5,6,10],rootfs_imag:10,rootfs_siz:6,rootm:5,rootpw:[5,11],roughli:10,round:[10,11],round_to_block:10,rout:[0,7,10],rpm:[4,5,7,10,11],rpmbuild:11,rpmfluff:11,rpmname:[7,11],rpmreleas:[7,11],rpmversion:[7,11],rtype:11,rule:11,run:[1,2,5,7,9,10,11],run_creat:10,run_pkg_transact:[6,10],runcmd:[6,10],runcmd_output:10,rundir:10,runner:10,runtim:[5,9,10],runtimebuild:[9,10],runtimeerror:[0,10,11],rxxx:11,s390x:10,safe:[7,10],samba:11,same:[5,6,7,10,11],sampl:10,satisfi:11,save:[0,1,2,6,7,10,11],sbin:[5,10],scene:7,scm:7,script:[4,5,10,11],scriptlet:10,search:[3,10,11],second:[5,11],secondari:7,section:[5,7,10,11],secur:1,see:[5,10,11],seem:10,select:[1,2,5,6,7,10,11],self:[7,10,11],selinux:[5,7,10],semver:[7,11],send:[0,1],separ:[2,10,11],sequenc:10,server:[0,1,2,7,8,10],servic:[6,10,11],services_cmd:11,set:[2,4,5,6,7,10,11],setenforc:6,setenv:10,setup:[5,6,7,10,11],setup_log:10,sever:[5,9,11],sha256:5,shallow:10,share:[5,6,7,9,10,11],share_dir:11,sharedir:[6,7,10],shell:7,ship:6,shlex:10,shortnam:10,should:[0,5,6,7,10,11],should_exit_now:2,show:[1,2,5,6,7,10],show_json:2,shutdown:[5,10],sig:11,sig_dfl:10,sig_ign:10,sign:[7,10,11],signal:10,signific:7,similar:[6,7],simpl:[2,6,7],simple_test:10,simplerpmbuild:11,simpli:7,simul:2,sinc:[5,7,11],singl:[2,5],singleton:10,site:5,situat:7,size:[1,2,5,6,10,11],skip:[5,10,11],skip_rul:11,slice:11,slightli:5,slow:5,small:10,smp:5,socket:[0,1,2,7],socket_path:[0,2],socketserv:10,softwar:11,solut:5,solv:11,some:[0,4,5,6,7,10,11],someplac:7,someth:[4,5,7,10,11],sometim:5,sort:[6,11],sound:[6,10],sourc:[0,1,6,8,10,11],source_glob:11,source_nam:11,source_path:11,source_ref:11,source_to_repo:11,sources_add:2,sources_cmd:2,sources_delet:2,sources_info:2,sources_list:2,sourcesdir:11,space:[2,6,7,10,11],sparingli:11,spars:[5,10],speak:[4,6],spec:11,special:[6,11],specif:[5,6,7,9,10,11],specifi:[0,5,7,10,11],speed:5,spin:5,spline:10,split:10,split_and_expand:10,squashf:[5,10],squashfs_arg:[5,10],squashfs_onli:10,src:[3,5,10],srcdir:10,srcglob:10,srv:7,ssh:[5,7,11],sshd:[5,7],sshkei:11,ssl:[6,10],sslverifi:10,stage2:10,stage:[4,5],standard:[10,11],start:[1,2,5,6,7,10,11],start_build:11,start_queue_monitor:11,startprogram:10,startup:7,state:[1,5,7,10,11],statement:10,statu:[0,7,8,10],status_cmd:2,status_filt:11,stderr:10,stdin:10,stdout:[10,11],step:[4,5],stick:7,still:[5,7,10],stop:[5,7],storag:[1,2,5,7,10,11],store:[5,6,7,10,11],str1:2,str2:2,str:[0,2,10,11],strang:5,stream:11,strict:11,strictli:6,string:[0,2,7,10,11],string_low:10,stuck:5,stuff:5,style:10,sub:10,subclass:11,subdirectori:11,submit:11,submodul:8,submount:10,subpackag:8,subprocess:10,subset:11,substitut:[5,6],succe:11,success:[10,11],sudo:[5,7],suffix:10,suit:[1,7],suitabl:[10,11],summari:[7,11],support:[1,2,4,5,6,9,11],sure:[5,7,10,11],suspect:5,swap:5,symlink:[6,10,11],sys:[2,10],sys_root_dir:10,sysimag:10,syslinux:5,sysroot:10,system:[1,5,6,7,10,11],system_sourc:11,systemctl:[6,7,10],systemd:[5,6,7,10],sysutil:8,tag:[1,2,6,7,11],tag_file_commit:11,tag_recipe_commit:11,take:[2,5,7,9,10,11],take_limit:11,talk:[0,2],tar:[1,2,7,11],tar_disk_nam:5,tar_img:10,tarbal:10,tarfil:[5,10],target:[5,6,10],tcp:[7,10],tcpserver:10,tear:11,tegra:5,tell:6,telnet:7,telnetd:7,tempdir:10,templat:[4,5,7,9,10,11],template_fil:10,templatedir:10,templatefil:10,templaterunn:10,temporari:[1,2,4,5,6,7,10,11],termin:[5,10],test:[1,5,7,11],test_config:11,test_mod:11,test_templ:11,testmod:[1,2],text:[6,7,11],textiowrapp:10,than:[5,7,10,11],thei:[1,5,6,7,11],thelogg:10,them:[4,6,7,10,11],therefor:7,thi:[0,1,2,5,6,7,9,10,11],thing:[4,5,10,11],those:[4,9,11],though:[4,11],thread:[5,7,10,11],three:[2,7],thu:10,ti_don:10,ti_tot:10,time:[5,6,7,9,10,11],timedatectl:7,timeout:[0,5,10],timestamp:[8,10],timestamp_dict:11,timezon:11,timezone_cmd:11,titl:[5,10,11],tmp:[5,6,7,10,11],tmpdir:[10,11],tmpl:[9,10,11],to_commit:11,token:10,told:6,toml:[0,1,2,7,8,10],toml_dict:11,toml_filenam:2,tomldecodeerror:11,tomlerror:11,tool:[1,4,5,6],top:[5,6,7,9,10,11],total:[5,11],total_drpm:10,total_fil:10,total_fn:0,total_s:10,touch:10,trace:10,traceback:10,track:[1,11],trail:11,transact:10,transactionprogress:10,transmogrifi:10,trash:5,treat:[7,10],tree:[4,5,6,9,10,11],treebuild:[8,9,11],treeinfo:[6,8],tri:[5,10,11],truckin:10,ts_done:10,ts_total:10,tty1:5,tty3:5,tui:5,tupl:[2,10,11],turn:4,two:[2,11],type:[0,1,2,5,10],typic:10,udev_escap:10,udp:7,uid:[7,11],umask:10,umount:[5,7,10],uncompress:11,undelet:11,under:[5,6,7,10,11],understand:7,undo:[1,2,11],unicodedecodeerror:10,uniqu:11,unit:[7,10],unix:[0,2,7,11],unix_socket:8,unixhttpconnect:0,unixhttpconnectionpool:0,unknown:10,unless:11,unmaintain:4,unmount:[5,10],unneed:[4,6,7,10,11],unpack:4,unpartit:10,until:[7,10],untouch:10,unus:[2,5],upd:4,updat:[2,3,5,6,7,10,11],update_vagrant_metadata:10,upgrad:10,upload:[5,7],upstream:11,upstream_vc:11,url:[0,5,6,7,10,11],url_prefix:11,urllib3:0,usabl:5,usag:[1,5,6,7,10],usbutil:10,use:[0,1,2,5,6,7,10,11],used:[1,2,4,5,6,7,10,11],useful:[5,10],user:[1,2,10,11],user_dracut_arg:10,useradd:7,uses:[5,6,7,10,11],using:[1,2,5,6,7,9,10,11],usr:[5,6,7,9,10,11],usual:[5,7,11],utc:[7,11],utf:[7,10],util:[0,5,8],uuid:[1,2,7,11],uuid_cancel:11,uuid_delet:11,uuid_dir:11,uuid_imag:11,uuid_info:11,uuid_log:11,uuid_statu:11,uuid_tar:11,v0_api:11,v0_blueprints_chang:11,v0_blueprints_delet:11,v0_blueprints_delete_workspac:11,v0_blueprints_depsolv:11,v0_blueprints_diff:11,v0_blueprints_freez:11,v0_blueprints_info:11,v0_blueprints_list:11,v0_blueprints_new:11,v0_blueprints_tag:11,v0_blueprints_undo:11,v0_blueprints_workspac:11,v0_compose_cancel:11,v0_compose_delet:11,v0_compose_fail:11,v0_compose_finish:11,v0_compose_imag:11,v0_compose_info:11,v0_compose_log:11,v0_compose_log_tail:11,v0_compose_metadata:11,v0_compose_queu:11,v0_compose_result:11,v0_compose_start:11,v0_compose_statu:11,v0_compose_typ:11,v0_modules_info:11,v0_modules_list:11,v0_projects_depsolv:11,v0_projects_info:11,v0_projects_list:11,v0_projects_source_delet:11,v0_projects_source_info:11,v0_projects_source_list:11,v0_projects_source_new:11,vagrant:10,vagrant_metadata:5,vagrantfil:5,valid:[7,10,11],valu:[2,5,7,10,11],valueerror:11,valuetok:10,variabl:[5,6,10],variant:[6,10],variou:[10,11],vcpu:[5,10],verbatim:5,veri:5,verifi:[1,6,10],version:[0,1,2,4,5,6,7,10,11],vhd:1,via:[5,6,7],video:10,view:[1,11],view_func:11,virt:[10,11],virt_instal:10,virtio:10,virtio_consol:10,virtio_host:10,virtio_port:10,virtual:[5,10],vmdk:1,vmlinuz:[5,10],vnc:[5,10],volid:[5,6,10],volum:[5,6],wai:[2,5,7,11],wait:[1,10,11],want:[5,7,11],warfar:11,warn:[10,11],wasn:5,watch:5,web:[5,7],websit:5,weight:6,welcom:5,welder:7,weldr:[1,7,11],well:[5,6,7,11],were:[10,11],what:[0,4,5,6,7,10,11],whatev:11,wheel:[5,7],when:[5,6,7,10,11],whenev:10,where:[1,5,6,7,10,11],whether:[2,10,11],which:[1,2,4,5,6,7,9,10,11],whitespac:10,who:5,whole:10,widest:7,widget:7,wildcard:7,winnt:10,with_cor:11,with_rng:5,without:[5,6,7,11],word:10,work:[10,11],work_dir:10,workdir:[6,10],workflow:4,workspac:[1,2,8,10],workspace_delet:11,workspace_dir:11,workspace_read:11,workspace_writ:11,world:5,would:[5,7,9,10],wrapper:11,write:[4,10,11],write_commit:11,write_fil:11,write_ks_group:11,write_ks_root:11,write_ks_us:11,write_timestamp:11,writepkglist:10,writepkgs:10,written:[4,5,7,10],wrong:10,wrote:11,wwood:10,www:11,x86:[6,9,10,11],x86_64:[5,6,10,11],xattr:10,xfce:5,xfsprog:10,xml:5,xorrisof:6,xxxx:5,xxxxx:5,yield:11,you:[1,5,6,7,9,10,11],your:[5,6,7,9,11],yourdomain:5,yum:[4,5,7,11],yumbas:11,yumlock:11,zero:[10,11],zerombr:5},titles:["composer package","composer-cli","composer.cli package","Welcome to Lorax's documentation!","Introduction to Lorax","livemedia-creator","Lorax","lorax-composer","src","Product and Updates Images","pylorax package","pylorax.api package"],titleterms:{"import":7,"new":11,Adding:[7,11],The:6,Using:5,add:7,ami:5,anaconda:5,api:11,applianc:5,argument:[1,5,6,7],atom:5,base:10,befor:4,bisect:11,blueprint:[1,2,7],blueprint_nam:[],boot:5,branch:3,build:1,buildstamp:10,cancel:[],chang:[],checkparam:11,cleanup:6,cli:[1,2],cmdline:[1,2,5,6,7,10,11],commit:[],compos:[0,1,2,7,11],compose_statu:[],compose_typ:[],config:11,contain:5,content:[0,2,10,11],creat:5,creation:[5,6],creator:[5,10],crossdomain:[],custom:[6,7],debug:5,decor:10,delet:[],depsolv:[],diff:[],discinfo:10,disk:[5,7],dnfbase:[10,11],dnfhelper:10,docker:5,document:3,download:1,dracut:[5,6],dvd:7,edit:1,error:11,exampl:7,executil:10,fail:[],file:5,filesystem:[5,6],finish:[],firewal:7,flask_blueprint:11,format:[],freez:[],from_commit:[],git:7,gitrpm:11,group:7,hack:5,help:2,how:[5,6,7],http_client:0,imag:[1,5,7,9],imgutil:10,indic:3,info:[],initi:5,insid:6,instal:[5,6,7,10],introduct:4,iso:[5,6,7],json:[],kbyte:[],kernel:7,kickstart:5,limit:[],list:[],live:5,livemedia:5,local:7,log:7,lorax:[3,4,6,7],ltmpl:10,metadata:[],mock:[5,6],modul:[0,2,7,10,11],module_nam:[],monitor:[1,10],mount:10,name:[1,5,6,7],note:7,oci:5,offset:[],open:5,openstack:5,other:3,output:[7,10,11],packag:[0,2,7,10,11],partit:7,posit:[1,6,7],post:[],postinstal:6,problem:5,product:9,project:[2,11],project_nam:[],proxi:5,pxe:5,pylorax:[10,11],qemu:5,queue:11,quickstart:[5,6,7],recip:11,regex:11,repo:[5,7],repositori:5,requir:6,respons:11,result:[],rout:11,run:6,runtim:6,secur:7,server:11,servic:7,size:[],sourc:[2,7],squashf:6,src:8,sshkei:7,statu:[1,2,11],submodul:[0,2,10,11],subpackag:[0,10],support:7,sysutil:10,tabl:3,tag:[],tar:5,templat:6,thing:7,timestamp:11,timezon:7,tmpl:6,to_commit:[],toml:11,treebuild:10,treeinfo:10,type:[7,11],uefi:5,undo:[],unix_socket:0,updat:9,user:[5,7],util:2,uuid:[],vagrant:5,virt:5,welcom:3,work:[5,6,7],workspac:11}}) \ No newline at end of file