Skip to content

Commit 2936759

Browse files
authored
Add verification steps when releasing the images. (apache#24520)
After the images are pushed in CI we are running the verification of the AMD image now. This cannot be really done during building and pushing the image, because we are using multi-platform images using remote builders so the image is not even available locally, so we need to actually pull the images after they are built in order to verify them. This PR adds those features: * ability to pull images for verification with --pull-flag * ability to verify slim images (regular tests are skipped and we only expect the preinstalled providers to be available * the steps to verify the images (both regular and slim) are added to the workflow
1 parent cabbf61 commit 2936759

File tree

10 files changed

+177
-112
lines changed

10 files changed

+177
-112
lines changed

.github/workflows/release_dockerhub_image.yml

+18-3
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,27 @@ jobs:
119119
${{ needs.build-info.outputs.skipLatest }}
120120
${{ needs.build-info.outputs.limitPlatform }}
121121
--limit-python ${{ matrix.python-version }} --slim-images
122-
- name: "Docker logout"
123-
run: docker logout
124-
if: always()
125122
- name: "Stop ARM instance"
126123
run: ./scripts/ci/images/ci_stop_arm_instance.sh
127124
if: always() && github.repository == 'apache/airflow'
125+
- name: >
126+
Verify regular AMD64 image: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }}
127+
run: >
128+
breeze verify-prod-image
129+
--pull-image
130+
--image-name
131+
${{github.repository}}:${{github.event.inputs.airflowVersion}}-python${{matrix.python-version}}
132+
- name: >
133+
Verify slim AMD64 image: ${{ github.event.inputs.airflowVersion }}, ${{ matrix.python-version }}
134+
run: >
135+
breeze verify-prod-image
136+
--pull-image
137+
--slim-image
138+
--image-name
139+
${{github.repository}}:slim-${{github.event.inputs.airflowVersion}}-python${{matrix.python-version}}
140+
- name: "Docker logout"
141+
run: docker logout
142+
if: always()
128143
- name: "Fix ownership"
129144
run: breeze fix-ownership
130145
if: always()

