|
rdobuilder |
6b0be9 |
#!/usr/bin/python3
|
|
rdobuilder |
6b0be9 |
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
rdobuilder |
6b0be9 |
# SPDX-FileCopyrightText 2022 Maxwell G <gotmax@e.email>
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
"""
|
|
rdobuilder |
6b0be9 |
This script uses Ansible Collection metadata from galaxy.yml to figure out the
|
|
rdobuilder |
6b0be9 |
namespace, name, and version of the collection being packaged.
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
``ansible_collection.py install`` (used by %ansible_collecton_install) uses
|
|
rdobuilder |
6b0be9 |
this information to find and install the collection artifact that was just
|
|
rdobuilder |
6b0be9 |
built with %ansible_collection_build. It also generates a files list for use
|
|
rdobuilder |
6b0be9 |
with `%files -f`.
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
``ansible_collection.py test`` (used by %ansible_test_unit) parses galaxy.yml
|
|
rdobuilder |
6b0be9 |
to determine the collection namespace and name that's needed to create the
|
|
rdobuilder |
6b0be9 |
directory structure that ansible-test expects. After creating a temporary build
|
|
rdobuilder |
6b0be9 |
directory with the needed structure, the script runs ansible-test units with
|
|
rdobuilder |
6b0be9 |
the provided arguments.
|
|
rdobuilder |
6b0be9 |
"""
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
import argparse
|
|
rdobuilder |
6b0be9 |
import shutil
|
|
rdobuilder |
6b0be9 |
import subprocess
|
|
rdobuilder |
6b0be9 |
import sys
|
|
rdobuilder |
6b0be9 |
from pathlib import Path
|
|
rdobuilder |
6b0be9 |
from tempfile import TemporaryDirectory
|
|
rdobuilder |
6b0be9 |
from typing import Any, Dict, Optional, Sequence, Union
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
from yaml import CSafeLoader, load
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
class CollectionError(Exception):
|
|
rdobuilder |
6b0be9 |
pass
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
class AnsibleCollection:
|
|
rdobuilder |
6b0be9 |
def __init__(self, collection_srcdir: Optional[Path] = None) -> None:
|
|
rdobuilder |
6b0be9 |
self.collection_srcdir = collection_srcdir or Path.cwd()
|
|
rdobuilder |
6b0be9 |
self.data = self._load_data()
|
|
rdobuilder |
6b0be9 |
self.namespace = self.data["namespace"]
|
|
rdobuilder |
6b0be9 |
self.name = self.data["name"]
|
|
rdobuilder |
6b0be9 |
self.version = self.data["version"]
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def _load_data(self) -> Dict[str, Any]:
|
|
rdobuilder |
6b0be9 |
path = self.collection_srcdir / "galaxy.yml"
|
|
rdobuilder |
6b0be9 |
if not path.exists():
|
|
rdobuilder |
6b0be9 |
raise CollectionError(f"{path} does not exist!")
|
|
rdobuilder |
6b0be9 |
print(f"Loading collection metadata from {path}")
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
with open(path, encoding="utf-8") as file:
|
|
rdobuilder |
6b0be9 |
return load(file, Loader=CSafeLoader)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def install(self, destdir: Union[str, Path]) -> None:
|
|
rdobuilder |
6b0be9 |
artifact = self.collection_srcdir / Path(
|
|
rdobuilder |
6b0be9 |
f"{self.namespace}-{self.name}-{self.version}.tar.gz"
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
if not artifact.exists() and not artifact.is_file():
|
|
rdobuilder |
6b0be9 |
raise CollectionError(
|
|
rdobuilder |
6b0be9 |
f"{artifact} does not exist! Did you run %ansible_collection_build?"
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
args = (
|
|
rdobuilder |
6b0be9 |
"ansible-galaxy",
|
|
rdobuilder |
6b0be9 |
"collection",
|
|
rdobuilder |
6b0be9 |
"install",
|
|
rdobuilder |
6b0be9 |
"-n",
|
|
rdobuilder |
6b0be9 |
"-p",
|
|
rdobuilder |
6b0be9 |
str(destdir),
|
|
rdobuilder |
6b0be9 |
str(artifact),
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
print(f"Running: {args}")
|
|
rdobuilder |
6b0be9 |
print()
|
|
rdobuilder |
6b0be9 |
# Without this, the print statements are shown after the command
|
|
rdobuilder |
6b0be9 |
# output when building in mock.
|
|
rdobuilder |
6b0be9 |
sys.stdout.flush()
|
|
rdobuilder |
6b0be9 |
subprocess.run(args, check=True, cwd=self.collection_srcdir)
|
|
rdobuilder |
6b0be9 |
print()
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def write_filelist(self, filelist: Path) -> None:
|
|
rdobuilder |
6b0be9 |
filelist.parent.mkdir(parents=True, exist_ok=True)
|
|
rdobuilder |
6b0be9 |
contents = "%{ansible_collections_dir}/" + self.namespace
|
|
rdobuilder |
6b0be9 |
print(f"Writing filelist to {filelist}")
|
|
rdobuilder |
6b0be9 |
with open(filelist, "w", encoding="utf-8") as file:
|
|
rdobuilder |
6b0be9 |
file.write(contents)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def unit_test(self, extra_args: Sequence) -> None:
|
|
rdobuilder |
6b0be9 |
with TemporaryDirectory() as temp:
|
|
rdobuilder |
6b0be9 |
temppath = Path(temp) / "ansible_collections" / self.namespace / self.name
|
|
rdobuilder |
6b0be9 |
shutil.copytree(
|
|
rdobuilder |
6b0be9 |
self.collection_srcdir,
|
|
rdobuilder |
6b0be9 |
temppath,
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
args = ("ansible-test", "units", *extra_args)
|
|
rdobuilder |
6b0be9 |
print(f"Running: {args}")
|
|
rdobuilder |
6b0be9 |
print()
|
|
rdobuilder |
6b0be9 |
# Without this, the print statements are shown after the command
|
|
rdobuilder |
6b0be9 |
# output when building in mock.
|
|
rdobuilder |
6b0be9 |
sys.stdout.flush()
|
|
rdobuilder |
6b0be9 |
subprocess.run(args, cwd=temppath, check=True)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def parseargs() -> argparse.Namespace:
|
|
rdobuilder |
6b0be9 |
parser = argparse.ArgumentParser(
|
|
rdobuilder |
6b0be9 |
"Install and test Ansible Collections in an rpmbuild environment"
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
subparsers = parser.add_subparsers(dest="action")
|
|
rdobuilder |
6b0be9 |
install_parser = subparsers.add_parser(
|
|
rdobuilder |
6b0be9 |
"install",
|
|
rdobuilder |
6b0be9 |
help="Run ansible-galaxy collection install and write filelist",
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
install_parser.add_argument(
|
|
rdobuilder |
6b0be9 |
"--collections-dir",
|
|
rdobuilder |
6b0be9 |
required=True,
|
|
rdobuilder |
6b0be9 |
help="Collection destination directory",
|
|
rdobuilder |
6b0be9 |
type=Path,
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
install_parser.add_argument(
|
|
rdobuilder |
6b0be9 |
"--filelist",
|
|
rdobuilder |
6b0be9 |
type=Path,
|
|
rdobuilder |
6b0be9 |
required=True,
|
|
rdobuilder |
6b0be9 |
help="%%{ansible_collection_filelist}",
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
test_parser = subparsers.add_parser(
|
|
rdobuilder |
6b0be9 |
"test",
|
|
rdobuilder |
6b0be9 |
help="Run ansible-test unit after creating the necessary directory structure",
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
test_parser.add_argument(
|
|
rdobuilder |
6b0be9 |
"extra_args", nargs="*", help="Extra arguments to pass to ansible-test"
|
|
rdobuilder |
6b0be9 |
)
|
|
rdobuilder |
6b0be9 |
args = parser.parse_args()
|
|
rdobuilder |
6b0be9 |
# add_subparsers does not support required on Python 3.6
|
|
rdobuilder |
6b0be9 |
if not args.action:
|
|
rdobuilder |
6b0be9 |
parser.print_usage()
|
|
rdobuilder |
6b0be9 |
sys.exit(2)
|
|
rdobuilder |
6b0be9 |
return args
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
def main():
|
|
rdobuilder |
6b0be9 |
args = parseargs()
|
|
rdobuilder |
6b0be9 |
collection = AnsibleCollection()
|
|
rdobuilder |
6b0be9 |
if args.action == "install":
|
|
rdobuilder |
6b0be9 |
collection.install(args.collections_dir)
|
|
rdobuilder |
6b0be9 |
collection.write_filelist(args.filelist)
|
|
rdobuilder |
6b0be9 |
elif args.action == "test":
|
|
rdobuilder |
6b0be9 |
collection.unit_test(args.extra_args)
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
|
|
rdobuilder |
6b0be9 |
if __name__ == "__main__":
|
|
rdobuilder |
6b0be9 |
try:
|
|
rdobuilder |
6b0be9 |
main()
|
|
rdobuilder |
6b0be9 |
except (CollectionError, subprocess.CalledProcessError) as err:
|
|
rdobuilder |
6b0be9 |
sys.exit(err)
|