plugins: support for ostree specific options
OStree compose requests need special options, like the `ref` the
`parent` and the `url`. Add support for those options to all three
plugins:
The command line plugin now takes `--ostree-{parent,ref,url}`
and passes it to koji via the existing options dictionary.
The JSON schemata in the hub plugin was adjusted to allow these
new options.
Finally the builder plugin will look for the new `ostree` dict
inside the options, create an `OSTreeOptions` object from it,
and attach it to each image request.
NB: since the ostree options are per image request and are thus
architecture dependent we support a "$arch" substition in the
`parent` and `ref` options that will be resolved by the plugin;
this allows to builds arch specific commits for with a single
compose request.
Add the respective unit tests.
This commit is contained in:
parent
ce21817676
commit
78ed04dbd6
5 changed files with 189 additions and 2 deletions
|
|
@ -55,6 +55,30 @@ KOJIAPI_IMAGE_TYPES = {
|
|||
# cloud API. It is based on the corresponding OpenAPI specification
|
||||
# version '2' with integrated koji support (>= commit c81d0d0).
|
||||
|
||||
|
||||
class OSTreeOptions:
|
||||
def __init__(self, data) -> None:
|
||||
self.parent = data.get("parent")
|
||||
self.ref = data.get("ref")
|
||||
self.url = data.get("url")
|
||||
|
||||
def as_dict(self, arch: str = ""):
|
||||
res = {}
|
||||
|
||||
if self.parent:
|
||||
tmp = Template(self.parent)
|
||||
res["parent"] = tmp.substitute(arch=arch)
|
||||
|
||||
if self.ref:
|
||||
tmp = Template(self.ref)
|
||||
res["ref"] = tmp.substitute(arch=arch)
|
||||
|
||||
if self.url:
|
||||
res["url"] = self.url
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class Repository:
|
||||
def __init__(self, baseurl: str, gpgkey: str = None):
|
||||
self.baseurl = baseurl
|
||||
|
|
@ -79,16 +103,21 @@ class ImageRequest:
|
|||
self.architecture = arch
|
||||
self.image_type = image_type
|
||||
self.repositories = repos
|
||||
self.ostree: OSTreeOptions = None
|
||||
|
||||
def as_dict(self):
|
||||
arch = self.architecture
|
||||
return {
|
||||
res = {
|
||||
"architecture": self.architecture,
|
||||
"image_type": self.image_type,
|
||||
"repositories": [
|
||||
repo.as_dict(arch) for repo in self.repositories
|
||||
]
|
||||
}
|
||||
if self.ostree:
|
||||
res["ostree"] = self.ostree.as_dict(self.architecture)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class NVR:
|
||||
|
|
@ -571,6 +600,15 @@ class OSBuildImage(BaseTaskHandler):
|
|||
# Arches and image types
|
||||
image_types = [self.map_koji_api_image_type(i) for i in image_types]
|
||||
ireqs = [ImageRequest(a, i, repos) for a in arches for i in image_types]
|
||||
|
||||
# OStree specific options
|
||||
ostree = opts.get("ostree")
|
||||
if ostree:
|
||||
ostree = OSTreeOptions(ostree)
|
||||
|
||||
for ireq in ireqs:
|
||||
ireq.ostree = ostree
|
||||
|
||||
self.logger.debug("Creating compose: %s (%s)\n koji: %s\n images: %s",
|
||||
nvr, distro, self.koji_url,
|
||||
str([i.as_dict() for i in ireqs]))
|
||||
|
|
|
|||
|
|
@ -21,6 +21,12 @@ def parse_args(argv):
|
|||
|
||||
parser.add_option("--nowait", action="store_false", dest="wait",
|
||||
help="Don't wait on image creation")
|
||||
parser.add_option("--ostree-parent", type=str, dest="ostree_parent",
|
||||
help="The OSTree commit parent for OSTree commit image types")
|
||||
parser.add_option("--ostree-ref", type=str, dest="ostree_ref",
|
||||
help="The OSTree commit ref for OSTree commit image types")
|
||||
parser.add_option("--ostree-url", type=str, dest="ostree_url",
|
||||
help="URL to the OSTree repo for OSTree commit image types")
|
||||
parser.add_option("--release", help="Forcibly set the release field")
|
||||
parser.add_option("--repo", action="append",
|
||||
help=("Specify a repo that will override the repo used to install "
|
||||
|
|
@ -82,6 +88,21 @@ def handle_osbuild_image(options, session, argv):
|
|||
if args.skip_tag:
|
||||
opts["skip_tag"] = True
|
||||
|
||||
# ostree command line parameters
|
||||
ostree = {}
|
||||
|
||||
if args.ostree_parent:
|
||||
ostree["parent"] = args.ostree_parent
|
||||
|
||||
if args.ostree_ref:
|
||||
ostree["ref"] = args.ostree_ref
|
||||
|
||||
if args.ostree_url:
|
||||
ostree["url"] = args.ostree_url
|
||||
|
||||
if ostree:
|
||||
opts["ostree"] = ostree
|
||||
|
||||
# Do some early checks to be able to give quick feedback
|
||||
check_target(session, target)
|
||||
|
||||
|
|
|
|||
|
|
@ -49,11 +49,31 @@ OSBUILD_IMAGE_SCHEMA = {
|
|||
"$ref": "#/definitions/options"
|
||||
}],
|
||||
"definitions": {
|
||||
"ostree": {
|
||||
"title": "OSTree specific options",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"parent": {
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"title": "Optional arguments",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"ostree": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/ostree"
|
||||
},
|
||||
"repo": {
|
||||
"type": "array",
|
||||
"description": "Repositories",
|
||||
|
|
|
|||
|
|
@ -909,3 +909,54 @@ class TestBuilderPlugin(PluginTest):
|
|||
|
||||
res = handler.handler(*args)
|
||||
assert res, "invalid compose result"
|
||||
|
||||
@httpretty.activate
|
||||
def test_ostree_compose(self):
|
||||
# Check we properly handle ostree compose requests
|
||||
session = self.mock_session()
|
||||
handler = self.make_handler(session=session)
|
||||
|
||||
arches = ["x86_64", "s390x"]
|
||||
repos = ["http://1.repo", "https://2.repo"]
|
||||
args = ["name", "version", "distro",
|
||||
["image_type"],
|
||||
"fedora-candidate",
|
||||
arches,
|
||||
{"repo": repos,
|
||||
"ostree": {
|
||||
"parent": "osbuild/$arch/p",
|
||||
"ref": "osbuild/$arch/r",
|
||||
"url": "https://osbuild.org/repo"
|
||||
}}]
|
||||
|
||||
url = self.plugin.DEFAULT_COMPOSER_URL
|
||||
composer = MockComposer(url, architectures=arches)
|
||||
composer.httpretty_regsiter()
|
||||
|
||||
res = handler.handler(*args)
|
||||
assert res, "invalid compose result"
|
||||
compose_id = res["composer"]["id"]
|
||||
compose = composer.composes.get(compose_id)
|
||||
self.assertIsNotNone(compose)
|
||||
|
||||
ireqs = compose["request"]["image_requests"]
|
||||
|
||||
# Check we got all the requested architectures
|
||||
ireq_arches = [i["architecture"] for i in ireqs]
|
||||
diff = set(arches) ^ set(ireq_arches)
|
||||
self.assertEqual(diff, set())
|
||||
|
||||
for ir in ireqs:
|
||||
assert "ostree" in ir
|
||||
ostree = ir["ostree"]
|
||||
for key in ("parent", "ref", "url"):
|
||||
assert key in ostree
|
||||
assert ostree["url"] == "https://osbuild.org/repo"
|
||||
|
||||
ireq_parents = [i["ostree"]["parent"] for i in ireqs]
|
||||
diff = set(f"osbuild/{a}/p" for a in arches) ^ set(ireq_parents)
|
||||
self.assertEqual(diff, set())
|
||||
|
||||
ireq_refs = [i["ostree"]["ref"] for i in ireqs]
|
||||
diff = set(f"osbuild/{a}/r" for a in arches) ^ set(ireq_refs)
|
||||
self.assertEqual(diff, set())
|
||||
|
|
|
|||
|
|
@ -125,6 +125,63 @@ class TestCliPlugin(PluginTest):
|
|||
r = self.plugin.handle_osbuild_image(options, session, argv)
|
||||
self.assertEqual(r, 0)
|
||||
|
||||
def test_ostree_options(self):
|
||||
# Check we properly handle ostree specific options
|
||||
|
||||
argv = [
|
||||
# the required positional arguments
|
||||
"name", "version", "distro", "target", "arch1",
|
||||
# optional keyword arguments
|
||||
"--repo", "https://first.repo",
|
||||
"--repo", "https://second.repo",
|
||||
"--release", "20200202.n2",
|
||||
"--ostree-parent", "ostree/$arch/staging",
|
||||
"--ostree-ref", "ostree/$arch/production",
|
||||
"--ostree-url", "https://osbuild.org/repo",
|
||||
]
|
||||
|
||||
expected_args = ["name", "version", "distro",
|
||||
['guest-image'], # the default image type
|
||||
"target",
|
||||
['arch1']]
|
||||
|
||||
expected_opts = {
|
||||
"release": "20200202.n2",
|
||||
"repo": ["https://first.repo", "https://second.repo"],
|
||||
"ostree": {
|
||||
"parent": "ostree/$arch/staging",
|
||||
"ref": "ostree/$arch/production",
|
||||
"url": "https://osbuild.org/repo",
|
||||
}
|
||||
}
|
||||
|
||||
task_result = {"compose_id": "42", "build_id": 23}
|
||||
task_id = 1
|
||||
koji_lib = self.mock_koji_lib()
|
||||
|
||||
options = self.mock_options()
|
||||
session = flexmock()
|
||||
|
||||
self.mock_session_add_valid_tag(session)
|
||||
|
||||
session.should_receive("osbuildImage") \
|
||||
.with_args(*expected_args, opts=expected_opts) \
|
||||
.and_return(task_id) \
|
||||
.once()
|
||||
|
||||
session.should_receive("logout") \
|
||||
.with_args() \
|
||||
.once()
|
||||
|
||||
session.should_receive("getTaskResult") \
|
||||
.with_args(task_id) \
|
||||
.and_return(task_result) \
|
||||
.once()
|
||||
|
||||
setattr(self.plugin, "kl", koji_lib)
|
||||
r = self.plugin.handle_osbuild_image(options, session, argv)
|
||||
self.assertEqual(r, 0)
|
||||
|
||||
def test_target_check(self):
|
||||
# unknown build target
|
||||
session = flexmock()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue