Skip to content

Commit 3987db8

Browse files
wangxinCopilot
authored andcommitted
ansible: support pulling ceos_image from docker registry (sonic-net#22794)
What is the motivation for this PR? In environments that enforce registry-only container image policies (e.g. Microsoft requiring all images to originate from ACR or MCR), the previous approach of building ceos_image locally or re-tagging a pulled image with a local name would trigger security alerts. This PR allows ceos_image to be sourced directly from a user-configured registry, so containers always reference the registry-prefixed image name and no locally-built alias is created. How did you do it? Three files are changed: ansible/group_vars/vm_host/ceos.yml Added three commented-out placeholder variables: ceos_registry, ceos_registry_username, ceos_registry_password. When ceos_registry is uncommented and set, the new registry logic is activated. Credentials are optional and only needed for authenticated registries. ansible/roles/vm_set/tasks/add_ceos_list.yml When ceos_registry is defined, check whether <registry>/<ceos_image> is already cached locally (a prior pull). If found, it is used directly — no docker tag is performed, so no local alias is created. If not cached and ceos_registry is defined, optionally log in (only when credentials are provided) and docker pull the image. Only falls back to the existing download-ceos_image_orig-and-build path when registry is not configured or the pull fails. ceos_image_found logic is registry-aware: when ceos_registry is defined, a plain local ceos_image does not count as "found", ensuring the registry path is always taken. ansible/roles/eos/tasks/ceos.yml and ceos_ensure_reachable.yml After loading group_vars/vm_host/ceos.yml, a docker_image_info check determines whether the registry image is available locally. ceos_effective_image is set to <registry>/<ceos_image> when the registry image is present, or plain ceos_image otherwise. All docker_container tasks use ceos_effective_image instead of ceos_image, so containers always reference the registry image in registry-enabled environments. How did you verify/test it? Tested "add-topo" by specifying ceos_registry. The ceos image from the registry is used successfully. Tested "add-topo" without specifying ceos_registry. The existing logic of using a local ceos image or preparing ceos image from ceos_image_orig works as expected. Signed-off-by: Xin Wang <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent e3d0fa0 commit 3987db8

4 files changed

Lines changed: 186 additions & 89 deletions

File tree

ansible/group_vars/vm_host/ceos.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,16 @@ ceos_image_url:
99
- "http://example1.com/cEOS64-lab-4.32.5M.tar"
1010
- "http://example2.com/cEOS64-lab-4.32.5M.tar"
1111
skip_ceos_image_downloading: false
12+
13+
# Registry settings for pulling ceos docker image. If ceos_registry is defined, the code will first
14+
# check whether ceos_image is already cached locally from the registry, and if not, try to pull it
15+
# from the registry before falling back to the download-and-build approach.
16+
#
17+
# Uncomment ceos_registry and set it to your registry URL to enable registry pulling.
18+
# If the registry requires authentication, also uncomment and set ceos_registry_username and
19+
# ceos_registry_password. If the registry is publicly accessible without authentication, leave the
20+
# username and password commented out.
21+
#
22+
# ceos_registry: "your-registry.example.com"
23+
# ceos_registry_username: "your-username"
24+
# ceos_registry_password: "your-password"

ansible/roles/eos/tasks/ceos.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,32 @@
2323
- include_vars: group_vars/vm_host/ceos.yml
2424
- include_tasks: ceos_config.yml
2525

26+
- name: Check if ceos_image from registry is available locally
27+
docker_image_info:
28+
name:
29+
- "{{ ceos_registry }}/{{ ceos_image }}"
30+
become: yes
31+
register: ceos_registry_image_info
32+
delegate_to: "{{ VM_host[0] }}"
33+
when: ceos_registry is defined
34+
35+
- name: Set ceos_effective_image
36+
set_fact:
37+
# Use registry-prefixed image name when the registry image is available locally (was pulled
38+
# from registry). This avoids creating a local alias and ensures containers always reference
39+
# the registry image, satisfying security requirements (e.g. Microsoft ACR/MCR policy).
40+
# Fall back to the plain ceos_image name when no registry is configured or registry image
41+
# is not available (e.g. pull failed and image was built from ceos_image_orig instead).
42+
ceos_effective_image: >-
43+
{{ ceos_registry + '/' + ceos_image
44+
if (ceos_registry is defined and ceos_registry_image_info.images | length > 0)
45+
else ceos_image }}
46+
2647
- name: Create cEOS container
2748
become: yes
2849
docker_container:
2950
name: ceos_{{ vm_set_name }}_{{ inventory_hostname }}
30-
image: "{{ ceos_image }}"
51+
image: "{{ ceos_effective_image }}"
3152
command: /sbin/init systemd.setenv=INTFTYPE=eth systemd.setenv=ETBA=1 systemd.setenv=SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 systemd.setenv=CEOS=1 systemd.setenv=EOS_PLATFORM=ceoslab systemd.setenv=container=docker systemd.setenv=MGMT_INTF=eth0
3253
pull: no
3354
state: started

ansible/roles/eos/tasks/ceos_ensure_reachable.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
- name: Set ceos_effective_image fallback if not already defined
2+
# ceos_effective_image is normally set by the caller (ceos.yml in the eos role) before this
3+
# file is included. This task provides a safe fallback in case this file is invoked
4+
# independently, so it does not fail with an undefined variable error.
5+
set_fact:
6+
ceos_effective_image: "{{ ceos_image }}"
7+
when: ceos_effective_image is not defined
8+
19
- block:
210
- name: set time out threshold
311
set_fact:
@@ -18,7 +26,7 @@
1826
become: yes
1927
docker_container:
2028
name: ceos_{{ vm_set_name }}_{{ inventory_hostname }}
21-
image: "{{ ceos_image }}"
29+
image: "{{ ceos_effective_image }}"
2230
command: /sbin/init systemd.setenv=INTFTYPE=eth systemd.setenv=ETBA=1 systemd.setenv=SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 systemd.setenv=CEOS=1 systemd.setenv=EOS_PLATFORM=ceoslab systemd.setenv=container=docker systemd.setenv=MGMT_INTF=eth0
2331
pull: no
2432
state: started

ansible/roles/vm_set/tasks/add_ceos_list.yml

Lines changed: 142 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,158 @@
1-
- name: Check if cEOS docker image exists or not
1+
- name: Check if cEOS docker image exists locally
22
docker_image_info:
33
name:
44
- "{{ ceos_image }}"
55
become: yes
6-
register: ceos_docker_image_stat
6+
register: ceos_local_image_stat
7+
8+
- name: Check if cEOS docker image from registry is already cached locally
9+
docker_image_info:
10+
name:
11+
- "{{ ceos_registry }}/{{ ceos_image }}"
12+
become: yes
13+
register: ceos_registry_cached_image_stat
14+
when: ceos_registry is defined
15+
16+
- name: Set fact for whether ceos_image is already available
17+
set_fact:
18+
# When registry is defined, only the registry-prefixed image is considered "found" - using
19+
# a local image in that case would bypass the registry requirement (e.g. Microsoft ACR/MCR).
20+
# When registry is not defined, only the locally-named image is considered.
21+
# The | bool filter ensures this is stored as a Python boolean, not the string "True"/"False",
22+
# so that "when: not ceos_image_found" evaluates correctly.
23+
ceos_image_found: "{{ ((ceos_registry is not defined and ceos_local_image_stat.images | length > 0) or
24+
(ceos_registry is defined and ceos_registry_cached_image_stat.images | length > 0)) | bool }}"
725

