blob: d6c82dbb3d13bc10df8c62d437fa5b2a49afd490 [file] [log] [blame]
Jakub Josef79ecec32017-02-17 14:36:28 +01001package com.mirantis.mk
2
3/**
4 *
5 * Debian functions
6 *
7 */
8
9def cleanup(image="debian:sid") {
10 def common = new com.mirantis.mk.Common()
11 def img = docker.image(image)
12
13 workspace = common.getWorkspace()
14 sh("docker run -e DEBIAN_FRONTEND=noninteractive -v ${workspace}:${workspace} -w ${workspace} --rm=true --privileged ${image} /bin/bash -c 'rm -rf build-area || true'")
15}
16
17/*
18 * Build binary Debian package from existing dsc
19 *
20 * @param file dsc file to build
21 * @param image Image name to use for build (default debian:sid)
22 */
23def buildBinary(file, image="debian:sid", extraRepoUrl=null, extraRepoKeyUrl=null) {
24 def common = new com.mirantis.mk.Common()
Filip Pytloun81c864d2017-03-21 15:19:30 +010025 def jenkinsUID = common.getJenkinsUid()
26 def jenkinsGID = common.getJenkinsGid()
Jakub Josef79ecec32017-02-17 14:36:28 +010027 def pkg = file.split('/')[-1].split('_')[0]
chnyda1cf6f0d2017-06-02 11:01:04 +020028 def dockerLib = new com.mirantis.mk.Docker()
29 def imageArray = image.split(":")
30 def os = imageArray[0]
31 def dist = imageArray[1]
Jakub Josefd4887ab2018-05-10 16:13:33 +020032 def img = dockerLib.getImage("mirantis/debian-build-${os}-${dist}:latest", image)
chnyda1cf6f0d2017-06-02 11:01:04 +020033 def workspace = common.getWorkspace()
Jakub Josef13214312018-02-06 16:34:14 +010034 def debug = env.getEnvironment().containsKey("DEBUG") && env["DEBUG"].toBoolean() ? "true" : ""
Jakub Josef79ecec32017-02-17 14:36:28 +010035
chnyda8ad962e2017-06-02 12:24:15 +020036 img.inside("-u root:root" ) {
Petr Ruzickac9eaa7e2018-02-07 08:51:38 +010037 sh("""bash -x -c 'cd ${workspace} && (which eatmydata || (apt-get update && apt-get install -y eatmydata)) &&
Jakub Josef13214312018-02-06 16:34:14 +010038 export DEBUG="${debug}" &&
Jakub Josef79ecec32017-02-17 14:36:28 +010039 export LD_LIBRARY_PATH=\${LD_LIBRARY_PATH:+"\$LD_LIBRARY_PATH:"}/usr/lib/libeatmydata &&
40 export LD_PRELOAD=\${LD_PRELOAD:+"\$LD_PRELOAD "}libeatmydata.so &&
Kirill Mashchenkob4d2fba2018-04-20 16:23:04 +030041 export DEB_BUILD_OPTIONS=nocheck &&
Oleh Hryhorovd28a9742018-03-06 17:41:38 +020042 [[ -z "${extraRepoUrl}" && "${extraRepoUrl}" != "null" ]] || echo "${extraRepoUrl}" | tr ";" "\\\\n" >/etc/apt/sources.list.d/extra.list &&
Jakub Josef79ecec32017-02-17 14:36:28 +010043 [[ -z "${extraRepoKeyUrl}" && "${extraRepoKeyUrl}" != "null" ]] || (
44 which curl || (apt-get update && apt-get install -y curl) &&
Oleh Hryhorovd28a9742018-03-06 17:41:38 +020045 EXTRAKEY=`echo "${extraRepoKeyUrl}" | tr ";" " "` &&
46 for RepoKey in \${EXTRAKEY}; do curl --insecure -ss -f "\${RepoKey}" | apt-key add - ; done
Jakub Josef79ecec32017-02-17 14:36:28 +010047 ) &&
Filip Pytloun81c864d2017-03-21 15:19:30 +010048 apt-get update && apt-get install -y build-essential devscripts equivs sudo &&
49 groupadd -g ${jenkinsGID} jenkins &&
50 useradd -s /bin/bash --uid ${jenkinsUID} --gid ${jenkinsGID} -m jenkins &&
Filip Pytloun78b91832017-06-30 13:16:31 +020051 chown -R ${jenkinsUID}:${jenkinsGID} /home/jenkins &&
Jakub Josef6bebf162017-05-10 14:21:00 +020052 [ ! -f pre_build_script.sh ] || bash ./pre_build_script.sh &&
Filip Pytlounff82fc02017-03-27 12:17:05 +020053 sudo -H -E -u jenkins dpkg-source -x ${file} build-area/${pkg} && cd build-area/${pkg} &&
Filip Pytloun2f7302a2017-06-30 14:59:30 +020054 mk-build-deps -t "apt-get -o Debug::pkgProblemResolver=yes -y" -i debian/control &&
Petr Ruzicka638e0bf2018-02-07 13:31:25 +010055 sudo -H -E -u jenkins debuild --preserve-envvar DEBUG --no-lintian -uc -us -b'""")
chnyda1cf6f0d2017-06-02 11:01:04 +020056 }
57
Jakub Josef79ecec32017-02-17 14:36:28 +010058}
59
60/*
61 * Build source package from directory
62 *
63 * @param dir Tree to build
64 * @param image Image name to use for build (default debian:sid)
65 * @param snapshot Generate snapshot version (default false)
66 */
Oleg Iurchenko68e17b02018-01-02 12:24:49 +020067def buildSource(dir, image="debian:sid", snapshot=false, gitEmail='jenkins@dummy.org', gitName='Jenkins', revisionPostfix="", remote="origin/") {
Jakub Josef79ecec32017-02-17 14:36:28 +010068 def isGit
69 try {
70 sh("test -d ${dir}/.git")
71 isGit = true
72 } catch (Exception e) {
73 isGit = false
74 }
75
76 if (isGit == true) {
Oleg Iurchenko68e17b02018-01-02 12:24:49 +020077 buildSourceGbp(dir, image, snapshot, gitEmail, gitName, revisionPostfix, remote)
Jakub Josef79ecec32017-02-17 14:36:28 +010078 } else {
79 buildSourceUscan(dir, image)
80 }
81}
82
83/*
84 * Build source package, fetching upstream code using uscan
85 *
86 * @param dir Tree to build
87 * @param image Image name to use for build (default debian:sid)
88 */
89def buildSourceUscan(dir, image="debian:sid") {
90 def common = new com.mirantis.mk.Common()
chnyda1cf6f0d2017-06-02 11:01:04 +020091 def dockerLib = new com.mirantis.mk.Docker()
92 def imageArray = image.split(":")
93 def os = imageArray[0]
94 def dist = imageArray[1]
Jakub Josefd4887ab2018-05-10 16:13:33 +020095 def img = dockerLib.getImage("mirantis/debian-build-${os}-${dist}:latest", image)
chnyda1cf6f0d2017-06-02 11:01:04 +020096 def workspace = common.getWorkspace()
97
chnyda8ad962e2017-06-02 12:24:15 +020098 img.inside("-u root:root" ) {
chnyda12f3b3f2017-06-02 12:19:38 +020099 sh("""cd ${workspace} && apt-get update && apt-get install -y build-essential devscripts &&
chnyda1cf6f0d2017-06-02 11:01:04 +0200100 cd ${dir} && uscan --download-current-version &&
101 dpkg-buildpackage -S -nc -uc -us""")
102 }
Jakub Josef79ecec32017-02-17 14:36:28 +0100103}
104
105/*
106 * Build source package using git-buildpackage
107 *
108 * @param dir Tree to build
109 * @param image Image name to use for build (default debian:sid)
110 * @param snapshot Generate snapshot version (default false)
111 */
Oleg Iurchenko68e17b02018-01-02 12:24:49 +0200112def buildSourceGbp(dir, image="debian:sid", snapshot=false, gitName='Jenkins', gitEmail='jenkins@dummy.org', revisionPostfix="", remote="origin/") {
Jakub Josef79ecec32017-02-17 14:36:28 +0100113 def common = new com.mirantis.mk.Common()
Filip Pytloun81c864d2017-03-21 15:19:30 +0100114 def jenkinsUID = common.getJenkinsUid()
115 def jenkinsGID = common.getJenkinsGid()
Jakub Josef79ecec32017-02-17 14:36:28 +0100116
117 if (! revisionPostfix) {
118 revisionPostfix = ""
119 }
120
chnyda1cf6f0d2017-06-02 11:01:04 +0200121 def workspace = common.getWorkspace()
122 def dockerLib = new com.mirantis.mk.Docker()
123 def imageArray = image.split(":")
124 def os = imageArray[0]
125 def dist = imageArray[1]
Jakub Josefd4887ab2018-05-10 16:13:33 +0200126 def img = dockerLib.getImage("mirantis/debian-build-${os}-${dist}:latest", image)
chnyda1cf6f0d2017-06-02 11:01:04 +0200127
chnyda8ad962e2017-06-02 12:24:15 +0200128 img.inside("-u root:root") {
chnyda1cf6f0d2017-06-02 11:01:04 +0200129
130 withEnv(["DEBIAN_FRONTEND=noninteractive", "DEBFULLNAME='${gitName}'", "DEBEMAIL='${gitEmail}'"]) {
Petr Ruzickac9eaa7e2018-02-07 08:51:38 +0100131 sh("""bash -x -c 'cd ${workspace} && (which eatmydata || (apt-get update && apt-get install -y eatmydata)) &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100132 export LD_LIBRARY_PATH=\${LD_LIBRARY_PATH:+"\$LD_LIBRARY_PATH:"}/usr/lib/libeatmydata &&
133 export LD_PRELOAD=\${LD_PRELOAD:+"\$LD_PRELOAD "}libeatmydata.so &&
Jakub Josef5de05f62017-05-30 15:25:55 +0200134 apt-get update && apt-get install -y build-essential git-buildpackage dpkg-dev sudo &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100135 groupadd -g ${jenkinsGID} jenkins &&
136 useradd -s /bin/bash --uid ${jenkinsUID} --gid ${jenkinsGID} -m jenkins &&
Filip Pytloun78b91832017-06-30 13:16:31 +0200137 chown -R ${jenkinsUID}:${jenkinsGID} /home/jenkins &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100138 cd ${dir} &&
Filip Pytlounff82fc02017-03-27 12:17:05 +0200139 sudo -H -E -u jenkins git config --global user.name "${gitName}" &&
140 sudo -H -E -u jenkins git config --global user.email "${gitEmail}" &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100141 [[ "${snapshot}" == "false" ]] || (
Alexander Noskov2b6b4be2017-09-13 17:32:44 +0400142 VERSION=`dpkg-parsechangelog --count 1 --show-field Version` &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100143 UPSTREAM_VERSION=`echo \$VERSION | cut -d "-" -f 1` &&
144 REVISION=`echo \$VERSION | cut -d "-" -f 2` &&
145 TIMESTAMP=`date +%Y%m%d%H%M` &&
146 if [[ "`cat debian/source/format`" = *quilt* ]]; then
147 UPSTREAM_BRANCH=`(grep upstream-branch debian/gbp.conf || echo master) | cut -d = -f 2 | tr -d " "` &&
Oleg Iurchenko68e17b02018-01-02 12:24:49 +0200148 UPSTREAM_REV=`git rev-parse --short ${remote}\$UPSTREAM_BRANCH` &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100149 NEW_UPSTREAM_VERSION="\$UPSTREAM_VERSION+\$TIMESTAMP.\$UPSTREAM_REV" &&
Alexander Noskov2b6b4be2017-09-13 17:32:44 +0400150 NEW_UPSTREAM_VERSION_TAG=`echo \$NEW_UPSTREAM_VERSION | sed 's/.*://'` &&
Jakub Josef79ecec32017-02-17 14:36:28 +0100151 NEW_VERSION=\$NEW_UPSTREAM_VERSION-\$REVISION$revisionPostfix &&
Alexander Noskov2b6b4be2017-09-13 17:32:44 +0400152 echo "Generating new upstream version \$NEW_UPSTREAM_VERSION_TAG" &&
Oleg Iurchenko68e17b02018-01-02 12:24:49 +0200153 sudo -H -E -u jenkins git tag \$NEW_UPSTREAM_VERSION_TAG ${remote}\$UPSTREAM_BRANCH &&
Alexander Noskov2b6b4be2017-09-13 17:32:44 +0400154 sudo -H -E -u jenkins git merge -X theirs \$NEW_UPSTREAM_VERSION_TAG
Jakub Josef79ecec32017-02-17 14:36:28 +0100155 else
156 NEW_VERSION=\$VERSION+\$TIMESTAMP.`git rev-parse --short HEAD`$revisionPostfix
157 fi &&
Dmitry Burmistrov65098ac2018-05-04 14:33:01 +0400158 sudo -H -E -u jenkins gbp dch \
159 --auto \
160 --git-author \
161 --id-length=7 \
162 --git-log='--reverse' \
163 --ignore-branch \
164 --new-version=\$NEW_VERSION \
165 --distribution `lsb_release -c -s` \
166 --force-distribution &&
Filip Pytlounff82fc02017-03-27 12:17:05 +0200167 sudo -H -E -u jenkins git add -u debian/changelog &&
168 sudo -H -E -u jenkins git commit -m "New snapshot version \$NEW_VERSION"
Jakub Josef79ecec32017-02-17 14:36:28 +0100169 ) &&
chnydaa3603b42017-06-02 12:36:08 +0200170 sudo -H -E -u jenkins gbp buildpackage -nc --git-force-create --git-notify=false --git-ignore-branch --git-ignore-new --git-verbose --git-export-dir=../build-area -sa -S -uc -us '""")
chnyda1cf6f0d2017-06-02 11:01:04 +0200171 }
172 }
Jakub Josef79ecec32017-02-17 14:36:28 +0100173}
174
175/*
176 * Run lintian checks
177 *
178 * @param changes Changes file to test against
179 * @param profile Lintian profile to use (default debian)
180 * @param image Image name to use for build (default debian:sid)
181 */
182def runLintian(changes, profile="debian", image="debian:sid") {
183 def common = new com.mirantis.mk.Common()
chnyda1cf6f0d2017-06-02 11:01:04 +0200184 def workspace = common.getWorkspace()
185 def dockerLib = new com.mirantis.mk.Docker()
186 def imageArray = image.split(":")
187 def os = imageArray[0]
188 def dist = imageArray[1]
Jakub Josefd4887ab2018-05-10 16:13:33 +0200189 def img = dockerLib.getImage("mirantis/debian-build-${os}-${dist}:latest", image)
chnyda8ad962e2017-06-02 12:24:15 +0200190 img.inside("-u root:root") {
chnyda12f3b3f2017-06-02 12:19:38 +0200191 sh("""cd ${workspace} && apt-get update && apt-get install -y lintian &&
chnyda1cf6f0d2017-06-02 11:01:04 +0200192 lintian -Ii -E --pedantic --profile=${profile} ${changes}""")
193 }
Jakub Josef79ecec32017-02-17 14:36:28 +0100194}
chnyda4e5ac792017-03-14 15:24:18 +0100195
196/*
197 * Import gpg key
198 *
199 * @param privateKeyCredId Public key jenkins credential id
200 */
201def importGpgKey(privateKeyCredId)
202{
203 def common = new com.mirantis.mk.Common()
204 def workspace = common.getWorkspace()
205 def privKey = common.getCredentials(privateKeyCredId, "key")
206 def private_key = privKey.privateKeySource.privateKey
chnydac6846452017-03-21 16:50:43 +0100207 def gpg_key_id = common.getCredentials(privateKeyCredId, "key").username
208 def retval = sh(script: "export GNUPGHOME=${workspace}/.gnupg; gpg --list-secret-keys | grep ${gpg_key_id}", returnStatus: true)
209 if (retval) {
210 writeFile file:"${workspace}/private.key", text: private_key
211 sh(script: "gpg --no-tty --allow-secret-key-import --homedir ${workspace}/.gnupg --import ./private.key")
212 }
chnyda4e5ac792017-03-14 15:24:18 +0100213}
214
215/*
216 * upload source package to launchpad
217 *
218 * @param ppaRepo ppa repository on launchpad
219 * @param dirPath repository containing the source packages
220 */
221
222def uploadPpa(ppaRepo, dirPath, privateKeyCredId) {
223
224 def common = new com.mirantis.mk.Common()
225 def workspace = common.getWorkspace()
226 def gpg_key_id = common.getCredentials(privateKeyCredId, "key").username
227
228 dir(dirPath)
229 {
230 def images = findFiles(glob: "*.orig*.tar.gz")
231 for (int i = 0; i < images.size(); ++i) {
232 def name = images[i].getName()
233 def orig_sha1 = common.cutOrDie("sha1sum ${name}", 0)
234 def orig_sha256 = common.cutOrDie("sha256sum ${name}", 0)
235 def orig_md5 = common.cutOrDie("md5sum ${name}", 0)
236 def orig_size = common.cutOrDie("ls -l ${name}", 4)
237
chnyda5d1e97f2017-03-17 15:53:47 +0100238 def retval = sh(script: "wget --quiet -O orig-tmp https://launchpad.net/ubuntu/+archive/primary/+files/${name}", returnStatus: true)
chnyda4e5ac792017-03-14 15:24:18 +0100239 if (retval == 0) {
240 sh("mv orig-tmp ${name}")
241 def new_sha1 = common.cutOrDie("sha1sum ${name}", 0)
242 def new_sha256 = common.cutOrDie("sha256sum ${name}", 0)
243 def new_md5 = common.cutOrDie("md5sum ${name}", 0)
244 def new_size = common.cutOrDie("ls -l ${name}", 4)
245
246 sh("sed -i -e s,$orig_sha1,$new_sha1,g -e s,$orig_sha256,$new_sha256,g -e s,$orig_size,$new_size,g -e s,$orig_md5,$new_md5,g *.dsc")
chnyda3c93ff62017-03-23 10:11:36 +0100247 sh("sed -i -e s,$orig_sha1,$new_sha1,g -e s,$orig_sha256,$new_sha256,g -e s,$orig_size,$new_size,g -e s,$orig_md5,$new_md5,g *_source.changes")
chnyda4e5ac792017-03-14 15:24:18 +0100248 }
chnyda4e5ac792017-03-14 15:24:18 +0100249 }
chnyda34e5c942017-03-22 18:06:06 +0100250 sh("export GNUPGHOME=${workspace}/.gnupg; debsign --re-sign -k ${gpg_key_id} *_source.changes")
251 sh("export GNUPGHOME=${workspace}/.gnupg; dput -f \"ppa:${ppaRepo}\" *_source.changes")
chnyda4e5ac792017-03-14 15:24:18 +0100252 }
Filip Pytlounfbbd1682017-03-17 22:48:04 +0100253}
Vasyl Saienkobe38d9b2018-09-03 12:17:09 +0300254
255/**
256* Upgrade packages on given target.
257*
258* @param env Salt Connection object or env Salt command map
259* @param target Salt target to upgrade packages on.
260*/
261def osUpgrade(env, target){
262 def common = new com.mirantis.mk.Common()
263 def salt = new com.mirantis.mk.Salt()
264
265 common.infoMsg("Running upgrade on ${target}")
266
267 salt.runSaltProcessStep(env, target, 'pkg.refresh_db', [], null, true)
268 def cmd = 'export DEBIAN_FRONTEND=noninteractive; apt-get -y -q --allow-downgrades -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" upgrade;'
269 salt.runSaltProcessStep(env, target, 'cmd.run', [cmd])
270}
271
272/**
273* Running dist-upgrade on given target.
274*
275* @param env Salt Connection object or env Salt command map
276* @param target Salt target to upgrade packages on.
277*/
278def osDistUpgrade(env, target){
279 def salt = new com.mirantis.mk.Salt()
280 def common = new com.mirantis.mk.Common()
281
282 common.infoMsg("Running dist-upgrade on ${target}")
283 salt.runSaltProcessStep(env, target, 'pkg.refresh_db', [], null, true)
284 def cmd = 'export DEBIAN_FRONTEND=noninteractive; apt-get -y -q --allow-downgrades -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" dist-upgrade;'
285 salt.runSaltProcessStep(env, target, 'cmd.run', [cmd])
286}
287
288/**
289* Reboot specified target, and wait when minion is UP.
290*
291* @param env Salt Connection object or env Salt command map
292* @param target Salt target to upgrade packages on.
293* @param timeout Sleep timeout when doing retries.
294* @param attempts Number of attemps to wait for.
295*/
296def osReboot(env, target, timeout=30, attempts=10){
297 def salt = new com.mirantis.mk.Salt()
298 def common = new com.mirantis.mk.Common()
299
300 salt.runSaltProcessStep(env, target, 'cmd.run', ["touch /tmp/rebooting"])
301 salt.runSaltProcessStep(env, target, 'system.reboot', [], null, true, 5)
302
303 common.retry(timeout, attempts){
304 if (salt.runSaltProcessStep(env, target, 'file.file_exists', ['/tmp/rebooting'], null, true, 5)['return'][0].values()[0].toBoolean()){
305 error("The system is still rebooting...")
306 }
307 }
308}
309
310/**
311* Upgrade OS on given node, wait when minion become reachable.
312*
313* @param env Salt Connection object or env Salt command map
314* @param target Salt target to upgrade packages on.
315* @param mode 'upgrade' or 'dist-upgrade'
316* @param postponeReboot Boolean flag to specify if reboot have to be postponed.
317* @param timeout Sleep timeout when doing retries.
318* @param attempts Number of attemps to wait for.
319*/
320def osUpgradeNode(env, target, mode, postponeReboot=false, timeout=30, attempts=10){
321 def common = new com.mirantis.mk.Common()
322 def salt = new com.mirantis.mk.Salt()
323
324 def rebootRequired = false
325 if (mode == 'dist-upgrade'){
326 osDistUpgrade(env, target)
327 } else if (mode == 'upgrade'){
328 osUpgrade(env, target)
329 }
330 rebootRequired = salt.runSaltProcessStep(env, target, 'file.file_exists', ['/var/run/reboot-required'], null, true, 5)['return'][0].values()[0].toBoolean()
331 if (rebootRequired) {
332 if (!postponeReboot){
333 common.infoMsg("Reboot is required after upgrade on ${target} Rebooting...")
334 osReboot(env, target, timeout, attempts)
335 } else {
336 common.infoMsg("Postponing reboot on node ${target}")
337 }
338 }
339}