summaryrefslogtreecommitdiff
path: root/scripts/image-build
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/image-build')
-rwxr-xr-xscripts/image-build/build-vyos-image140
-rw-r--r--scripts/image-build/utils.py7
2 files changed, 96 insertions, 51 deletions
diff --git a/scripts/image-build/build-vyos-image b/scripts/image-build/build-vyos-image
index a0acd184..a9294f38 100755
--- a/scripts/image-build/build-vyos-image
+++ b/scripts/image-build/build-vyos-image
@@ -95,7 +95,7 @@ else:
import utils
import raw_image
-from utils import cmd
+from utils import cmd, rc_cmd
## Check if there are missing build dependencies
deps = {
@@ -192,7 +192,8 @@ if __name__ == "__main__":
'vyos-mirror': ('VyOS package mirror', None),
'build-type': ('Build type, release or development', lambda x: x in ['release', 'development']),
'version': ('Version number (release builds only)', None),
- 'build-comment': ('Optional build comment', None)
+ 'build-comment': ('Optional build comment', None),
+ 'build-hook-opts': ('Custom options for the post-build hook', None)
}
# Create the option parser
@@ -336,6 +337,17 @@ if __name__ == "__main__":
if type(build_config["image_format"]) != list:
build_config["image_format"] = [ build_config["image_format"] ]
+ ## If the user didn't explicitly specify what extensions build artifact should have,
+ ## assume that the list is the same as image formats.
+ ## One case when it's not the same is when a custom build hook is used
+ ## to build a format that our build script doesn't support natively.
+ if not has_nonempty_key(build_config, "artifact_format"):
+ build_config["artifact_format"] = build_config["image_format"]
+ else:
+ # If the option is there, also make it list if it's a scalar
+ if type(build_config["artifact_format"]) != list:
+ build_config["artifact_format"] = [ build_config["artifact_format"] ]
+
## Dump the complete config if the user enabled debug mode
if debug:
import json
@@ -355,10 +367,18 @@ if __name__ == "__main__":
# not to the vyos-build repository root.
os.chdir(defaults.BUILD_DIR)
+ ## Initialize build manifest
+ manifest = {
+ 'build_config' : build_config,
+ 'artifacts' : [],
+ 'pre_build_config' : pre_build_config
+ }
+
iso_file = None
if build_config["reuse_iso"]:
iso_file = build_config["reuse_iso"]
+ manifest["artifacts"] = [iso_file]
else:
## Create the version file
@@ -412,11 +432,6 @@ if __name__ == "__main__":
# Release build, use the version from ./configure arguments
version = build_config['version']
- if build_config['build_type'] == 'development':
- lts_build = False
- else:
- lts_build = True
-
version_data = {
'version': version,
'flavor': build_config["build_flavor"],
@@ -427,7 +442,7 @@ if __name__ == "__main__":
'build_branch': git_branch,
'release_train': build_config['release_train'],
'architecture': build_config['architecture'],
- 'lts_build': lts_build,
+ 'build_type': build_config['build_type'],
'build_comment': build_config['build_comment'],
'bugtracker_url': build_config['bugtracker_url'],
'documentation_url': build_config['documentation_url'],
@@ -437,19 +452,18 @@ if __name__ == "__main__":
# Multi line strings needs to be un-indented to not have leading
# whitespaces in the resulting file
- os_release = f"""
- PRETTY_NAME="VyOS {version} ({build_config['release_train']})"
- NAME="VyOS"
- VERSION_ID="{version}"
- VERSION="{version} ({build_config['release_train']})"
- VERSION_CODENAME={build_defaults['debian_distribution']}
- ID=vyos
- BUILD_ID="{build_git}"
- HOME_URL="{build_defaults['website_url']}"
- SUPPORT_URL="{build_defaults['support_url']}"
- BUG_REPORT_URL="{build_defaults['bugtracker_url']}"
- DOCUMENTATION_URL="{build_config['documentation_url']}"
- """
+ os_release = f"""PRETTY_NAME="VyOS {version} ({build_config['release_train']})"
+NAME="VyOS"
+VERSION_ID="{version}"
+VERSION="{version} ({build_config['release_train']})"
+VERSION_CODENAME={build_defaults['debian_distribution']}
+ID=vyos
+BUILD_ID="{build_git}"
+HOME_URL="{build_defaults['website_url']}"
+SUPPORT_URL="{build_defaults['support_url']}"
+BUG_REPORT_URL="{build_defaults['bugtracker_url']}"
+DOCUMENTATION_URL="{build_config['documentation_url']}"
+"""
# Reminder: all paths relative to the build dir, not to the repository root
chroot_includes_dir = defaults.CHROOT_INCLUDES_DIR
@@ -469,8 +483,8 @@ if __name__ == "__main__":
print("Version: {0}".format(version), file=f)
# Define variables that influence to welcome message on boot
- os.makedirs(os.path.join(chroot_includes_dir, 'usr/lib/'), exist_ok=True)
- with open(os.path.join(chroot_includes_dir, 'usr/lib/os-release'), 'w') as f:
+ os.makedirs(os.path.join(chroot_includes_dir, 'etc/'), exist_ok=True)
+ with open(os.path.join(chroot_includes_dir, 'etc/os-release'), 'w') as f:
print(os_release, file=f)
## Clean up earlier build state and artifacts
@@ -548,13 +562,6 @@ if __name__ == "__main__":
with open(file_path, 'w') as f:
f.write(build_config["default_config"])
- ## Initialize build manifest
- manifest = {
- 'build_config' : build_config,
- 'artifacts' : [iso_file],
- 'pre_build_config' : pre_build_config
- }
-
## Configure live-build
lb_config_tmpl = jinja2.Template("""
lb config noauto \
@@ -571,7 +578,7 @@ if __name__ == "__main__":
--checksums 'sha256 md5' \
--chroot-squashfs-compression-type "{{squashfs_compression_type}}" \
--debian-installer none \
- --debootstrap-options "--variant=minbase --exclude=isc-dhcp-client,isc-dhcp-common,ifupdown --include=apt-utils,ca-certificates,gnupg2" \
+ --debootstrap-options "--variant=minbase --exclude=isc-dhcp-client,isc-dhcp-common,ifupdown --include=apt-utils,ca-certificates,gnupg2,linux-kbuild-6.1" \
--distribution {{debian_distribution}} \
--firmware-binary false \
--firmware-chroot false \
@@ -586,7 +593,8 @@ if __name__ == "__main__":
--mirror-chroot {{debian_mirror}} \
--mirror-chroot-security {{debian_security_mirror}} \
--security true \
- --updates true
+ --updates true \
+ --utc-time true
"${@}"
""")
@@ -629,29 +637,59 @@ Pin-Priority: 600
# Copy the image
shutil.copy("live-image-{0}.hybrid.iso".format(build_config["architecture"]), iso_file)
- # Build additional flavors from the ISO,
- # if the flavor calls for them
+ # Add the image to the manifest
+ manifest['artifacts'].append(iso_file)
+
+ # If the flavor has `image_format = "iso"`, then the work is done.
+ # If not, build additional flavors from the ISO.
if build_config["image_format"] != ["iso"]:
+ # For all non-iso formats, we always build a raw image first
raw_image = raw_image.create_raw_image(build_config, iso_file, "tmp/")
manifest['artifacts'].append(raw_image)
- if has_nonempty_key(build_config, "post_build_hook"):
- # Some flavors require special procedures that aren't covered by qemu-img
- # (most notably, the VMware OVA that requires a custom tool to make and sign the image).
- # For those cases, we support running a post-build hook on the raw image.
- # The image_format field should be 'raw' if a post-build hook is used.
- hook_path = build_config["post_build_hook"]
- cmd(f"{hook_path} {raw_image}")
- else:
- # Most other formats, thankfully, can be produced with just `qemu-img convert`
- other_formats = filter(lambda x: x not in ["iso", "raw"], build_config["image_format"])
- for f in other_formats:
- image_ext = build_config.get("image_ext", f)
- image_opts = build_config.get("image_opts", "")
- target = f"{os.path.splitext(raw_image)[0]}.{image_ext}"
- print(f"I: Building {f} file {target}")
- cmd(f"qemu-img convert -f raw -O {f} {image_opts} {raw_image} {target}")
- manifest['artifacts'].append(target)
+ # If there are other formats in the flavor, the assumptions is that
+ # they can be produced from a raw image with `qemu-img convert`
+ other_formats = filter(lambda x: x not in ["iso", "raw"], build_config["image_format"])
+ for f in other_formats:
+ image_ext = build_config.get("image_ext", f)
+ image_opts = build_config.get("image_opts", "")
+ target = f"{os.path.splitext(raw_image)[0]}.{image_ext}"
+ print(f"I: Building {f} file {target}")
+ cmd(f"qemu-img convert -f raw -O {f} {image_opts} {raw_image} {target}")
+ manifest['artifacts'].append(target)
+
+ # Finally, there are formats that require special procedures.
+ # For example, a VMware OVA needs a custom tool for image building and signing.
+ # For those cases, we support custom build hooks that run on raw images.
+ # A post-build hook is a script embedded in the flavor file
+ # that must return the artifact name via stdout.
+ if has_nonempty_key(build_config, "build_hook"):
+ hook_source = build_config["build_hook"]
+
+ with open('build_hook', 'w') as f:
+ f.write(hook_source)
+ os.chmod('build_hook', 0o755)
+
+ if has_nonempty_key(build_config, "build_hook_opts"):
+ hook_opts = build_config["build_hook_opts"]
+ else:
+ hook_opts = ""
+ custom_image = rc_cmd(f"./build_hook {raw_image} {build_config['version']} \
+ {build_config['architecture']} {hook_opts}")
+ manifest['artifacts'].append(custom_image)
+
+ # Filter out unwanted files from the artifact list
+ # and leave only those the user specified
+ # in either `artifact_format` or `image_format`.
+ #
+ # For example, with `image_format = "raw"`,
+ # the ISO image is just an intermediate object, not an target artifact.
+
+ # os.path.splitext returns extensions with dots,
+ # so we need to remove the dots, hence [1:]
+ is_artifact = lambda f: os.path.splitext(f)[-1][1:] in build_config['artifact_format']
+
+ manifest['artifacts'] = list(filter(is_artifact, manifest['artifacts']))
with open('manifest.json', 'w') as f:
f.write(json.dumps(manifest))
diff --git a/scripts/image-build/utils.py b/scripts/image-build/utils.py
index 7002b281..081327cd 100644
--- a/scripts/image-build/utils.py
+++ b/scripts/image-build/utils.py
@@ -82,3 +82,10 @@ def cmd(command):
res = vyos.utils.process.call(command, shell=True)
if res > 0:
raise OSError(f"Command '{command}' failed")
+
+def rc_cmd(command):
+ code, out = vyos.utils.process.rc_cmd(command, shell=True)
+ if code > 0:
+ raise OSError(f"Command '{command}' failed")
+ else:
+ return out