2022-06-06 22:02:08 +00:00
|
|
|
"""
|
|
|
|
Builds ISO's for Rocky Linux.
|
|
|
|
|
|
|
|
Louis Abel <label AT rockylinux.org>
|
|
|
|
"""
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import subprocess
|
|
|
|
import shlex
|
|
|
|
import time
|
|
|
|
import re
|
2022-06-13 14:37:50 +00:00
|
|
|
from productmd.common import SortedConfigParser
|
2022-06-06 22:02:08 +00:00
|
|
|
from common import Color
|
2022-06-15 20:53:12 +00:00
|
|
|
from jinja2 import Environment, FileSystemLoader
|
2022-06-06 22:02:08 +00:00
|
|
|
|
|
|
|
class IsoBuild:
|
|
|
|
"""
|
|
|
|
This helps us build the generic ISO's for a Rocky Linux release. In
|
2022-06-15 20:53:12 +00:00
|
|
|
particular, this is for the boot images.
|
2022-06-06 22:02:08 +00:00
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
While there is a function for building the DVD and live images, this not
|
|
|
|
the main design of this class. The other functions can be called on their
|
|
|
|
own to facilitate those particular builds.
|
2022-06-06 22:02:08 +00:00
|
|
|
"""
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
rlvars,
|
|
|
|
config,
|
|
|
|
major,
|
2022-06-16 19:24:19 +00:00
|
|
|
rc: bool = False,
|
2022-06-15 20:53:12 +00:00
|
|
|
isolation: str = 'auto',
|
|
|
|
compose_dir_is_here: bool = False,
|
2022-06-06 22:02:08 +00:00
|
|
|
image=None,
|
|
|
|
logger=None
|
|
|
|
):
|
|
|
|
self.image = image
|
2022-06-13 14:37:50 +00:00
|
|
|
self.fullname = rlvars['fullname']
|
2022-06-15 20:53:12 +00:00
|
|
|
self.distname = config['distname']
|
|
|
|
self.shortname = config['shortname']
|
2022-06-06 22:02:08 +00:00
|
|
|
# Relevant config items
|
|
|
|
self.major_version = major
|
2022-06-15 20:53:12 +00:00
|
|
|
self.compose_dir_is_here = compose_dir_is_here
|
2022-06-13 14:37:50 +00:00
|
|
|
self.disttag = config['dist']
|
2022-06-06 22:02:08 +00:00
|
|
|
self.date_stamp = config['date_stamp']
|
2022-06-13 14:37:50 +00:00
|
|
|
self.timestamp = time.time()
|
2022-06-06 22:02:08 +00:00
|
|
|
self.compose_root = config['compose_root']
|
|
|
|
self.compose_base = config['compose_root'] + "/" + major
|
2022-06-13 14:37:50 +00:00
|
|
|
self.iso_drop = config['compose_root'] + "/" + major + "/isos"
|
2022-06-06 22:02:08 +00:00
|
|
|
self.current_arch = config['arch']
|
2022-06-15 20:53:12 +00:00
|
|
|
self.required_pkgs = rlvars['iso_map']['required_pkgs']
|
|
|
|
self.mock_work_root = config['mock_work_root']
|
|
|
|
self.lorax_result_root = config['mock_work_root'] + "/" + "lorax"
|
|
|
|
self.mock_isolation = isolation
|
|
|
|
self.iso_map = rlvars['iso_map']
|
2022-06-16 19:24:19 +00:00
|
|
|
self.release_candidate = rc
|
2022-06-06 22:02:08 +00:00
|
|
|
|
|
|
|
# Relevant major version items
|
2022-06-15 20:53:12 +00:00
|
|
|
self.release = rlvars['revision']
|
2022-06-17 06:25:17 +00:00
|
|
|
self.minor_version = rlvars['minor']
|
2022-06-06 22:02:08 +00:00
|
|
|
self.revision = rlvars['revision'] + "-" + rlvars['rclvl']
|
2022-06-16 19:24:19 +00:00
|
|
|
self.rclvl = rlvars['rclvl']
|
2022-06-15 20:53:12 +00:00
|
|
|
self.repos = rlvars['iso_map']['repos']
|
|
|
|
self.repo_base_url = config['repo_base_url']
|
|
|
|
self.project_id = rlvars['project_id']
|
|
|
|
|
|
|
|
self.extra_files = rlvars['extra_files']
|
2022-06-06 22:02:08 +00:00
|
|
|
|
|
|
|
self.staging_dir = os.path.join(
|
|
|
|
config['staging_root'],
|
|
|
|
config['category_stub'],
|
|
|
|
self.revision
|
|
|
|
)
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
# Templates
|
|
|
|
file_loader = FileSystemLoader('templates')
|
|
|
|
self.tmplenv = Environment(loader=file_loader)
|
|
|
|
|
2022-06-06 22:02:08 +00:00
|
|
|
self.compose_latest_dir = os.path.join(
|
|
|
|
config['compose_root'],
|
|
|
|
major,
|
|
|
|
"latest-Rocky-{}".format(major)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.compose_latest_sync = os.path.join(
|
|
|
|
self.compose_latest_dir,
|
|
|
|
"compose"
|
|
|
|
)
|
|
|
|
|
|
|
|
self.compose_log_dir = os.path.join(
|
|
|
|
self.compose_latest_dir,
|
|
|
|
"work/logs"
|
|
|
|
)
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
self.iso_work_dir = os.path.join(
|
|
|
|
self.compose_latest_dir,
|
|
|
|
"work/iso",
|
|
|
|
config['arch']
|
|
|
|
)
|
|
|
|
|
2022-06-06 22:02:08 +00:00
|
|
|
# This is temporary for now.
|
|
|
|
if logger is None:
|
|
|
|
self.log = logging.getLogger("iso")
|
|
|
|
self.log.setLevel(logging.INFO)
|
|
|
|
handler = logging.StreamHandler(sys.stdout)
|
|
|
|
handler.setLevel(logging.INFO)
|
|
|
|
formatter = logging.Formatter(
|
|
|
|
'%(asctime)s :: %(name)s :: %(message)s',
|
|
|
|
'%Y-%m-%d %H:%M:%S'
|
|
|
|
)
|
|
|
|
handler.setFormatter(formatter)
|
|
|
|
self.log.addHandler(handler)
|
|
|
|
|
|
|
|
self.log.info('iso build init')
|
2022-06-15 20:53:12 +00:00
|
|
|
self.repolist = self.build_repo_list()
|
2022-06-06 22:02:08 +00:00
|
|
|
self.log.info(self.revision)
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
work_root = os.path.join(
|
|
|
|
self.compose_latest_dir,
|
|
|
|
'work'
|
|
|
|
)
|
|
|
|
sync_root = self.compose_latest_sync
|
|
|
|
|
|
|
|
log_root = os.path.join(
|
|
|
|
work_root,
|
|
|
|
"logs"
|
|
|
|
)
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
self.iso_build()
|
2022-06-06 22:02:08 +00:00
|
|
|
|
|
|
|
self.log.info('Compose repo directory: %s' % sync_root)
|
|
|
|
self.log.info('ISO Build Logs: %s' % log_root)
|
|
|
|
self.log.info('ISO Build completed.')
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
def build_repo_list(self):
|
2022-06-06 22:02:08 +00:00
|
|
|
"""
|
2022-06-15 20:53:12 +00:00
|
|
|
Builds the repo dictionary
|
2022-06-06 22:02:08 +00:00
|
|
|
"""
|
2022-06-15 20:53:12 +00:00
|
|
|
repolist = []
|
|
|
|
for name in self.repos:
|
|
|
|
if not self.compose_dir_is_here:
|
|
|
|
constructed_url = '{}/{}/repo/hashed-{}/{}'.format(
|
|
|
|
self.repo_base_url,
|
|
|
|
self.project_id,
|
|
|
|
name,
|
|
|
|
self.current_arch
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
constructed_url = 'file://{}/{}/{}/os'.format(
|
|
|
|
self.compose_latest_sync,
|
|
|
|
name,
|
|
|
|
self.current_arch
|
|
|
|
)
|
2022-06-06 22:02:08 +00:00
|
|
|
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
repodata = {
|
|
|
|
'name': name,
|
|
|
|
'url': constructed_url
|
|
|
|
}
|
|
|
|
|
|
|
|
repolist.append(repodata)
|
|
|
|
|
|
|
|
return repolist
|
2022-06-06 22:02:08 +00:00
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
def iso_build(self):
|
2022-06-06 22:02:08 +00:00
|
|
|
"""
|
2022-06-15 20:53:12 +00:00
|
|
|
This does the general ISO building for the current running
|
|
|
|
architecture. This generates the mock config and the general script
|
|
|
|
needed to get this part running.
|
2022-06-06 22:02:08 +00:00
|
|
|
"""
|
2022-06-15 20:53:12 +00:00
|
|
|
# Check for local build, build accordingly
|
|
|
|
# Check for arch specific build, build accordingly
|
|
|
|
# local AND arch cannot be used together, local supersedes. print
|
|
|
|
# warning.
|
|
|
|
self.generate_iso_scripts()
|
2022-06-17 05:55:07 +00:00
|
|
|
self.run_lorax()
|
2022-06-06 22:02:08 +00:00
|
|
|
|
2022-06-13 14:37:50 +00:00
|
|
|
def generate_iso_scripts(self):
|
|
|
|
"""
|
2022-06-17 05:55:07 +00:00
|
|
|
Generates the scripts needed to be ran to run lorax in mock as well as
|
|
|
|
package up the results.
|
2022-06-13 14:37:50 +00:00
|
|
|
"""
|
2022-06-16 19:24:19 +00:00
|
|
|
self.log.info('Generating ISO configuration and scripts')
|
2022-06-15 20:53:12 +00:00
|
|
|
mock_iso_template = self.tmplenv.get_template('isomock.tmpl.cfg')
|
|
|
|
mock_sh_template = self.tmplenv.get_template('isobuild.tmpl.sh')
|
|
|
|
iso_template = self.tmplenv.get_template('buildImage.tmpl.sh')
|
|
|
|
|
|
|
|
mock_iso_path = '/var/tmp/lorax-' + self.major_version + '.cfg'
|
|
|
|
mock_sh_path = '/var/tmp/isobuild.sh'
|
|
|
|
iso_template_path = '/var/tmp/buildImage.sh'
|
|
|
|
|
2022-06-16 19:24:19 +00:00
|
|
|
rclevel = ''
|
|
|
|
if self.release_candidate:
|
|
|
|
rclevel = '-' + self.rclvl
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
mock_iso_template_output = mock_iso_template.render(
|
|
|
|
arch=self.current_arch,
|
|
|
|
major=self.major_version,
|
|
|
|
fullname=self.fullname,
|
2022-06-17 05:55:07 +00:00
|
|
|
shortname=self.shortname,
|
2022-06-15 20:53:12 +00:00
|
|
|
required_pkgs=self.required_pkgs,
|
|
|
|
dist=self.disttag,
|
|
|
|
repos=self.repolist,
|
|
|
|
user_agent='{{ user_agent }}',
|
|
|
|
)
|
|
|
|
|
|
|
|
mock_sh_template_output = mock_sh_template.render(
|
|
|
|
arch=self.current_arch,
|
|
|
|
major=self.major_version,
|
|
|
|
isolation=self.mock_isolation,
|
|
|
|
builddir=self.mock_work_root,
|
|
|
|
shortname=self.shortname,
|
|
|
|
)
|
|
|
|
|
|
|
|
iso_template_output = iso_template.render(
|
|
|
|
arch=self.current_arch,
|
|
|
|
major=self.major_version,
|
|
|
|
minor=self.minor_version,
|
|
|
|
shortname=self.shortname,
|
|
|
|
repos=self.repolist,
|
|
|
|
variant=self.iso_map['variant'],
|
|
|
|
lorax=self.iso_map['lorax_removes'],
|
|
|
|
distname=self.distname,
|
|
|
|
revision=self.release,
|
2022-06-16 19:24:19 +00:00
|
|
|
rc=rclevel,
|
2022-06-17 05:55:07 +00:00
|
|
|
builddir=self.mock_work_root,
|
|
|
|
lorax_work_root=self.lorax_result_root,
|
2022-06-15 20:53:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
mock_iso_entry = open(mock_iso_path, "w+")
|
|
|
|
mock_iso_entry.write(mock_iso_template_output)
|
|
|
|
mock_iso_entry.close()
|
|
|
|
|
|
|
|
mock_sh_entry = open(mock_sh_path, "w+")
|
|
|
|
mock_sh_entry.write(mock_sh_template_output)
|
|
|
|
mock_sh_entry.close()
|
|
|
|
|
|
|
|
iso_template_entry = open(iso_template_path, "w+")
|
|
|
|
iso_template_entry.write(iso_template_output)
|
|
|
|
iso_template_entry.close()
|
2022-06-13 14:37:50 +00:00
|
|
|
|
2022-06-17 05:55:07 +00:00
|
|
|
os.chmod(mock_sh_path, 0o755)
|
|
|
|
os.chmod(iso_template_path, 0o755)
|
|
|
|
|
|
|
|
def run_lorax(self):
|
|
|
|
"""
|
|
|
|
This actually runs lorax on this system. It will call the right scripts
|
|
|
|
to do so.
|
|
|
|
"""
|
|
|
|
lorax_cmd = '/bin/bash /var/tmp/isobuild.sh'
|
|
|
|
self.log.info('Starting lorax...')
|
|
|
|
|
|
|
|
try:
|
|
|
|
subprocess.call(shlex.split(lorax_cmd))
|
|
|
|
except:
|
|
|
|
self.log.error('An error occured during execution.')
|
|
|
|
self.log.error('See the logs for more information.')
|
|
|
|
raise SystemExit()
|
|
|
|
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
# !!! Send help, we would prefer to do this using the productmd python
|
|
|
|
# !!! library. If you are reading this and you can help us, please do so!
|
2022-06-13 14:37:50 +00:00
|
|
|
def treeinfo_write(self):
|
|
|
|
"""
|
|
|
|
Ensure treeinfo is written correctly
|
|
|
|
"""
|
|
|
|
print()
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
# !!! Send help, we would prefer to do this using the productmd python
|
|
|
|
# !!! library. If you are reading this and you can help us, please do so!
|
2022-06-13 14:37:50 +00:00
|
|
|
def discinfo_write(self):
|
|
|
|
"""
|
|
|
|
Ensure discinfo is written correctly
|
|
|
|
"""
|
|
|
|
#with open(file_path, "w") as f:
|
|
|
|
# f.write("%s\n" % self.timestamp)
|
|
|
|
# f.write("%s\n" % self.fullname)
|
|
|
|
# f.write("%s\n" % self.arch)
|
|
|
|
# if disc_numbers:
|
|
|
|
# f.write("%s\n" % ",".join([str(i) for i in disc_numbers]))
|
|
|
|
print()
|
|
|
|
|
|
|
|
def write_media_repo(self):
|
|
|
|
"""
|
|
|
|
Ensure media.repo exists
|
|
|
|
"""
|
|
|
|
data = [
|
|
|
|
"[InstallMedia]",
|
|
|
|
"name=%s" % self.fullname,
|
|
|
|
"mediaid=%s" % self.timestamp,
|
|
|
|
"metadata_expire=-1",
|
|
|
|
"gpgcheck=0",
|
|
|
|
"cost=500",
|
|
|
|
"",
|
|
|
|
]
|
|
|
|
|
2022-06-15 20:53:12 +00:00
|
|
|
def build_extra_iso(self):
|
|
|
|
"""
|
|
|
|
Builds DVD images based on the data created from the initial lorax on
|
|
|
|
each arch. This should NOT be called during the usual run() section.
|
|
|
|
"""
|
|
|
|
print()
|
2022-06-13 14:37:50 +00:00
|
|
|
|
|
|
|
def generate_graft_points(self):
|
|
|
|
"""
|
2022-06-15 20:53:12 +00:00
|
|
|
Get a list of packages for an extras ISO. This should NOT be called
|
|
|
|
during the usual run() section.
|
2022-06-13 14:37:50 +00:00
|
|
|
"""
|
|
|
|
print()
|
|
|
|
|
2022-06-06 22:02:08 +00:00
|
|
|
class LiveBuild:
|
|
|
|
"""
|
|
|
|
This helps us build the live images for Rocky Linux.
|
|
|
|
"""
|