826
- name: Prepare ceos_image if it does not exist
927
block:
1028

11-
- name: Check if ceos_image_orig exists or not
12-
docker_image_info:
13-
name:
14-
- "{{ ceos_image_orig }}"
15-
become: yes
16-
register: ceos_image_orig_stat
29+
- name: Try to get ceos_image from registry
30+
block:
31+
32+
- name: Login to ceos registry if credentials are defined
33+
become: yes
34+
docker_login:
35+
registry_url: "{{ ceos_registry }}"
36+
username: "{{ ceos_registry_username }}"
37+
password: "{{ ceos_registry_password }}"
38+
when: >
39+
ceos_registry_username is defined and
40+
ceos_registry_password is defined
41+
42+
- name: Pull ceos_image from registry
43+
become: yes
44+
docker_image:
45+
name: "{{ ceos_registry }}/{{ ceos_image }}"
46+
source: pull
47+
register: ceos_registry_pull_result
48+
ignore_errors: yes
49+
50+
- name: Warn that registry pull failed, will fall back to download and build
51+
debug:
52+
msg: >-
53+
WARNING: Failed to pull {{ ceos_registry }}/{{ ceos_image }} from registry.
54+
Will fall back to the download-and-build path. Check ceos_registry and credentials.
55+
when: ceos_registry_pull_result is failed
56+
57+
when: ceos_registry is defined
1758

