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