예제 #1
0
파일: remoteloop.py 프로젝트: 4383/osbuild
 def __init__(self, sock):
     self.devs = []
     self.sock = sock
     self.ctl = loop.LoopControl()
     self.event_loop = asyncio.new_event_loop()
     self.event_loop.add_reader(self.sock, self._dispatch)
     self.thread = threading.Thread(target=self._run_event_loop)
예제 #2
0
파일: test_loop.py 프로젝트: thozza/osbuild
def test_on_close(tempdir):

    path = os.path.join(tempdir, "test.img")
    ctl = loop.LoopControl()

    assert ctl

    lo, f = None, None
    invoked = False

    def on_close(l):
        nonlocal invoked
        invoked = True

        # check that this is a no-op
        l.close()

    try:
        f = open(path, "wb+")
        f.truncate(1024)
        f.flush()
        lo = ctl.loop_for_fd(f.fileno(), autoclear=True, lock=True)
        assert lo

        lo.on_close = on_close
        lo.close()

        assert invoked

    finally:
        if lo:
            lo.close()

        ctl.close()
예제 #3
0
    def test_qemu(self):
        loctl = loop.LoopControl()
        with self.osbuild as osb:
            for fmt in ["raw", "raw.xz", "qcow2", "vmdk", "vdi"]:
                for fs_type in ["ext4", "xfs", "btrfs"]:
                    with self.subTest(fmt=fmt, fs_type=fs_type):
                        print(f"  {fmt} {fs_type}", flush=True)
                    options = {
                        "format": fmt,
                        "filename": f"image.{fmt}",
                        "ptuuid": "b2c09a39-db93-44c5-846a-81e06b1dc162",
                        "root_fs_uuid": "aff010e9-df95-4f81-be6b-e22317251033",
                        "size": 1024 * MEBIBYTE,
                        "root_fs_type": fs_type,
                    }
                    with self.run_assembler(osb, "org.osbuild.qemu", options,
                                            f"image.{fmt}") as (tree, image):
                        if fmt == "raw.xz":
                            subprocess.run(
                                ["unxz", "--keep", "--force", image],
                                check=True)
                            image = image[:-3]
                            fmt = "raw"
                        self.assertImageFile(image, fmt, options["size"])
                        with open_image(loctl, image, fmt) as (target, device):
                            ptable = self.read_partition_table(device)
                            self.assertPartitionTable(ptable,
                                                      "dos",
                                                      options["ptuuid"],
                                                      1,
                                                      boot_partition=1)
                            if fs_type == "btrfs":
                                l2hash = "daa74a424a41e2a13c6c4f6bada0e80d84a9865b12d3369470fc5e74004ed329"
                            elif fs_type == "xfs":
                                l2hash = "58ebc5a9b594607f49c290572e027c353a6359da83099020e6f3b9b1f22a897a"
                            else:
                                l2hash = "9b31c8fbc59602a38582988bf91c3948ae9c6f2a231ab505ea63a7005e302147"
                            self.assertGRUB2(
                                device,
                                "26e3327c6b5ac9b5e21d8b86f19ff7cb4d12fb2d0406713f936997d9d89de3ee",
                                l2hash, 1024 * 1024)

                            p1 = ptable["partitions"][0]
                            ssize = ptable.get("sectorsize", 512)
                            start, size = p1["start"] * ssize, p1[
                                "size"] * ssize
                            with loop_open(loctl,
                                           target,
                                           offset=start,
                                           size=size) as dev:
                                self.assertFilesystem(dev,
                                                      options["root_fs_uuid"],
                                                      fs_type, tree)
