Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
thegreyd committed Apr 24, 2023
1 parent d667a3a commit ed24b34
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 79 deletions.
60 changes: 5 additions & 55 deletions elliottlib/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
# stdlib
from multiprocessing import cpu_count
from multiprocessing.dummy import Pool as ThreadPool
import asyncio
import datetime
import json
import sys
from typing import Dict, List

# ours
from elliottlib import exectools
from elliottlib import util
from elliottlib import Runtime
from elliottlib import rhcos
import elliottlib.constants
Expand All @@ -29,7 +28,7 @@
import elliottlib.exceptions

from elliottlib.exceptions import ElliottFatalError
from elliottlib.util import exit_unauthenticated, green_prefix
from elliottlib.util import green_prefix
from elliottlib.util import red_print
from elliottlib.util import green_print, red_prefix
from elliottlib.util import yellow_print, yellow_prefix
Expand Down Expand Up @@ -208,57 +207,7 @@ async def verify_payload(runtime, payload, advisory):

click.echo("Found {} builds".format(len(all_advisory_nvrs)))

all_payload_nvrs = {}
click.echo("Fetching release info")
release_export_cmd = 'oc adm release info {} -o json'.format(payload)

rc, stdout, stderr = exectools.cmd_gather(release_export_cmd)
if rc != 0:
# Probably no point in continuing.. can't contact brew?
print("Unable to run oc release info: out={} ; err={}".format(stdout, stderr))
exit(1)
else:
click.echo("Got release info")

payload_json = json.loads(stdout)

green_prefix("Looping over payload images: ")
click.echo("{} images to check".format(len(payload_json['references']['spec']['tags'])))
cmds = [['oc', 'image', 'info', '-o', 'json', tag['from']['name']] for tag in payload_json['references']['spec']['tags']]

green_prefix("Querying image infos...")
cmd_results = await asyncio.gather(*[exectools.cmd_gather_async(cmd) for cmd in cmds])

for image, cmd, cmd_result in zip(payload_json['references']['spec']['tags'], cmds, cmd_results):
click.echo("----")
image_name = image['name']
rc, stdout, stderr = cmd_result
if rc != 0:
# Probably no point in continuing.. can't contact brew?
red_prefix("Unable to run oc image info: ")
red_print(f"cmd={cmd!r}, out={stdout} ; err={stderr}")
exit(1)

image_info = json.loads(stdout)
labels = image_info['config']['config']['Labels']

# The machine-os-content image doesn't follow the standard
# pattern. We need to skip that image when we find it, it is
# not attached to advisories.
if image_name in rhcos_images:
yellow_prefix(f"Skipping rhcos image {image_name}: ")
click.echo("Not required for checks")
continue

if not labels or any(i not in labels for i in ['version', 'release', 'com.redhat.component']):
red_print(f"For image {image_name} expected labels don't exist")
exit(1)
component = labels['com.redhat.component']
click.echo(f"Payload name: {image_name}")
click.echo(f"Brew name: {component}")
v = labels['version']
r = labels['release']
all_payload_nvrs[component] = f"{v}-{r}"
all_payload_nvrs = await util.get_nvrs_from_payload(payload, rhcos_images, runtime.logger)

missing_in_errata = {}
payload_doesnt_match_errata = {}
Expand All @@ -274,7 +223,8 @@ async def verify_payload(runtime, payload, advisory):
green_prefix("Analyzing data: ")
click.echo("{} images to consider from payload".format(len(all_payload_nvrs)))

for image, vr in all_payload_nvrs.items():
for image, vr_tuple in all_payload_nvrs.items():
vr = f"{vr_tuple[0]}-{vr_tuple[1]}"
imagevr = f"{image}-{vr}"
yellow_prefix("Cross-checking from payload: ")
click.echo(imagevr)
Expand Down
78 changes: 55 additions & 23 deletions elliottlib/cli/get_golang_versions_cli.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import click

from elliottlib import errata, logutil, util
from elliottlib import errata, logutil, util, rhcos
from elliottlib.cli.common import (cli, find_default_advisory,
use_default_advisory_option)
from elliottlib.cli.common import click_coroutine
from elliottlib.rpm_utils import parse_nvr

