|
16 | 16 | from azext_confcom.container import ContainerImage, UserContainerImage |
17 | 17 | from azext_confcom.errors import eprint |
18 | 18 | from azext_confcom.fragment_util import sanitize_fragment_fields |
19 | | -from azext_confcom.oras_proxy import create_list_of_standalone_imports |
| 19 | +from azext_confcom.oras_proxy import create_list_of_standalone_imports, get_image_platforms |
20 | 20 | from azext_confcom.rootfs_proxy import SecurityPolicyProxy |
21 | 21 | from azext_confcom.template_util import (case_insensitive_dict_get, |
22 | 22 | compare_env_vars, |
|
41 | 41 | process_fragment_imports, |
42 | 42 | process_mounts, |
43 | 43 | process_mounts_from_config, |
44 | | - readable_diff) |
| 44 | + readable_diff, |
| 45 | + find_value_in_params_and_vars) |
45 | 46 | from azext_confcom.lib.images import get_image_platform # pylint: disable=unused-import |
46 | 47 | from azext_confcom.lib.defaults import get_debug_mode_exec_procs |
47 | 48 | from knack.log import get_logger |
@@ -669,6 +670,36 @@ def set_images(self, images: List[ContainerImage]) -> None: |
669 | 670 | self._images = images |
670 | 671 |
|
671 | 672 |
|
| 673 | +def validate_image_platform(image_name: str, platform: str) -> None: |
| 674 | + """Validate that a single-platform image matches the specified platform. |
| 675 | +
|
| 676 | + Uses the registry manifest to detect supported platforms. If the image |
| 677 | + supports only one platform and it differs from the requested platform, |
| 678 | + an error is raised. Multi-platform images and detection failures are |
| 679 | + allowed to pass through. |
| 680 | + """ |
| 681 | + try: |
| 682 | + supported = get_image_platforms(image_name) |
| 683 | + except Exception: # pylint: disable=broad-except |
| 684 | + # If registry detection fails, skip validation gracefully |
| 685 | + return |
| 686 | + |
| 687 | + if not supported: |
| 688 | + return |
| 689 | + |
| 690 | + if len(supported) == 1 and supported[0] != platform: |
| 691 | + eprint( |
| 692 | + f'Image "{image_name}" only supports platform "{supported[0]}", ' |
| 693 | + f'which does not match the specified platform "{platform}".' |
| 694 | + ) |
| 695 | + |
| 696 | + if len(supported) > 1 and platform not in supported: |
| 697 | + eprint( |
| 698 | + f'Image "{image_name}" supports platforms {supported}, ' |
| 699 | + f'which does not include the specified platform "{platform}".' |
| 700 | + ) |
| 701 | + |
| 702 | + |
672 | 703 | # pylint: disable=R0914, |
673 | 704 | def load_policy_from_arm_template_str( |
674 | 705 | template_data: str, |
@@ -830,6 +861,10 @@ def load_policy_from_arm_template_str( |
830 | 861 | f'Field ["{config.ACI_FIELD_TEMPLATE_IMAGE}"] is empty or cannot be found' |
831 | 862 | ) |
832 | 863 |
|
| 864 | + # Resolve ARM parameters/variables to get the real image name for validation |
| 865 | + resolved_image = find_value_in_params_and_vars(all_params, all_vars, image_name) |
| 866 | + validate_image_platform(resolved_image, platform) |
| 867 | + |
833 | 868 | exec_processes = [] |
834 | 869 | extract_probe(exec_processes, image_properties, config.ACI_FIELD_CONTAINERS_READINESS_PROBE) |
835 | 870 | extract_probe(exec_processes, image_properties, config.ACI_FIELD_CONTAINERS_LIVENESS_PROBE) |
@@ -920,6 +955,8 @@ def load_policy_from_image_name( |
920 | 955 |
|
921 | 956 | containers = [] |
922 | 957 | for image_name in image_names: |
| 958 | + validate_image_platform(image_name, platform) |
| 959 | + |
923 | 960 | container = {} |
924 | 961 | # assign just the fields that are expected |
925 | 962 | # the values will come when calling |
@@ -1037,6 +1074,8 @@ def load_policy_from_json( |
1037 | 1074 | f'Field ["{config.ACI_FIELD_TEMPLATE_IMAGE}"] is empty or cannot be found' |
1038 | 1075 | ) |
1039 | 1076 |
|
| 1077 | + validate_image_platform(image_name, platform) |
| 1078 | + |
1040 | 1079 | container_name = case_insensitive_dict_get( |
1041 | 1080 | container, config.ACI_FIELD_CONTAINERS_NAME |
1042 | 1081 | ) or image_name |
@@ -1250,6 +1289,8 @@ def load_policy_from_virtual_node_yaml_str( |
1250 | 1289 | if not image: |
1251 | 1290 | eprint("Container does not have an image field") |
1252 | 1291 |
|
| 1292 | + validate_image_platform(image, platform) |
| 1293 | + |
1253 | 1294 | # env vars |
1254 | 1295 | envs = process_env_vars_from_yaml( |
1255 | 1296 | container, |
|
0 commit comments