Skip to content

Commit 57cbfb5

Browse files
committed
jobs/fix-build: new job to fix archived builds
Very often, our pipeline flakes after the final archiving stage, e.g. if the fedora-messaging queue is down, or Robosignatory is backed up. Ideally, as discussed in #566, we could just rerun the job and have it know to salvage the builds, but there's a lot of details there that we need to get right. (And... it's probably not worth tackling if we're eventually moving away from Jenkins anyway.) For now at least, it's not hard to just have a separate job that reruns those last final steps from the `build` and `build-arch` jobs so we can salvage those builds. You need to know what you're doing when using this job. It should only be used when strictly necessary. It's often better to just do a new build instead. Fixes: #566
1 parent d95cc5f commit 57cbfb5

File tree

1 file changed

+165
-0
lines changed

1 file changed

+165
-0
lines changed

jobs/fix-build.Jenkinsfile

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
node {
2+
checkout scm
3+
// these are script global vars
4+
pipeutils = load("utils.groovy")
5+
pipecfg = pipeutils.load_pipecfg()
6+
libcloud = load("libcloud.groovy")
7+
}
8+
9+
properties([
10+
pipelineTriggers([]),
11+
parameters([
12+
choice(name: 'STREAM',
13+
choices: pipeutils.get_streams_choices(pipecfg),
14+
description: 'CoreOS stream to sign'),
15+
string(name: 'VERSION',
16+
description: 'CoreOS version to sign',
17+
defaultValue: '',
18+
trim: true),
19+
string(name: 'ARCHES',
20+
description: "Override architectures (space-separated) to sign. " +
21+
"Defaults to all arches for this stream.",
22+
defaultValue: "",
23+
trim: true),
24+
booleanParam(name: 'SKIP_SIGNING',
25+
defaultValue: false,
26+
description: 'Skip signing artifacts'),
27+
booleanParam(name: 'SKIP_COMPOSE_IMPORT',
28+
defaultValue: false,
29+
description: 'Skip requesting compose repo import'),
30+
booleanParam(name: 'SKIP_TESTS',
31+
defaultValue: false,
32+
description: 'Skip triggering cloud and upgrade tests'),
33+
string(name: 'COREOS_ASSEMBLER_IMAGE',
34+
description: 'Override coreos-assembler image to use',
35+
defaultValue: "",
36+
trim: true)
37+
] + pipeutils.add_hotfix_parameters_if_supported()),
38+
durabilityHint('PERFORMANCE_OPTIMIZED')
39+
])
40+
41+
def build_description = "[${params.STREAM}]"
42+
43+
// Reload pipecfg if a hotfix build was provided. The reason we do this here
44+
// instead of loading the right one upfront is so that we don't modify the
45+
// parameter definitions above and their default values.
46+
if (params.PIPECFG_HOTFIX_REPO || params.PIPECFG_HOTFIX_REF) {
47+
node {
48+
pipecfg = pipeutils.load_pipecfg(params.PIPECFG_HOTFIX_REPO, params.PIPECFG_HOTFIX_REF)
49+
build_description = "[${params.STREAM}-${pipecfg.hotfix.name}]"
50+
}
51+
}
52+
53+
// no way to make a parameter required directly so manually check
54+
// https://issues.jenkins-ci.org/browse/JENKINS-3509
55+
if (params.VERSION == "") {
56+
throw new Exception("Missing VERSION parameter!")
57+
}
58+
59+
// runtime parameter always wins
60+
def cosa_img = params.COREOS_ASSEMBLER_IMAGE
61+
cosa_img = cosa_img ?: pipeutils.get_cosa_img(pipecfg, params.STREAM)
62+
63+
def basearches = []
64+
if (params.ARCHES != "") {
65+
basearches = params.ARCHES.split() as List
66+
} else {
67+
basearches += 'x86_64'
68+
basearches += pipeutils.get_additional_arches(pipecfg, params.STREAM)
69+
}
70+
71+
// make sure there are no duplicates
72+
basearches = basearches.unique()
73+
74+
def stream_info = pipecfg.streams[params.STREAM]
75+
76+
currentBuild.description = "${build_description} Waiting"
77+
78+
// We just lock here out of an abundance of caution in case somehow
79+
// two jobs run for the same stream, but that really shouldn't happen.
80+
// Also lock version-arch-specific locks to make sure these builds are finished.
81+
lock(resource: "sign-${params.VERSION}") {
82+
cosaPod(cpu: "1", memory: "512Mi", image: cosa_img,
83+
serviceAccount: "jenkins") {
84+
try {
85+
currentBuild.description = "${build_description} Running"
86+
87+
def s3_stream_dir = pipeutils.get_s3_streams_dir(pipecfg, params.STREAM)
88+
89+
// Fetch metadata files for the build we are interested in
90+
stage('Fetch Metadata') {
91+
def ref = pipeutils.get_source_config_ref_for_stream(pipecfg, params.STREAM)
92+
def variant = stream_info.variant ? "--variant ${stream_info.variant}" : ""
93+
def arch_args = basearches.collect{"--arch=$it"}
94+
pipeutils.shwrapWithAWSBuildUploadCredentials("""
95+
cosa init --branch ${ref} ${variant} ${pipecfg.source_config.url}
96+
cosa buildfetch --build=${params.VERSION} \
97+
${arch_args} --artifact=all --url=s3://${s3_stream_dir}/builds \
98+
--aws-config-file \${AWS_BUILD_UPLOAD_CONFIG}
99+
""")
100+
}
101+
102+
def builtarches = shwrapCapture("""
103+
cosa shell -- cat builds/builds.json | \
104+
jq -r '.builds | map(select(.id == \"${params.VERSION}\"))[].arches[]'
105+
""").split() as Set
106+
assert builtarches.contains("x86_64"): "The x86_64 architecture was not in builtarches."
107+
if (!builtarches.containsAll(basearches)) {
108+
echo "ERROR: Some requested architectures did not successfully build"
109+
echo "ERROR: Detected built architectures: $builtarches"
110+
echo "ERROR: Requested base architectures: $basearches"
111+
currentBuild.result = 'FAILURE'
112+
return
113+
}
114+
115+
// Update description based on updated set of architectures
116+
build_description = "[${params.STREAM}][${basearches.join(' ')}][${params.VERSION}]"
117+
currentBuild.description = "${build_description} Running"
118+
119+
def src_config_commit = shwrapCapture("""
120+
jq '.[\"coreos-assembler.config-gitrev\"]' builds/${params.VERSION}/${basearches[0]}/meta.json
121+
""")
122+
123+
for (basearch in basearches) {
124+
if (!params.SKIP_SIGNING || !params.SKIP_COMPOSE_IMPORT) {
125+
pipeutils.tryWithMessagingCredentials() {
126+
def parallelruns = [:]
127+
if (!params.SKIP_SIGNING) {
128+
parallelruns['Sign Images'] = {
129+
pipeutils.signImages(params.STREAM, params.VERSION, basearch, s3_stream_dir)
130+
}
131+
}
132+
if (!params.SKIP_COMPOSE_IMPORT) {
133+
parallelruns['OSTree Import: Compose Repo'] = {
134+
pipeutils.composeRepoImport(params.VERSION, basearch, s3_stream_dir)
135+
}
136+
}
137+
// process this batch
138+
parallel parallelruns
139+
}
140+
}
141+
142+
if (!params.SKIP_TESTS) {
143+
stage('Cloud Tests') {
144+
pipeutils.run_cloud_tests(pipecfg, params.STREAM, params.VERSION,
145+
cosa_img, basearch, src_config_commit)
146+
}
147+
if (pipecfg.misc?.run_extended_upgrade_test_fcos) {
148+
stage('Upgrade Tests') {
149+
pipeutils.run_fcos_upgrade_tests(pipecfg, params.STREAM, params.VERSION,
150+
cosa_img, basearch, src_config_commit)
151+
}
152+
}
153+
}
154+
}
155+
156+
currentBuild.result = 'SUCCESS'
157+
currentBuild.description = "${build_description} ✓"
158+
159+
// main try finishes here
160+
} catch (e) {
161+
currentBuild.result = 'FAILURE'
162+
throw e
163+
} finally {
164+
pipeutils.trySlackSend(message: ":key: fix-build #${env.BUILD_NUMBER} <${env.BUILD_URL}|:jenkins:> <${env.RUN_DISPLAY_URL}|:ocean:> [${params.STREAM}][${basearches.join(' ')}] (${params.VERSION})")
165+
}}} // try-catch-finally, cosaPod and lock finish here

0 commit comments

Comments
 (0)