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