_LOGGER = logutil.getLogger(__name__)


@cli.command("go", short_help="Get version of Go for advisory builds")
@click.option("--release", "-r",
help="Release/nightly pullspec to inspect builds for")
@click.option('--advisory', '-a', 'advisory_id', type=int,
help="The advisory ID to fetch builds from")
@use_default_advisory_option
Expand All @@ -17,54 +19,67 @@
@click.option('--components', '-c',
help="Only show go versions for these components (rpms/images) in advisory. Comma separated")
@click.pass_obj
def get_golang_versions_cli(runtime, advisory_id, default_advisory_type, nvrs, components):
@click_coroutine
async def get_golang_versions_cli(runtime, release, advisory_id, default_advisory_type, nvrs, components):
"""
Prints the Go version used to build a component to stdout.
Get the Go version for brew builds specified via nvrs / advisory / release
Usage:
\b
$ elliott go -a 76557
List go version for brew builds in the given advisory
List go version for all golang builds in the given advisory
\b
$ elliott go -a 79683 -c ironic-container,ose-ovirt-csi-driver-container
List go version for brew builds in the given advisory
List go version for the given brew components in the advisory
\b
$ elliott -g openshift-4.8 go --use-default-advisory image -c grafana-container,ose-installer-container
$ elliott -g openshift-4.12 --assembly 4.12.13 go --use-default-advisory image
List go version for brew builds for given component names attached to the default advisory for a group
Use default advisory for a group/assembly
\b
$ elliott go -n podman-3.0.1-6.el8,podman-1.9.3-3.rhaos4.6.el8
List go version for given brew builds
List go version for given brew nvrs
\b
$ elliott go -r registry.ci.openshift.org/ocp/release:4.14.0-0.nightly-2023-04-24-145153
List go version for given release pullspec
"""
count_options = sum(map(bool, [advisory_id, nvrs, default_advisory_type]))
count_options = sum(map(bool, [advisory_id, nvrs, default_advisory_type, release]))
if count_options > 1:
raise click.BadParameter("Use only one of --advisory, --nvrs, --use-default-advisory")
raise click.BadParameter("Use only one of --release, --advisory, --nvrs, --use-default-advisory")

if default_advisory_type:
advisory_id, rhcos_images = None, None
if default_advisory_type or release:
runtime.initialize()
advisory_id = find_default_advisory(runtime, default_advisory_type)
if default_advisory_type:
advisory_id = find_default_advisory(runtime, default_advisory_type)
elif release:
rhcos_images = {c['name'] for c in rhcos.get_container_configs(runtime)}
else:
runtime.initialize(no_group=True)

if advisory_id:
if components:
components = [c.strip() for c in components.split(',')]
return get_advisory_golang(advisory_id, components)
if components:
components = [c.strip() for c in components.split(',')]

if release:
return await print_release_golang(release, rhcos_images, components)
elif advisory_id:
return print_advisory_golang(advisory_id, components)
elif nvrs:
nvrs = [n.strip() for n in nvrs.split(',')]
return get_nvrs_golang(nvrs)
return print_nvrs_golang(nvrs)
else:
util.red_print('The input value is not valid.')


def get_nvrs_golang(nvrs):
def print_nvrs_golang(nvrs):
container_nvrs, rpm_nvrs = [], []
for n in nvrs:
parsed_nvr = parse_nvr(n)
Expand All @@ -81,15 +96,15 @@ def get_nvrs_golang(nvrs):
go_nvr_map = util.get_golang_container_nvrs(container_nvrs, _LOGGER)
util.pretty_print_nvrs_go(go_nvr_map)
else:
util.green_print('There is no builds related to golang.')
util.green_print('No golang builds detected')


def get_advisory_golang(advisory_id, components):
def print_advisory_golang(advisory_id, components):
nvrs = errata.get_all_advisory_nvrs(advisory_id)
_LOGGER.debug(f'{len(nvrs)} builds found in advisory')
if not nvrs:
_LOGGER.debug('No builds found. exiting')
util.green_print('there is no builds related to golang')
_LOGGER.debug('No golang builds found. exiting')
util.green_print(f'No golang builds found in advisory {advisory_id}')
return
if components:
if 'openshift' in components:
Expand All @@ -104,3 +119,20 @@ def get_advisory_golang(advisory_id, components):
go_nvr_map = util.get_golang_rpm_nvrs(nvrs, _LOGGER)

