]>
Commit | Line | Data |
---|---|---|
358ea1df JS |
1 | #!/bin/bash |
2 | ||
3 | # Constants | |
4 | ||
5 | # Proper error codes | |
6 | EXIT_OK=0 | |
7 | EXIT_ERROR=1 | |
8 | EXIT_CONF_ERROR=2 | |
9 | EXIT_NOT_SUPPORTED=3 | |
10 | EXIT_NOT_HANDLED=4 | |
11 | EXIT_COMMAND_NOT_FOUND=127 | |
12 | EXIT_ERROR_ASSERT=128 | |
13 | ||
14 | EXIT_TRUE=0 | |
15 | EXIT_FALSE=1 | |
16 | EXIT_UNKNOWN=2 | |
17 | ||
18 | TRUE=0 | |
19 | FALSE=1 | |
20 | ||
b7ec229b JS |
21 | IMAGE_RELEASE=${FALSE} |
22 | ||
7dc7fa1d JS |
23 | # maybe mounted dirs |
24 | MOUNTED_DIRS="/proc" "/sys" "dev/pts" "dev/shm" "dev" "run" "tmp" "" | |
25 | ||
26 | ||
358ea1df JS |
27 | # Functions |
28 | ||
29 | log() { | |
30 | local level=${1} | |
31 | local message=${2} | |
32 | echo "[${level}] ${message}" | |
33 | } | |
34 | ||
35 | cmd() { | |
8b38bb23 | 36 | local cmd="$@" |
358ea1df JS |
37 | local ret |
38 | ||
39 | log DEBUG "Running command: ${cmd}" | |
40 | ||
41 | ${cmd} | |
42 | ret=$? | |
43 | ||
44 | case "${ret}" in | |
45 | ${EXIT_OK}) | |
46 | return ${EXIT_OK} | |
47 | ;; | |
48 | *) | |
49 | log DEBUG "Returned with code '${ret}'" | |
50 | return ${ret} | |
51 | ;; | |
52 | esac | |
53 | } | |
54 | ||
55 | ||
56 | cleanup_stage_1() { | |
7dc7fa1d JS |
57 | |
58 | local mounted_dir | |
59 | for mounted_dir in ${MOUNTED_DIRS} | |
60 | do | |
61 | ||
62 | if is_mounted "${IMAGE_MOUNT_DIR}${mounted_dir}"; then | |
63 | umount "${IMAGE_MOUNT_DIR}${mounted_dir}" | |
64 | else | |
65 | log DEBUG "${IMAGE_MOUNT_DIR}${mounted_dir} is not mounted" | |
66 | fi | |
67 | done | |
68 | ||
358ea1df JS |
69 | |
70 | # Remove partition from the kernel table. | |
71 | partx -d ${outlo}p1 | |
72 | ||
73 | # Remove loopback device | |
74 | losetup -d ${outlo} | |
75 | ||
76 | ||
77 | ||
78 | # Cleanup Config file for the local repo | |
79 | if [ -f "${LOCAL_REPO_FILE}" ]; then | |
80 | rm -f "${LOCAL_REPO_FILE}" | |
81 | fi | |
82 | ||
83 | } | |
84 | ||
7dc7fa1d JS |
85 | is_mounted() { |
86 | local mounted_dir=${1} | |
87 | ||
88 | if [ ! -d ${mounted_dir} ]; then | |
89 | log ERROR "Is not a directory ${mounted_dir}" | |
90 | return ${FALSE} | |
91 | else | |
92 | mountpoint ${mounted_dir} | |
93 | fi | |
94 | } | |
95 | ||
358ea1df | 96 | cleanup_stage_2() { |
7dc7fa1d JS |
97 | #Check that nothing is mounted in working dir |
98 | local mounted_dir | |
99 | for mounted_dir in ${MOUNTED_DIRS} | |
100 | do | |
101 | ||
102 | if is_mounted "${IMAGE_MOUNT_DIR}${mounted_dir}"; then | |
103 | log ERROR "${IMAGE_MOUNT_DIR}${mounted_dir} is still mounted" | |
104 | return ${EXIT_ERROR} | |
105 | else | |
106 | log DEBUG "${IMAGE_MOUNT_DIR}${mounted_dir} is not mounted" | |
107 | ||
108 | fi | |
109 | done | |
110 | ||
358ea1df JS |
111 | # Drop working dir |
112 | if [ -d "${WORKING_DIR}" ]; then | |
113 | rm -dfR "${WORKING_DIR}" | |
114 | fi | |
115 | } | |
116 | ||
117 | cleanup() { | |
118 | cleanup_stage_1 | |
119 | cleanup_stage_2 | |
120 | } | |
121 | ||
122 | generate_image_filename() { | |
123 | local distro=${1} | |
124 | local version=${2} | |
125 | local arch=${3} | |
126 | ||
127 | echo "${distro}-${version}-${arch}" | |
128 | } | |
129 | ||
130 | check_for_pakfire() { | |
131 | local return_value=0 | |
132 | ||
133 | # TODO | |
134 | # Check that pakfire-server binary is available | |
135 | # Check that pakfire binary is available | |
136 | ||
137 | # Check that repo files are installed. (pakfire need to know which repos exist) | |
138 | local repo_dir="/etc/pakfire/repos" | |
139 | ||
140 | if [ ! -d "${repo_dir}" ]; then | |
141 | log ERROR "Could not find respository directory ${repo_dir}" | |
142 | return_value=1 | |
143 | fi | |
144 | ||
145 | return ${return_value} | |
146 | } | |
147 | ||
148 | compress_image() { | |
149 | local compression=${1} | |
150 | local image_file=${2} | |
151 | local level=${3} | |
152 | ||
153 | log debug "Compressing ${image_file} with ${compression}" | |
154 | ||
155 | case "${compression}" in | |
156 | "xz") | |
157 | # Check that the file does not exist yet | |
158 | if [ -f "${image_file}.xz" ]; then | |
159 | log ERROR "Failed to compress the image. The file already exists" | |
160 | return ${EXIT_ERROR} | |
161 | fi | |
162 | cmd xz "-${level}" "${image_file}" | |
163 | ;; | |
164 | "zip") | |
165 | # Check that the file does not exist yet | |
166 | if [ -f "${image_file}.zip" ]; then | |
167 | log ERROR "Failed to compress the image. The file already exists" | |
168 | return ${EXIT_ERROR} | |
169 | ||
170 | fi | |
171 | cmd zip "-${level}" "${image_file}.zip" "${image_file}" | |
172 | # Remove the file which we compressed+ | |
173 | rm -f "${image_file}" | |
174 | ;; | |
175 | ||
176 | esac | |
177 | } | |
178 | ||
179 | reset_root_password() { | |
180 | local root_dir=${1} | |
181 | # Backup passwd file | |
182 | cp -avf ${root_dir}/etc/passwd ${root_dir}/etc/passwd.orig | |
183 | ||
184 | # Drop root password. | |
185 | sed -e "s/^\(root:\)[^:]*:/\1:/" ${root_dir}/etc/passwd.orig > ${root_dir}/etc/passwd | |
186 | ||
187 | # Remove passwd backup file. | |
188 | rm -rvf ${root_dir}/etc/passwd.orig | |
189 | } | |
190 | ||
191 | clone_git_repos() { | |
192 | # Dir where the repos should be located | |
193 | local dir=${1} | |
194 | shift | |
195 | local repos="$@" | |
196 | ||
197 | local repo | |
198 | ||
199 | mkdir -pv ${dir} | |
200 | ||
201 | ( | |
202 | cd ${dir} | |
203 | # Clone git repositories. | |
204 | for repo in ${repos}; do | |
205 | git clone ${repo} | |
206 | done | |
207 | ) | |
208 | } | |
209 | ||
210 | # This function is used to publish the produced images | |
211 | ||
212 | publish() { | |
213 | local path=${1} | |
214 | # The image we created usually a img. file | |
215 | local image_base_file=${2} | |
216 | ||
217 | local image_name_final="$(generate_image_filename "${DISTRO}" "${VERSION}" "${ARCH}")" | |
218 | local image_type | |
219 | ||
220 | # Do these steps for every image format we like to publish | |
221 | for image_type in ${IMAGE_TYPES_PUBLISH}; do | |
222 | # Convert images to the type specified in IMAGE_TYPES_PUBLISH | |
223 | convert_image "${image_type}" "${image_base_file}" "${image_name_final}" | |
224 | ||
225 | # compress image. | |
226 | if [[ ${IMAGE_RELEASE} -eq ${TRUE} ]]; then | |
227 | local compression_type | |
228 | local compression_level | |
229 | ||
230 | ||
231 | # Get compressioon type | |
232 | compression_type="$(get_compression_type ${image_type})" | |
233 | ||
234 | compression_level=1 | |
235 | compress_image "${compression_type}" "${image_name_final}.${image_type}" ${compression_level} | |
236 | ||
237 | # Move images to this path | |
238 | mv -f "${image_name_final}.${image_type}.${compression_type}" ${path} | |
239 | ||
240 | # point the latest links to these images | |
241 | ln -s -f "${path}/${image_name_final}.${image_type}.${compression_type}" \ | |
242 | "${path}/$(generate_image_filename "${DISTRO}" "latest" "${ARCH}").${image_type}.${compression_type}" | |
243 | else | |
244 | ||
245 | # Move images to this path | |
246 | mv -f "${image_name_final}.${image_type}" ${path} | |
247 | fi | |
248 | done | |
249 | ||
250 | } | |
251 | ||
252 | convert_image() { | |
253 | local type=${1} | |
254 | local from=${2} | |
255 | local to=${3} | |
256 | ||
257 | if [[ ${type} = "img" ]]; then | |
258 | # We do not need to convert the image here but we need to rename | |
259 | mv -f ${from} ${to}.${type} | |
260 | return $? | |
261 | fi | |
262 | ||
263 | if [[ ${type} = "qcow2" ]]; then | |
264 | local command="qemu-img convert -c -O ${type} ${from} ${to}.${type}" | |
265 | else | |
266 | local command="qemu-img convert -O ${type} ${from} ${to}.${type}" | |
267 | fi | |
268 | ||
269 | cmd ${command} | |
270 | } | |
271 | ||
272 | get_compression_type() { | |
273 | local image_type=${1} | |
274 | ||
275 | case "${image_type}" in | |
276 | "qcow2" | "img") | |
277 | # These types can be used only under Unix so we use xz as compression | |
278 | echo "xz" | |
279 | ;; | |
280 | "vmdk" | "vdi") | |
281 | # These types can be also under Windows so we use zip as compression | |
282 | echo "zip" | |
283 | ;; | |
284 | esac | |
285 | ||
286 | } | |
287 | ||
288 | check_for_free_space() { | |
289 | local space=${1} | |
290 | local path=${2} | |
291 | local space_in_path=0 | |
292 | ||
293 | space_in_path=$(df -h -B MB --output=avail ${path} | tail -n 1) | |
294 | space_in_path=${space_in_path%MB} | |
295 | log debug ${space_in_path} | |
296 | log debug ${space} | |
297 | ||
298 | if [ ${space_in_path} -lt ${space} ]; then | |
299 | log error "Not enough free space available under ${path}" | |
300 | log error "Free space is ${space_in_path}MB but we need at least ${space}MB" | |
301 | return ${EXIT_ERROR} | |
302 | fi | |
303 | } | |
304 | ||
305 | parse_cmdline() { | |
306 | while [ $# -gt 0 ]; do | |
307 | case "${1}" in | |
308 | "--release") | |
309 | IMAGE_RELEASE=${TRUE} | |
310 | ;; | |
311 | ||
312 | *) | |
313 | error "Invalid argument: ${1}" | |
314 | return ${EXIT_CONF_ERROR} | |
315 | ;; | |
316 | esac | |
317 | shift | |
318 | done | |
319 | } | |
320 | ||
7eb693d2 JS |
321 | chroot_wrapper() { |
322 | local chroot_dir="${1}" | |
323 | ||
324 | shift | |
325 | ||
326 | local command | |
327 | ||
328 | if [ ! -d ${chroot_dir} ]; then | |
329 | log ERROR "Cannot chroot in a non directory ${chroot_dir}" | |
330 | fi | |
331 | ||
332 | mount proc "${chroot_dir}/proc" -t proc -o nosuid,noexec,nodev | |
333 | mount sys "${chroot_dir}/sys" -t sysfs -o nosuid,noexec,nodev,ro | |
334 | mount udev "${chroot_dir}/dev" -t devtmpfs -o mode=0755,nosuid | |
335 | mount devpts "${chroot_dir}/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec | |
336 | mount shm "${chroot_dir}/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev | |
337 | mount /run "${chroot_dir}/run" --bind | |
338 | mount tmp "${chroot_dir}/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid | |
339 | ||
340 | for command in "$@" | |
341 | do | |
342 | cmd chroot "${chroot_dir}" "${command}" | |
343 | done | |
344 | ||
345 | umount "${chroot_dir}/proc" | |
346 | umount "${chroot_dir}/sys" | |
347 | umount "${chroot_dir}/dev/pts" | |
348 | umount "${chroot_dir}/dev/shm" | |
349 | umount "${chroot_dir}/dev" | |
350 | umount "${chroot_dir}/run" | |
351 | umount "${chroot_dir}/tmp" | |
352 | } |