Add support for groups to blueprints.
Nothing is currently being done with this information, but it will be soon. (cherry picked from commit0f69d2084c) (cherry picked from commit76d376fe18)
This commit is contained in:
parent
f5115291bd
commit
f1f8980c49
@ -137,6 +137,18 @@ NOTE: As of lorax-composer-29.2-1 the versions are not used for depsolving,
|
||||
that is planned for a future release. And currently there are no differences
|
||||
between ``packages`` and ``modules`` in ``lorax-composer``.
|
||||
|
||||
[[groups]]
|
||||
~~~~~~~~~~
|
||||
|
||||
These entries describe a group of packages to be installed into the image. Package groups are
|
||||
defined in the repository metadata. Each group has a descriptive name used primarily for display
|
||||
in user interfaces and an ID more commonly used in kickstart files. Here, the ID is the expected
|
||||
way of listing a group.
|
||||
|
||||
Groups have three different ways of categorizing their packages: mandatory, default, and optional.
|
||||
For purposes of blueprints, mandatory and default packages will be installed. There is no mechanism
|
||||
for selecting optional packages.
|
||||
|
||||
Customizations
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@ -47,21 +47,24 @@ class Recipe(dict):
|
||||
and adds a .filename property to return the recipe's filename,
|
||||
and a .toml() function to return the recipe as a TOML string.
|
||||
"""
|
||||
def __init__(self, name, description, version, modules, packages, customizations=None):
|
||||
def __init__(self, name, description, version, modules, packages, groups, customizations=None):
|
||||
# Check that version is empty or semver compatible
|
||||
if version:
|
||||
semver.Version(version)
|
||||
|
||||
# Make sure modules and packages are listed by their case-insensitive names
|
||||
# Make sure modules, packages, and groups are listed by their case-insensitive names
|
||||
if modules is not None:
|
||||
modules = sorted(modules, key=lambda m: m["name"].lower())
|
||||
if packages is not None:
|
||||
packages = sorted(packages, key=lambda p: p["name"].lower())
|
||||
if groups is not None:
|
||||
groups = sorted(groups, key=lambda g: g["name"].lower())
|
||||
dict.__init__(self, name=name,
|
||||
description=description,
|
||||
version=version,
|
||||
modules=modules,
|
||||
packages=packages,
|
||||
groups=groups,
|
||||
customizations=customizations)
|
||||
|
||||
# We don't want customizations=None to show up in the TOML so remove it
|
||||
@ -88,6 +91,11 @@ class Recipe(dict):
|
||||
"""Return the names and version globs of the modules"""
|
||||
return [(m["name"], m["version"]) for m in self["modules"] or []]
|
||||
|
||||
@property
|
||||
def group_names(self):
|
||||
"""Return the names of the groups. Groups do not have versions."""
|
||||
return map(lambda g: g["name"], self["groups"] or [])
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
"""Return the Recipe's filename
|
||||
@ -144,21 +152,25 @@ class Recipe(dict):
|
||||
"""
|
||||
module_names = self.module_names
|
||||
package_names = self.package_names
|
||||
group_names = self.group_names
|
||||
|
||||
new_modules = []
|
||||
new_packages = []
|
||||
new_groups = []
|
||||
for dep in deps:
|
||||
if dep["name"] in package_names:
|
||||
new_packages.append(RecipePackage(dep["name"], dep_evra(dep)))
|
||||
elif dep["name"] in module_names:
|
||||
new_modules.append(RecipeModule(dep["name"], dep_evra(dep)))
|
||||
elif dep["name"] in group_names:
|
||||
new_groups.append(RecipeGroup(dep["name"]))
|
||||
if "customizations" in self:
|
||||
customizations = self["customizations"]
|
||||
else:
|
||||
customizations = None
|
||||
|
||||
return Recipe(self["name"], self["description"], self["version"],
|
||||
new_modules, new_packages, customizations)
|
||||
new_modules, new_packages, new_groups, customizations)
|
||||
|
||||
class RecipeModule(dict):
|
||||
def __init__(self, name, version):
|
||||
@ -167,6 +179,10 @@ class RecipeModule(dict):
|
||||
class RecipePackage(RecipeModule):
|
||||
pass
|
||||
|
||||
class RecipeGroup(dict):
|
||||
def __init__(self, name):
|
||||
dict.__init__(self, name=name)
|
||||
|
||||
def recipe_from_file(recipe_path):
|
||||
"""Return a recipe file as a Recipe object
|
||||
|
||||
@ -210,6 +226,10 @@ def recipe_from_dict(recipe_dict):
|
||||
packages = [RecipePackage(p.get("name"), p.get("version")) for p in recipe_dict["packages"]]
|
||||
else:
|
||||
packages = []
|
||||
if recipe_dict.get("groups"):
|
||||
groups = [RecipeGroup(g.get("name")) for g in recipe_dict["groups"]]
|
||||
else:
|
||||
groups = []
|
||||
name = recipe_dict["name"]
|
||||
description = recipe_dict["description"]
|
||||
version = recipe_dict.get("version", None)
|
||||
@ -217,7 +237,7 @@ def recipe_from_dict(recipe_dict):
|
||||
except KeyError as e:
|
||||
raise RecipeError("There was a problem parsing the recipe: %s" % str(e))
|
||||
|
||||
return Recipe(name, description, version, modules, packages, customizations)
|
||||
return Recipe(name, description, version, modules, packages, groups, customizations)
|
||||
|
||||
def gfile(path):
|
||||
"""Convert a string path to GFile for use with Git"""
|
||||
@ -897,5 +917,6 @@ def recipe_diff(old_recipe, new_recipe):
|
||||
|
||||
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"]))
|
||||
|
||||
return diffs
|
||||
|
||||
@ -1 +1 @@
|
||||
{'name': 'custom-base', 'description': 'A base system with customizations', 'version': '0.0.1', 'modules': [], 'packages': [{'name': 'bash', 'version': '4.4.*'}], 'customizations': {'hostname': 'custombase', 'sshkey': [{'user': 'root', 'key': 'A SSH KEY FOR ROOT'}]}}
|
||||
{'name': 'custom-base', 'description': 'A base system with customizations', 'version': '0.0.1', 'groups': [], 'modules': [], 'packages': [{'name': 'bash', 'version': '4.4.*'}], 'customizations': {'hostname': 'custombase', 'sshkey': [{'user': 'root', 'key': 'A SSH KEY FOR ROOT'}]}}
|
||||
|
||||
@ -1 +1 @@
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [{'version': u'6.6.*', 'name': u'openssh-server'}, {'version': u'3.0.*', 'name': u'rsync'}, {'version': u'2.2', 'name': u'tmux'}], 'modules': [{'version': u'2.4.*', 'name': u'httpd'}, {'version': u'5.4', 'name': u'mod_auth_kerb'}, {'version': u'2.4.*', 'name': u'mod_ssl'}, {'version': u'5.4.*', 'name': u'php'}, {'version': u'5.4.*', 'name': u'php-mysql'}], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [{'version': u'6.6.*', 'name': u'openssh-server'}, {'version': u'3.0.*', 'name': u'rsync'}, {'version': u'2.2', 'name': u'tmux'}], 'groups': [], 'modules': [{'version': u'2.4.*', 'name': u'httpd'}, {'version': u'5.4', 'name': u'mod_auth_kerb'}, {'version': u'2.4.*', 'name': u'mod_ssl'}, {'version': u'5.4.*', 'name': u'php'}, {'version': u'5.4.*', 'name': u'php-mysql'}], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
|
||||
@ -1 +1 @@
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [], 'modules': [], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [], 'groups': [], 'modules': [], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
|
||||
@ -1 +1 @@
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [], 'modules': [{'version': u'2.4.*', 'name': u'httpd'}, {'version': u'5.4', 'name': u'mod_auth_kerb'}, {'version': u'2.4.*', 'name': u'mod_ssl'}, {'version': u'5.4.*', 'name': u'php'}, {'version': u'5.4.*', 'name': u'php-mysql'}], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [], 'groups': [], 'modules': [{'version': u'2.4.*', 'name': u'httpd'}, {'version': u'5.4', 'name': u'mod_auth_kerb'}, {'version': u'2.4.*', 'name': u'mod_ssl'}, {'version': u'5.4.*', 'name': u'php'}, {'version': u'5.4.*', 'name': u'php-mysql'}], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
|
||||
@ -1 +1 @@
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [{'version': u'6.6.*', 'name': u'openssh-server'}, {'version': u'3.0.*', 'name': u'rsync'}, {'version': u'2.2', 'name': u'tmux'}], 'modules': [], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
{'description': u'An example http server with PHP and MySQL support.', 'packages': [{'version': u'6.6.*', 'name': u'openssh-server'}, {'version': u'3.0.*', 'name': u'rsync'}, {'version': u'2.2', 'name': u'tmux'}], 'groups': [], 'modules': [], 'version': u'0.0.1', 'name': u'http-server'}
|
||||
|
||||
@ -95,27 +95,27 @@ class BasicRecipeTest(unittest.TestCase):
|
||||
"""Test the Recipe's version bump function"""
|
||||
|
||||
# Neither have a version
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None, None)
|
||||
new_version = recipe.bump_version(None)
|
||||
self.assertEqual(new_version, "0.0.1")
|
||||
|
||||
# Original has a version, new does not
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None, None)
|
||||
new_version = recipe.bump_version("0.0.1")
|
||||
self.assertEqual(new_version, "0.0.2")
|
||||
|
||||
# Original has no version, new does
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.0", None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.0", None, None, None)
|
||||
new_version = recipe.bump_version(None)
|
||||
self.assertEqual(new_version, "0.1.0")
|
||||
|
||||
# New and Original are the same
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.0.1", None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.0.1", None, None, None)
|
||||
new_version = recipe.bump_version("0.0.1")
|
||||
self.assertEqual(new_version, "0.0.2")
|
||||
|
||||
# New is different from Original
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.1", None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.1", None, None, None)
|
||||
new_version = recipe.bump_version("0.0.1")
|
||||
self.assertEqual(new_version, "0.1.1")
|
||||
|
||||
@ -136,8 +136,8 @@ class BasicRecipeTest(unittest.TestCase):
|
||||
|
||||
def recipe_diff_test(self):
|
||||
"""Test the recipe_diff function"""
|
||||
old_recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.1", self.old_modules, self.old_packages)
|
||||
new_recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.3.1", self.new_modules, self.new_packages)
|
||||
old_recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.1.1", self.old_modules, self.old_packages, [])
|
||||
new_recipe = recipes.Recipe("test-recipe", "A recipe used for testing", "0.3.1", self.new_modules, self.new_packages, [])
|
||||
result = [{'new': {'Version': '0.3.1'}, 'old': {'Version': '0.1.1'}},
|
||||
{'new': {'Module': {'name': 'openssh', 'version': '2.8.1'}}, 'old': None},
|
||||
{'new': None, 'old': {'Module': {'name': 'bash', 'version': '4.*'}}},
|
||||
@ -182,7 +182,7 @@ version = "2.7.*"
|
||||
|
||||
def test_02_commit_recipe(self):
|
||||
"""Test committing a Recipe object"""
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None)
|
||||
recipe = recipes.Recipe("test-recipe", "A recipe used for testing", None, None, None, None)
|
||||
oid = recipes.commit_recipe(self.repo, "master", recipe)
|
||||
self.assertNotEqual(oid, None)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user