Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add basic nydusify conversion case #566

Merged
merged 2 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions contrib/nydus-test/framework/nydusify.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def work_dir(self, work_dir):
return self.set_param("work-dir", work_dir)

def fs_version(self, fs_version):
return self.set_param("fs-version", fs_version)
return self.set_param("fs-version", str(fs_version))


class Nydusify(LinuxCommand):
def __init__(self, anchor: NydusAnchor):
Expand All @@ -45,7 +46,7 @@ def __init__(self, anchor: NydusAnchor):
self.cmd = NydusifyParam(self.nydusify_bin)
self.cmd.nydus_image(self.image_builder).work_dir(self.work_dir)

def convert(self, source, suffix="_converted", target_ref=None, fs_version="5"):
def convert(self, source, suffix="_converted", target_ref=None, fs_version=5):
"""
A reference to image looks like registry/namespace/repo:tag
Before conversion begins, split the reference into those parts.
Expand All @@ -69,7 +70,9 @@ def convert(self, source, suffix="_converted", target_ref=None, fs_version="5"):
self.target_ref = target_ref

cmd = str(self.cmd)
with utils.timer("### Image convertion time including Pull and Push ###"):
with utils.timer(
f"### Rafs V{fs_version} Image conversion time including Pull and Push ###"
):
_, p = utils.run(
cmd,
False,
Expand All @@ -80,7 +83,7 @@ def convert(self, source, suffix="_converted", target_ref=None, fs_version="5"):
p.wait()
assert p.returncode == 0

def check(self, source, suffix="_converted", target_ref=None, fs_version="5"):
def check(self, source, suffix="_converted", target_ref=None, fs_version=5):
"""
A reference to image looks like registry/namespace/repo:tag
Before conversion begins, split the reference into those parts.
Expand Down Expand Up @@ -261,12 +264,12 @@ def pull_bootstrap(self, downloaded_dir, bootstrap_name, arch="amd64"):

import requests

# Currently, we can handle auth
# Currently, we can not handle auth
# OCI distribution spec: /v2/<name>/blobs/<digest>
os.makedirs(downloaded_dir, exist_ok=True)

reader = requests.get(
f"http://{self.registry_url}/v2/{self.original_repo}/blobs/{bootstrap_digest}",
f"http://{self.registry_url}/v2/{self.anchor.registry_namespace}/{self.original_repo}/blobs/{bootstrap_digest}",
stream=True,
)
with utils.pushd(downloaded_dir):
Expand Down
240 changes: 73 additions & 167 deletions contrib/nydus-test/functional-test/test_nydusify.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,72 @@
@pytest.mark.parametrize(
"source",
[
"python:3.7",
"docker.io/busybox:latest",
],
)
@pytest.mark.parametrize("fs_version", [5, 6])
def test_basic_conversion(
nydus_anchor: NydusAnchor,
rafs_conf: RafsConf,
source,
fs_version,
local_registry,
nydusify_converter,
):
"""
No need to locate where bootstrap is as we can directly pull it from registry
"""
converter = Nydusify(nydus_anchor)

time.sleep(1)

converter.docker_v2().enable_multiplatfrom(False).convert(
source, fs_version=fs_version
)
assert converter.locate_bootstrap() is not None
pulled_bootstrap = converter.pull_bootstrap(
tempfile.TemporaryDirectory(
dir=nydus_anchor.workspace, suffix="bootstrap"
).name,
"pulled_bootstrap",
)

# Skopeo does not support media type: "application/vnd.oci.image.layer.nydus.blob.v1",
# So can't download build cache like a oci image.

layers, base = converter.extract_source_layers_names_and_download()
nydus_anchor.mount_overlayfs(layers, base)

converted_layers = converter.extract_converted_layers_names()
converted_layers.sort()

rafs_conf.set_rafs_backend(
Backend.REGISTRY, repo=posixpath.basename(source).split(":")[0]
)
rafs_conf.enable_fs_prefetch()
rafs_conf.enable_rafs_blobcache()
rafs_conf.dump_rafs_conf()

rafs = RafsMount(nydus_anchor, None, rafs_conf)

# Use `nydus-image inspect` to compare blob table in bootstrap and manifest

workload_gen = WorkloadGen(nydus_anchor.mount_point, nydus_anchor.overlayfs)
# No need to locate where bootstrap is as we can directly pull it from registry
rafs.thread_num(6).bootstrap(pulled_bootstrap).prefetch_files("/").mount()

assert workload_gen.verify_entire_fs()
workload_gen.setup_workload_generator()
workload_gen.torture_read(4, 6, verify=True)
workload_gen.finish_torture_read()


@pytest.mark.parametrize(
"source",
[
"python:3.7",
"docker.io/busybox:latest",
"reg.docker.alibaba-inc.com/chge-mirrors/python:3.7",
],
)
@pytest.mark.parametrize("enable_multiplatform", [False])
Expand All @@ -29,7 +93,7 @@ def test_build_cache(
nydusify_converter,
):
"""
No need to locate where boostrap is as we can directly pull it from registry
No need to locate where bootstrap is as we can directly pull it from registry
"""
converter = Nydusify(nydus_anchor)

