Beispiel #1
0
 def nbd(self, bind_address: str, bind_port: str, read_only: bool) -> None:
     with Benji(self.config) as benji_obj:
         store = BenjiStore(benji_obj)
         addr = (bind_address, bind_port)
         server = NbdServer(addr, store, read_only)
         logger.info("Starting to serve NBD on %s:%s" % (addr[0], addr[1]))
         server.serve_forever()
Beispiel #2
0
 def nbd(self, bind_address, bind_port, read_only):
     benji_obj = None
     try:
         benji_obj = Benji(self.config)
         store = BenjiStore(benji_obj)
         addr = (bind_address, bind_port)
         server = NbdServer(addr, store, read_only)
         logger.info("Starting to serve nbd on %s:%s" % (addr[0], addr[1]))
         server.serve_forever()
     finally:
         if benji_obj:
             benji_obj.close()
Beispiel #3
0
    def test(self):
        benji_obj = self.benjiOpen()
        store = BenjiStore(benji_obj)
        addr = ('127.0.0.1', self.SERVER_PORT)
        read_only = False
        self.nbd_server = NbdServer(addr, store, read_only)
        logger.info("Starting to serve NBD on %s:%s" % (addr[0], addr[1]))

        self.subprocess_run(args=['sudo', 'modprobe', 'nbd'])

        self.nbd_client_thread = threading.Thread(target=self.nbd_client, daemon=True, args=(self.version_uid,))
        self.nbd_client_thread.start()
        self.nbd_server.serve_forever()
        self.nbd_client_thread.join()

        self.assertEqual({self.version_uid[0], VersionUid(2)}, set([version.uid for version in benji_obj.ls()]))

        benji_obj.close()
Beispiel #4
0
class NbdTestCase:

    @staticmethod
    def patch(filename, offset, data=None):
        """ write data into a file at offset """
        if not os.path.exists(filename):
            open(filename, 'wb').close()
        with open(filename, 'r+b') as f:
            f.seek(offset)
            f.write(data)

    @staticmethod
    def read_file(file1):
        with open(file1, 'rb') as f1:
            data = f1.read()
        return data

    def generate_version(self, testpath):
        size = 4 * MB
        image_filename = os.path.join(testpath, 'image')
        with open(image_filename, 'wb') as f:
            f.truncate(size)
        for j in range(random.randint(20, 30)):
            patch_size = random.randint(0, 128 * kB)
            data = self.random_bytes(patch_size)
            offset = random.randint(0, size - 1 - patch_size)
            self.patch(image_filename, offset, data)

        benji_obj = self.benji_open(init_database=True)
        version = benji_obj.backup(version_uid=str(uuid.uuid4()),
                                   volume='data-backup',
                                   snapshot='snapshot-name',
                                   source='file:' + image_filename)
        version_uid = version.uid
        benji_obj.close()
        return version_uid, size

    def setUp(self):
        super().setUp()
        self.version_uid = self.generate_version(self.testpath.path)

    def tearDown(self):
        self.subprocess_run(args=['sudo', 'nbd-client', '-d', self.NBD_DEVICE], check=False)
        super().tearDown()

    def test(self):
        benji_obj = self.benji_open()
        store = BenjiStore(benji_obj)
        addr = ('127.0.0.1', self.SERVER_PORT)
        read_only = False
        self.nbd_server = NbdServer(addr, store, read_only)
        logger.info("Starting to serve NBD on %s:%s" % (addr[0], addr[1]))

        self.subprocess_run(args=['sudo', 'modprobe', 'nbd'])

        self.nbd_client_thread = threading.Thread(target=self.nbd_client, daemon=True, args=(self.version_uid,))
        self.nbd_client_thread.start()
        self.nbd_server.serve_forever()
        self.nbd_client_thread.join()

        self.assertEqual({self.version_uid[0], VersionUid(2)},
                         {version.uid for version in benji_obj.find_versions_with_filter()})

        benji_obj.close()

    def subprocess_run(self, args, success_regexp=None, check=True):
        completed = subprocess.run(args=args,
                                   stdin=subprocess.DEVNULL,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT,
                                   encoding='utf-8',
                                   errors='ignore')

        if check and completed.returncode != 0:
            self.fail('command {} failed: {}'.format(' '.join(args), completed.stdout.replace('\n', '|')))

        if success_regexp:
            if not re.match(success_regexp, completed.stdout, re.I | re.M | re.S):
                self.fail('command {} failed: {}'.format(' '.join(args), completed.stdout.replace('\n', '|')))

    def nbd_client(self, version_uid):
        self.subprocess_run(args=['sudo', 'nbd-client', '127.0.0.1', '-p',
                                  str(self.SERVER_PORT), '-l'],
                            success_regexp='^Negotiation: ..\n{}\n$'.format(version_uid[0]))

        version_uid, size = version_uid
        self.subprocess_run(
            args=['sudo', 'nbd-client', '-N', version_uid, '127.0.0.1', '-p',
                  str(self.SERVER_PORT), self.NBD_DEVICE],
            success_regexp='^Negotiation: ..size = \d+MB\nbs=1024, sz=\d+ bytes\n$|^Negotiation: ..size = \d+MB|Connected /dev/nbd\d+$')

        count = 0
        nbd_data = bytearray()
        with open(self.NBD_DEVICE, 'rb') as f:
            while True:
                data = f.read(64 * 1024 + random.randint(0, 8192))
                if not data:
                    break
                count += len(data)
                nbd_data += data
        self.assertEqual(size, count)

        image_data = self.read_file(self.testpath.path + '/image')
        logger.info('image_data size {}, nbd_data size {}'.format(len(image_data), len(nbd_data)))
        self.assertEqual(image_data, bytes(nbd_data))

        f = os.open(self.NBD_DEVICE, os.O_RDWR)
        for offset in range(0, size, 4096):
            os.lseek(f, offset, os.SEEK_SET)
            data = self.random_bytes(4096)
            written = os.write(f, data)
            os.fsync(f)
            self.assertEqual(len(data), written)
            # Discard cache so that the read request below really goes to the NBD server
            os.posix_fadvise(f, offset, len(data), os.POSIX_FADV_DONTNEED)

            os.lseek(f, offset, os.SEEK_SET)
            read_data = os.read(f, 4096)
            self.assertEqual(data, read_data)
        os.close(f)

        self.subprocess_run(args=['sudo', 'nbd-client', '-d', self.NBD_DEVICE],
                            success_regexp='^disconnect, sock, done\n$')

        # Signal NBD server to stop
        self.nbd_server.stop()