Skip to content

Commit d358aba

Browse files
authored
mirror validation should pass with local image only; more testing for mirroring (#47)
* mirror validation should pass with local image only; more testing for mirror * address review
1 parent d1ce6c5 commit d358aba

File tree

5 files changed

+218
-46
lines changed

5 files changed

+218
-46
lines changed

mirror/defs.bzl

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ def _replace_colon_except_last_segment(input_string):
1010
output_string = "/".join(segments)
1111
return output_string
1212

13-
def _mirror_image_impl(ctx):
13+
# Common implementation for mirror_image and mirror_image_test
14+
# Uses the following ctx attributes: src_image, digest, dst, dst_prefix
15+
# Returns the src_image, digest, and dst_without_hash
16+
def _impl_common(ctx):
1417
digest = ctx.attr.digest
1518
src_image = ctx.attr.src_image
1619
v = src_image.split("@", 1)
@@ -39,6 +42,11 @@ def _mirror_image_impl(ctx):
3942
dst_prefix = ctx.expand_make_variables("dst_prefix", ctx.attr.dst_prefix, {})
4043
dst_without_hash = dst_prefix.strip("/") + "/" + src_repository
4144

45+
return src_image, digest, dst_without_hash
46+
47+
def _mirror_image_impl(ctx):
48+
src_image, digest, dst_without_hash = _impl_common(ctx)
49+
4250
digest_file = ctx.actions.declare_file(ctx.label.name + ".digest")
4351
ctx.actions.write(
4452
output = digest_file,
@@ -81,9 +89,6 @@ mirror_image_rule = rule(
8189
mandatory = True,
8290
doc = "The image to mirror",
8391
),
84-
"image_name": attr.string(
85-
doc = "The name that could be referred in manifests. This field is deprecated and unused.",
86-
),
8792
"digest": attr.string(
8893
mandatory = False,
8994
doc = "The digest of the image. If not provided, it will be extracted from the src_image.",
@@ -114,46 +119,63 @@ Implements GitopsPushInfo and K8sPushInfo providers so the returned image can be
114119
""",
115120
)
116121

117-
def validate_image_test(name, image, digest, tags = [], **kwargs):
118-
"""
119-
Create a test that validates the image existance using crane validate.
120-
Image tag will be ignored if provided and only the digest will be used.
121-
if digest is provided as a part of the image, it will be used.
122-
It is an error to provide both digest and image with digest if they do not match.
123-
"""
124-
src_image = image
125-
v = src_image.split("@", 1)
126-
s = v[0]
127-
if len(v) > 1:
128-
# If the image has a digest, use that.
129-
if digest and v[1] != digest:
130-
fail("digest mismatch: %s != %s" % (v[1], digest))
131-
digest = v[1]
132-
else:
133-
# If the image does not have a digest, use the one provided.
134-
src_image = s + "@" + digest
135-
136-
if not digest:
137-
fail("digest must be provided as an attribute to mirror_image or in the src_image")
122+
def _validate_mirror_impl(ctx):
123+
src_image, digest, dst_without_hash = _impl_common(ctx)
138124

139-
native.sh_test(
140-
name = name,
141-
size = "small",
142-
srcs = ["@rules_gitops//mirror:validate_image.sh"],
143-
data = [
144-
"@rules_gitops//vendor/github.com/google/go-containerregistry/cmd/crane:crane",
145-
],
146-
args = [
147-
src_image,
148-
],
149-
tags = ["requires-network"] + tags,
150-
env = {
151-
"CRANE_BIN": "$(location @rules_gitops//vendor/github.com/google/go-containerregistry/cmd/crane:crane)",
125+
ctx.actions.expand_template(
126+
template = ctx.file._validate_image_script,
127+
output = ctx.outputs.executable,
128+
substitutions = {
129+
"{crane_tool}": ctx.executable.crane_tool.short_path,
130+
"{src_image}": src_image,
131+
"{digest}": digest,
132+
"{dst_image}": dst_without_hash,
152133
},
153-
**kwargs
134+
is_executable = True,
154135
)
155136

156-
def mirror_image(name, src_image, digest, tags = [], **kwargs):
157-
visibility = kwargs.pop("visibility", None)
158-
mirror_image_rule(name = name, src_image = src_image, digest = digest, tags = tags, visibility = visibility, **kwargs)
159-
validate_image_test(name = name + "_validate_src", image = src_image, digest = digest, visibility = visibility, tags = tags)
137+
runfiles = ctx.runfiles(files = [ctx.file._validate_image_script]).merge(ctx.attr.crane_tool[DefaultInfo].default_runfiles)
138+
139+
return DefaultInfo(
140+
runfiles = runfiles,
141+
executable = ctx.outputs.executable,
142+
)
143+
144+
validate_mirror_test = rule(
145+
implementation = _validate_mirror_impl,
146+
test = True,
147+
attrs = {
148+
"src_image": attr.string(
149+
mandatory = True,
150+
doc = "The image to mirror",
151+
),
152+
"digest": attr.string(
153+
mandatory = False,
154+
doc = "The digest of the image. If not provided, it will be extracted from the src_image.",
155+
),
156+
"dst_prefix": attr.string(
157+
doc = "The prefix of the destination image, should include the registry and repository. Either dst_prefix or dst_image must be specified.",
158+
),
159+
"dst": attr.string(
160+
doc = "The destination image location, should include the registry and repository. Either dst_prefix or dst_image must be specified.",
161+
),
162+
"crane_tool": attr.label(
163+
default = Label("//vendor/github.com/google/go-containerregistry/cmd/crane:crane"),
164+
executable = True,
165+
cfg = "exec",
166+
),
167+
"_validate_image_script": attr.label(
168+
default = ":validate_image.sh",
169+
allow_single_file = True,
170+
),
171+
},
172+
executable = True,
173+
doc = """Validate a mirrored image. It checks if at least one of remote or local image exists.
174+
""",
175+
)
176+
177+
def mirror_image(name, image_name = None, push_timeout = "30s", **kwargs):
178+
if image_name:
179+
fail("image_name is deprecated and unused")
180+
mirror_image_rule(name = name, push_timeout = push_timeout, **kwargs)
181+
validate_mirror_test(name = name + "_validate_src", **kwargs)

mirror/mirror_image.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/bin/bash
1+
#!/bin/bash -x
22
set -eu
33

44
function guess_runfiles() {

mirror/tests/BUILD.bazel

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,25 @@ sh_test(
202202
},
203203
tags = ["exclusive"], # this test starts a registry on fixed port 1338
204204
)
205+
206+
sh_test(
207+
name = "image_mirror_verify_test",
208+
srcs = ["image_mirror_test.sh"],
209+
data = [
210+
":image_mirror",
211+
":image_mirror_validate_src",
212+
":push_image",
213+
"//vendor/github.com/google/go-containerregistry/cmd/crane",
214+
"//vendor/github.com/google/go-containerregistry/cmd/registry",
215+
],
216+
env = {
217+
"LOCAL": "localhost:1338/mirror/localhost1338/image@sha256:b812c0570a7c369b2863c64e22760dc1b1dbc025a739f02db376bac62862f4cc",
218+
"REMOTE": "localhost:1338/image@sha256:b812c0570a7c369b2863c64e22760dc1b1dbc025a739f02db376bac62862f4cc",
219+
"PUSH_IMAGE": "$(location :push_image)",
220+
"IMAGE_MIRROR": "$(location :image_mirror)",
221+
"IMAGE_MIRROR_VALIDATE_SRC": "$(location :image_mirror_validate_src)",
222+
"CRANE_BIN": "$(location //vendor/github.com/google/go-containerregistry/cmd/crane)",
223+
"REGISTRY_BIN": "$(location //vendor/github.com/google/go-containerregistry/cmd/registry)",
224+
},
225+
tags = ["exclusive"], # this test starts a registry on fixed port 1338
226+
)

mirror/tests/image_mirror_test.sh

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/bin/bash -x
2+
#
3+
# This test runs the script passed as the first argument and verifies the image is pushed to the registry
4+
#
5+
${REGISTRY_BIN}&
6+
registry_pid=$!
7+
trap "kill -9 $registry_pid" EXIT
8+
9+
echo verifying image $REMOTE does not exist
10+
${CRANE_BIN} validate -v --fast --remote $REMOTE
11+
if [ $? -eq 0 ]; then
12+
echo "Image $REMOTE should not exist"
13+
exit 1
14+
fi
15+
16+
echo verifying image $LOCAL does not exist
17+
${CRANE_BIN} validate -v --fast --remote $LOCAL
18+
if [ $? -eq 0 ]; then
19+
echo "Image $LOCAL should not exist"
20+
exit 1
21+
fi
22+
23+
#test should fail before pushing the image (no src, no dst)
24+
echo verifying mirror image validation fails
25+
${IMAGE_MIRROR_VALIDATE_SRC}
26+
if [ $? -eq 0 ]; then
27+
echo "Image verification should fail"
28+
exit 1
29+
fi
30+
31+
echo pushing image $SRC_IMAGE
32+
${PUSH_IMAGE}
33+
34+
echo verifying image $REMOTE exists
35+
${CRANE_BIN} validate -v --fast --remote $REMOTE
36+
if [ $? -ne 0 ]; then
37+
echo "Image $REMOTE should exist"
38+
exit 1
39+
fi
40+
41+
echo verifying image $LOCAL does not exist
42+
${CRANE_BIN} validate -v --fast --remote $LOCAL
43+
if [ $? -eq 0 ]; then
44+
echo "Image $LOCAL should not exist"
45+
exit 1
46+
fi
47+
48+
#test should succeed with src image only
49+
echo verifying mirror image validation fails
50+
${IMAGE_MIRROR_VALIDATE_SRC}
51+
if [ $? -ne 0 ]; then
52+
echo "Image verification should succeed"
53+
exit 1
54+
fi
55+
56+
echo running image mirror
57+
${IMAGE_MIRROR}
58+
if [ $? -ne 0 ]; then
59+
echo "Image mirroring should succeed"
60+
exit 1
61+
fi
62+
63+
echo verifying image $LOCAL exists
64+
${CRANE_BIN} validate -v --fast --remote $LOCAL
65+
if [ $? -ne 0 ]; then
66+
echo "Image $LOCAL should exist"
67+
exit 1
68+
fi
69+
70+
echo verifying image $REMOTE exists
71+
${CRANE_BIN} validate -v --fast --remote $REMOTE
72+
if [ $? -ne 0 ]; then
73+
echo "Image $REMOTE should exist"
74+
exit 1
75+
fi
76+
77+
#test should succeed with src and dst images
78+
echo verifying mirror image validation succeeds
79+
${IMAGE_MIRROR_VALIDATE_SRC}
80+
if [ $? -ne 0 ]; then
81+
echo "Image verification should succeed"
82+
exit 1
83+
fi
84+
85+
echo removing image $REMOTE
86+
${CRANE_BIN} delete $REMOTE || exit 1
87+
88+
echo verifying image $REMOTE does not exist
89+
${CRANE_BIN} validate -v --fast --remote $REMOTE
90+
if [ $? -eq 0 ]; then
91+
echo "Image $REMOTE should not exist"
92+
exit 1
93+
fi
94+
95+
echo verifying image $LOCAL exists
96+
${CRANE_BIN} validate -v --fast --remote $LOCAL
97+
if [ $? -ne 0 ]; then
98+
echo "Image $LOCAL should exist"
99+
exit 1
100+
fi
101+
102+
#test should succeed with dst image only
103+
echo verifying mirror image validation succeeds
104+
${IMAGE_MIRROR_VALIDATE_SRC}
105+
if [ $? -ne 0 ]; then
106+
echo "Image verification should succeed"
107+
exit 1
108+
fi
109+
110+
111+
# exit 1

mirror/validate_image.sh

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
#!/bin/bash
2-
echo "Validating image $1"
3-
$CRANE_BIN validate -v --fast --remote $1
2+
REMOTE="{src_image}"
3+
LOCAL="{dst_image}@{digest}"
4+
echo "Validating images ${REMOTE} and ${LOCAL}"
5+
{crane_tool} validate -v --fast --remote ${REMOTE}
6+
if [ $? -eq 0 ]; then
7+
echo "Image ${REMOTE} exist"
8+
exit 0
9+
fi
10+
11+
echo "Image ${REMOTE} does not exist, checking ${LOCAL}"
12+
13+
{crane_tool} validate -v --fast --remote ${LOCAL}
14+
if [ $? -eq 0 ]; then
15+
echo "Image ${LOCAL} exist"
16+
exit 0
17+
fi
18+
19+
echo "Image ${LOCAL} does not exist"
20+
exit 1

0 commit comments

Comments
 (0)