c94f4458012e318a0ae3ba98b548fa615e976ab4
[csit.git] / resources / tools / disk-image-builder / ubuntu / build.sh
1 #!/bin/bash -e
2
3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # Purpose of this script is to build a VirtualBox or QCOW2 disk image
17 # for use with CSIT testing.
18 #
19 # As input parameters, the script takes:
20 #
21 # - A base Linux distribution (currently, only "ubuntu-14.04.4" is
22 #   supported),
23 # - A release timestamp in the format "YYYY-MM-DD" eg. "2016-05-21".
24 #   This timestamp MUST reference to a list of packages (APT, PIP)
25 #   that was previously generated by the "listmaker" VM and script.
26 # - A path to the nested VM image.
27 #
28 # The bullk of the work is done by packer,
29 # while this script does some of the pre- and post-processing.
30 # Steps executed are:
31 #
32 # 1.) Determine if building a QCOW or VirtualBox image. Currently,
33 #     we build a QCOW image if VIRL_* environment variables are
34 #     present (and we therefore assume we are building for VIRL),
35 #     or VirtualBox otherwise.
36 #
37 # 2.) Download packer, if not already installed.
38 #
39 # 3.) Download APT and PIP packages as required for the image.
40 #     We're downloading them here, rather than letting the VM
41 #     download them off the public internet, for two reasons:
42 #     a.) This allows us to keep and cache packets between runs
43 #         and download them only once,
44 #     b.) This means only the build host needs a working proxy
45 #         configuration and we do not need to worry about setting
46 #         a proxy inside the VM.
47 #
48 # 4.) Link the nested VM image into the main VM's temp directory
49 #
50 # 5.) Create Version and Changelog files
51 #
52 # 6.) Run Packer. Packer, in turn, will:
53 #     6.1.) Download the Operating System ISO image,
54 #     6.2.) Start a VM using the selected hypervisor (VirtualBox or Qemu),
55 #     6.3.) Boot the VM using the ISO image and send initial keystrokes
56 #           to initiate installation using a Preseed or Kickstart file,
57 #     6.4.) Drive the installation using until the point the VM is reachable
58 #           over SSH,
59 #     6.5.) Copy the temporary directory populated in steps 3-5 above to the VM,
60 #     6.6.) Run a script on the VM that performs post-installation:
61 #           6.6.1.) Install selected .deb packages
62 #           6.6.2.) Install PIP packages as per requirements.txt file
63 #           6.6.3.) Install nested VM image and VERSION/CHANGELOG files
64 #     6.7.) Run a script on VM that creates a Vagrant user (VirtualBox only)
65 #     6.8.) Run a script on VM that performs clean-up:
66 #           6.8.1.) Remove any temporary files created,
67 #           6.8.2.) Remove SSH host-keys
68 #           6.8.3.) Remove root user password
69 #           6.8.4.) Shut down the VM
70 #     6.9.) [TODO]: Upload the image to VIRL (QCOW only), -or-
71 #           Convert the image into a Vagrant box (VirtualBox only), and
72 #           [TODO/FIX]: Upload the Vagrant box to Atlas (VirtualBox only)
73 #
74 # 7.) Clean up
75
76 ###
77 ### 0. Set constants and verify parameters.
78 ###
79 cd $(dirname $0)
80 BUILD_DIR="$(pwd)/build"
81 PACKER_DIR="${BUILD_DIR}/packer"
82
83 APT_CACHE_DIR="${BUILD_DIR}/cache/apt"
84 PIP_CACHE_DIR="${BUILD_DIR}/cache/pip"
85
86 PACKER_TEMPLATE="ubuntu-14.04.4.json"
87 LISTS_DIR="$(dirname $0)/lists"
88
89 function syntax {
90   echo 'Syntax: $0 <Operating System> <Release> <Nested VM image>'
91   echo
92   echo '<Operating System>: Base distro, eg. ubuntu-14.04.4'
93   echo '<Release>:          Release timestamp, eg. 2016-05-21'
94   echo '<Nested VM image>:  Path to nested VM image'
95
96   exit 1
97 }
98
99 ## Parse command line options
100
101 OS=$1
102 RELDATE=$2
103 NESTED_IMG=$3
104
105 if [ "$3" = "" ]
106 then
107   syntax
108 fi
109
110 ## Identify version by looking at topmost version statement in CHANGELOG
111
112 VERSION=$(cat $(dirname $0)/CHANGELOG  | grep '^## ' | head -1 | \
113   sed -e 's/.*\[\(.*\)\].*/\1/')
114 if [ "${VERSION}" = "" ]
115 then
116   echo "Unable to determine build version from CHANGELOG file. Make sure"
117   echo "that there is an entry for the most recent version in CHANGELOG,"
118   echo "and that the entry is formated like"
119   echo
120   echo "## [1.0] - 2016-05-20"
121   exit 1
122 fi
123 RELEASE="csit-${OS}_${RELDATE}_${VERSION}"
124
125 OUTPUT_DIR="${BUILD_DIR}/output/${RELEASE}"
126 LIST="${LISTS_DIR}/${OS}_${RELDATE}_${VERSION}"
127
128 if [ ! -d "${LIST}" ]
129 then
130   echo "${LIST} not found"
131   syntax
132   exit 1
133 fi
134 if [ ! -f $NESTED_IMG ]
135 then
136   echo "Nested image $NESTED_IMG not found"
137   syntax
138   exit 1
139 fi
140
141 ATLAS_RELDATE=${RELDATE//-}
142 ATLAS_VERSION="${ATLAS_RELDATE}.${VERSION}"
143
144 # Find an MD5 checksum utility
145
146 MD5UTIL=$(which md5sum) || MD5UTIL=$(which md5)
147 if [ $? -ne 0 ]
148 then
149   echo "No MD5 utility found."
150   echo "Please make sure you either have \"md5sum\" or \"md5\" installed."
151   exit 1
152 fi
153
154 ###
155 ### 1. Determine build target.
156 ###
157 if [ "$VIRL_USER" = "" ] || [ "$VIRL_PASSWORD" = "" ]
158 then
159   OUTPUT_PROVIDER="virtualbox"
160 else
161   OUTPUT_PROVIDER="qemu"
162 fi
163
164 echo "Building version $VERSION for ${OUTPUT_PROVIDER}"
165 echo "Release ${RELEASE}"
166 echo "Using Nested VM image: ${NESTED_IMG}"
167 echo
168
169
170 ###
171 ### 2. Download and extract packer, if not already installed
172 ###
173 packer_os=$(uname -s)
174 if [ "$packer_os" = "Darwin" ]
175 then
176   packer_url="https://releases.hashicorp.com/packer/0.10.1/packer_0.10.1_darwin_amd64.zip"
177 elif [ "$packer_os" = "Linux" ]
178 then
179   packer_url="https://releases.hashicorp.com/packer/0.10.1/packer_0.10.1_linux_amd64.zip"
180 fi
181
182 mkdir -p $BUILD_DIR
183 wget -P ${PACKER_DIR} -N ${packer_url}
184
185 unzip -n ${PACKER_DIR}/packer*zip -d ${PACKER_DIR}
186
187 ###
188 ### 3. Download APT and PIP packages, and cache them
189 ###    Verify checksum of downloaded APT packages.
190 ###    Link required packages into a temp directory for the VM image.
191 ###
192
193 ## APT
194
195 rm -fr ${OUTPUT_DIR}
196 mkdir -p ${OUTPUT_DIR}/temp/deb
197 mkdir -p ${APT_CACHE_DIR}
198
199 APT_FILE="${LIST}/apt-packages.txt"
200 while read url name size checksum
201 do
202   # Download if not already present
203   if [ ! -f ${APT_CACHE_DIR}/$name ]
204   then
205     wget -P ${APT_CACHE_DIR} -O ${APT_CACHE_DIR}/$name ${url//\'}
206   fi
207
208   # Verify checksum (always -- regardless of whether the package was
209   # just downloaded, or already tehere
210   actual_md5sum=$(${MD5UTIL} < ${APT_CACHE_DIR}/$name)
211   if [ ! "${actual_md5sum:0:32}" = "${checksum:7}" ]
212   then
213     echo File $name checksum failure."
214     echo "Got ${actual_md5sum:0:31} expected ${checksum:7}.
215     rm -f ${APT_CACHE_DIR}/$name
216     exit 1
217   fi
218
219   # Link package into VM temp directory
220   ln ${APT_CACHE_DIR}/$name ${OUTPUT_DIR}/temp/deb/${name}
221 done < $APT_FILE
222
223 ## PIP
224
225 mkdir -p ${PIP_CACHE_DIR}
226
227 # Let PIP do the work of downloading and verifying packages
228 pip install --download ${PIP_CACHE_DIR} -r ${LIST}/pip-requirements.txt
229
230 # Link packages and requirements file into VM's temp directory
231 mkdir -p ${OUTPUT_DIR}/temp/pip
232 ln ${PIP_CACHE_DIR}/* ${OUTPUT_DIR}/temp/pip/
233 ln ${LIST}/pip-requirements.txt ${OUTPUT_DIR}/temp/requirements.txt
234
235 ###
236 ### 4. Link the nested VM image
237 ###
238 rm -fr ${OUTPUT_DIR}/temp/nested-vm
239 mkdir ${OUTPUT_DIR}/temp/nested-vm
240 ln $NESTED_IMG ${OUTPUT_DIR}/temp/nested-vm/
241
242 ###
243 ### 5. Create Version and Changelog files
244 ###
245
246 echo ${RELEASE} > ${OUTPUT_DIR}/temp/VERSION
247 ln CHANGELOG ${OUTPUT_DIR}/temp/CHANGELOG
248
249 ###
250 ### 6. Run packer
251 ###
252 export PACKER_LOG=1
253 export PACKER_LOG_PATH=${OUTPUT_DIR}/packer.log
254 ${PACKER_DIR}/packer build -var "release=${RELEASE}" \
255  -only ${RELEASE}-${OUTPUT_PROVIDER} \
256  -var "output_dir=${OUTPUT_DIR}/packer" \
257  -var "temp_dir=${OUTPUT_DIR}/temp" \
258  -var "atlas_version=${ATLAS_VERSION}" \
259  -force \
260  -machine-readable ${PACKER_TEMPLATE}
261
262 # TODO: Need to figure out "packer push" later. Currently keeps failing.
263 # ${PACKER_DIR}/packer push -name ckoester/test123 -var "release=${RELEASE}" \
264 #   -var "output_dir=${OUTPUT_DIR}/packer" \
265 #   -var "temp_dir=${OUTPUT_DIR}/temp" \
266 #   ${PACKER_TEMPLATE}
267
268 ###
269 ### 7. Clean up
270 ###
271 rm -fr ${OUTPUT_DIR}/temp
272
273 echo "Done."
274 echo "Artifacts:"
275 echo
276 ls -lR ${OUTPUT_DIR}