Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 1 | /** |
| 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 |
azvyagintsev | d162b91 | 2018-07-26 10:52:14 +0200 | [diff] [blame] | 10 | * SOURCE_IMAGE_TAG Tag to use when pulling images(optional,if SOURCE_IMAGE_TAG has been found) |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 11 | * SET_DEFAULT_ARTIFACTORY_PROPERTIES Add extra props. directly to artifactory, |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 12 | * IMAGE_LIST List of images to mirror |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 13 | * 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 Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 17 | * |
| 18 | */ |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 19 | import java.util.regex.Pattern |
| 20 | import groovy.json.JsonSlurper |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 21 | |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 22 | common = new com.mirantis.mk.Common() |
| 23 | external = false |
| 24 | externalMarker = '/mirantis/external/' |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 25 | |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 26 | slaveNode = env.SLAVE_NODE ?: 'docker' |
| 27 | setDefaultArtifactoryProperties = env.SET_DEFAULT_ARTIFACTORY_PROPERTIES ?: true |
| 28 | |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 29 | def getImageName(String image) { |
| 30 | def regex = Pattern.compile('(?:.+/)?([^:]+)(?::.+)?') |
| 31 | def matcher = regex.matcher(image) |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 32 | if (matcher.find()) { |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 33 | def imageName = matcher.group(1) |
| 34 | return imageName |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 35 | } else { |
| 36 | error("Wrong format of image name.") |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 37 | } |
| 38 | } |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 39 | |
| 40 | timeout(time: 4, unit: 'HOURS') { |
| 41 | node(slaveNode) { |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 42 | try { |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 43 | stage("Mirror Docker Images") { |
| 44 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 45 | def images = IMAGE_LIST.tokenize('\n') |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 46 | def imageName, sourceImage, targetRegistryPath, imageArray |
| 47 | for (image in images) { |
| 48 | if (image.trim().indexOf(' ') == -1) { |
| 49 | error("Wrong format of image and target repository input") |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 50 | } |
| 51 | imageArray = image.trim().tokenize(' ') |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 52 | sourceImage = imageArray[0] |
| 53 | if (sourceImage.contains('SUBS_SOURCE_IMAGE_TAG')) { |
| 54 | common.warningMsg("Replacing SUBS_SOURCE_IMAGE_TAG => ${env.SOURCE_IMAGE_TAG}") |
| 55 | sourceImage = sourceImage.replace('SUBS_SOURCE_IMAGE_TAG', env.SOURCE_IMAGE_TAG) |
azvyagintsev | d162b91 | 2018-07-26 10:52:14 +0200 | [diff] [blame] | 56 | } |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 57 | targetRegistryPath = imageArray[1] |
| 58 | targetRegistry = imageArray[1].split('/')[0] |
| 59 | imageName = getImageName(sourceImage) |
| 60 | targetImageFull = "${targetRegistryPath}/${imageName}:${env.IMAGE_TAG}" |
| 61 | srcImage = docker.image(sourceImage) |
| 62 | srcImage.pull() |
| 63 | // Use sh-docker call for tag, due magic code in plugin: |
| 64 | // https://github.com/jenkinsci/docker-workflow-plugin/blob/docker-workflow-1.17/src/main/resources/org/jenkinsci/plugins/docker/workflow/Docker.groovy#L168-L170 |
| 65 | sh("docker tag ${srcImage.id} ${targetImageFull}") |
| 66 | common.infoMsg("Attempt to push docker image into remote registry: ${env.REGISTRY_URL}") |
| 67 | sh("docker push ${targetImageFull}") |
| 68 | if (targetImageFull.contains(externalMarker)) { |
| 69 | external = true |
| 70 | } |
| 71 | |
| 72 | if (setDefaultArtifactoryProperties) { |
| 73 | common.infoMsg("Processing artifactory props for : ${targetImageFull}") |
| 74 | LinkedHashMap artifactoryProperties = [:] |
| 75 | // Get digest of pushed image |
| 76 | String unique_image_id = sh( |
| 77 | script: "docker inspect --format='{{index .RepoDigests 0}}' '${targetImageFull}'", |
| 78 | returnStdout: true, |
| 79 | ).trim() |
| 80 | def image_sha256 = unique_image_id.tokenize(':')[1] |
| 81 | def ret = new URL("https://${targetRegistry}/artifactory/api/search/checksum?sha256=${image_sha256}").getText() |
| 82 | // Most probably, we would get many images, especially for external images. We need to guess |
| 83 | // exactly one, which we pushing now |
| 84 | guessImage = targetImageFull.replace(':', '/').replace(targetRegistry, '') |
| 85 | ArrayList img_data = new JsonSlurper().parseText(ret)['results'] |
| 86 | img_data*.uri.each { imgUrl -> |
| 87 | if (imgUrl.contains(guessImage)) { |
| 88 | artifactoryProperties = [ |
| 89 | 'com.mirantis.targetTag' : env.IMAGE_TAG, |
| 90 | 'com.mirantis.uniqueImageId': unique_image_id, |
| 91 | ] |
| 92 | if (external) { |
| 93 | artifactoryProperties << ['com.mirantis.externalImage': external] |
| 94 | } |
| 95 | common.infoMsg("artifactoryProperties=> ${artifactoryProperties}") |
| 96 | // Call pipeline-library routine to set properties |
| 97 | def mcp_artifactory = new com.mirantis.mcp.MCPArtifactory() |
| 98 | mcp_artifactory.setProperties(imgUrl - '/manifest.json', artifactoryProperties) |
| 99 | } |
| 100 | } |
| 101 | } |
Richard Felkl | 7c920d0 | 2017-12-11 15:28:18 +0100 | [diff] [blame] | 102 | } |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 103 | } |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 104 | } catch (Throwable e) { |
azvyagintsev | 388a1bd | 2018-09-06 12:39:49 +0300 | [diff] [blame] | 105 | // Stub for future processing |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 106 | currentBuild.result = "FAILURE" |
| 107 | throw e |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 108 | } |
Richard Felkl | e90ef1c | 2017-12-08 00:13:56 +0100 | [diff] [blame] | 109 | } |
azvyagintsev | d162b91 | 2018-07-26 10:52:14 +0200 | [diff] [blame] | 110 | } |