Expand All @@ -39,7 +103,7 @@ def test_build_cache(
"localhost:5000/build_cache:000"
).enable_multiplatfrom(enable_multiplatform).convert(source)

# No need to locate where boostrap is as we can directly pull it from registry
# No need to locate where bootstrap is as we can directly pull it from registry
bootstrap = converter.locate_bootstrap()

converter.docker_v2().build_cache_ref("localhost:5000/build_cache:000").convert(
Expand Down Expand Up @@ -83,7 +147,7 @@ def test_build_cache(
# Use `nydus-image inspect` to compare blob table in bootstrap and manifest

workload_gen = WorkloadGen(nydus_anchor.mount_point, nydus_anchor.overlayfs)
# No need to locate where boostrap is as we can directly pull it from registry
# No need to locate where bootstrap is as we can directly pull it from registry
rafs.thread_num(6).bootstrap(pulled_bootstrap).prefetch_files("/").mount()

assert workload_gen.verify_entire_fs()
Expand All @@ -92,16 +156,11 @@ def test_build_cache(
workload_gen.finish_torture_read()


@pytest.mark.skip(reason="Get rid of OSS dependency!")
@pytest.mark.parametrize(
"source",
[
# "reg.docker.alibaba-inc.com/antmesh/odp:1.5.6",
# "reg.docker.alibaba-inc.com/antfin/antcoderpc:20210702-2",
# "reg.docker.alibaba-inc.com/antfin/dpprecompilestream:20210702-1",
"docker.io/busybox:latest",
"reg.docker.alibaba-inc.com/chge-mirrors/python:3.7",
"reg.docker.alibaba-inc.com/chge-mirrors/node:13.13.0",
"reg.docker.alibaba-inc.com/chge-mirrors/redis:5.0.5",
],
)
def test_upload_oss(
Expand Down Expand Up @@ -142,10 +201,8 @@ def test_upload_oss(

# `check` deletes all files
checker = Nydusify(nydus_anchor)
checker.backend_type(
"oss", oss_object_prefix=oss_prefix
).with_new_work_dir(
nydus_anchor.nydusify_work_dir+'-check'
checker.backend_type("oss", oss_object_prefix=oss_prefix).with_new_work_dir(
nydus_anchor.nydusify_work_dir + "-check"
).check(source)

converted_layers = converter.extract_converted_layers_names()
Expand Down Expand Up @@ -190,93 +247,10 @@ def test_upload_oss(
oss.rm(b)


@pytest.mark.parametrize(
"source,chunk_dict_arg",
[
(
"reg.docker.alibaba-inc.com/antsys/nydus-image:supportd-1026-1",
"bootstrap:registry:reg.docker.alibaba-inc.com/antsys/chunkdict_test:antfin_supportprod"
),
(
"reg.docker.alibaba-inc.com/antsys/nydus-image:mirrorprod-1027-3",
"bootstrap:registry:reg.docker.alibaba-inc.com/antsys/chunkdict_test:antfin_mirrorprod"
)
]
)
def test_chunk_dict(
nydus_anchor: NydusAnchor,
rafs_conf: RafsConf,
source,
chunk_dict_arg,
local_registry,
nydusify_converter,
):
'''
only support oss backend now
- convert image with chunk-dict
- check new image
'''
converter = Nydusify(nydus_anchor)

time.sleep(1)

oss_prefix = "nydus_v2/"

converter.docker_v2().backend_type(
"oss", oss_object_prefix=oss_prefix
).build_cache_ref(
"localhost:5000/build_cache:000"
).force_push().chunk_dict(chunk_dict_arg).convert(source)

rafs_conf.set_rafs_backend(Backend.OSS, prefix=oss_prefix)
rafs_conf.enable_fs_prefetch()
rafs_conf.enable_rafs_blobcache()
rafs_conf.dump_rafs_conf()

bootstrap = converter.locate_bootstrap()

checker = Nydusify(nydus_anchor)
checker.backend_type(
"oss", oss_object_prefix=oss_prefix
).with_new_work_dir(
nydus_anchor.nydusify_work_dir+'-check'
).check(source)

converted_layers = converter.extract_converted_layers_names()

# With oss backend, ant useage, `layers` only has one member
records = converter.get_build_cache_records("localhost:5000/build_cache:000")
assert len(records) != 0
cached_layers = [c["digest"] for c in records]
assert cached_layers.sort() == converted_layers.sort()

pulled_bootstrap = converter.pull_bootstrap(
tempfile.TemporaryDirectory(
dir=nydus_anchor.workspace, suffix="bootstrap"
).name,
"pulled_bootstrap",
)

# Mount source rootfs (ociv1)
layers, base = converter.extract_source_layers_names_and_download()
nydus_anchor.mount_overlayfs(layers, base)
# Mount rafs rootfs
rafs = RafsMount(nydus_anchor, None, rafs_conf)

workload_gen = WorkloadGen(nydus_anchor.mount_point, nydus_anchor.overlayfs)
rafs.thread_num(6).bootstrap(pulled_bootstrap).prefetch_files("/").mount()

assert workload_gen.verify_entire_fs()
workload_gen.setup_workload_generator()
workload_gen.torture_read(8, 12, verify=True)
workload_gen.finish_torture_read()


@pytest.mark.parametrize(
"source",
[
"busybox:latest", # From dockerhub, manifest list image foramt, image config includes os/arch
# "reg.docker.alibaba-inc.com/swiftimage/basementtask-assets:12b2b720210429235656909_aarch64", # Single manifest from internal registry
"busybox:latest", # From DockerHub, manifest list image format, image config includes os/arch
],
)
@pytest.mark.parametrize("arch", ["arm64", "amd64"])
Expand Down Expand Up @@ -370,79 +344,11 @@ def test_cross_platform_multiplatform(

# Use `nydus-image inspect` to compare blob table in bootstrap and manifest
workload_gen = WorkloadGen(nydus_anchor.mount_point, nydus_anchor.overlayfs)
# No need to locate where boostrap is as we can directly pull it from registry
# No need to locate where bootstrap is as we can directly pull it from registry
rafs = RafsMount(nydus_anchor, None, rafs_conf)
rafs.thread_num(6).bootstrap(pulled_bootstrap).prefetch_files("/").mount()

assert workload_gen.verify_entire_fs()
workload_gen.setup_workload_generator()
workload_gen.torture_read(8, 12, verify=True)
workload_gen.finish_torture_read()


@pytest.mark.skipif(platform.machine() == "x86_64", reason="Only supported x86")
@pytest.mark.parametrize(
"source",
[
"reg.docker.alibaba-inc.com/swiftimage/basementtask-assets:12b2b720210429235656909_aarch64", # Single manifest from internal registry
],
)
def test_arm64_single_manifest(
nydus_anchor: NydusAnchor,
rafs_conf: RafsConf,
source,
local_registry,
nydusify_converter,
):

converter = Nydusify(nydus_anchor)
arch = "arm64"

converter.docker_v2().build_cache_ref("localhost:5000/build_cache:000").convert(
source
)

# TODO: configure registry backend from `local_registry` rather than anchor
rafs_conf.set_rafs_backend(
Backend.REGISTRY, repo=posixpath.basename(source).split(":")[0]
)
rafs_conf.enable_fs_prefetch()
rafs_conf.enable_rafs_blobcache()

pulled_bootstrap = converter.pull_bootstrap(
tempfile.TemporaryDirectory(
dir=nydus_anchor.workspace, suffix="bootstrap"
).name,
"pulled_bootstrap",
arch,
)

# Skopeo does not support media type: "application/vnd.oci.image.layer.nydus.blob.v1",
# So can't download build cache like a oci image.
layers, base = converter.extract_source_layers_names_and_download(arch=arch)
nydus_anchor.mount_overlayfs(layers, base)

converted_layers = converter.extract_converted_layers_names(arch=arch)
converted_layers.sort()

records = converter.get_build_cache_records("localhost:5000/build_cache:000")
assert len(records) != 0
cached_layers = [c["digest"] for c in records]
cached_layers.sort()
# > assert cached_layers == converted_layers
# E AssertionError: assert None == ['sha256:3f18...af3234b4c257']
# E +None
# E -['sha256:3f18b27a912188108c8590684206bd9da7d81bbfd0e8325f3ef0af3234b4c257']
for l in converted_layers:
assert l in cached_layers

# Use `nydus-image inspect` to compare blob table in bootstrap and manifest
workload_gen = WorkloadGen(nydus_anchor.mount_point, nydus_anchor.overlayfs)
# No need to locate where boostrap is as we can directly pull it from registry
rafs = RafsMount(nydus_anchor, None, rafs_conf)
rafs.thread_num(2).bootstrap(pulled_bootstrap).prefetch_files("/").mount()

assert workload_gen.verify_entire_fs()
workload_gen.setup_workload_generator()
workload_gen.torture_read(4, 4, verify=True)
workload_gen.finish_torture_read()
4 changes: 2 additions & 2 deletions contrib/nydus-test/functional-test/test_stargz.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_stargz(
image = RafsImage(
nydus_anchor,
toc,
"boostrap_scratched",
"bootstrap_scratched",
"blob_scratched",
clear_from_oss=True,
)
Expand All @@ -77,4 +77,4 @@ def test_stargz(
wg.torture_read(4, 4)

wg.finish_torture_read()
assert not wg.io_error
assert not wg.io_error
2 changes: 1 addition & 1 deletion contrib/nydus-test/functional-test/test_stress.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def setup_module(module):
SCRATCH_IMAGE = RafsImage(
ANCHOR,
ANCHOR.scratch_dir,
"boostrap_scratched",
"bootstrap_scratched",
"blob_scratched",
clear_from_oss=True,
)
Expand Down
1 change: 1 addition & 0 deletions src/bin/nydus-image/core/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ impl Node {

// update all the inodes's offset according to the new 'meta_addr'.
self.offset = self.offset - orig_meta_addr + meta_addr;

// Only dir and symlink file can be of EROFS_INODE_FLAT_INLINE layout,
// so the `dirents_offset` is only used for these two types.
// For other types, the `dirents_offset` will always be 0,
Expand Down