예제 #4
0
    def test_qemu(self):
        loctl = loop.LoopControl()
        with self.osbuild as osb:
            for fmt in ["raw", "raw.xz", "qcow2", "vmdk", "vdi"]:
                for fs_type in ["ext4", "xfs", "btrfs"]:
                    with self.subTest(fmt=fmt, fs_type=fs_type):
                        print(f"  {fmt} {fs_type}", flush=True)
                    options = {
                        "format": fmt,
                        "filename": f"image.{fmt}",
                        "ptuuid": "b2c09a39-db93-44c5-846a-81e06b1dc162",
                        "root_fs_uuid": "aff010e9-df95-4f81-be6b-e22317251033",
                        "size": 1024 * MEBIBYTE,
                        "root_fs_type": fs_type,
                    }
                    with self.run_assembler(osb, "org.osbuild.qemu", options,
                                            f"image.{fmt}") as (tree, image):
                        if fmt == "raw.xz":
                            subprocess.run(
                                ["unxz", "--keep", "--force", image],
                                check=True)
                            image = image[:-3]
                            fmt = "raw"
                        self.assertImageFile(image, fmt, options["size"])
                        with open_image(loctl, image, fmt) as (target, device):
                            ptable = self.read_partition_table(device)
                            self.assertPartitionTable(ptable,
                                                      "dos",
                                                      options["ptuuid"],
                                                      1,
                                                      boot_partition=1)
                            if fs_type == "btrfs":
                                l2hash = "919aad44d37aa9fdbb8cb1bbd8ce2a44e64aee76f4dceb805eaab041b7f62348"
                            elif fs_type == "xfs":
                                l2hash = "1729f531281e4c3cbcde2a39b587c9dd5334ea1335bb860905556d5b73603de6"
                            else:
                                l2hash = "24c3ad6be9a5687d5140e0bf66d25953c4f0c7eeb6aaced4cc64685f5b3cfa9e"
                            self.assertGRUB2(
                                device,
                                "26e3327c6b5ac9b5e21d8b86f19ff7cb4d12fb2d0406713f936997d9d89de3ee",
                                l2hash, 1024 * 1024)

                            p1 = ptable["partitions"][0]
                            ssize = ptable.get("sectorsize", 512)
                            start, size = p1["start"] * ssize, p1[
                                "size"] * ssize
                            with loop_open(loctl,
                                           target,
                                           offset=start,
                                           size=size) as dev:
                                self.assertFilesystem(dev,
                                                      options["root_fs_uuid"],
                                                      fs_type, tree)
예제 #5
0
    def test_qemu(self):
        loctl = loop.LoopControl()
        for fmt in ["raw", "raw.xz", "qcow2", "vmdk", "vdi"]:
            with self.subTest(fmt=fmt):
                print(f"  {fmt}", flush=True)
                options = {
                    "format": fmt,
                    "filename": f"image.{fmt}",
                    "ptuuid": "b2c09a39-db93-44c5-846a-81e06b1dc162",
                    "root_fs_uuid": "aff010e9-df95-4f81-be6b-e22317251033",
                    "size": 2 * 1024 * 1024 * 1024
                }
                with self.run_assembler("org.osbuild.qemu", options,
                                        f"image.{fmt}") as (tree, image):
                    if fmt == "raw.xz":
                        subprocess.run(["unxz", "--keep", "--force", image],
                                       check=True)
                        image = image[:-3]
                        fmt = "raw"
                    self.assertImageFile(image, fmt, options["size"])
                    with open_image(loctl, image, fmt) as (target, device):
                        ptable = self.read_partition_table(device)
                        self.assertPartitionTable(ptable,
                                                  "dos",
                                                  options["ptuuid"],
                                                  1,
                                                  boot_partition=1)
                        self.assertGRUB2(
                            device,
                            "26e3327c6b5ac9b5e21d8b86f19ff7cb4d12fb2d0406713f936997d9d89de3ee",
                            "9b31c8fbc59602a38582988bf91c3948ae9c6f2a231ab505ea63a7005e302147",
                            1024 * 1024)

                        p1 = ptable["partitions"][0]
                        ssize = ptable.get("sectorsize", 512)
                        start, size = p1["start"] * ssize, p1["size"] * ssize
                        with loop_open(loctl, target, offset=start,
                                       size=size) as dev:
                            self.assertFilesystem(dev, options["root_fs_uuid"],
                                                  "ext4", tree)
예제 #6
0
def test_lock(tempdir):

    path = os.path.join(tempdir, "test.img")
    ctl = loop.LoopControl()

    assert ctl

    lo, lo2, f = None, None, None
    try:
        f = open(path, "wb+")
        f.truncate(1024)
        f.flush()
        lo = ctl.loop_for_fd(f.fileno(), autoclear=True, lock=True)
        assert lo

        lo2 = loop.Loop(lo.minor)
        assert lo2

        with pytest.raises(BlockingIOError):
            lo2.flock(fcntl.LOCK_EX | fcntl.LOCK_NB)

        lo.close()
        lo = None

        # after lo is closed, the lock should be release and
        # we should be able to obtain the lock
        lo2.flock(fcntl.LOCK_EX | fcntl.LOCK_NB)
        lo2.clear_fd()

    finally:
        if lo2:
            lo2.close()
        if lo:
            lo.close()
        if f:
            f.close()

        ctl.close()
