Sergey Otpuschennikov | bf37760 | 2019-09-23 13:33:51 +0400 | [diff] [blame] | 1 | /** |
| 2 | * |
| 3 | * Mirror list 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 |
| 10 | * SOURCE_IMAGE_TAG Tag to use when pulling images(optional,if SOURCE_IMAGE_TAG has been found) |
| 11 | * SET_DEFAULT_ARTIFACTORY_PROPERTIES Add extra props. directly to artifactory, |
| 12 | * IMAGE_LIST List of images to mirror |
| 13 | * Example: docker-dev-local.docker.mirantis.net/mirantis/external/docker.elastic.co/elasticsearch |
| 14 | * docker-dev-local.docker.mirantis.net/mirantis/external/elasticsearch:${IMAGE_TAG}* |
| 15 | * docker-dev-local.docker.mirantis.net/mirantis/external/docker.elastic.co/elasticsearch/elasticsearch:5.4.1 |
| 16 | */ |
| 17 | |
| 18 | import java.util.regex.Pattern |
| 19 | |
| 20 | common = new com.mirantis.mk.Common() |
| 21 | jenkinsUtils = new com.mirantis.mk.JenkinsUtils() |
| 22 | |
| 23 | def registryRegex = Pattern.compile('docker-dev|dev-docker') |
| 24 | def namespaceRegex = Pattern.compile('mirantis|library') |
| 25 | def componentRegex = Pattern.compile('kaas|kaas-bm|oscore') |
| 26 | |
| 27 | String external = false |
| 28 | String externalMarker = '/mirantis/external/' |
| 29 | def artifactory = new com.mirantis.mcp.MCPArtifactory() |
| 30 | def artifactoryServer = Artifactory.server('mcp-ci') |
| 31 | def git = new com.mirantis.mk.Git() |
| 32 | def releaseWorkflow = new com.mirantis.mk.ReleaseWorkflow() |
| 33 | |
| 34 | // imageList = env.IMAGE_LIST ?: '' |
| 35 | slaveNode = env.SLAVE_NODE ?: 'python' |
| 36 | |
| 37 | timeout(time: 4, unit: 'HOURS') { |
| 38 | node(slaveNode) { |
| 39 | def user = jenkinsUtils.currentUsername() |
| 40 | currentBuild.description = "${user}: [${env.SOURCE_IMAGE_TAG} => ${env.IMAGE_TAG}]\n${env.IMAGE_LIST}" |
| 41 | try { |
| 42 | allowedGroups = ['release-engineering'] |
| 43 | releaseTags = ['proposed', 'release', '2018', '2019', '2020'] |
| 44 | tags = [env.SOURCE_IMAGE_TAG, env.IMAGE_TAG] |
| 45 | tagInRelease = tags.any { tag -> releaseTags.any { tag.contains(it) } } |
| 46 | if (tagInRelease) { |
| 47 | if (!jenkinsUtils.currentUserInGroups(allowedGroups)) { |
| 48 | throw new Exception("You - ${user} - don't have permissions to run this job with tags ${tags}!") |
| 49 | } else { |
| 50 | echo "User `${user}` belongs to one of groups `${allowedGroups}`. Proceeding..." |
| 51 | } |
| 52 | } |
| 53 | stage('Mirror Docker Images') { |
| 54 | def images = IMAGE_LIST.tokenize('\n') |
| 55 | for (image in images) { |
| 56 | lengthImageName = image.tokenize('/').size() |
| 57 | if (lengthImageName <= 3) { |
| 58 | error("Image ${sourceImage} contains very short path") |
| 59 | } |
| 60 | String src = '' |
| 61 | String dst = '' |
| 62 | def (sourceImage, sourceTag) = image.trim().tokenize(':') |
| 63 | def (sourceRegistry, namespace, componentNamespace) = image.tokenize('/') |
| 64 | String componentNamespace = sourceImage.tokenize('/')[-(lengthImageName - 3)..-2].join('/') |
| 65 | |
| 66 | if (!registryRegex.matcher(sourceRegistry).find() || !namespaceRegex.matcher(namespace).find() || !componentRegex.matcher(component)) { |
| 67 | error ("Image ${sourceImage} contains wrong data in path/URL") |
| 68 | } |
| 69 | if (env.IMAGE_TAG) { |
| 70 | targetTag = env.IMAGE_TAG |
| 71 | } else { |
| 72 | targetTag = sourceTag |
| 73 | } |
| 74 | String sourceDockerRepo = sourceRegistry.split(/\./)[0] |
| 75 | if (sourceDockerRepo.contains('dev-kaas')) { |
| 76 | src = 'dev-' |
| 77 | dst = '' |
| 78 | } else { |
| 79 | src = 'dev' |
| 80 | dst = 'prod' |
| 81 | } |
| 82 | String targetDockerRepo = sourceDockerRepo.replaceAll("${src}", "${dst}") |
| 83 | String targetImage = sourceImage.replaceAll("${src}", "${dst}") |
| 84 | String targetRegistryUrl = sourceRegistry.replaceAll("${src}", "${dst}") |
| 85 | String imageRepo = targetImage - targetRegistryUrl |
| 86 | if (sourceImage.contains('SUBS_SOURCE_IMAGE_TAG')) { |
| 87 | common.warningMsg("Replacing SUBS_SOURCE_IMAGE_TAG => ${env.SOURCE_IMAGE_TAG}") |
| 88 | sourceImage = sourceImage.replace('SUBS_SOURCE_IMAGE_TAG', env.SOURCE_IMAGE_TAG) |
| 89 | } |
| 90 | |
| 91 | if (targetImage.contains(externalMarker)) { |
| 92 | external = true |
| 93 | // check if images exists - raise error, as we don't want to rewrite existing one |
| 94 | // http://artifactory.mcp.mirantis.net/test-prod-openstack-docker/mysql/5.6/manifest.json |
| 95 | if (artifactory.imageExists(targetRegistryUrl, "${imageRepo}", targetTag)) { |
| 96 | echo "Image ${targetImage} already exists!" |
| 97 | continue |
| 98 | } |
| 99 | } |
| 100 | common.infoMsg("Attempt to push docker image into remote registry: ${env.REGISTRY_URL}") |
| 101 | common.retry(3, 5) { |
| 102 | artifactory.promoteDockerArtifact(artifactoryServer.getUrl(), |
| 103 | sourceDockerRepo, |
| 104 | targetDockerRepo, |
| 105 | imageRepo, |
| 106 | sourceTag, |
| 107 | targetTag, |
| 108 | true) |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | } catch (Throwable e) { |
| 113 | // Stub for future processing |
| 114 | currentBuild.result = 'FAILURE' |
| 115 | throw e |
| 116 | } |
| 117 | } |
| 118 | } |