blob: dbd95f265d3f47946e3d035c0d26bff64ee05c17 [file] [log] [blame]
Jakub Josef79ecec32017-02-17 14:36:28 +01001package com.mirantis.mk
2
3/**
4 *
5 * Aptly functions
6 *
7 */
8
9/**
10 * Upload package into local repo
11 *
12 * @param file File path
13 * @param server Server host
14 * @param repo Repository name
15 */
16def uploadPackage(file, server, repo, skipExists=false) {
17 def pkg = file.split('/')[-1].split('_')[0]
18 def jobName = currentBuild.build().environment.JOB_NAME
19
20 sh("curl -v -f -F file=@${file} ${server}/api/files/${pkg}")
21 sh("curl -v -o curl_out_${pkg}.log -f -X POST ${server}/api/repos/${repo}/file/${pkg}")
22
23 try {
24 sh("cat curl_out_${pkg}.log | json_pp | grep 'Unable to add package to repo' && exit 1 || exit 0")
25 } catch (err) {
26 sh("curl -s -f -X DELETE ${server}/api/files/${pkg}")
27 if (skipExists == true) {
28 println "[WARN] Package ${pkg} already exists in repo so skipping it's upload as requested"
29 } else {
30 error("Package ${pkg} already exists in repo, did you forget to add changelog entry and raise version?")
31 }
32 }
33}
34
35/**
36 * Build step to upload package. For use with eg. parallel
37 *
38 * @param file File path
39 * @param server Server host
40 * @param repo Repository name
41 */
42def uploadPackageStep(file, server, repo, skipExists=false) {
43 return {
44 uploadPackage(
45 file,
46 server,
47 repo,
48 skipExists
49 )
50 }
51}
52
53def snapshotRepo(server, repo, timestamp = null) {
54 // XXX: timestamp parameter is obsoleted, time of snapshot creation is
55 // what we should always use, not what calling pipeline provides
56 def now = new Date();
57 def ts = now.format("yyyyMMddHHmmss", TimeZone.getTimeZone('UTC'));
58
59 def snapshot = "${repo}-${ts}"
60 sh("curl -f -X POST -H 'Content-Type: application/json' --data '{\"Name\":\"$snapshot\"}' ${server}/api/repos/${repo}/snapshots")
61}
62
Richard Felkl80c1d372018-03-26 13:03:10 +020063/**
64 * Cleanup snapshots
65 *
66 * @param server Server host
67 * @param opts Options: debug, timeout, ...
68 */
69def cleanupSnapshots(server, opts='-d'){
70 sh("aptly-publisher --url ${server} ${opts} cleanup")
Jakub Josef79ecec32017-02-17 14:36:28 +010071}
72
73def diffPublish(server, source, target, components=null, opts='--timeout 600') {
74 if (components) {
75 def componentsStr = components.join(' ')
76 opts = "${opts} --components ${componentsStr}"
77 }
78 sh("aptly-publisher --dry --url ${server} promote --source ${source} --target ${target} --diff ${opts}")
79}
80
chnyda751ac402017-11-28 17:32:43 +010081def promotePublish(server, source, target, recreate=false, components=null, packages=null, diff=false, opts='-d --timeout 600', dump_publish=false, storage="") {
chnydabe46ffa2017-03-21 13:19:08 +010082 if (components && components != "all" && components != "") {
83 def componentsStr = components.replaceAll(",", " ")
Jakub Josef79ecec32017-02-17 14:36:28 +010084 opts = "${opts} --components ${componentsStr}"
85 }
chnydabe46ffa2017-03-21 13:19:08 +010086 if (packages && packages != "all" && packages != "") {
87 def packagesStr = packages.replaceAll(",", " ")
Jakub Josef79ecec32017-02-17 14:36:28 +010088 opts = "${opts} --packages ${packagesStr}"
89 }
90 if (recreate.toBoolean() == true) {
91 opts = "${opts} --recreate"
92 }
93 if (diff.toBoolean() == true) {
chnyda5de5d432017-04-10 15:35:47 +020094 opts = "${opts} --dry --diff"
Jakub Josef79ecec32017-02-17 14:36:28 +010095 }
chnydabe46ffa2017-03-21 13:19:08 +010096
chnyda751ac402017-11-28 17:32:43 +010097 if (storage && storage != "") {
98 opts = "${opts} --storage ${storage}"
99 }
100
chnyda4906ce02017-08-22 14:45:13 +0200101 if (dump_publish) {
102 def now = new Date();
chnydaf2f95792017-12-11 17:09:27 +0100103 dumpTarget = target
chnyda4906ce02017-08-22 14:45:13 +0200104 def timestamp = now.format("yyyyMMddHHmmss", TimeZone.getTimeZone('UTC'));
chnydaf2f95792017-12-11 17:09:27 +0100105
chnyda7bdfeab2017-12-18 17:10:14 +0100106 if (source.contains(')') || source.contains('*')) {
chnydaf2f95792017-12-11 17:09:27 +0100107 sourceTarget = source.split('/')
108 dumpTarget = target.split('/')[-1]
109 sourceTarget[-1] = dumpTarget
110 dumpTarget = sourceTarget.join('/')
111 }
112
113 dumpPublishes(server, timestamp, dumpTarget)
chnyda4906ce02017-08-22 14:45:13 +0200114 }
chnydac78dfa52017-08-22 14:39:43 +0200115
Jakub Josefa3a4db92018-04-12 11:50:20 +0000116 sh("aptly-publisher --url ${server} promote --acquire-by-hash --source '${source}' --target '${target}' --force-overwrite ${opts}")
chnydac78dfa52017-08-22 14:39:43 +0200117
Jakub Josef79ecec32017-02-17 14:36:28 +0100118}
119
Filip Pytloun15fbbc92017-11-27 14:33:22 +0100120def publish(server, config='/etc/aptly-publisher.yaml', recreate=false, only_latest=true, force_overwrite=true, opts='-d --timeout 3600') {
Jakub Josef79ecec32017-02-17 14:36:28 +0100121 if (recreate == true) {
122 opts = "${opts} --recreate"
123 }
Filip Pytloun62fe3a42017-11-27 14:30:19 +0100124 if (only_latest == true) {
125 opts = "${opts} --only-latest"
126 }
127 if (force_overwrite == true) {
128 opts = "${opts} --force-overwrite"
129 }
chnydadc7292f2018-01-17 14:30:22 +0100130 sh("aptly-publisher --url ${server} -c ${config} ${opts} --acquire-by-hash publish")
chnydad8f51af2017-07-24 10:39:48 +0200131}
132
133/**
134 * Dump publishes
135 *
136 * @param server Server host
137 * @param save-dir Directory where publishes are to be serialized
138 * @param publishes Publishes to be serialized
139 * @param prefix Prefix of dump files
140 * @param opts Options: debug, timeout, ...
141 */
chnyda5fe91ca2017-09-19 09:19:46 +0200142def dumpPublishes(server, prefix, publishes='all', opts='-d --timeout 600') {
chnydaf2f95792017-12-11 17:09:27 +0100143 sh("aptly-publisher dump --url ${server} --save-dir . --prefix ${prefix} -p '${publishes}' ${opts}")
Jakub Josef30cf6502018-04-04 12:48:03 +0200144 if (findFiles(glob: "${prefix}*")) {
145 archiveArtifacts artifacts: "${prefix}*"
146 } else {
147 throw new Exception("Aptly dump publishes for a prefix ${prefix}* failed. No dump files found!")
148 }
chnydad8f51af2017-07-24 10:39:48 +0200149}
150
151/**
152 * Restore publish from YAML file
153 *
154 * @param server Server host
155 * @param recreate Recreate publishes
156 * @param publish Serialized YAML of Publish
157 * @param components Components to restore
158 */
159def restorePublish(server, recreate, publish, components='all') {
160
161 opts = ""
162 if (recreate) {
163 opts << " --recreate"
164 }
165
166 sh("rm tmpFile || true")
167 writeFile(file: "tmpFile", text: publish)
168 sh("aptly-publisher restore --url ${server} --restore-file tmpFile --components ${components} ${opts}")
169}
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200170
171/**
172 * The function return name of the snapshot belongs to repo considering the prefix with storage by REST API.
173 *
174 * @param server URI the server to connect to aptly API
175 * @param destribution Destiribution of the repo which have to be found
176 * @param prefix Prefix of the repo including storage eg. prefix or s3:aptcdn:prefix
177 * @param component Component of the repo
178 *
179 * @return snapshot name
180 **/
181def getSnapshotByAPI(server, distribution, prefix, component) {
182 http = new com.mirantis.mk.Http()
183 def list_published = http.restGet(server, '/api/publish')
184 def storage
185 for (items in list_published) {
186 for (row in items) {
187 if (prefix.tokenize(':')[1]) {
188 storage = prefix.tokenize(':')[0] + ':' + prefix.tokenize(':')[1]
189 } else {
190 storage = ''
191 }
192 if (row.key == 'Distribution' && row.value == distribution && items['Prefix'] == prefix.tokenize(':').last() && items['Storage'] == storage) {
193 for (source in items['Sources']){
194 if (source['Component'] == component) {
195 if(env.getEnvironment().containsKey('DEBUG') && env['DEBUG'] == "true"){
196 println ('Snapshot belongs to ' + distribution + '/' + prefix + ': ' + source['Name'])
197 }
198 return source['Name']
199 }
200 }
201 }
202 }
203 }
204 return false
205}
206
207/**
Richard Felkld2000552018-04-18 17:29:47 +0200208 * Returns list of the packages from specified Aptly repo by REST API
209 *
210 * @param server URI of the server insluding port and protocol
211 * @param repo Local repo name
212 **/
213def listPackagesFromRepoByAPI(server, repo){
214 http = new com.mirantis.mk.Http()
215 def packageList = http.restGet(server, "/api/repos/${repo}/packages")
216 return packageList
217}
218
219/**
220 * Deletes packages from specified Aptly repo by REST API
221 *
222 * @param server URI of the server insluding port and protocol
223 * @param repo Local repo name
224 * @param packageRefs Package list specified by packageRefs
225 **/
226def deletePackagesFromRepoByAPI(server, repo, packageRefs){
227 http = new com.mirantis.mk.Http()
228 def data = [:]
229 data['PackageRefs'] = packageRefs
230 http.restDelete(server, "/api/repos/${repo}/packages", data)
231}
232
233/**
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200234 * Returns list of the packages matched to pattern and
235 * belonged to particular snapshot by REST API
236 *
237 * @param server URI of the server insluding port and protocol
238 * @param snapshotName Snapshot to check
239 * @param packagesList Pattern of the components to be compared
240 **/
241def snapshotPackagesByAPI(server, snapshotName, packagesList) {
242 http = new com.mirantis.mk.Http()
243 def pkgs = http.restGet(server, "/api/snapshots/${snapshotName}/packages")
244 def packages = []
245
246 for (package_pattern in packagesList.tokenize(',')) {
247 def pkg = pkgs.find { item -> item.contains(package_pattern) }
248 packages.add(pkg)
249 }
250
251 return packages
252}
253
254
255/**
256 * Creates snapshot of the repo or package refs by REST API
257 * @param server URI of the server insluding port and protocol
258 * @param repo Local repo name
259 * @param snapshotName Snapshot name is going to be created
260 * @param snapshotDescription Snapshot description
261 * @param packageRefs List of the packages are going to be included into the snapshot
262 **/
263def snapshotCreateByAPI(server, repo, snapshotName, snapshotDescription = null, packageRefs = null) {
264 http = new com.mirantis.mk.Http()
265 def data = [:]
266 data['Name'] = snapshotName
267 if (snapshotDescription) {
268 data['Description'] = snapshotDescription
269 } else {
270 data['Description'] = "Snapshot of ${repo} repo"
271 }
272 if (packageRefs) {
273 data['PackageRefs'] = packageRefs
274 http.restPost(server, '/api/snapshots', data)
275 } else {
Richard Felkld2000552018-04-18 17:29:47 +0200276 http.restPost(server, "/api/repos/${repo}/snapshots", data)
Oleg Iurchenko85bb5d72018-02-15 16:45:22 +0200277 }
278}
279
280/**
281 * Publishes the snapshot accodgin to distribution, components and prefix by REST API
282 * @param server URI of the server insluding port and protocol
283 * @param snapshotName Snapshot is going to be published
284 * @param distribution Distribution for the published repo
285 * @param components Component for the published repo
286 * @param prefix Prefix for thepubslidhed repo including storage
287 **/
288def snapshotPublishByAPI(server, snapshotName, distribution, components, prefix) {
289 http = new com.mirantis.mk.Http()
290 def source = [:]
291 source['Name'] = snapshotName
292 source['Component'] = components
293 def data = [:]
294 data['SourceKind'] = 'snapshot'
295 data['Sources'] = [source]
296 data['Architectures'] = ['amd64']
297 data['Distribution'] = distribution
298 return http.restPost(server, "/api/publish/${prefix}", data)
299}
300
301/**
302 * Unpublish Aptly repo by REST API
303 *
304 * @param aptlyServer Aptly connection object
305 * @param aptlyPrefix Aptly prefix where need to delete a repo
306 * @param aptlyRepo Aptly repo name
307 */
308def unpublishByAPI(aptlyServer, aptlyPrefix, aptlyRepo){
309 http = new com.mirantis.mk.Http()
310 http.restDelete(aptlyServer, "/api/publish/${aptlyPrefix}/${aptlyRepo}")
311}
312
313/**
314 * Delete Aptly repo by REST API
315 *
316 * @param aptlyServer Aptly connection object
317 * @param aptlyRepo Aptly repo name
318 */
319def deleteRepoByAPI(aptlyServer, aptlyRepo){
320 http = new com.mirantis.mk.Http()
321 http.restDelete(aptlyServer, "/api/repos/${aptlyRepo}")
322}