build-image: rename ISO to reflect build timestamp

Builds generated by Jenkins are identified by a timestamp, set in the
environment, such as TIMESTAMP=2024-06-12_19-00-08. Yet the ISO file
created by build-image is named after the clock value at the point of
creation, ie a different time stamp.

This patch renames the ISO to match the overall build timestamp, if
TIMESTAMP is set in the environment.

EXAMPLE
==========================
* Original file created by LAT SDK is similar to:
    starlingx-intel-x86-64-20240613180213-cd.iso
* With TIMESTAMP=2024-06-12_19-00-08 it's renamed to:
    starlingx-intel-x86-64-2024-06-12_19-00-08-cd.iso
  along with the signatures and symlinks

TESTS
==========================
* Call build-image with TIMESTAMP set and make sure the ISO file, the
  signature and the symlinks are generated correctly
* Call build-image w/o the TIMESTAMP and check that the files are not
  renamed

Story: 2010055
Task: 50358

Signed-off-by: Davlet Panech <davlet.panech@windriver.com>
Change-Id: I184f6a4f79688e0c8a3029d2aafa22c383b5a524
This commit is contained in:
Davlet Panech 2024-06-17 11:48:27 -04:00
parent 5d60f45f2c
commit 3f4058b566

View File

@ -19,6 +19,7 @@ import discovery
import getopt import getopt
import logging import logging
import os import os
from pathlib import Path
import re import re
import repo_manage import repo_manage
import shutil import shutil
@ -485,25 +486,88 @@ def user_register_signals():
signal.signal(signal.SIGPIPE, user_signal_handler) signal.signal(signal.SIGPIPE, user_signal_handler)
def sign_iso_dev(img_yaml): def get_iso_name(iso_name_prefix: str, timestamp: str = None) -> str:
if timestamp is not None:
return '%s-%s-cd' % (iso_name_prefix, timestamp)
return '%s-cd' % iso_name_prefix
def rename_iso(deploy_dir: str, iso_name_prefix: str, timestamp: str) -> None:
iso_name = get_iso_name(iso_name_prefix)
iso_basename = '%s.iso' % iso_name
iso_file = '%s/%s' % (deploy_dir, iso_basename)
iso_name_regex = re.compile('^%s-[0-9]{4,}.*[.]iso$' % re.escape(iso_name_prefix))
if not os.path.islink(iso_file):
if not os.path.exists(iso_file):
logger.warning('%s: file not found', iso_file)
else:
logger.warning('%s: expecting a symlink', iso_file)
return
def check_iso_file_name(file_name: str) -> bool:
if not iso_name_regex.match(file_name):
logger.warning('failed to rename %s: unexpected file name pattern', file_name)
return False
return True
def create_renamed_info_file(iso_dir, iso_basename, new_iso_basename) -> None:
info_file = '%s/%s.RENAMED.txt' % (iso_dir, iso_basename)
with open(info_file, 'w') as f:
print('File %s renamed to %s by build-image script' % (iso_basename, new_iso_basename), file=f)
iso_target = os.readlink(iso_file)
if os.path.isabs(iso_target):
real_iso_file = iso_target
else:
real_iso_file = os.path.join(os.path.dirname(iso_file), iso_target)
# make sure target exists
if not os.path.exists(real_iso_file):
raise RuntimeError('%s: broken symlink', iso_file)
real_iso_dir = os.path.dirname(real_iso_file) # .../deploy
real_iso_basename = os.path.basename(real_iso_file) # starlingx-intel-x86-64-${OLD_TIMESTAMP}-cd.iso
# reject unexpected file names
if not check_iso_file_name(real_iso_basename):
return
new_real_iso_basename = '%s.iso' % get_iso_name(iso_name_prefix, timestamp) # starlingx-intel-x86-64-${TIMESTAMP}-cd.iso
new_real_iso_file = os.path.join(real_iso_dir, new_real_iso_basename) # .../deploy/starlingx-intel-x86-64-${TIMESTAMP}-cd.iso
# basename already correct, bail out
if real_iso_basename == new_real_iso_basename:
logger.debug('ISO file name is already correct: %s', real_iso_basename)
return
# if original symlink had a directory component, keep it in the new symlink
if iso_target.find('/') != -1:
new_iso_target = os.path.join(os.path.dirname(iso_target), new_real_iso_basename)
else:
new_iso_target = new_real_iso_basename
# Rename and link
Path(iso_file).unlink(missing_ok=True) # remove symlink
Path(new_real_iso_file).unlink(missing_ok=True) # remove new filename (rename target)
os.rename(real_iso_file, new_real_iso_file) # rename old to new name
os.symlink(new_iso_target, iso_file) # re-create symlink
# create XYZ.iso.RENAMED.txt
create_renamed_info_file(real_iso_dir, real_iso_basename, new_real_iso_basename)
logger.info('renamed %s/{%s => %s}' % (real_iso_dir, real_iso_basename, new_real_iso_basename))
def sign_iso_dev(deploy_dir: str, iso_name_prefix: str)->None:
''' '''
Sign the .iso file with the developer key Sign the .iso file with the developer key
img_yaml: lat.yaml path deploy_dir: ISO directory
iso_name_prefix: prefix for ISO files, eg starlingx-intel-x86-64
''' '''
logger.info("Trying to sign iso image with developer key") logger.info("Trying to sign iso image with developer key")
key_path = os.path.join(os.environ.get('MY_REPO'), 'build-tools/signing/dev-private-key.pem') key_path = os.path.join(os.environ.get('MY_REPO'), 'build-tools/signing/dev-private-key.pem')
deploy_dir = '/localdisk/deploy' iso_name = get_iso_name(iso_name_prefix)
try:
with open(img_yaml) as f:
yaml_doc = yaml.safe_load(f)
except IOError as e:
logger.error(str(e))
if yaml_doc['name'] and yaml_doc['machine']:
iso_name = yaml_doc['name'] + '-' + yaml_doc['machine'] + '-cd'
else:
# default image name
iso_name = 'starlingx-intel-x86-64-cd'
iso_file = f'{deploy_dir}/{iso_name}.iso' iso_file = f'{deploy_dir}/{iso_name}.iso'
sig_file = f'{deploy_dir}/{iso_name}.sig' sig_file = f'{deploy_dir}/{iso_name}.sig'
@ -534,10 +598,10 @@ def sign_iso_dev(img_yaml):
if ret != 0: if ret != 0:
raise Exception("Error while signing the image") raise Exception("Error while signing the image")
# ISO is a symlink => create the matc hing .sig link # ISO is a symlink => create the matching .sig link
if os.path.islink (iso_file): if os.path.islink (iso_file):
if os.path.exists (sig_file): if os.path.exists (sig_file):
os.path.remove (sig_file) os.remove (sig_file)
os.symlink (sig_target, sig_file) os.symlink (sig_target, sig_file)
logger.info("Image signed %s", real_iso_file) logger.info("Image signed %s", real_iso_file)
@ -580,6 +644,26 @@ def get_binary_repositories(config: str):
logger.info("Processing complete.") logger.info("Processing complete.")
return repositories return repositories
def post_process(deploy_dir: str, yaml_file: str, sign: bool)->None:
# find out ISO file name prefix
logger.debug('reading %s', yaml_file)
with open(yaml_file) as f:
yaml_doc = yaml.safe_load(f)
assert yaml_doc['name']
assert yaml_doc['machine']
iso_name_prefix = yaml_doc['name'] + '-' + yaml_doc['machine']
# rename ISO if necessary
new_timestamp = os.getenv('TIMESTAMP')
if new_timestamp:
#new_timestamp = re.sub(r'[^a-zA-Z0-9]+', '', new_timestamp)
rename_iso(deploy_dir, iso_name_prefix, new_timestamp)
# sign ISO with developer key
if sign:
sign_iso_dev(deploy_dir, iso_name_prefix)
if __name__ == "__main__": if __name__ == "__main__":
@ -761,9 +845,10 @@ if __name__ == "__main__":
# stop latd # stop latd
stop_latd() stop_latd()
os.system('sudo chown -R ${USER}: ' + LAT_ROOT + '/deploy' ) deploy_dir = '%s/deploy' % LAT_ROOT
# Sign iso with developer key subprocess.run('sudo chown -R ${USER}: "%s"' % deploy_dir, shell=True, check=True)
if ret == 0 and not args.no_sign:
sign_iso_dev(lat_yaml) if ret == 0:
post_process(deploy_dir, lat_yaml, not args.no_sign)
sys.exit(ret) sys.exit(ret)