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()
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()
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()
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()