18-
- name: Prepare ceos_image_orig if it does not exist
59+
- name: Prepare ceos_image via download and build if registry pull failed or registry not defined
1960
block:
20-
- name: Check if local ceos image file exists or not
21-
stat:
22-
path: "{{ root_path }}/images/{{ ceos_image_filename }}"
23-
register: ceos_image_file_stat
2461

25-
- name: Download cEOS image file if no local ceos image file exists
62+
- name: Check if ceos_image_orig exists or not
63+
docker_image_info:
64+
name:
65+
- "{{ ceos_image_orig }}"
66+
become: yes
67+
register: ceos_image_orig_stat
68+
69+
- name: Prepare ceos_image_orig if it does not exist
2670
block:
27-
- name: Fail if skip_ceos_image_downloading is true
28-
fail:
29-
msg: [
30-
"Failed, no ceos docker image, no ceos image file and skip_ceos_image_downloading is true",
31-
"Please manually put cEOS image to {{ root_path }}/images/{{ ceos_image_filename }}"
32-
]
33-
when: skip_ceos_image_downloading == true
34-
35-
- name: Init ceos_image_urls when ceos_image_url value type is string
36-
set_fact:
37-
ceos_image_urls:
38-
- "{{ ceos_image_url }}"
39-
when: ceos_image_url | type_debug == 'string'
40-
41-
- name: Init ceos_image_urls when ceos_image_url value type is list
42-
set_fact:
43-
ceos_image_urls: "{{ ceos_image_url }}"
44-
when: ceos_image_url | type_debug == 'list'
45-
46-
- name: Init working_image_urls list
47-
set_fact:
48-
working_image_urls: []
49-
50-
- name: Loop ceos_image_urls to find out working URLs
51-
include_tasks: probe_image_url.yml
52-
loop: "{{ ceos_image_urls }}"
53-
54-
- name: Fail if no working ceos image download url is found
55-
fail:
56-
msg: [
57-
"Failed, no working ceos image download URL is found. There are 2 options to fix it:",
58-
" 1. Fix ceos_image_url defined in ansible/group_vars/vm_host/ceos.yml",
59-
" 2. Manually put cEOS image to {{ root_path }}/images/{{ ceos_image_filename }}",
60-
]
61-
when: working_image_urls | length == 0
62-
63-
- name: Ensure {{ root_path }}/images exists
64-
file: path={{ root_path }}/images state=directory
65-
66-
- name: Download cEOS image file from working ceos_image_urls using the first working URL
67-
get_url:
68-
url: "{{ working_image_urls[0] }}"
69-
dest: "{{ root_path }}/images/{{ ceos_image_filename }}"
70-
environment: "{{ proxy_env | default({}) }}"
71-
register: ceos_image_download_result
72-
73-
when: ceos_image_file_stat.stat.exists == false
74-
75-
- name: Import ceos_image_orig docker image
71+
- name: Check if local ceos image file exists or not
72+
stat:
73+
path: "{{ root_path }}/images/{{ ceos_image_filename }}"
74+
register: ceos_image_file_stat
75+
76+
- name: Download cEOS image file if no local ceos image file exists
77+
block:
78+
- name: Fail if skip_ceos_image_downloading is true
79+
fail:
80+
msg: [
81+
"Failed, no ceos docker image, no ceos image file and skip_ceos_image_downloading is true",
82+
"Please manually put cEOS image to {{ root_path }}/images/{{ ceos_image_filename }}"
83+
]
84+
when: skip_ceos_image_downloading == true
85+
86+
- name: Init ceos_image_urls when ceos_image_url value type is string
87+
set_fact:
88+
ceos_image_urls:
89+
- "{{ ceos_image_url }}"
90+
when: ceos_image_url | type_debug == 'string'
91+
92+
- name: Init ceos_image_urls when ceos_image_url value type is list
93+
set_fact:
94+
ceos_image_urls: "{{ ceos_image_url }}"
95+
when: ceos_image_url | type_debug == 'list'
96+
97+
- name: Init working_image_urls list
98+
set_fact:
99+
working_image_urls: []
100+
101+
- name: Loop ceos_image_urls to find out working URLs
102+
include_tasks: probe_image_url.yml
103+
loop: "{{ ceos_image_urls }}"
104+
105+
- name: Fail if no working ceos image download url is found
106+
fail:
107+
msg: [
108+
"Failed, no working ceos image download URL is found. There are 2 options to fix it:",
109+
" 1. Fix ceos_image_url defined in ansible/group_vars/vm_host/ceos.yml",
110+
" 2. Manually put cEOS image to {{ root_path }}/images/{{ ceos_image_filename }}",
111+
]
112+
when: working_image_urls | length == 0
113+
114+
- name: Ensure {{ root_path }}/images exists
115+
file: path={{ root_path }}/images state=directory
116+
117+
- name: Download cEOS image file from working ceos_image_urls using the first working URL
118+
get_url:
119+
url: "{{ working_image_urls[0] }}"
120+
dest: "{{ root_path }}/images/{{ ceos_image_filename }}"
121+
environment: "{{ proxy_env | default({}) }}"
122+
register: ceos_image_download_result
123+
124+
when: ceos_image_file_stat.stat.exists == false
125+
126+
- name: Import ceos_image_orig docker image
127+
become: yes
128+
shell: "docker import {{ root_path }}/images/{{ ceos_image_filename }} {{ ceos_image_orig }}"
129+
130+
when: ceos_image_orig_stat.images | length == 0
131+
132+
- name: Create directory for building ceos docker image
133+
become: yes
134+
file:
135+
path: "/tmp/ceosimage"
136+
state: directory
137+
138+
- name: Copy the ceos image template
76139
become: yes
77-
shell: "docker import {{ root_path }}/images/{{ ceos_image_filename }} {{ ceos_image_orig }}"
78-
79-
when: ceos_image_orig_stat.images | length == 0
80-
81-
- name: Create directory for building ceos docker image
82-
become: yes
83-
file:
84-
path: "/tmp/ceosimage"
85-
state: directory
86-
87-
- name: Copy the ceos image template
88-
become: yes
89-
template: src=ceos_dockerfile.j2 dest=/tmp/ceosimage/Dockerfile mode=0644
90-
91-
- name: Build the ceos image with increasing inotify limit
92-
become: yes
93-
docker_image:
94-
name: "{{ ceos_image }}"
95-
build:
96-
path: "/tmp/ceosimage"
97-
pull: no
98-
source: build
99-
100-
when: ceos_docker_image_stat.images | length == 0
140+
template: src=ceos_dockerfile.j2 dest=/tmp/ceosimage/Dockerfile mode=0644
141+
142+
- name: Build the ceos image with increasing inotify limit
143+
become: yes
144+
docker_image:
145+
name: "{{ ceos_image }}"
146+
build:
147+
path: "/tmp/ceosimage"
148+
pull: no
149+
source: build
150+
151+
when: >
152+
ceos_registry is not defined or
153+
(ceos_registry_pull_result is defined and ceos_registry_pull_result is failed)
154+
155+
when: not ceos_image_found
101156

102157
- name: Create VMs network
103158
become: yes

0 commit comments

Comments
 (0)