Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
432 lines (391 loc) · 24.7 KB
/
Copy pathMakefile
File metadata and controls
432 lines (391 loc) · 24.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# Defines the container runtime to use for building images and running tests. We
# default to "docker" because it works in most environments. Most users will
# have Docker installed, or use Podman with the "alias docker=podman" set up. In
# GitHub actions runner VM (ubuntu) both Podman and Docker are installed so we
# set this variable to "podman" because we want to use it in CI.
export CONTAINER_RUNTIME?=docker
# helper function to turn a string into lower case
lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
ifneq ($(CI_REGISTRY),)
export IMAGE_PATH?=$(call lc,$(CI_REGISTRY)/$(CI_PROJECT_NAMESPACE)/notconf/)
endif
ifneq ($(CI_PIPELINE_ID),)
PNS:=$(CI_PIPELINE_ID)
else ifneq ($(GITHUB_RUN_ID),)
PNS:=$(GITHUB_RUN_ID)
else
PNS:=$(shell whoami | sed 's/[^[:alnum:]._-]\+/_/g')
endif
# If we are running in CI and on the default branch (like 'main' or 'master'),
# disable the build cache for docker builds. We do this with ?= operator in
# make so we only set DOCKER_BUILD_CACHE_ARG if it is not already set, this
# makes it possible to still use the cache if explicitly set through
# environment variables in CI.
ifneq ($(CI),)
ifeq ($(CI_COMMIT_REF_NAME),$(CI_DEFAULT_BRANCH))
DOCKER_BUILD_CACHE_ARG?=--no-cache
endif
endif
# Include the architecture (x86_64 or aarch64) in the image tag if it is set. We
# use this in CI to build and push images for multiple architectures, which are
# then combined in a manifest list.
ifdef ARCH
export IMAGE_TAG?=$(PNS)-$(ARCH)
RELEASE_IMAGE_TAG=-$(ARCH)
else
export IMAGE_TAG?=$(PNS)
RELEASE_IMAGE_TAG=
endif
# BuildKit speeds up the image builds by running independent stages in a
# multi-stage Dockerfile concurrently. BuildKit is a breeze to use with Docker -
# everything just works automagically when you set the env var. The process is a
# bit more involved when using Podman so we are currently only using BuildKit on
# Docker.
export DOCKER_BUILDKIT=1
# The standardized OCI image spec does not store the healthcheck in image
# metadata, so there is no support for the HEALTHCHECK directive in the
# Dockerfile. We can use the "docker" image spec with Podman.
export BUILDAH_FORMAT=docker
.PHONY: clone-deps build test tag-release push-release push test tag-release-composed-notconf push-release-composed-notconf
clone-or-update: BRANCH?=devel
clone-or-update: DIR:=$(basename $(lastword $(subst /, ,$(REPOSITORY))))
clone-or-update:
@mkdir -p src
if ! git clone $(REPOSITORY) src/$(DIR); then \
cd src/$(DIR); \
git fetch origin; \
fi
cd src/$(DIR); \
git checkout $(BRANCH); \
# Reset to origin branch if it exists, otherwise reset to commit hash \
git show-ref --verify refs/remotes/origin/$(BRANCH) 2>&1 >/dev/null && git reset --hard origin/$(BRANCH) || git reset --hard $(BRANCH); \
# The sysrepo / netopeer2 projects appear to use a git workflow where the
# 'master' branch is stable and the 'devel' branch is the integration branch
# where new features and fixes first get introduced or merged. The pace of
# changes in the development branch is quite high which makes it difficult to
# keep up with new features (and bugs) so we now have the option of pinning a
# specific version (hash) of the development branches.
# These are defined in the versions.json file. The top dictionary key is the
# branch name or our custom pinning name. The value is a dictionary with the
# keys being the project names and the values being the git commit hash or
# branch name. If the branch name is not defined for a project, the default is
# to use the branch name from the top level dictionary.
PIN_NAME?=2025-08-04-rousette
clone-deps:
$(MAKE) clone-or-update REPOSITORY=https://github.com/CESNET/libyang.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."libyang" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/sysrepo/sysrepo.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."sysrepo" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/CESNET/libnetconf2.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."libnetconf2" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/CESNET/netopeer2.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."netopeer2" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/CESNET/rousette.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."rousette" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/CESNET/libyang-cpp.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."libyang-cpp" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/sysrepo/sysrepo-cpp.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."sysrepo-cpp" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/nghttp2/nghttp2-asio.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."nghttp2-asio" // "$(PIN_NAME)"' versions.json)
$(MAKE) clone-or-update REPOSITORY=https://github.com/HowardHinnant/date.git BRANCH=$(shell jq --raw-output '."$(PIN_NAME)"."date" // "v3.0.1"' versions.json)
CONTAINER_BUILD_ARGS=--build-arg SYSREPO_PYTHON_VERSION=$(shell jq --raw-output '."$(PIN_NAME)"."sysrepo-python" // "$(PIN_NAME)"' versions.json) --build-arg LIBYANG_PYTHON_VERSION=$(shell jq --raw-output '."$(PIN_NAME)"."libyang-python" // "$(PIN_NAME)"' versions.json)
build:
# We explicitly build the first 'build-tools-source' stage (where the
# dependencies are installed and source code is pulled), which allows us to
# control caching of it through the DOCKER_BUILD_CACHE_ARG.
$(CONTAINER_RUNTIME) build --target build-tools-source $(DOCKER_BUILD_CACHE_ARG) .
$(CONTAINER_RUNTIME) build --target notconf-release -t $(IMAGE_PATH)notconf:$(IMAGE_TAG) --build-arg BUILD_TYPE=Release $(CONTAINER_BUILD_ARGS) .
$(CONTAINER_RUNTIME) build --target notconf-debug -t $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug --build-arg BUILD_TYPE=Debug $(CONTAINER_BUILD_ARGS) .
tag-release:
$(CONTAINER_RUNTIME) tag $(IMAGE_PATH)notconf:$(IMAGE_TAG) $(IMAGE_PATH)notconf:latest$(RELEASE_IMAGE_TAG)
$(CONTAINER_RUNTIME) tag $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug $(IMAGE_PATH)notconf:debug$(RELEASE_IMAGE_TAG)
push-release:
$(CONTAINER_RUNTIME) push $(IMAGE_PATH)notconf:debug$(RELEASE_IMAGE_TAG)
$(CONTAINER_RUNTIME) push $(IMAGE_PATH)notconf:latest$(RELEASE_IMAGE_TAG)
push:
$(CONTAINER_RUNTIME) push $(IMAGE_PATH)notconf:$(IMAGE_TAG)
$(CONTAINER_RUNTIME) push $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug
create-manifest:
$(CONTAINER_RUNTIME) manifest create $(IMAGE_PATH)notconf:$(IMAGE_TAG) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-x86_64 $(IMAGE_PATH)notconf:$(IMAGE_TAG)-aarch64
$(CONTAINER_RUNTIME) manifest create $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug $(IMAGE_PATH)notconf:$(IMAGE_TAG)-x86_64-debug $(IMAGE_PATH)notconf:$(IMAGE_TAG)-aarch64-debug
push-manifest:
$(CONTAINER_RUNTIME) manifest push $(IMAGE_PATH)notconf:$(IMAGE_TAG) docker://$(IMAGE_PATH)notconf:$(IMAGE_TAG)
$(CONTAINER_RUNTIME) manifest push $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug docker://$(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug
create-release-manifest:
$(CONTAINER_RUNTIME) manifest create $(IMAGE_PATH)notconf:latest $(IMAGE_PATH)notconf:latest-x86_64 $(IMAGE_PATH)notconf:latest-aarch64
$(CONTAINER_RUNTIME) manifest create $(IMAGE_PATH)notconf:debug $(IMAGE_PATH)notconf:debug-x86_64 $(IMAGE_PATH)notconf:debug-aarch64
push-release-manifest:
$(CONTAINER_RUNTIME) manifest push $(IMAGE_PATH)notconf:latest docker://$(IMAGE_PATH)notconf:latest
$(CONTAINER_RUNTIME) manifest push $(IMAGE_PATH)notconf:debug docker://$(IMAGE_PATH)notconf:debug
# Release manifest list name for composed images is the composed image name for
# a given YANG_PATH with stripped -$(PNS)-$(ARCH) (a.k.a. $(IMAGE_TAG)) suffix.
# ghcr.io/notconf/notconf-junos:21.1R1-12743215247-x86_64 -> ghcr.io/notconf/notconf-junos:21.1R
RELEASE_COMPOSED_MANIFEST_LIST_NAME = $(subst -$(IMAGE_TAG),,$(IMAGE_PATH)notconf-$(COMPOSE_IMAGE_NAME):$(COMPOSE_IMAGE_TAG))
# Release composed image name is the composed image name for a given YANG_PATH
# with stripped $(PNS)-$(ARCH) (a.k.a. $(IMAGE_TAG)) suffix.
# ghcr.io/notconf/notconf-junos:21.1R1-12743215247-x86_64 -> ghcr.io/notconf/notconf-junos:21.1R1
RELEASE_COMPOSED_IMAGE_NAME = $(IMAGE_PATH)notconf-$(COMPOSE_IMAGE_NAME):$(COMPOSE_IMAGE_TAG_PREFIX)
create-release-composed-notconf-manifest:
$(CONTAINER_RUNTIME) manifest create $(RELEASE_COMPOSED_MANIFEST_LIST_NAME)
$(CONTAINER_RUNTIME) manifest add $(RELEASE_COMPOSED_MANIFEST_LIST_NAME) $(RELEASE_COMPOSED_IMAGE_NAME)-x86_64
$(CONTAINER_RUNTIME) manifest add $(RELEASE_COMPOSED_MANIFEST_LIST_NAME) $(RELEASE_COMPOSED_IMAGE_NAME)-aarch64
push-release-composed-notconf-manifest:
$(CONTAINER_RUNTIME) manifest push $(RELEASE_COMPOSED_MANIFEST_LIST_NAME) docker://$(RELEASE_COMPOSED_MANIFEST_LIST_NAME)
tag-release-composed-notconf: composed-notconf.txt
for tag in $$(uniq $<); do release_tag=$$(echo $${tag} | sed 's/-$(IMAGE_TAG)$$/$(RELEASE_IMAGE_TAG)/'); $(CONTAINER_RUNTIME) tag $${tag} $${release_tag}; done
push-release-composed-notconf: composed-notconf.txt
for release_tag in $$(sed 's/-$(IMAGE_TAG)$$/$(RELEASE_IMAGE_TAG)/g' $< | uniq); do $(CONTAINER_RUNTIME) push $${release_tag}; done
push-composed-notconf: composed-notconf.txt
for tag in $$(uniq $<); do $(CONTAINER_RUNTIME) push $${tag}; done
test:
$(MAKE) test-notconf-mount
$(MAKE) test-compose-yang YANG_PATH=test/yang-modules
test-yangmodels:
> composed-notconf.txt
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/nokia/7x50_YangModels/latest_sros_21.20
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/nokia/7x50_YangModels/latest_sros_22.2
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/juniper/21.1/21.1R1/junos
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/juniper/23.4/23.4R1/native/conf-and-rpcs/junos
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/cisco/xr/771
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/cisco/xr/2411
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/cisco/xr/2531
$(MAKE) test-compose-yang YANG_PATH=yang/vendor/cisco/nx/10.4-4
# test-notconf-mount: start a notconf:latest container with the test YANG
# modules mounted to /yang-modules in the container. All YANG modules and XML
# init files in the directory are installed into sysrepo automatically at
# container startup.
test-notconf-mount: export CNT_PREFIX=test-notconf-mount-$(PNS)
test-notconf-mount:
-$(CONTAINER_RUNTIME) rm -f $(CNT_PREFIX)
# Usually we would start the notconf container with the desired YANG module
# (located on host) mounted to /yang-modules (in container). When the test
# itself is executed in a (CI runner) container bind mounting a path won't work
# because the path does not exist on the host, only in the test container. As a
# workaround we first create the container and then copy the YANG module to the
# target location. The following command would probably work on your local machine:
# $(CONTAINER_RUNTIME) run -d --name $(CNT_PREFIX) -v $$(pwd)/test/yang-modules:/yang-modules $(IMAGE_PATH)notconf:$(IMAGE_TAG)
$(CONTAINER_RUNTIME) create --log-driver json-file --name $(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)
$(CONTAINER_RUNTIME) cp test/yang-modules $(CNT_PREFIX):/
$(CONTAINER_RUNTIME) start $(CNT_PREFIX)
$(MAKE) wait-healthy
$(MAKE) test-notconf-netconf
$(MAKE) test-notconf-restconf
$(MAKE) save-logs
$(MAKE) test-stop
test-notconf-netconf:
@echo "=== Running NETCONF tests ==="
@echo "Testing startup configuration retrieval..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --get-config -x /bob/startup | grep Robert
@echo "Testing configuration update via NETCONF..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --ns test=urn:notconf:test --set /test:bob/test:bert=Robert
@echo "Verifying the configuration update..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --get-config -x /bob/bert | grep Robert
@echo "Testing operational data retrieval..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --get -x /bob/state/great | grep success
@echo "Testing configuration data with enabled feature..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --get-config -x /bob/alice | grep super
@echo "=== All NETCONF tests passed ==="
test-notconf-restconf:
@echo "=== Running RESTCONF tests ==="
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -s http://localhost/.well-known/host-meta | grep -q restconf
@echo "Testing YANG library endpoint..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -sf -u admin:admin http://localhost/restconf/data/ietf-yang-library:modules-state | grep -q modules-state
@echo "Testing operational data retrieval..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -sf -u admin:admin http://localhost/restconf/data/test:bob/state | grep -q great
@echo "Testing configuration data retrieval..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -sf -u admin:admin http://localhost/restconf/data/test:bob | grep -q alice
@echo "Testing RESTCONF capabilities..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -sf -u admin:admin http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities | grep -q capability
@echo "Testing PATCH operation..."
@echo "Sending PATCH request to update test:bob/bert..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -u admin:admin -X PATCH \
-H "Content-Type: application/yang-data+json" \
-d '{"test:bob": {"bert": "Updated"}}' \
http://localhost/restconf/data/test:bob
@echo "Verifying the update via RESTCONF (using NMDA to read from running datastore)..."
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug curl -sf -u admin:admin "http://localhost/restconf/ds/ietf-datastores:running/test:bob/bert" | grep -q Updated || \
(echo "PATCH test failed - value was not updated"; exit 1)
@echo "=== All RESTCONF tests passed ==="
# test-restconf-full: Start a container and run RESTCONF tests
test-restconf-full: export CNT_PREFIX=test-restconf-$(PNS)
test-restconf-full:
-$(CONTAINER_RUNTIME) rm -f $(CNT_PREFIX)
$(CONTAINER_RUNTIME) create --log-driver json-file --name $(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug
$(CONTAINER_RUNTIME) cp test/yang-modules $(CNT_PREFIX):/
$(CONTAINER_RUNTIME) start $(CNT_PREFIX)
# Start rousette in the background
$(CONTAINER_RUNTIME) exec -d $(CNT_PREFIX) /bin/sh -c "sleep 5 && rousette"
$(MAKE) wait-healthy CNT_PREFIX=$(CNT_PREFIX)
$(MAKE) test-restconf CNT_PREFIX=$(CNT_PREFIX)
$(MAKE) save-logs CNT_PREFIX=$(CNT_PREFIX)
$(MAKE) test-stop CNT_PREFIX=$(CNT_PREFIX)
test-stop: CNT_PREFIX?=test-notconf
test-stop:
$(CONTAINER_RUNTIME) ps -aqf name=$(CNT_PREFIX) | xargs --no-run-if-empty $(CONTAINER_RUNTIME) rm -f
# This test exports the images we built with Podman to Docker and then runs the
# test suite in Docker. Obviously both container runtimes must be installed on
# the machine.
test-podman-to-docker:
podman save $(IMAGE_PATH)notconf:$(IMAGE_TAG) | docker load
podman save $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug | docker load
CONTAINER_RUNTIME=docker $(MAKE) test
save-logs: CNT_PREFIX?=test-notconf
save-logs:
mkdir -p container-logs
@for c in $$($(CONTAINER_RUNTIME) ps -af name=$(CNT_PREFIX) --format '{{.Names}}'); do \
echo "== Collecting $(CONTAINER_RUNTIME) logs from $${c}"; \
$(CONTAINER_RUNTIME) logs --timestamps $${c} > container-logs/$(CONTAINER_RUNTIME)_$${c}.log 2>&1; \
$(CONTAINER_RUNTIME) inspect $${c} > container-logs/$(CONTAINER_RUNTIME)_$${c}_inspect.log; \
$(CONTAINER_RUNTIME) run -i --rm --network container:$${c} $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --hello > container-logs/$(CONTAINER_RUNTIME)_$${c}_netconf.log || true; \
for logfile in $$($(CONTAINER_RUNTIME) exec $${c} sh -c 'ls /log/*.log'); do \
filename=$$(basename $${logfile}); \
$(CONTAINER_RUNTIME) cp $${c}:$${logfile} container-logs/$(CONTAINER_RUNTIME)_$${c}_$${filename} 2>/dev/null || true; \
done; \
done
SHELL=/bin/bash
wait-healthy:
@echo "Waiting (up to 900 seconds) for containers with prefix $(CNT_PREFIX) to become healthy"
ifeq ($(CONTAINER_RUNTIME),docker)
@OLD_COUNT=0; for I in $$(seq 1 900); do \
STOPPED=$$($(CONTAINER_RUNTIME) ps -a --filter name=$(CNT_PREFIX) | grep "Exited"); \
if [ -n "$${STOPPED}" ]; then \
echo -e "\e[31m=== $${SECONDS}s elapsed - Container(s) unexpectedly exited"; \
echo -e "$${STOPPED} \\e[0m"; \
exit 1; \
fi; \
COUNT=$$($(CONTAINER_RUNTIME) ps --filter name=$(CNT_PREFIX) | egrep "(unhealthy|health: starting)" | wc -l); \
if [ $${COUNT} -gt 0 ]; then \
if [ $${OLD_COUNT} -ne $${COUNT} ];\
then \
echo -e "\e[31m=== $${SECONDS}s elapsed - Found unhealthy/starting ($${COUNT}) containers";\
$(CONTAINER_RUNTIME) ps --filter name=$(CNT_PREFIX) | egrep "(unhealthy|health: starting)" | awk '{ print $$(NF) }';\
echo -e "Checking again every 1 second, no more messages until changes detected\\e[0m"; \
fi;\
sleep 1; \
OLD_COUNT=$${COUNT};\
continue; \
else \
echo -e "\e[32m=== $${SECONDS}s elapsed - Did not find any unhealthy containers, all is good.\e[0m"; \
exit 0; \
fi ;\
done; \
echo -e "\e[31m=== $${SECONDS}s elapsed - Found unhealthy/starting ($${COUNT}) containers";\
$(CONTAINER_RUNTIME) ps -a --filter name=$(CNT_PREFIX) --format 'table {{.Names}}\t{{.Status}}'; \
echo -e "\e[0m"; \
exit 1
else
# This is a compatibility hack for old podman (3.x) not properly reading the
# healtcheck config from (docker) image metadata. The containers start without a
# healthcheck so we have to emulate it here. This is supposedly fixed in 4.x:
# https://github.com/containers/podman/pull/12239
@OLD_COUNT=0; for I in $$(seq 1 900); do \
STOPPED=$$($(CONTAINER_RUNTIME) ps -a --filter name=$(CNT_PREFIX) | grep "Exited"); \
if [ -n "$${STOPPED}" ]; then \
echo -e "\e[31m=== $${SECONDS}s elapsed - Container(s) unexpectedly exited"; \
echo -e "$${STOPPED} \\e[0m"; \
exit 1; \
fi; \
CONTAINERS=$$($(CONTAINER_RUNTIME) ps -aq --filter name=$(CNT_PREFIX)); \
TOTAL_COUNT=$$(echo "${CONTAINERS}" | wc -l); \
HEALTHY_COUNT=$$($(CONTAINER_RUNTIME) logs $${CONTAINERS} | egrep 'Listening on .* for SSH connections' | wc -l); \
COUNT=$$(echo "$${TOTAL_COUNT}-$${HEALTHY_COUNT}" | bc); \
if [ $$COUNT -gt 0 ]; then \
if [ $$OLD_COUNT -ne $$COUNT ];\
then \
echo -e "\e[31m=== $${SECONDS}s elapsed - Found unhealthy/starting ($${COUNT}) containers";\
$(CONTAINER_RUNTIME) ps -f name=$(CNT_PREFIX) | egrep "(unhealthy|health: starting)" | awk '{ print $$(NF) }';\
echo -e "Checking again every 1 second, no more messages until changes detected\\e[0m"; \
fi;\
sleep 1; \
OLD_COUNT=$$COUNT;\
continue; \
else \
echo -e "\e[32m=== $${SECONDS}s elapsed - Did not find any unhealthy containers, all is good.\e[0m"; \
exit 0; \
fi ;\
done; \
echo -e "\e[31m=== $${SECONDS}s elapsed - Found unhealthy/starting ($${COUNT}) containers";\
$(CONTAINER_RUNTIME) ps -a --filter name=$(CNT_PREFIX) --format 'table {{.Names}}\t{{.Status}}'; \
echo -e "\e[0m"; \
exit 1
endif
.PHONY: clone-yangmodels compose-notconf-yang test-compose-yang test-composed-notconf-yang
# clone-yangmodels: clones and checks out the yangmodels/yang repository
# including submodules
clone-yangmodels:
if [ ! -d yang ]; then \
git clone --depth 1 --recurse-submodules=vendor --shallow-submodules https://github.com/yangmodels/yang.git; \
else \
cd yang; \
git pull && git submodule update --recursive --recommend-shallow; \
fi
# Set up COMPOSE_IMAGE_* variables by examining the provided YANG_PATH variable.
# The conditions below knows how to extract the platform and version from the
# yangmodules/yang paths. If none match, default to just using YANG_PATH.
EXPLODED_YANG_PATH=$(subst /, ,$(YANG_PATH))
ifneq (,$(findstring standard/ietf,$(YANG_PATH)))
# yang/standard/ietf/RFC
COMPOSE_IMAGE_NAME?=ietf
COMPOSE_IMAGE_TAG_PREFIX?=latest
else ifneq (,$(findstring latest_sros,$(YANG_PATH)))
COMPOSE_IMAGE_NAME?=sros
COMPOSE_IMAGE_TAG_PREFIX?=$(subst latest_sros_,,$(filter latest_sros%,$(EXPLODED_YANG_PATH)))
else ifneq (,$(findstring native/conf-and-rpcs/junos,$(YANG_PATH)))
# ../vendor/juniper/23.4/23.4R1/native/conf-and-rpcs/junos
# last word is the os - junos
COMPOSE_IMAGE_NAME?=$(lastword $(EXPLODED_YANG_PATH))
# Fourth element from the end is the version (23.4R1) - get the word at this position
COMPOSE_IMAGE_TAG_PREFIX?=$(word $(shell echo $$(( $(words $(EXPLODED_YANG_PATH)) - 3 )) ),$(EXPLODED_YANG_PATH))
else ifneq (,$(findstring junos,$(YANG_PATH)))
# .../vendor/juniper/20.1/20.1R1/junos
# last word is the os - junos
COMPOSE_IMAGE_NAME?=$(lastword $(EXPLODED_YANG_PATH))
# second to last word is the version - 21.1R1
COMPOSE_IMAGE_TAG_PREFIX?=$(lastword $(filter-out $(lastword $(EXPLODED_YANG_PATH)),$(EXPLODED_YANG_PATH)))
else ifneq (,$(findstring cisco,$(YANG_PATH)))
# .../vendor/cisco/xr/751
# 3rd and 2nd words from the right are the os - cisco-xr
COMPOSE_IMAGE_NAME?=cisco-$(lastword $(filter-out $(lastword $(EXPLODED_YANG_PATH)),$(EXPLODED_YANG_PATH)))
COMPOSE_IMAGE_TAG_PREFIX?=$(lastword $(EXPLODED_YANG_PATH))
else
COMPOSE_IMAGE_NAME?=$(subst /,_,$(patsubst %/,%,$(YANG_PATH)))
COMPOSE_IMAGE_TAG_PREFIX?=latest
endif
COMPOSE_IMAGE_TAG:=$(COMPOSE_IMAGE_TAG_PREFIX)-$(IMAGE_TAG)
# compose-notconf-yang: build a docker image with notconf:base with the given
# YANG modules already installed. Provide the path to the modules (and init
# XMLs) with the YANG_PATH variable.
compose-notconf-yang: COMPOSE_PATH=build/$(COMPOSE_IMAGE_NAME)/$(COMPOSE_IMAGE_TAG_PREFIX)
compose-notconf-yang:
@if [ -z "$(YANG_PATH)" ]; then echo "The YANG_PATH variable must be set"; exit 1; fi
rm -rf $(COMPOSE_PATH)
mkdir -p $(COMPOSE_PATH)
@set -e; \
for fixup in `find fixups -type f -name Makefile | sed 's#^fixups/##' | awk -F/ '{ print NF "\t" $$0; }' | sort -nr | cut -f2-`; do \
echo "Checking if $(YANG_PATH) matches $${fixup}"; \
if [[ "$(YANG_PATH)" =~ ^$$(dirname $${fixup}).* ]]; then \
echo "Executing fixups/$${fixup}"; \
make -f fixups/$$fixup -j YANG_PATH=$(YANG_PATH) COMPOSE_PATH=$(COMPOSE_PATH); \
fi \
done
if ! ls $(COMPOSE_PATH)/*.yang > /dev/null 2>&1; then \
echo "Copying files directly from $(YANG_PATH) without fixups"; \
cp -av $(YANG_PATH)/. $(COMPOSE_PATH); \
fi
$(CONTAINER_RUNTIME) build -f Dockerfile.yang -t $(IMAGE_PATH)notconf-$(COMPOSE_IMAGE_NAME):$(COMPOSE_IMAGE_TAG) \
--build-arg COMPOSE_PATH=$(COMPOSE_PATH) --build-arg IMAGE_PATH=$(IMAGE_PATH) --build-arg IMAGE_TAG=$(IMAGE_TAG) $(DOCKER_BUILD_CACHE_ARG) \
--label org.opencontainers.image.description="This image contains the base notconf installation (sysrepo+netopeer2) with the following YANG modules pre-installed: $(COMPOSE_IMAGE_NAME)/$(COMPOSE_IMAGE_TAG)" .
echo $(IMAGE_PATH)notconf-$(COMPOSE_IMAGE_NAME):$(COMPOSE_IMAGE_TAG) >> composed-notconf.txt
test-compose-yang: compose-notconf-yang
$(MAKE) test-composed-notconf-yang
test-composed-notconf-yang: export CNT_PREFIX=test-yang-$(COMPOSE_IMAGE_NAME)-$(COMPOSE_IMAGE_TAG)
test-composed-notconf-yang:
-$(CONTAINER_RUNTIME) rm -f $(CNT_PREFIX)
$(CONTAINER_RUNTIME) run -d --log-driver json-file --name $(CNT_PREFIX) $(IMAGE_PATH)notconf-$(COMPOSE_IMAGE_NAME):$(COMPOSE_IMAGE_TAG)
$(MAKE) wait-healthy
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --hello
$(CONTAINER_RUNTIME) run -i --rm --network container:$(CNT_PREFIX) $(IMAGE_PATH)notconf:$(IMAGE_TAG)-debug netconf-console2 --port 830 --get -x /modules-state
set -e; for fixup in `find fixups -type f -name Makefile | sed 's#^fixups/##' | awk -F/ '{ print NF "\t" $$0; }' | sort -nr | cut -f2-`; do \
if [[ "$(YANG_PATH)" =~ ^$$(dirname $${fixup}).* ]] && make -C $$(dirname "fixups/$${fixup}") -n test >/dev/null 2>&1; then \
echo "Executing test in fixups/$${fixup}"; \
make -C $$(dirname "fixups/$${fixup}") test; \
fi \
done
$(MAKE) save-logs
$(MAKE) test-stop
# Print the value of a variable, for debugging / CI
print-%:
@echo $*=$($*)