avocado/plugins/vmimage.py
import json
import os
import re
from avocado.core import exit_codes, output
from avocado.core.output import LOG_UI
from avocado.core.plugin_interfaces import CLICmd
from avocado.core.settings import settings
from avocado.utils import astring, vmimage
def list_downloaded_images():
"""
List the available Image inside avocado cache
:return: list with image's parameters
:rtype: list of dicts
"""
images = []
for cache_dir in settings.as_dict().get("datadir.paths.cache_dirs"):
for root, _, files in os.walk(cache_dir):
if files:
metadata_files = [
pos_json
for pos_json in files
if pos_json.endswith("_metadata.json")
]
files = list(set(files) - set(metadata_files))
for metadata_file in metadata_files:
with open(
os.path.join(root, metadata_file), "r", encoding="utf-8"
) as data:
metadata = json.loads(data.read())
if isinstance(metadata, dict):
if metadata.get("type", None) == "vmimage":
provider = None
for p in vmimage.IMAGE_PROVIDERS:
if p.name == metadata["name"]:
provider = p(
metadata["version"],
metadata["build"],
metadata["arch"],
)
break
if provider is not None:
for image in files:
if re.match(provider.file_name, image):
data = {
"name": provider.name,
"version": provider.version,
"arch": provider.arch,
"file": os.path.join(root, image),
}
images.append(data)
break
return images
def download_image(distro, version=None, arch=None):
"""
Downloads the vmimage to the cache directory if doesn't already exist
:param distro: Name of image distribution
:type distro: str
:param version: Version of image
:type version: str
:param arch: Architecture of image
:type arch: str
:raise AttributeError: When image can't be downloaded
:return: Information about downloaded image
:rtype: dict
"""
cache_dir = settings.as_dict().get("datadir.paths.cache_dirs")[0]
image_info = vmimage.get(
name=distro, version=version, arch=arch, cache_dir=cache_dir
)
file_path = image_info.base_image
image = {
"name": distro,
"version": image_info.version,
"arch": image_info.arch,
"file": file_path,
}
return image
def display_images_list(images):
"""
Displays table with information about images
:param images: list with image's parameters
:type images: list of dicts
"""
image_matrix = [
[image["name"], image["version"], image["arch"], image["file"]]
for image in images
]
header = (
output.TERM_SUPPORT.header_str("Provider"),
output.TERM_SUPPORT.header_str("Version"),
output.TERM_SUPPORT.header_str("Architecture"),
output.TERM_SUPPORT.header_str("File"),
)
return astring.tabular_output(image_matrix, header=header, strip=True)
class VMimage(CLICmd):
"""
Implements the avocado 'vmimage' subcommand
"""
name = "vmimage"
description = "Provides VM images acquired from official repositories"
def configure(self, parser):
parser = super().configure(parser)
subcommands = parser.add_subparsers(dest="vmimage_subcommand")
subcommands.required = True
subcommands.add_parser("list", help="List of all downloaded images")
get_parser = subcommands.add_parser(
"get",
help="Downloads chosen VMimage if " "it's not already in the " "cache",
)
help_msg = "Name of image distribution"
settings.register_option(
section="vmimage.get",
key="distro",
default=None,
help_msg=help_msg,
key_type=str,
parser=get_parser,
long_arg="--distro",
required=True,
)
help_msg = "Image version"
settings.register_option(
section="vmimage.get",
key="version",
default=None,
help_msg=help_msg,
key_type=str,
parser=get_parser,
long_arg="--distro-version",
)
help_msg = "Image architecture"
settings.register_option(
section="vmimage.get",
key="arch",
default=None,
help_msg=help_msg,
key_type=str,
parser=get_parser,
long_arg="--arch",
)
def run(self, config):
subcommand = config.get("vmimage_subcommand")
if subcommand == "list":
images = list_downloaded_images()
LOG_UI.debug(display_images_list(images))
elif subcommand == "get":
name = config.get("vmimage.get.distro")
version = config.get("vmimage.get.version")
arch = config.get("vmimage.get.arch")
try:
image = download_image(name, version, arch)
except AttributeError:
LOG_UI.debug("The requested image could not be downloaded")
return exit_codes.AVOCADO_FAIL
LOG_UI.debug("The image was downloaded:")
LOG_UI.debug(display_images_list([image]))
return exit_codes.AVOCADO_ALL_OK