]> git.ipfire.org Git - people/jschlag/ipfire-3.x-image.git/blame - generate_image.sh
Reduce image size to something minor 8 GB
[people/jschlag/ipfire-3.x-image.git] / generate_image.sh
CommitLineData
5bbf7721
JS
1#!/bin/bash
2###############################################################################
3# IPFire.org - An Open Source Firewall Solution #
4# Copyright (C) - IPFire Development Team <info@ipfire.org> #
5###############################################################################
6
7# Constants
8
9# Proper error codes
10EXIT_OK=0
11EXIT_ERROR=1
12EXIT_CONF_ERROR=2
13EXIT_NOT_SUPPORTED=3
14EXIT_NOT_HANDLED=4
15EXIT_COMMAND_NOT_FOUND=127
16EXIT_ERROR_ASSERT=128
17
18EXIT_TRUE=0
19EXIT_FALSE=1
20EXIT_UNKNOWN=2
21
22# Functions
23
24log() {
25 local level=${1}
26 local message=${2}
27 echo "[${level}] ${message}"
28}
29
30cleanup() {
31 # Unmount image
32 umount ${IMAGE_MOUNT_DIR}
33
5bbf7721
JS
34 # Remove partition from the kernel table.
35 partx -d ${outlo}p1
36
37 # Remove loopback device
38 losetup -d ${outlo}
39
91a03596
JS
40 # Drop working dir
41 if [ -d "${WORKING_DIR}" ]; then
42 rm -dfR "${WORKING_DIR}"
5bbf7721
JS
43 fi
44}
45
46generate_image_filename() {
47 local distro=${1}
48 local version=${2}
e04a0de0 49 local arch=${3}
5bbf7721 50
e04a0de0 51 echo "${distro}-${version}-${arch}"
5bbf7721
JS
52}
53
54check_for_pakfire() {
55 local return_value=0
56
57 # TODO
58 # Check that pakfire-server binary is available
59 # Check that pakfire binary is available
60
61 # Check that repo files are installed. (pakfire need to know which repos exist)
62 local repo_dir="/etc/pakfire/repos"
63
64 if [ ! -d "${repo_dir}" ]; then
65 log ERROR "Could not find respository directory ${repo_dir}"
66 return_value=1
67 fi
68
69 return ${return_value}
70}
71
72compress_image() {
73 local compression=${1}
74 local image_file=${2}
75 local level=${3}
76
77 log debug "Compressing ${image_file} with ${compression}"
78
79 case "${compression}" in
80 "xz")
81 # Check that the file does not exist yet
82 if [ -f "${image_file}.xz" ]; then
83 log ERROR "Failed to compress the image. The file already exists"
84 return ${EXIT_ERROR}
85 fi
86 xz "-${level}" "${image_file}"
87 ;;
88 "zip")
89 # Check that the file does not exist yet
90 if [ -f "${image_file}.zip" ]; then
91 log ERROR "Failed to compress the image. The file already exists"
92 return ${EXIT_ERROR}
93
94 fi
95 zip "-${level}" "${image_file}.zip" "${image_file}"
96 # Remove the file which we compressed+
97 rm -f "${image_file}"
98 ;;
99
100 esac
101}
102
103reset_root_password() {
104 local root_dir=${1}
105 # Backup passwd file
106 cp -avf ${root_dir}/etc/passwd ${root_dir}/etc/passwd.orig
107
108 # Drop root password.
109 sed -e "s/^\(root:\)[^:]*:/\1:/" ${root_dir}/etc/passwd.orig > ${root_dir}/etc/passwd
110
111 # Remove passwd backup file.
112 rm -rvf ${root_dir}/etc/passwd.orig
113}
114
115clone_git_repos() {
116 # Dir where the repos should be located
117 local dir=${1}
118 shift
119 local repos="$@"
120
121 local repo
122
123 mkdir -pv ${dir}
124
125 (
126 cd ${dir}
127 # Clone git repositories.
128 for repo in ${repos}; do
129 git clone ${repo}
130 done
131 )
132}
133
134# This function is used to publish the produced images
135
136publish() {
137 local path=${1}
138 # The image we created usually a img. file
e04a0de0 139 local image_base_file=${2}
5bbf7721 140
e04a0de0 141 local image_name_final="$(generate_image_filename "${DISTRO}" "${VERSION}" "${ARCH}")"
5bbf7721 142
e04a0de0 143 local image_type
5bbf7721
JS
144 local compression_type
145
146 # Do these steps for every image format we like to publish
e04a0de0 147 for image_type in ${IMAGE_TYPES_PUBLISH}; do
5bbf7721 148 # Get compressioon type
e04a0de0 149 compression_type="$(get_compression_type ${image_type})"
5bbf7721 150 # Convert images to the type specified in IMAGE_TYPES_PUBLISH
e04a0de0 151 convert_image "${image_type}" "${image_base_file}" "${image_name_final}"
5bbf7721
JS
152
153 # compress image.
e04a0de0 154 compress_image "${compression_type}" "${image_name_final}.${image_type}" "1"
5bbf7721
JS
155
156 # Move images to this path
e04a0de0 157 mv -f "${image_name_final}.${image_type}.${compression_type}" ${path}
5bbf7721
JS
158
159 # point the latest links to these images
e04a0de0
JS
160 ln -s -f "${path}/${image_name_final}.${image_type}.${compression_type}" \
161 "${path}/$(generate_image_filename "${DISTRO}" "latest" "${ARCH}").${image_type}.${compression_type}"
5bbf7721
JS
162
163 done
164
165}
166
167convert_image() {
168 local type=${1}
169 local from=${2}
170 local to=${3}
171
172 if [[ ${type} = "img" ]]; then
e04a0de0
JS
173 # We do not need to convert the image here but we need to rename
174 mv -f ${from} ${to}.${type}
5bbf7721
JS
175 fi
176
177 if [[ ${type} = "qcow2" ]]; then
178 local cmd="qemu-img convert -c -O ${type} ${from} ${to}.${type}"
179 else
180 local cmd="qemu-img convert -O ${type} ${from} ${to}.${type}"
181 fi
182
183 log debug "${cmd}"
184
185 # Execute the command to convert the image
186 ${cmd}
187}
188
189get_compression_type() {
190 local image_type=${1}
191
192 case "${image_type}" in
193 "qcow2" | "img")
194 # These types can be used only under Unix so we use xz as compression
195 echo "xz"
196 ;;
197 "vmdk" | "vdi")
198 # These types can be also under Windows so we use zip as compression
199 echo "zip"
200 ;;
201 esac
202
203}
204
c38c098c
JS
205check_for_free_space() {
206 local space=${1}
207 local path=${2}
208
209 # Space needs to passed in MB
210 # df returns bytes so we multiple by 1024²
211 space=$(( ${space} * 1024 * 1024 ))
212
213 if [[ $(df --output=avail ${path} | tail -n 1) -lt ${space} ]]; then
214 log error "Not enough free space available under ${path}"
215 log error "Free space is $(df -h -B MB --output=avail ${path} | tail -n 1) but we need at least $(( ${space} / 1024 / 1024 ))MB"
216 return ${EXIT_ERROR}
217 fi
218}
219
5bbf7721
JS
220#
221# General settings
222#
223
224ARCH="x86_64"
225DISTRO="ipfire3"
226VERSION="$(date +"%Y%m%d")"
e04a0de0
JS
227WORKING_DIR=$(mktemp -d /tmp/ipfire3_image.XXXXXXXX)
228
229log DEBUG "Working dir is ${WORKING_DIR}"
5bbf7721
JS
230
231#
232# Image
233#
234
235IMAGE_TYPE="img"
e04a0de0 236IMAGE_BASE_FILE="$(mktemp -u ${WORKING_DIR}/image_base_file.XXXXXXX.img)"
535dee06 237IMAGE_SIZE="8100"
e04a0de0 238IMAGE_MOUNT_DIR="$(mktemp -d ${WORKING_DIR}/image.XXXXXXX)"
5bbf7721
JS
239
240IMAGE_TYPES_PUBLISH="qcow2 vmdk vdi img"
241
242# The used filesystem.
243FILESYSTEM="xfs"
244
245# Additional packages which should be installed.
246PACKAGES="xfsprogs kernel openssh-server wget htop tmux"
247
248# Use git network stack. ( When using the git network stack,
249# development tools and git automatically will be installed.)
250USE_GIT_NETWORK_STACK="True"
251
252# List of packages which are required to build the network stack.
253NETWORK_BUILD_DEPS="autoconf automake docbook-xsl libnl3-devel libxslt systemd-devel"
254
255# Install development tools.
256INSTALL_DEV_PACKAGES="False"
257
258# List of development tools which should be installed.
259DEVELOPMENT_PACKAGES="make gcc libtool git"
260
261
262# Git repositories which also should be checked, out.
263GIT_REPOS=""
264
265#
266# Stuff for the local repo
267#
268
269# Use local repository.
270USE_LOCAL_REPO="True"
271
272# Source path for the local repo packages.
273LOCAL_REPO_SOURCE_PATH="/var/lib/pakfire/local/"
274
275# Path were the local repo is created
e04a0de0 276LOCAL_REPO_DIR="$(mktemp -d ${WORKING_DIR}/ipfire-repo.XXXXXXX)"
5bbf7721
JS
277
278# Config file for the local repo
279LOCAL_REPO_FILE="/etc/pakfire/repos/local.repo"
280
281
282# Check that pakfire is working
283check_for_pakfire
284
c38c098c
JS
285if ! check_for_free_space 10000 "${WORKING_DIR}"; then
286 exit ${EXIT_ERROR}
287fi
5bbf7721
JS
288
289# Check that the image does not exist yet
e04a0de0 290if [ -f ${IMAGE_BASE_FILE} ]; then
5bbf7721
JS
291 log ERROR "Image file does already exists"
292 exit 1
293fi
294
295# Check that the local repo file does not exists yet.
296# We do not want to override custom user configurations.
297if [ -f "${LOCAL_REPO_FILE}" ]; then
298 log ERROR "Config file ${LOCAL_REPO_FILE} for the local repo does already exists"
299 exit 1
300fi
301
e04a0de0
JS
302# cd into working directory
303cd ${WORKING_DIR} || exit ${EXIT_ERROR}
304
5bbf7721
JS
305#
306## Create the disk image.
307#
e04a0de0 308dd if=/dev/zero of=${IMAGE_BASE_FILE} seek=${IMAGE_SIZE}MB count=1k bs=1
5bbf7721
JS
309
310# Setup the loopback device.
e04a0de0 311outlo=`losetup -f --show ${IMAGE_BASE_FILE}`
5bbf7721
JS
312
313log INFO "Create partions and filesystem"
314
315# Create and msdos compatible table on the image.
316parted ${outlo} mklabel msdos
317
318# Add a new partition to the image.
319parted ${outlo} mkpart primary ${FILESYSTEM} 2048k 100% -a minimal
320
321# Make the primary partition bootable.
322parted ${outlo} set 1 boot on
323
324# Notify the kernel about the new partition.
325partx -a ${outlo}
326
327#
328## Create the filesystem.
329#
330mkfs.${FILESYSTEM} ${outlo}p1
331
332#
333## Mount the filesystem.
334#
335
336log INFO "Mount partion in ${IMAGE_MOUNT_DIR}"
337
338# Create a temporary mountpoint.
339mkdir -p ${IMAGE_MOUNT_DIR}
340
341# Afterwards mount the image.
342mount -t ${FILESYSTEM} ${outlo}p1 ${IMAGE_MOUNT_DIR}
343
344#
345## Install IPFire 3.x.
346#
347
348# Add grub on x86_64 to the package list.
349if [ "${ARCH}" == "x86_64" ] || [ "${ARCH}" == "i686" ]; then
350 PACKAGES="${PACKAGES} grub"
351
352 # Store, that grub is present.
353 HAVE_GRUB="True"
354fi
355
356# Check if the git network stack should be installed.
357if [ "${USE_GIT_NETWORK_STACK}" == "True" ]; then
358 GIT_REPOS="${GIT_REPOS} git://git.ipfire.org/network.git"
359
360 # Add build dependencies of network package.
361 PACKAGES="${PACKAGES} ${NETWORK_BUILD_DEPS}"
362fi
363
364# Add develoment packes to the package list, if required.
365if [ "${INSTALL_DEV_PACKAGES}" == "True" ] || [ ! -z "${GIT_REPOS}" ]; then
366 PACKAGES="${PACKAGES} ${DEVELOPMENT_PACKAGES}"
367fi
368
369log INFO "Create local respository"
370
371
372# Check if the local repo should be used.
373if [ "${USE_LOCAL_REPO}" == "True" ]; then
374 # Create local repository.
375 mkdir -pv "${LOCAL_REPO_DIR}"
376
377 # Master repository.
378 if ! pakfire-server repo create ${LOCAL_REPO_DIR} ${LOCAL_REPO_SOURCE_PATH}; then
379 log ERROR "Failed to create a local respository"
91a03596 380 cleanup
5bbf7721
JS
381 exit 1
382 fi
383
384 # Create temporary pakfire repo file.
385 echo "[repo:local]" >> "${LOCAL_REPO_FILE}"
386 echo "description = Local repository." >> "${LOCAL_REPO_FILE}"
387 echo "enabled = 0" >> "${LOCAL_REPO_FILE}"
388 echo "baseurl = ${LOCAL_REPO_DIR}" >> "${LOCAL_REPO_FILE}"
389
390 ENABLE_LOCAL="--enable-repo=local"
391fi
392
393# Install IPFire 3.x in the created image.
394yes | pakfire --root=${IMAGE_MOUNT_DIR} ${ENABLE_LOCAL} install @Base ${PACKAGES}
395
396#
397# Enable serial console
398#
399
400
401#echo "GRUB_TERMINAL=\"serial console\"" >> "${IMAGE_MOUNT_DIR}/etc/default/grub"
402#echo "GRUB_SERIAL_COMMAND=\"serial --unit=0 --speed=115200\"" >> "${IMAGE_MOUNT_DIR}/etc/default/grub"
403
404#Hack to install a /etc/default/grub file
405
406cp -f grub "${IMAGE_MOUNT_DIR}/etc/default"
407
408#
409## Install grub2 if neccessary
410#
411if [ "${HAVE_GRUB}" == "True" ]; then
412 grub2-install --boot-directory=${IMAGE_MOUNT_DIR}/boot/ --modules="${FILESYSTEM} part_msdos" ${outlo}
413fi
414
415#
416## Generate fstab
417#
418
419# Gather the uuid of the partition.
420FS_UUID=$(blkid -o value -s UUID ${outlo}p1)
421
422# Write fstab.
423echo "UUID=${FS_UUID} / ${FILESYSTEM} defaults 0 0" > ${IMAGE_MOUNT_DIR}/etc/fstab
424
425#
426## Remove the password for user root.
427#
428
429reset_root_password "${IMAGE_MOUNT_DIR}"
430
431#
432## Setup git repositories.
433#
434
435clone_git_repos "${IMAGE_MOUNT_DIR}/build" ${GIT_REPOS}
436
437#
438## Prepare chrooting into the image.
439#
440
441# Check if the network stack should be build.
442if [ "${USE_GIT_NETWORK_STACK}" == "True" ]; then
443 BUILD_NETWORK_CMDS="cd network/ && ./autogen.sh && ./configure && make && make install"
444fi
445
446ENABLE_GETTY="/bin/systemctl enable getty@.service"
447
448# Check if the arch uses grub
449if [ "${HAVE_GRUB}" == "True" ]; then
450 GENERATE_GRUB_CONF="grub-mkconfig -o /boot/grub2/grub.cfg"
451fi
452
453# Use systemd-nspawn to spawn a chroot environment and execute
454# commands inside it.
455#
456# The first command enables the terminal on TTY1.
457# The second command generates the configuration file for grub2.
458
459
460systemd-nspawn -D ${IMAGE_MOUNT_DIR} --bind /dev --capability=CAP_SYS_ADMIN,CAP_SYS_RAWIO --bind /proc --bind /sys << END
461 echo "Execute commands inside chroot"
462 ${ENABLE_GETTY}
463 ${GENERATE_GRUB_CONF}
464 cd /git-repos/ && ls
465 ${BUILD_NETWORK_CMDS}
466 echo "All commands executed"
467END
468
469
470
471# Insert the UUID because grub-mkconfig often fails to
472# detect that correctly
473
474sed -i "${IMAGE_MOUNT_DIR}/boot/grub2/grub.cfg" \
475 -e "s/root=[A-Za-z0-9\/=-]*/root=UUID=${FS_UUID}/g"
476
477cat "${IMAGE_MOUNT_DIR}/boot/grub2/grub.cfg"
478#
479## Tidy up.
480#
481
482# Wait a second.
483sleep 5
484
485# Check filesystem for damage.
486fsck.${FILESYSTEM} ${outlo}p1
487
488# Cleanup
489cleanup
490
e04a0de0 491publish "/home/jschlag/public/ipfire3-images" "${IMAGE_BASE_FILE}"
5bbf7721 492
e04a0de0 493#compress_image "xz" "${IMAGE_BASE_FILE}"