util.pretty_print_nvrs_go(go_nvr_map)

async def print_release_golang(pullspec, rhcos_images, components):
nvr_map = await util.get_nvrs_from_payload(pullspec, rhcos_images, _LOGGER)
nvrs = [(n, vr_tuple[0], vr_tuple[1]) for n, vr_tuple in nvr_map.items()]
_LOGGER.debug(f'{len(nvrs)} builds found in {pullspec}')
if not nvrs:
_LOGGER.debug('No golang builds found. exiting')
util.green_print(f'No golang builds found in release {pullspec}')
return
if components:
if 'openshift' in components:
components.remove('openshift')
components.append('openshift-hyperkube')
nvrs = [p for p in nvrs if p[0] in components]

go_nvr_map = util.get_golang_container_nvrs(nvrs, _LOGGER)
util.pretty_print_nvrs_go(go_nvr_map)
53 changes: 52 additions & 1 deletion elliottlib/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import datetime, re, click
import json
import asyncio
from collections import deque
from itertools import chain
from multiprocessing import cpu_count
Expand All @@ -7,6 +9,7 @@
from typing import Dict, Iterable, List, Optional, Tuple, Sequence, Any

from elliottlib import brew
from elliottlib import exectools
from elliottlib.exceptions import BrewBuildException

from errata_tool import Erratum
Expand Down Expand Up @@ -632,7 +635,7 @@ def get_golang_rpm_nvrs(nvrs, logger):
def pretty_print_nvrs_go(go_nvr_map):
for go_version in sorted(go_nvr_map.keys()):
nvrs = go_nvr_map[go_version]
green_print(f'Following nvrs are built with {go_version}:')
green_print(f'* Following nvrs ({len(nvrs)}) are built with {go_version}:')
for nvr in sorted(nvrs):
pretty_nvr = '-'.join(nvr)
print(pretty_nvr)
Expand Down Expand Up @@ -683,3 +686,51 @@ def all_same(items: Iterable[Any]):
it = iter(items)
first = next(it, None)
return all(x == first for x in it)

async def get_nvrs_from_payload(pullspec, rhcos_images, logger):
all_payload_nvrs = {}
logger.info("Fetching release info...")
release_export_cmd = f'oc adm release info {pullspec} -o json'

rc, stdout, stderr = exectools.cmd_gather(release_export_cmd)
if rc != 0:
# Probably no point in continuing.. can't contact brew?
msg = f"Unable to run oc release info: out={stdout} ; err={stderr}"
logger.error(msg)
raise RuntimeError(msg)

payload_json = json.loads(stdout)
logger.info("Looping over payload images...")
logger.info(f"{len(payload_json['references']['spec']['tags'])} images to check")
cmds = [['oc', 'image', 'info', '-o', 'json', tag['from']['name']] for tag in
payload_json['references']['spec']['tags']]

logger.info("Querying image infos...")
cmd_results = await asyncio.gather(*[exectools.cmd_gather_async(cmd) for cmd in cmds])

for image, cmd, cmd_result in zip(payload_json['references']['spec']['tags'], cmds, cmd_results):
image_name = image['name']
rc, stdout, stderr = cmd_result
if rc != 0:
# Probably no point in continuing.. can't contact brew?
msg = f"Unable to run oc image info: cmd={cmd!r}, out={stdout} ; err={stderr}"
logger.error(msg)
raise RuntimeError(msg)

image_info = json.loads(stdout)
labels = image_info['config']['config']['Labels']

# RHCOS images are not built in brew, so skip them
if image_name in rhcos_images:
logger.info(f"Skipping rhcos image {image_name}")
continue

if not labels or any(i not in labels for i in ['version', 'release', 'com.redhat.component']):
msg = f"For image {image_name} expected labels don't exist"
logger.error(msg)
raise ValueError(msg)
component = labels['com.redhat.component']
v = labels['version']
r = labels['release']
all_payload_nvrs[component] = (v, r)
return all_payload_nvrs

0 comments on commit ed24b34

Please sign in to comment.