3333 type : boolean
3434 required : false
3535 default : true
36+ push-dirty :
37+ description : Push scanned images that have vulnerabilities?
38+ type : boolean
39+ required : false
40+ # NOTE(Alex-Welsh): This default should be flipped once we resolve existing failures
41+ default : true
3642
3743env :
3844 ANSIBLE_FORCE_COLOR : True
5460 id : openstack_release
5561 run : |
5662 BRANCH=$(awk -F'=' '/defaultbranch/ {print $2}' .gitreview)
57- echo "openstack_release=${BRANCH}" | sed "s| stable/|| " >> $GITHUB_OUTPUT
63+ echo "openstack_release=${BRANCH}" | sed -E "s,( stable|unmaintained)/,, " >> $GITHUB_OUTPUT
5864
5965 # Generate a tag to apply to all built container images.
6066 # Without this, each kayobe * container image build command would use a different tag.
@@ -100,7 +106,15 @@ jobs:
100106 - name : Install package dependencies
101107 run : |
102108 sudo apt update
103- sudo apt install -y build-essential git unzip nodejs python3-wheel python3-pip python3-venv
109+ sudo apt install -y build-essential git unzip nodejs python3-wheel python3-pip python3-venv curl jq wget
110+
111+ - name : Install gh
112+ run : |
113+ sudo mkdir -p -m 755 /etc/apt/keyrings && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
114+ sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
115+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
116+ sudo apt update
117+ sudo apt install gh -y
104118
105119 - name : Checkout
106120 uses : actions/checkout@v4
@@ -118,6 +132,10 @@ jobs:
118132 run : |
119133 docker ps
120134
135+ - name : Install Trivy
136+ run : |
137+ curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.49.0
138+
121139 - name : Install Kayobe
122140 run : |
123141 mkdir -p venvs &&
@@ -132,6 +150,10 @@ jobs:
132150 - name : Install Docker Python SDK
133151 run : |
134152 sudo pip install docker
153+
154+ - name : Get Kolla tag
155+ id : write-kolla-tag
156+ run : echo "kolla-tag=${{ needs.generate-tag.outputs.openstack_release }}-${{ matrix.distro }}-${{ matrix.distro == 'rocky' && '9' || 'jammy' }}-${{ needs.generate-tag.outputs.datetime_tag }}" >> $GITHUB_OUTPUT
135157
136158 - name : Configure localhost as a seed
137159 run : |
@@ -153,67 +175,124 @@ jobs:
153175 env :
154176 KAYOBE_VAULT_PASSWORD : ${{ secrets.KAYOBE_VAULT_PASSWORD }}
155177
156- - name : Build and push kolla overcloud images
178+ - name : Create build logs output directory
179+ run : mkdir image-build-logs
180+
181+ - name : Build kolla overcloud images
182+ id : build_overcloud_images
183+ continue-on-error : true
157184 run : |
158- args="${{ github.event. inputs.regexes }}"
185+ args="${{ inputs.regexes }}"
159186 args="$args -e kolla_base_distro=${{ matrix.distro }}"
160- args="$args -e kolla_tag=$KOLLA_TAG "
187+ args="$args -e kolla_tag=${{ steps.write-kolla-tag.outputs.kolla-tag }} "
161188 args="$args -e stackhpc_repo_mirror_auth_proxy_enabled=true"
162- if ${{ inputs.push }} == 'true'; then
163- args="$args --push"
164- fi
165189 source venvs/kayobe/bin/activate &&
166190 source src/kayobe-config/kayobe-env --environment ci-builder &&
167191 kayobe overcloud container image build $args
168192 env :
169193 KAYOBE_VAULT_PASSWORD : ${{ secrets.KAYOBE_VAULT_PASSWORD }}
170- KOLLA_TAG : " ${{ needs.generate-tag.outputs.openstack_release }}-${{ matrix.distro }}-${{ matrix.distro == 'rocky' && '9' || 'jammy' }}-${{ needs.generate-tag.outputs.datetime_tag }}"
171- if : github.event.inputs.overcloud == 'true'
194+ if : inputs.overcloud
195+
196+ - name : Copy overcloud container image build logs to output directory
197+ run : sudo mv /var/log/kolla-build.log image-build-logs/kolla-build-overcloud.log
198+ if : inputs.overcloud
172199
173- - name : Build and push kolla seed images
200+ - name : Build kolla seed images
201+ id : build_seed_images
202+ continue-on-error : true
174203 run : |
175204 args="-e kolla_base_distro=${{ matrix.distro }}"
176- args="$args -e kolla_tag=$KOLLA_TAG "
205+ args="$args -e kolla_tag=${{ steps.write-kolla-tag.outputs.kolla-tag }} "
177206 args="$args -e stackhpc_repo_mirror_auth_proxy_enabled=true"
178- if ${{ inputs.push }} == 'true'; then
179- args="$args --push"
180- fi
181207 source venvs/kayobe/bin/activate &&
182208 source src/kayobe-config/kayobe-env --environment ci-builder &&
183209 kayobe seed container image build $args
184210 env :
185211 KAYOBE_VAULT_PASSWORD : ${{ secrets.KAYOBE_VAULT_PASSWORD }}
186- KOLLA_TAG : " ${{ needs.generate-tag.outputs.openstack_release }}-${{ matrix.distro }}-${{ matrix.distro == 'rocky' && '9' || 'jammy' }}-${{ needs.generate-tag.outputs.datetime_tag }}"
187- if : github.event.inputs.seed == 'true'
212+ if : inputs.seed
213+
214+ - name : Copy seed container image build logs to output directory
215+ run : sudo mv /var/log/kolla-build.log image-build-logs/kolla-build-seed.log
216+ if : inputs.seed
188217
189218 - name : Get built container images
190- run : |
191- docker image ls --filter "reference=ark.stackhpc.com/stackhpc-dev/*:*${{ matrix.distro }}*${{ needs.generate-tag.outputs.datetime_tag }}" > ${{ matrix.distro }}-container-images
219+ run : docker image ls --filter "reference=ark.stackhpc.com/stackhpc-dev/*:${{ steps.write-kolla-tag.outputs.kolla-tag }}" > ${{ matrix.distro }}-container-images
192220
193221 - name : Fail if no images have been built
194222 run : if [ $(wc -l < ${{ matrix.distro }}-container-images) -le 1 ]; then exit 1; fi
195223
196- - name : Upload container images artifact
224+ - name : Scan built container images
225+ run : src/kayobe-config/tools/scan-images.sh ${{ matrix.distro }} ${{ steps.write-kolla-tag.outputs.kolla-tag }}
226+
227+ - name : Move image scan logs to output artifact
228+ run : mv image-scan-output image-build-logs/image-scan-output
229+
230+ - name : Fail if no images have passed scanning
231+ run : if [ $(wc -l < image-build-logs/image-scan-output/clean-images.txt) -le 0 ]; then exit 1; fi
232+ if : ${{ !inputs.push-dirty }}
233+
234+ - name : Copy clean images to push-attempt-images list
235+ run : cp image-build-logs/image-scan-output/clean-images.txt image-build-logs/push-attempt-images.txt
236+ if : inputs.push
237+
238+ - name : Append dirty images to push list
239+ run : |
240+ cat image-build-logs/image-scan-output/dirty-images.txt >> image-build-logs/push-attempt-images.txt
241+ if : ${{ inputs.push && inputs.push-dirty }}
242+
243+ - name : Push images
244+ run : |
245+ touch image-build-logs/push-failed-images.txt
246+ source venvs/kayobe/bin/activate &&
247+ source src/kayobe-config/kayobe-env --environment ci-builder &&
248+ kayobe playbook run ${KAYOBE_CONFIG_PATH}/ansible/docker-registry-login.yml &&
249+
250+ while read -r image; do
251+ # Retries!
252+ for i in {1..5}; do
253+ if docker push $image; then
254+ echo "Pushed $image"
255+ break
256+ elif $i == 5; then
257+ echo "Failed to push $image"
258+ echo $image >> image-build-logs/push-failed-images.txt
259+ else
260+ echo "Failed on retry $i"
261+ sleep 5
262+ fi;
263+ done
264+ done < image-build-logs/push-attempt-images.txt
265+ shell : bash
266+ env :
267+ KAYOBE_VAULT_PASSWORD : ${{ secrets.KAYOBE_VAULT_PASSWORD }}
268+ if : inputs.push
269+
270+ - name : Upload output artifact
197271 uses : actions/upload-artifact@v4
198272 with :
199- name : ${{ matrix.distro }} container images
200- path : ${{ matrix.distro }}-container-images
273+ name : ${{ matrix.distro }}-logs
274+ path : image-build-logs
201275 retention-days : 7
276+ if : ${{ !cancelled() }}
277+
278+ - name : Fail when images failed to build
279+ run : echo "An image build failed. Check the workflow artifact for build logs" && exit 1
280+ if : ${{ steps.build_overcloud_images.outcome == 'failure' || steps.build_seed_images.outcome == 'failure' }}
281+
282+ - name : Fail when images failed to push
283+ run : if [ $(wc -l < image-build-logs/push-failed-images.txt) -gt 0 ]; then cat image-build-logs/push-failed-images.txt && exit 1; fi
284+ if : ${{ !cancelled() }}
285+
286+ - name : Fail when images failed scanning
287+ run : if [ $(wc -l < image-build-logs/dirty-images.txt) -gt 0 ]; then cat image-build-logs/dirty-images.txt && exit 1; fi
288+ if : ${{ !inputs.push-dirty && !cancelled() }}
202289
203- sync-container-repositories :
204- name : Trigger container image repository sync
205- needs :
206- - container-image-build
207- if : github.repository == 'stackhpc/stackhpc-kayobe-config' && inputs.push
208- runs-on : ubuntu-latest
209- permissions : {}
210- steps :
211290 # NOTE(mgoddard): Trigger another CI workflow in the
212291 # stackhpc-release-train repository.
213292 - name : Trigger container image repository sync
214293 run : |
215294 filter='${{ inputs.regexes }}'
216- if [[ -n $filter ]] && [[ ${{ github.event. inputs.seed }} == 'true' ]]; then
295+ if [[ -n $filter ]] && [[ ${{ inputs.seed }} == 'true' ]]; then
217296 filter="$filter bifrost"
218297 fi
219298 gh workflow run \
@@ -224,7 +303,9 @@ jobs:
224303 -f sync-old-images=false
225304 env :
226305 GITHUB_TOKEN : ${{ secrets.STACKHPC_RELEASE_TRAIN_TOKEN }}
306+ if : ${{ github.repository == 'stackhpc/stackhpc-kayobe-config' && inputs.push && !cancelled() }}
227307
228308 - name : Display link to container image repository sync workflows
229309 run : |
230310 echo "::notice Container image repository sync workflows: https://github.com/stackhpc/stackhpc-release-train/actions/workflows/container-sync.yml"
311+ if : ${{ github.repository == 'stackhpc/stackhpc-kayobe-config' && inputs.push && !cancelled() }}
0 commit comments