You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

331 lines
9.3 KiB

pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
pipeline: Builder and stage implementation Provides `PipelineBuilder` for reading `.pipeline/config.yaml` and mapping user-defined pipelines, stages, and execution graphs to actual Jenkins Pipeline stage definitions. Provides `Pipeline` class that constructs a "stack" of `PipelineStage` objects from the user-provided configs, each with its own `NodeContext` for binding output values to names and consuming bound values from previous stages. Provides `PipelineStage` that contains core stage step implementations based on the existing `service-pipeline` JJB job definition in `integration/config`. A closure is returned by each stage for passing off to Jenkins Pipeline stage definitions by the builder. Steps have a fixed order within a given stage: build, run, publish, deploy, exports. This allows for concise definition of a stage that performs multiple steps, and deterministic behavior of default configuration that references locally bound output values (e.g. the default configuration of `image:` for an `publish: { type: image }` publish entry is `${.imageID}`, referencing the image built in the current stage's `build` step.) If the user needs to change ordering, they can simply break the stage out into multiple stages. See the `Pipeline` class for currently supported configuration. Note that the aforementioned context system allows for user's to make use of the same value bindings that step implementations use internally. They can also use the `exports` configuration field to bind new values. To illustrate the minimally required configuration, the following would approximate the current `service-pipeline-test-and-publish` JJB job for a project named "foo". pipelines: foo: directory: src/foo stages: - name: test # builds/runs "test" variant - name: candidate build: production publish: image: true deploy: # currently only the "ci" cluster chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true And to illustrate how the "candidate" stage in this example could be expressed as multiple stages using references to the output names that steps bind/export: pipelines: foo: directory: src/foo stages: - name: tested - name: built build: production - name: published publish: image: id: '${built.imageID}' exports: image: '${.imageFullName}:${.imageTag}' - name: staged deploy: image: '${published.image}' chart: https://releases.wikimedia.org/charts/foo-0.0.1.tgz test: true Bug: T210267 Change-Id: I5a41d0d33ed7e9174db6178ab7921f5143296c75
5 years ago
  1. package org.wikimedia.integration
  2. import java.io.FileNotFoundException
  3. import static org.wikimedia.integration.Utility.*
  4. import org.wikimedia.integration.GerritPipelineComment
  5. import org.wikimedia.integration.GerritReview
  6. /**
  7. * Provides an interface to common pipeline build/run/deploy functions.
  8. *
  9. * You must provide the Jenkins workflow script sandbox object that will be
  10. * used to declare Jenkins pipeline steps.
  11. *
  12. * {@code
  13. * // With just the Jenkins context
  14. * def pipeline = new PipelineRunner(this)
  15. *
  16. * // Or with a map of additional settings
  17. * def pipeline = new PipelineRunner(this, configPath: "dist/pipeline", registry: "foo.registry")
  18. * }
  19. */
  20. class PipelineRunner implements Serializable {
  21. /**
  22. * Relative path to Blubber config file.
  23. */
  24. def blubberConfig = "blubber.yaml"
  25. /**
  26. * Base URL for the Blubberoid service.
  27. */
  28. def blubberoidURL = "https://blubberoid.wikimedia.org/v1/"
  29. /**
  30. * Directory in which pipeline configuration is stored.
  31. */
  32. def configPath = ".pipeline"
  33. /**
  34. * Relative path to Helm config file.
  35. */
  36. def helmConfig = "helm.yaml"
  37. /**
  38. * Absolute path to a Kubernetes config file to specify when executing
  39. * `helm` or other k8s related commands. By default, none will be specified.
  40. */
  41. def kubeConfig = null
  42. /**
  43. * Namespace used for Helm/Kubernetes deployments.
  44. */
  45. def namespace = "ci"
  46. /**
  47. * Docker pull policy when deploying.
  48. */
  49. def pullPolicy = "IfNotPresent"
  50. /**
  51. * Default Docker registry host used when qualifying public image URLs.
  52. */
  53. def registry = "docker-registry.wikimedia.org"
  54. /**
  55. * Alternative Docker registry host used only when registering images.
  56. */
  57. def registryInternal = "docker-registry.discovery.wmnet"
  58. /**
  59. * Default Docker registry repository used for tagging and registering images.
  60. */
  61. def repository = "wikimedia"
  62. /**
  63. * Timeout for deployment using Helm.
  64. */
  65. def timeout = 120
  66. /**
  67. * Jenkins Pipeline Workflow context.
  68. */
  69. final def workflowScript
  70. /**
  71. * Constructor with Jenkins workflow script context and settings.
  72. *
  73. * @param settings Property map.
  74. * @param workflowScript Jenkins workflow script sandbox object.
  75. */
  76. PipelineRunner(Map settings = [:], workflowScript) {
  77. this.workflowScript = workflowScript
  78. settings.each { prop, value -> this.@"${prop}" = value }
  79. }
  80. /**
  81. * Builds the given image variant and returns an ID for the resulting image.
  82. *
  83. * @param variant Image variant name that should be built.
  84. * @param labels Additional name/value labels to add to the image metadata.
  85. */
  86. String build(String variant, Map labels = [:]) {
  87. def cfg = getConfigFile(blubberConfig)
  88. if (!workflowScript.fileExists(cfg)) {
  89. throw new FileNotFoundException("failed to build image: no Blubber config found at ${cfg}")
  90. }
  91. def blubber = new Blubber(workflowScript, cfg, blubberoidURL)
  92. def dockerfile = getTempFile("Dockerfile.")
  93. workflowScript.writeFile(text: blubber.generateDockerfile(variant), file: dockerfile)
  94. def labelFlags = labels.collect { k, v -> "--label ${arg(k + "=" + v)}" }.join(" ")
  95. def dockerBuild = "docker build --pull ${labelFlags} --file ${arg(dockerfile)} ."
  96. def output = workflowScript.sh(returnStdout: true, script: dockerBuild)
  97. // Return just the image ID from `docker build` output
  98. output.substring(output.lastIndexOf(" ") + 1).trim()
  99. }
  100. /**
  101. * Deploys the given registered image using the configured Helm chart and
  102. * returns the name of the release.
  103. *
  104. * @param imageName Name of the registered image to deploy.
  105. * @param imageTag Tag of the registered image to use.
  106. * @param overrides Additional Helm value overrides to set.
  107. */
  108. String deploy(String imageName, String imageTag, Map overrides = [:]) {
  109. def cfg = workflowScript.readYaml(file: getConfigFile(helmConfig))
  110. assert cfg instanceof Map && cfg.chart : "you must define 'chart: <helm chart url>' in ${cfg}"
  111. deployWithChart(cfg.chart, imageName, imageTag, overrides)
  112. }
  113. /**
  114. * Deploys the given registered image using the given Helm chart and returns
  115. * the name of the release.
  116. *
  117. * @param chart Chart URL.
  118. * @param imageName Name of the registered image to deploy.
  119. * @param imageTag Tag of the registered image to use.
  120. * @param overrides Additional Helm value overrides to set.
  121. */
  122. String deployWithChart(String chart, String imageName, String imageTag, Map overrides = [:]) {
  123. def values = [
  124. "docker.registry": registry,
  125. "docker.pull_policy": pullPolicy,
  126. "main_app.image": [repository, imageName].join("/"),
  127. "main_app.version": imageTag,
  128. ] + overrides
  129. values = values.collect { k, v -> arg(k + "=" + v) }.join(",")
  130. def release = imageName + "-" + randomAlphanum(8)
  131. helm("install --namespace=${arg(namespace)} --set ${values} -n ${arg(release)} " +
  132. "--debug --wait --timeout ${timeout} ${arg(chart)}")
  133. release
  134. }
  135. /**
  136. * Returns a path under configPath to the given config file.
  137. *
  138. * @param filePath Relative file path.
  139. */
  140. String getConfigFile(String filePath) {
  141. [configPath, filePath].join("/")
  142. }
  143. /**
  144. * Returns a path under configPath to a temp file with the given base name.
  145. *
  146. * @param baseName File base name.
  147. */
  148. String getTempFile(String baseName) {
  149. getConfigFile("${baseName}${randomAlphanum(8)}")
  150. }
  151. /**
  152. * Deletes and purges the given Helm release.
  153. *
  154. * @param release Previously deployed release name.
  155. */
  156. void purgeRelease(String release) {
  157. purgeReleases([release])
  158. }
  159. /**
  160. * Deletes and purges the given Helm release.
  161. *
  162. * @param release Previously deployed release name.
  163. */
  164. void purgeReleases(List releases) {
  165. if (releases.size() > 0) {
  166. helm("delete --purge ${args(releases)}")
  167. }
  168. }
  169. /**
  170. * Name and push an image specified by the given image ID to the WMF Docker
  171. * registry.
  172. *
  173. * The repo name is enforced as "docker-registry.wikimedia.org", and the
  174. * remote path prefix is enforced as "/wikimedia/".
  175. *
  176. * {@code
  177. * // Pushes built image to docker-registry.wikimedia.org/wikimedia/mathoid:build-123
  178. * def image = pipeline.build("production")
  179. * pipeline.registerAs(image, "mathoid", "build-123")
  180. * }
  181. * @param imageID Image ID.
  182. * @param name Remote name to use for the image.
  183. * @param tag Remote tag to use for the image.
  184. */
  185. String registerAs(String imageID, String name, String tag) {
  186. def nameAndTag = qualifyRegistryPath(name, registryInternal) + ":" + tag
  187. workflowScript.sh("docker tag ${arg(imageID)} ${arg(nameAndTag)} && " +
  188. "sudo /usr/local/bin/docker-pusher ${arg(nameAndTag)}")
  189. nameAndTag
  190. }
  191. /**
  192. * Removes the given image from the local cache. All tags are removed from
  193. * the image as well.
  194. *
  195. * @param imageID ID of the image to remove.
  196. */
  197. void removeImage(String imageID) {
  198. removeImages([imageID])
  199. }
  200. /**
  201. * Removes the given images from the local cache.
  202. *
  203. * @param imageIDs IDs of images to remove.
  204. */
  205. void removeImages(List imageIDs) {
  206. if (imageIDs.size() > 0) {
  207. workflowScript.sh("docker rmi --force ${args(imageIDs)}")
  208. }
  209. }
  210. /**
  211. * Submits a comment to Gerrit with the build result and links to published
  212. * images.
  213. *
  214. * @param imageName Fully qualified name of published image.
  215. * @param imageTags Image tags.
  216. */
  217. void reportToGerrit(imageName, imageTags = []) {
  218. def comment
  219. if (workflowScript.currentBuild.result == 'SUCCESS' && imageName) {
  220. comment = new GerritPipelineComment(
  221. jobName: workflowScript.env.JOB_NAME,
  222. buildNumber: workflowScript.env.BUILD_NUMBER,
  223. jobStatus: workflowScript.currentBuild.result,
  224. image: imageName,
  225. tags: imageTags,
  226. )
  227. } else {
  228. comment = new GerritPipelineComment(
  229. jobName: workflowScript.env.JOB_NAME,
  230. buildNumber: workflowScript.env.BUILD_NUMBER,
  231. jobStatus: workflowScript.currentBuild.result,
  232. )
  233. }
  234. GerritReview.post(workflowScript, comment)
  235. }
  236. /**
  237. * Runs a container using the image specified by the given ID.
  238. *
  239. * @param imageID Image ID.
  240. * @param arguments Entry-point arguments.
  241. */
  242. void run(String imageID, List arguments = []) {
  243. workflowScript.timeout(time: 20, unit: "MINUTES") {
  244. workflowScript.sh("exec docker run --rm ${args([imageID] + arguments)}")
  245. }
  246. }
  247. /**
  248. * Fully qualifies an image name to a public registry path.
  249. *
  250. * @param name Image name.
  251. * @param registryName Alternative registry. Defaults to {@link registry}.
  252. */
  253. String qualifyRegistryPath(String name, String registryName = "") {
  254. assert !name.contains("/") : "image name ${name} cannot contain slashes"
  255. [registryName ?: registry, repository, name].join("/")
  256. }
  257. /**
  258. * Runs end-to-end tests for the given release via `helm test`.
  259. *
  260. * @param release Previously deployed release name.
  261. */
  262. void testRelease(String release) {
  263. helm("test --cleanup ${arg(release)}")
  264. }
  265. private
  266. /**
  267. * Execute a helm command, specifying the right tiller namespace.
  268. */
  269. void helm(String cmd) {
  270. kubeCmd("helm --tiller-namespace=${arg(namespace)} ${cmd}")
  271. }
  272. /**
  273. * Execute a Kubernetes related command, specifying the configured
  274. * kubeConfig.
  275. */
  276. void kubeCmd(String cmd) {
  277. def env = kubeConfig ? "KUBECONFIG=${arg(kubeConfig)} " : ""
  278. workflowScript.sh("${env}${cmd}")
  279. }
  280. }