Skip to content

cmd-koji-upload: Add support for node-image #4081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 26, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 97 additions & 34 deletions src/cmd-koji-upload
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ sys.path.insert(0, f"{cosa_dir}/cosalib")
sys.path.insert(0, cosa_dir)

from cosalib.cmdlib import get_basearch, load_json, write_json
from enum import IntEnum

try:
from cosalib.build import _Build
Expand Down Expand Up @@ -96,6 +97,13 @@ def md5sum_file(path):
return h.hexdigest()


class RpmListType(IntEnum):
COMMITMETA = 1
EXTENSIONS = 2
HOST = 3
META = 4


class Build(_Build):
"""
Koji implementation of Build.
Expand All @@ -105,14 +113,34 @@ class Build(_Build):
# new kind of image here, but _Build is geared towards that and has a
# image_name_base() member that wants a platform string to name stuff
self.platform = "koji"
# Use a tempdir in builds/ because we want to use large scratch space
self._tmpdir = tempfile.mkdtemp(prefix="koji-build", dir="builds/")
self.buildroot = kwargs['buildroot']
self._tmpdir = tempfile.mkdtemp(prefix="koji-build", dir=self.buildroot)
self._state_file_tpl = self._tmpdir + "/cosa-cmd-koji-upload-{name}-{version}-{release}"
kwargs.update({
"require_commit": True,
"require_cosa": True,
})
_Build.__init__(self, **kwargs)
if kwargs.get('node_image') is True:
self.version = kwargs['build'].replace("-", ".")
self.release = "0"
self._build_dir = self.buildroot
self._basearch = kwargs['arch']
self.name = f"rhcos-{self.basearch}"
self.source = "https://github.com/openshift/os"
self.meta_file_path = f"{kwargs['buildroot']}/meta.json"
self._found_files = {}
self._build_json = {}
with open(self.meta_file_path) as f:
self._build_json['meta'] = json.load(f)
# We use podman build, there is no need for host rpms
self.host_rpms = ""
else:
_Build.__init__(self, **kwargs)
self.version, self.release = self.build_id.split('-')
self.name = f"{self.build_name}-{self.basearch}"
self.source = self.get_meta_key(
"meta", self.ckey("container-config-git"))
self.host_rpms = self.get_rpm_list(RpmListType.HOST)

def __del__(self):
try:
Expand Down Expand Up @@ -192,20 +220,41 @@ class Build(_Build):

return fname, True

def get_rpm_list(self, host=None):
def get_rpm_list(self, kind: RpmListType):
"""
Translate commitmeta.json/HOST OS rpms into a json list
Translate metadata/HOST OS rpms into a json list
Returns the json rpms list
"""
components = []
if host is None:
if kind == RpmListType.META:
file_path = f"{self.buildroot}/meta.json"
with open(file_path) as f:
data = json.load(f)
rpms = data['rpmdb.pkglist']
elif kind == RpmListType.EXTENSIONS:
file_path = f"{self.buildroot}/extensions.json"
with open(file_path) as f:
data = json.load(f)
rpms = []
# Extensions in node image are stored different
for name, full_version in data.items():
version_release, arch = full_version.rsplit('.', 1)
version_str, release = version_release.rsplit('-', 1)
if '.' in version_str:
epoch, version = version_str.split('.', 1)
else:
epoch = '0'
version = version_str
rpm_list = [name, epoch, version, release, arch]
rpms.append(rpm_list)
elif kind == RpmListType.COMMITMETA:
rpms = self.commit["rpmostree.rpmdb.pkglist"]
else:
elif kind == RpmListType.HOST:
host_rpms = subprocess.check_output('rpm -qa --qf="%{NAME}:%{EPOCH}:%{RELEASE}:%{VERSION}:%{ARCH}:%{SIGMD5}:%{SIGPGP} \n"', shell=True).strip()
rpms = (host_rpms.decode('utf-8')).split("\n")

for rpm in rpms:
if host is None:
if kind != RpmListType.HOST:
name, epoch, version, release, arch = rpm
sigmd5, sigpgp, epoch = None, None, None
else:
Expand Down Expand Up @@ -503,11 +552,10 @@ class Reserve(_KojiBase):
# Version = 414.92.202307170903
# Release = 0
# NVR = rhcos-x86_64-414.92.202307170903-0
version, release = build.build_id.split('-')
data = {
"name": f"{build.build_name}-{build.basearch}",
"release": release,
"version": version,
"name": build.name,
"release": build.release,
"version": build.version,
"cg": "coreos-assembler",
}

Expand All @@ -529,9 +577,13 @@ class Reserve(_KojiBase):
build.meta['koji'] = {
'build_id': koji_reservation['build_id'],
'token': koji_reservation['token'],
'release': release
'release': build.release
}
build.meta_write()
if hasattr(build, 'meta_file_path') and build.meta_file_path:
with open(build.meta_file_path, "w") as f:
json.dump(build.meta, f, indent=2)
else:
build.meta_write()


class Upload(_KojiBase):
Expand Down Expand Up @@ -646,6 +698,10 @@ class Upload(_KojiBase):

@property
def image_files(self):
""" Backward-compatible property to maintain existing behavior. """
return self.get_image_files(meta=False)

def get_image_files(self, meta=False):
""" Generate outputs prepares the output listing. """
if self._image_files is not None:
return self._image_files
Expand All @@ -655,7 +711,11 @@ class Upload(_KojiBase):
file_output = self.get_file_meta(value)
if file_output is not None:
if "commitmeta.json" in value['upload_path']:
file_output["components"] = self.build.get_rpm_list()
file_output["components"] = self.build.get_rpm_list(RpmListType.COMMITMETA)
elif "meta.json" in value['upload_path'] and meta is not False:
file_output["components"] = self.build.get_rpm_list(RpmListType.META)
elif "extensions.json" in value['upload_path'] and meta is not False:
file_output["components"] = self.build.get_rpm_list(RpmListType.EXTENSIONS)
outputs.append(file_output)
self._image_files = outputs
return self._image_files
Expand Down Expand Up @@ -707,11 +767,16 @@ class Upload(_KojiBase):
'public-url': self._s3_url
}
self.build.meta_write()
if 'origin' in self.build.source:
source = self.build.source['origin']
commit = self.build.source['commit']
meta = False
else:
source = self.build.source
commit = ""
meta = True

source = self.build.get_meta_key(
"meta", self.build.ckey("container-config-git"))

log.debug(f"Preparing manifest for {(len(self.image_files))} files")
log.debug(f"Preparing manifest for {(len(self.get_image_files(meta=meta)))} files")
# The koji/brew NVR is constructed like so:
# Name = "rhcos-$arch", like `rhcos-x86_64`
# Version = Everything before `-` in RHCOS version
Expand All @@ -722,7 +787,6 @@ class Upload(_KojiBase):
# Version = 414.92.202307170903
# Release = 0
# NVR = rhcos-x86_64-414.92.202307170903-0
version, release = self.build.build_id.split('-')
self._manifest = {
"metadata_version": 0,
"build": {
Expand All @@ -735,12 +799,12 @@ class Upload(_KojiBase):
}
}
},
"name": f"{self.build.build_name}-{self.build.basearch}",
"release": release,
"name": self.build.name,
"release": self.build.release,
"owner": self._owner,
"source": source['origin'],
"source": source,
"start_time": stamp,
"version": version
"version": self.build.version
},
"buildroots": [{
"id": 1,
Expand All @@ -750,16 +814,14 @@ class Upload(_KojiBase):
},
"content_generator": {
"name": "coreos-assembler",
"version": self.build.get_sub_obj(
"meta",
self.build.ckey("container-config-git"), "commit")
"version": commit
},
"container": {
"type": "docker",
"arch": self.build.basearch,
"name": "coreos-assembler"
},
"components": self.build.get_rpm_list('host'),
"components": self.build.host_rpms,
"extra": {
"coreos-assembler": {
"build_id": 1,
Expand All @@ -770,13 +832,11 @@ class Upload(_KojiBase):
"tools": [
{
"name": "coreos-assembler",
"version": self.build.get_sub_obj(
"meta",
self.build.ckey("container-config-git"), "commit")
"version": commit
}
]
}],
"output": self.image_files
"output": self.get_image_files(meta=meta)
}

return self._manifest
Expand Down Expand Up @@ -929,7 +989,9 @@ Environment variables are supported:
help="Do not upload, just parse the build")
parent_parser.add_argument("--arch", default=get_basearch(),
help="Set the build architecture")

# Node image sytle update
parent_parser.add_argument("--node-image", action='store_true', required=False,
help="Brew uploads for node image sytle")
# Koji specific options
parent_parser.add_argument("--no-auth", action='store_false', dest="auth",
help="Skip Kerberos auth, use if already auth'd")
Expand Down Expand Up @@ -1012,7 +1074,8 @@ Environment variables are supported:

args = parser.parse_args(namespace=args)

build = Build(buildroot=args.buildroot, build=args.build, arch=args.arch)
build = Build(buildroot=args.buildroot, build=args.build, arch=args.arch,
node_image=args.node_image)

if args.auth:
kinit(args.keytab, args.owner)
Expand Down
Loading