blob: aca4185315fc7862b9b81ee830892df84482da35 [file] [log] [blame]
Richard Felkle90ef1c2017-12-08 00:13:56 +01001/**
2 *
3 * Mirror Docker images
4 *
5 * Expected parameters:
6 * TARGET_REGISTRY_CREDENTIALS_ID Credentials for target Docker Registry
7 * TARGET_REGISTRY Target Docker Registry name
8 * REGISTRY_URL Target Docker Registry URL
9 * IMAGE_TAG Tag to use when pushing images
azvyagintsevd162b912018-07-26 10:52:14 +020010 * SOURCE_IMAGE_TAG Tag to use when pulling images(optional,if SOURCE_IMAGE_TAG has been found)
azvyagintsev388a1bd2018-09-06 12:39:49 +030011 * SET_DEFAULT_ARTIFACTORY_PROPERTIES Add extra props. directly to artifactory,
Richard Felkle90ef1c2017-12-08 00:13:56 +010012 * IMAGE_LIST List of images to mirror
azvyagintsev388a1bd2018-09-06 12:39:49 +030013 * Example: docker.elastic.co/elasticsearch/elasticsearch:5.4.1 docker-prod-local.docker.mirantis.net/mirantis/external/docker.elastic.co/elasticsearch
14 * docker.elastic.co/elasticsearch/elasticsearch:SUBS_SOURCE_IMAGE_TAG docker-prod-local.docker.mirantis.net/mirantis/external/elasticsearch:${IMAGE_TAG}* Will be proceed like:
15 * docker tag docker.elastic.co/elasticsearch/elasticsearch:5.4.1 docker-prod-local.docker.mirantis.net/mirantis/external/docker.elastic.co/elasticsearch/elasticsearch:5.4.1
16 *
Richard Felkle90ef1c2017-12-08 00:13:56 +010017 *
18 */
azvyagintsev388a1bd2018-09-06 12:39:49 +030019import java.util.regex.Pattern
Richard Felkle90ef1c2017-12-08 00:13:56 +010020
azvyagintsev388a1bd2018-09-06 12:39:49 +030021common = new com.mirantis.mk.Common()
22external = false
23externalMarker = '/mirantis/external/'
Richard Felkle90ef1c2017-12-08 00:13:56 +010024
azvyagintsev388a1bd2018-09-06 12:39:49 +030025slaveNode = env.SLAVE_NODE ?: 'docker'
26setDefaultArtifactoryProperties = env.SET_DEFAULT_ARTIFACTORY_PROPERTIES ?: true
27
Richard Felkle90ef1c2017-12-08 00:13:56 +010028def getImageName(String image) {
29 def regex = Pattern.compile('(?:.+/)?([^:]+)(?::.+)?')
30 def matcher = regex.matcher(image)
azvyagintsev388a1bd2018-09-06 12:39:49 +030031 if (matcher.find()) {
Richard Felkle90ef1c2017-12-08 00:13:56 +010032 def imageName = matcher.group(1)
33 return imageName
azvyagintsev388a1bd2018-09-06 12:39:49 +030034 } else {
35 error("Wrong format of image name.")
Richard Felkle90ef1c2017-12-08 00:13:56 +010036 }
37}
azvyagintsev388a1bd2018-09-06 12:39:49 +030038
39timeout(time: 4, unit: 'HOURS') {
40 node(slaveNode) {
Denis Egorenko899ee322018-11-19 17:35:50 +040041 def user = ''
42 wrap([$class: 'BuildUser']) {
43 user = env.BUILD_USER_ID
44 }
45 currentBuild.description = "${user}: [${env.SOURCE_IMAGE_TAG} => ${env.IMAGE_TAG}]\n${env.IMAGE_LIST}"
Jakub Josefa63f9862018-01-11 17:58:38 +010046 try {
azvyagintsev388a1bd2018-09-06 12:39:49 +030047 stage("Mirror Docker Images") {
48
Jakub Josefa63f9862018-01-11 17:58:38 +010049 def images = IMAGE_LIST.tokenize('\n')
azvyagintsev388a1bd2018-09-06 12:39:49 +030050 def imageName, sourceImage, targetRegistryPath, imageArray
51 for (image in images) {
52 if (image.trim().indexOf(' ') == -1) {
53 error("Wrong format of image and target repository input")
Jakub Josefa63f9862018-01-11 17:58:38 +010054 }
55 imageArray = image.trim().tokenize(' ')
azvyagintsev388a1bd2018-09-06 12:39:49 +030056 sourceImage = imageArray[0]
57 if (sourceImage.contains('SUBS_SOURCE_IMAGE_TAG')) {
58 common.warningMsg("Replacing SUBS_SOURCE_IMAGE_TAG => ${env.SOURCE_IMAGE_TAG}")
59 sourceImage = sourceImage.replace('SUBS_SOURCE_IMAGE_TAG', env.SOURCE_IMAGE_TAG)
azvyagintsevd162b912018-07-26 10:52:14 +020060 }
azvyagintsev388a1bd2018-09-06 12:39:49 +030061 targetRegistryPath = imageArray[1]
62 targetRegistry = imageArray[1].split('/')[0]
63 imageName = getImageName(sourceImage)
64 targetImageFull = "${targetRegistryPath}/${imageName}:${env.IMAGE_TAG}"
Denis Egorenko2ee651c2018-11-23 17:41:38 +040065
66 def mcp_artifactory = new com.mirantis.mcp.MCPArtifactory()
67 if (targetImageFull.contains(externalMarker)) {
68 external = true
69 // check if images exists - raise error, as we don't want to rewrite existing one
70 def imageRepo = targetRegistryPath - targetRegistry
Denis Egorenko1b207d12018-11-26 15:35:21 +040071 if (mcp_artifactory.imageExists(env.REGISTRY_URL, "${imageRepo}/${imageName}", env.IMAGE_TAG)) {
Denis Egorenko2ee651c2018-11-23 17:41:38 +040072 error("Image ${targetImageFull} already exists!")
73 }
74 }
75
azvyagintsev388a1bd2018-09-06 12:39:49 +030076 srcImage = docker.image(sourceImage)
azvyagintsev86ba4a02018-10-03 19:21:28 +030077 common.retry(3, 5) {
78 srcImage.pull()
79 }
azvyagintsev388a1bd2018-09-06 12:39:49 +030080 // Use sh-docker call for tag, due magic code in plugin:
81 // https://github.com/jenkinsci/docker-workflow-plugin/blob/docker-workflow-1.17/src/main/resources/org/jenkinsci/plugins/docker/workflow/Docker.groovy#L168-L170
82 sh("docker tag ${srcImage.id} ${targetImageFull}")
83 common.infoMsg("Attempt to push docker image into remote registry: ${env.REGISTRY_URL}")
azvyagintsev86ba4a02018-10-03 19:21:28 +030084 common.retry(3, 5) {
85 docker.withRegistry(env.REGISTRY_URL, env.TARGET_REGISTRY_CREDENTIALS_ID) {
Alexander Evseev3a37d082018-12-10 12:46:39 +000086 sh("docker push ${targetImageFull}")
azvyagintsev86ba4a02018-10-03 19:21:28 +030087 }
Alexander Evseevd70ef002018-10-02 13:01:27 +020088 }
Denis Egorenkoa0f1b2f2018-11-23 17:24:35 +000089 def buildTime = new Date().format("yyyyMMdd-HH:mm:ss.SSS", TimeZone.getTimeZone('UTC'))
azvyagintsev388a1bd2018-09-06 12:39:49 +030090
91 if (setDefaultArtifactoryProperties) {
92 common.infoMsg("Processing artifactory props for : ${targetImageFull}")
93 LinkedHashMap artifactoryProperties = [:]
Alexander Evseev014e12b2018-12-10 16:04:59 +030094 // Guess API image URL to use for setting properties
95 String artRepo
96 String tgtGuessImage
97 (artRepo, tgtGuessImage) = targetImageFull.split('/', 2)
98 artRepo = artRepo.tokenize('.')[0]
99 tgtGuessImage = artRepo + '/' + tgtGuessImage.replace(':', '/')
100 String tgtImgUrl = "https://${targetRegistry}/artifactory/api/storage/${tgtGuessImage}"
101 // Collect properties
Denis Egorenkoa0f1b2f2018-11-23 17:24:35 +0000102 artifactoryProperties = [
103 'com.mirantis.targetTag' : env.IMAGE_TAG,
104 'com.mirantis.uniqueImageId': unique_image_id,
105 ]
106 if (external) {
107 artifactoryProperties << ['com.mirantis.externalImage': external]
108 }
Denis Egorenko5b1ab7f2018-12-10 15:21:35 +0400109 def sourceRegistry = sourceImage.split('/')[0]
110 def sourceGuessImage = sourceImage.replace(':', '/').replace(sourceRegistry, '')
Denis Egorenko01918392018-12-10 12:28:46 +0400111 def sourceImgUrl = img_data*.uri.find { it.contains(sourceGuessImage) } - '/manifest.json'
112 def existingProps = mcp_artifactory.getPropertiesForArtifact(sourceImgUrl)
Denis Egorenkoa0f1b2f2018-11-23 17:24:35 +0000113 def historyProperties = []
Denis Egorenko01918392018-12-10 12:28:46 +0400114 // check does the source image have already history props
Denis Egorenkoa0f1b2f2018-11-23 17:24:35 +0000115 if (existingProps) {
116 historyProperties = existingProps.get('com.mirantis.versionHistory', [])
117 }
118 // %5C - backslash symbol is needed
119 historyProperties.add("${buildTime}%5C=${sourceImage}")
Denis Egorenko5b1ab7f2018-12-10 15:21:35 +0400120 artifactoryProperties << [ 'com.mirantis.versionHistory': historyProperties.join(',') ]
Denis Egorenkoa0f1b2f2018-11-23 17:24:35 +0000121 common.infoMsg("artifactoryProperties=> ${artifactoryProperties}")
122 common.retry(3, 5) {
Denis Egorenko01918392018-12-10 12:28:46 +0400123 mcp_artifactory.setProperties(tgtImgUrl, artifactoryProperties)
azvyagintsev388a1bd2018-09-06 12:39:49 +0300124 }
125 }
Richard Felkl7c920d02017-12-11 15:28:18 +0100126 }
Richard Felkle90ef1c2017-12-08 00:13:56 +0100127 }
Jakub Josefa63f9862018-01-11 17:58:38 +0100128 } catch (Throwable e) {
azvyagintsev388a1bd2018-09-06 12:39:49 +0300129 // Stub for future processing
Jakub Josefa63f9862018-01-11 17:58:38 +0100130 currentBuild.result = "FAILURE"
131 throw e
Richard Felkle90ef1c2017-12-08 00:13:56 +0100132 }
Richard Felkle90ef1c2017-12-08 00:13:56 +0100133 }
azvyagintsevd162b912018-07-26 10:52:14 +0200134}