dev/breeze/src/airflow_breeze/commands/ci_image_commands.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
option_parallelism,
5555
option_platform,
5656
option_prepare_buildx_cache,
57+
option_pull_image,
5758
option_push_image,
5859
option_python,
5960
option_python_versions,
@@ -181,6 +182,7 @@
181182
"--image-name",
182183
"--python",
183184
"--image-tag",
185+
"--pull-image",
184186
],
185187
}
186188
],
@@ -270,7 +272,7 @@ def run_build(ci_image_params: BuildCiParams) -> None:
270272
@option_image_tag
271273
@option_tag_as_latest
272274
@click.argument('extra_pytest_args', nargs=-1, type=click.UNPROCESSED)
273-
def pull_image(
275+
def pull_ci_image(
274276
verbose: bool,
275277
dry_run: bool,
276278
python: str,
@@ -338,27 +340,33 @@ def pull_image(
338340
@option_github_repository
339341
@option_image_tag
340342
@option_image_name
343+
@option_pull_image
341344
@click.argument('extra_pytest_args', nargs=-1, type=click.UNPROCESSED)
342-
def verify_image(
345+
def verify_ci_image(
343346
verbose: bool,
344347
dry_run: bool,
345348
python: str,
346349
github_repository: str,
347350
image_name: str,
348351
image_tag: str,
352+
pull_image: bool,
349353
extra_pytest_args: Tuple,
350354
):
351355
"""Verify CI image."""
352356
perform_environment_checks(verbose=verbose)
353357
if image_name is None:
354358
build_params = BuildCiParams(python=python, image_tag=image_tag, github_repository=github_repository)
355359
image_name = build_params.airflow_image_name_with_tag
360+
if pull_image:
361+
command_to_run = ["docker", "pull", image_name]
362+
run_command(command_to_run, verbose=verbose, dry_run=dry_run, check=True)
356363
get_console().print(f"[info]Verifying CI image: {image_name}[/]")
357364
return_code, info = verify_an_image(
358365
image_name=image_name,
359366
verbose=verbose,
360367
dry_run=dry_run,
361368
image_type='CI',
369+
slim_image=False,
362370
extra_pytest_args=extra_pytest_args,
363371
)
364372
sys.exit(return_code)

dev/breeze/src/airflow_breeze/commands/production_image_commands.py

+14
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
option_parallelism,
5353
option_platform,
5454
option_prepare_buildx_cache,
55+
option_pull_image,
5556
option_push_image,
5657
option_python,
5758
option_python_versions,
@@ -184,6 +185,7 @@
184185
"--image-name",
185186
"--python",
186187
"--image-tag",
188+
"--pull-image",
187189
],
188190
}
189191
],
@@ -382,6 +384,12 @@ def pull_prod_image(
382384
@option_github_repository
383385
@option_image_tag
384386
@option_image_name
387+
@option_pull_image
388+
@click.option(
389+
'--slim-image',
390+
help='The image to verify is slim and non-slim tests should be skipped.',
391+
is_flag=True,
392+
)
385393
@click.argument('extra_pytest_args', nargs=-1, type=click.UNPROCESSED)
386394
def verify_prod_image(
387395
verbose: bool,
@@ -390,6 +398,8 @@ def verify_prod_image(
390398
github_repository: str,
391399
image_name: str,
392400
image_tag: str,
401+
pull_image: bool,
402+
slim_image: bool,
393403
extra_pytest_args: Tuple,
394404
):
395405
"""Verify Production image."""
@@ -399,13 +409,17 @@ def verify_prod_image(
399409
python=python, image_tag=image_tag, github_repository=github_repository
400410
)
401411
image_name = build_params.airflow_image_name_with_tag
412+
if pull_image:
413+
command_to_run = ["docker", "pull", image_name]
414+
run_command(command_to_run, verbose=verbose, dry_run=dry_run, check=True)
402415
get_console().print(f"[info]Verifying PROD image: {image_name}[/]")
403416
return_code, info = verify_an_image(
404417
image_name=image_name,
405418
verbose=verbose,
406419
dry_run=dry_run,
407420
image_type='PROD',
408421
extra_pytest_args=extra_pytest_args,
422+
slim_image=slim_image,
409423
)
410424
sys.exit(return_code)
411425

dev/breeze/src/airflow_breeze/utils/common_options.py

+6
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,9 @@
434434
show_default=True,
435435
help='Mode of constraints for PROD image building',
436436
)
437+
option_pull_image = click.option(
438+
'--pull-image',
439+
help="Pull image is missing before attempting to verify it.",
440+
is_flag=True,
441+
envvar='PULL_IMAGE',
442+
)

dev/breeze/src/airflow_breeze/utils/image.py

+1
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def run_pull_and_verify_image(
201201
image_type=image_params.image_type,
202202
dry_run=dry_run,
203203
verbose=verbose,
204+
slim_image=False,
204205
extra_pytest_args=extra_pytest_args,
205206
)
206207

dev/breeze/src/airflow_breeze/utils/run_tests.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828
def verify_an_image(
29-
image_name: str, image_type: str, dry_run: bool, verbose: bool, extra_pytest_args: Tuple
29+
image_name: str, image_type: str, dry_run: bool, verbose: bool, slim_image: bool, extra_pytest_args: Tuple
3030
) -> Tuple[int, str]:
3131
command_result = run_command(
3232
["docker", "inspect", image_name], dry_run=dry_run, verbose=verbose, check=False, stdout=DEVNULL
@@ -43,6 +43,8 @@ def verify_an_image(
4343
test_path = AIRFLOW_SOURCES_ROOT / "docker_tests" / "test_ci_image.py"
4444
env = os.environ.copy()
4545
env['DOCKER_IMAGE'] = image_name
46+
if slim_image:
47+
env['TEST_SLIM_IMAGE'] = 'true'
4648
command_result = run_command(
4749
[sys.executable, "-m", "pytest", str(test_path), *pytest_args, *extra_pytest_args],
4850
dry_run=dry_run,

docker_tests/test_prod_image.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# under the License.
1717

1818
import json
19+
import os
1920
import subprocess
2021
import tempfile
2122
from pathlib import Path
@@ -30,6 +31,7 @@
3031
run_bash_in_docker,
3132
run_python_in_docker,
3233
)
34+
from setup import PREINSTALLED_PROVIDERS
3335

3436
INSTALLED_PROVIDER_PATH = SOURCE_ROOT / "scripts" / "ci" / "installed_providers.txt"
3537

@@ -74,8 +76,11 @@ def test_bash_version(self):
7476

7577
class TestPythonPackages:
7678
def test_required_providers_are_installed(self):
77-
lines = (d.strip() for d in INSTALLED_PROVIDER_PATH.read_text().splitlines())
78-
lines = (d for d in lines)
79+
if os.environ.get("TEST_SLIM_IMAGE"):
80+
lines = PREINSTALLED_PROVIDERS
81+
else:
82+
lines = (d.strip() for d in INSTALLED_PROVIDER_PATH.read_text().splitlines())
83+
lines = (d for d in lines)
7984
packages_to_install = {f"apache-airflow-providers-{d.replace('.', '-')}" for d in lines}
8085
assert len(packages_to_install) != 0
8186

@@ -163,6 +168,7 @@ def test_pip_dependencies_conflict(self):
163168
"virtualenv": ["virtualenv"],
164169
}
165170

171+
@pytest.mark.skipif(os.environ.get("TEST_SLIM_IMAGE") == "true", reason="Skipped with slim image")
166172
@pytest.mark.parametrize("package_name,import_names", PACKAGE_IMPORTS.items())
167173
def test_check_dependencies_imports(self, package_name, import_names):
168174
run_python_in_docker(f"import {','.join(import_names)}")
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
8b4116c1808c84d491961283a4ddbec2

0 commit comments

Comments
 (0)