예제 #7
0
def test_basic(tempdir):

    test_data = b"osbuild"

    path = os.path.join(tempdir, "test.img")
    ctl = loop.LoopControl()

    assert ctl

    with pytest.raises(ValueError):
        ctl.loop_for_fd(-1)

    lo, f = None, None
    try:
        f = open(path, "wb+")
        f.truncate(1024)
        f.flush()
        lo = ctl.loop_for_fd(f.fileno(), autoclear=True)

        assert lo.is_bound_to(f.fileno())

        sb = os.fstat(f.fileno())

        assert lo
        assert lo.devname

        info = lo.get_status()
        assert info.lo_inode == sb.st_ino
        assert info.lo_number == lo.minor

        # check for `LoopInfo.is_bound_to` helper
        assert info.is_bound_to(sb)

        with TemporaryFile(dir=tempdir) as t:
            t.write(b"")
            t.flush()

            st = os.fstat(t.fileno())
            assert not info.is_bound_to(st)

        # check for autoclear flags setting and helpers
        assert info.autoclear

        lo.set_status(autoclear=False)
        info = lo.get_status()
        assert not info.autoclear

        with open(os.path.join("/dev", lo.devname), "wb") as f:
            f.write(test_data)

        # the `flush_buf` seems to be necessary when calling
        # `LoopInfo.clear_fd`, otherwise the data integrity
        # check later will fail
        lo.flush_buf()
        lo.clear_fd()

    finally:
        if lo:
            with contextlib.suppress(OSError):
                lo.clear_fd()
            lo.close()
        if f:
            f.close()

        ctl.close()

    # check for data integrity, i.e. that what we wrote via the
    # loop device was actually written to the underlying file
    with open(path, "rb") as f:
        assert f.read(len(test_data)) == test_data

    # closing must be a no-op on a closed LoopControl
    ctl.close()

    # check we raise exceptions on methods that require
    # an open LoopControl

    for fn in (ctl.add, ctl.remove, ctl.get_unbound):
        with pytest.raises(RuntimeError):
            fn()

    with pytest.raises(RuntimeError):
        ctl.loop_for_fd(0)
예제 #8
0
def test_clear_fd_wait(tempdir):

    path = os.path.join(tempdir, "test.img")
    ctl = loop.LoopControl()

    assert ctl

    delay_time = 0.25

    def close_loop(lo, barrier):
        barrier.wait()
        time.sleep(delay_time)
        print("closing loop")
        lo.close()

    lo, lo2, f = None, None, None
    try:
        f = open(path, "wb+")
        f.truncate(1024)
        f.flush()
        lo = ctl.loop_for_fd(f.fileno(), autoclear=False)
        assert lo

        # Increase reference count of the loop to > 1 thus
        # preventing the kernel from immediately closing the
        # device. Instead the kernel will set the autoclear
        # attribute and return
        lo2 = loop.Loop(lo.minor)
        assert lo2

        # as long as the second loop is alive, the kernel can
        # not clear the fd and thus we will get a timeout
        with pytest.raises(TimeoutError):
            lo.clear_fd_wait(f.fileno(), 0.1, 0.01)

        # start a thread and sync with a barrier, then close
        # the loop device in the background thread while the
        # main thread is waiting in `clear_fd_wait`. We wait
        # four times the delay time of the thread to ensure
        # we don't get a timeout.
        barrier = threading.Barrier(2)
        thread = threading.Thread(target=close_loop, args=(lo2, barrier))
        barrier.reset()
        thread.start()
        barrier.wait()

        lo.clear_fd_wait(f.fileno(), 4 * delay_time, delay_time / 10)

        # no timeout exception has occurred and thus the device
        # must not be be bound to the original file anymore
        assert not lo.is_bound_to(f.fileno())

    finally:
        if lo2:
            lo2.close()
        if lo:
            with contextlib.suppress(OSError):
                lo.clear_fd()
            lo.close()
        if f:
            f.close()

        ctl.close()
예제 #9
0
def test_rename_vg_group(tempdir):

    path = os.path.join(tempdir, "lvm.img")
    ctl = loop.LoopControl()

    f = None
    lo = None
    try:
        f = open(path, "wb+")
        f.truncate(100 * 1024 * 1024)
        f.flush()
        lo = make_loop(ctl, f.fileno(), 0, None)
        devname = os.path.join("/dev", lo.devname)

        vg_name = str(uuid.uuid4())
        pvcreate(devname)
        vgcreate(devname, vg_name)
        lvcreate(vg_name, "lv1", r"100%FREE")

        vgs = list_vgs()
        vg = find_vg(vgs, vg_name)
        assert vg

    finally:
        if lo:
            lo.close()
        if f:
            f.close()

    new_name = str(uuid.uuid4())
    with lvm2.Disk.open(path) as disk:
        assert disk.metadata
        assert disk.metadata.vg_name == vg_name

        disk.rename_vg(new_name)
        disk.creation_host = "osbuild"
        disk.description = "created via lvm2 and osbuild"

        disk.flush_metadata()

    f = None
    lo = None
    try:
        f = open(path, "rb")
        lo = make_loop(ctl, f.fileno(), 0, None)
        devname = os.path.join("/dev", lo.devname)

        vg = None
        for i in range(3):
            vgs = list_vgs()
            vg = find_vg(vgs, new_name)
            if vg:
                break
            time.sleep(0.250 * (i+1))
        if not vg:
            raise RuntimeError(f"Could not find vg {new_name}")
    finally:
        if lo:
            lo.close()
        if f:
            f.close()