Пример #1
0
    def __init__(self,
                 exportName,
                 metaContext,
                 host="localhost",
                 port="10809"):
        """TODO: to be defined.

        :host: TODO
        :port: TODO

        """
        self._host = host
        self._port = port
        self._exportName = exportName
        if metaContext == None:
            self._metaContext = nbd.CONTEXT_BASE_ALLOCATION
        else:
            self._metaContext = metaContext

        self.maxRequestSize = 33554432
        self.minRequestSize = 65536

        self._connectionHandle = None

        self._nbdHandle = nbd.NBD()
Пример #2
0
    def test_get_size():
        """
        libnbd get_size test

        1) create a nbd server by nbdkit
        2) check the image size by get_size
        3) check the image content by pwrite and pread
        """
        expected_size = int(params.get('image_size', 1048576))
        real_size = 0
        # must be a bytes-like object for pwrite
        expected_str = b'hello, world'

        handle = nbd.NBD()
        handle.connect_command([
            "nbdkit", "--exit-with-parent", "-s", "memory",
            "size=%d" % expected_size
        ])
        real_size = handle.get_size()

        if real_size != expected_size:
            test.fail('get_size failed: expected: %s, real: %s' %
                      (expected_size, real_size))

        handle.pwrite(expected_str, 0, nbd.CMD_FLAG_FUA)
        real_str = handle.pread(len(expected_str), 0)

        if real_str != expected_str:
            test.fail('pwrite or pread failed: expected: %s, real: %s' %
                      (expected_str, real_str))
Пример #3
0
def conn(mode):
    global exports
    exports = []
    h = nbd.NBD()
    try:
        h.set_opt_mode(True)
        h.connect_command([
            "nbdkit", "-s", "--exit-with-parent", "-v", "sh", script,
            "mode=%d" % mode
        ])
        yield h
    finally:
        h.opt_abort()
        h = None
Пример #4
0
def shell():
    import argparse
    import code
    import sys

    import nbd

    description = '''Network Block Device (NBD) shell'''
    parser = argparse.ArgumentParser(prog='nbdsh', description=description)
    parser.add_argument('--connect', help="connect to NBD URI")
    parser.add_argument('-c',
                        '--command',
                        action='append',
                        help="run a command")
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=nbd.package_name + ' ' + nbd.__version__)
    args = parser.parse_args()

    h = nbd.NBD()
    sys.ps1 = "nbd> "

    banner = '''
Welcome to nbdsh, the shell for interacting with
Network Block Device (NBD) servers.

The ‘nbd’ module has already been imported and there
is an open NBD handle called ‘h’.

h.connect_tcp ("remote", "10809")   # Connect to a remote server.
h.get_size ()                       # Get size of the remote disk.
buf = h.pread (512, 0, 0)           # Read the first sector.
exit() or Ctrl-D                    # Quit the shell
help (nbd)                          # Display documentation
'''

    if args.connect is not None:
        h.connect_uri(args.connect)
    # If there are no -c or --command parameters, go interactive,
    # otherwise we run the commands and exit.
    if not args.command:
        code.interact(banner=banner, local=locals(), exitmsg='')
    else:
        for c in args.command:
            if c != '-':
                exec(c)
            else:
                exec(sys.stdin.read())
Пример #5
0
    def __new__(cls, data):
        if not data.get('two_phase', False):
            return None
        try:
            import nbd
        except ImportError:
            raise RuntimeError('libnbd is not available, it is required for '
                               'two-phase conversion')

        nbd_version = version.parse(nbd.NBD().get_version())
        if nbd_version < NBD_MIN_VERSION:
            raise RuntimeError('libnbd is too old (%s), '
                               'minimum version required is %s' %
                               (nbd_version, NBD_MIN_VERSION))
        return super(PreCopy, cls).__new__(cls)
Пример #6
0
    def __init__(self, exportName, metaContext, backupSocket):
        """Parameters:
        :exportName: name of nbd export
        :backupSocket: ndb server endpoint
        """
        self._socket = backupSocket
        self._exportName = exportName
        if metaContext is None:
            self._metaContext = nbd.CONTEXT_BASE_ALLOCATION
        else:
            self._metaContext = metaContext

        self.maxRequestSize = 33554432
        self.minRequestSize = 65536

        self._connectionHandle = None

        self._nbdHandle = nbd.NBD()

        self.version()
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of Red Hat nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

# Used by test-readahead.sh to make a linear series of requests
# with a constant, known size.

import nbd
import sys

h = nbd.NBD()
h.connect_unix(sys.argv[1])

for i in range(0, 512*10, 512):
    h.pread(512, i)
Пример #8
0
    def sync_disks(self, vm_id, disks_mappings, guestfs_helper, sync_index,
                   last_sync):
        MAX_PREAD_LEN = 23 << 20  # 23MB (24MB requests fail in VDDK)
        MAX_AIO_IN_FLIGHT = 2

        vm = self._find_vm_by_id(vm_id)
        snapshot = self.create_snapshot(vm_id,
                                        name="conversion-%s" %
                                        now.strftime('%Y%m%d-%H%M%S'))
        self._update_change_ids(vm_id, snapshot, disks_mappings)
        self._get_changed_extents(vm_id, snapshot, disks_mappings, sync_index,
                                  last_sync)

        for dm in disks_mappings:
            logging.debug("Opening locally attached disk %s" %
                          dm["destination"]["conversion_host_path"])
            fd = os.open(dm["destination"]["conversion_host_path"],
                         os.O_WRONLY | os.O_CREAT)

            if len(dm["source"]["extents"]) == 0:
                os.close(fd)
                continue

            logging.info("Connecting the source disk %s with NBD",
                         dm["source"]["id"])
            nbd_cmd = guestfs_helper.nbd_expose_disk_cmd(dm["source"],
                                                         None,
                                                         vm_moref=vm._moId,
                                                         sync_index=sync_index)
            logging.debug("NBD Command: %s", nbd_cmd)
            nbd_handle = nbd.NBD()
            nbd_handle.add_meta_context("base:allocation")
            nbd_handle.connect_command(nbd_cmd)

            logging.info("Getting block info for disk: %s" %
                         dm["source"]["id"])
            copied = 0
            position = 0
            data_blocks = []
            for extent in dm["source"]["extents"]:
                if extent.length < 1 << 20:
                    logging.debug(
                        "Skipping block status for extent of size %d B at offset %d B"
                        % (extent.length, extent.start))
                    data_blocks.append({
                        "offset": extent.start,
                        "length": extent.length,
                        "flags": 0
                    })
                    continue

                blocks = self._get_block_status(nbd_handle, extent)
                logging.debug("Gathered block status of %d: %s" %
                              (len(blocks), blocks))
                data_blocks += [
                    x for x in blocks if not x['flags'] & nbd.STATE_HOLE
                ]

            logging.debug("Block status filtered down to %d data blocks" %
                          len(data_blocks))
            if len(data_blocks) == 0:
                logging.debug("No extents have allocated data for disk: %s" %
                              dm["source"]["id"])
                os.close(fd)
                continue

            to_copy = sum([x['length'] for x in data_blocks])
            logging.debug("Copying %d B of data for disk %s" %
                          (to_copy, dm["source"]["id"]))

            self._state.disks[dm["source"]["id"]]["syncs"].append({
                "to_copy": to_copy,
                "copied": 0
            })
            self._state.write()

            for block in data_blocks:
                logging.debug("Block at offset %s flags: %s", block["offset"],
                              block["flags"])
                if block["flags"] & nbd.STATE_ZERO:
                    logging.debug("Writing %d B of zeros to offset %d B" %
                                  (block["length"], block["offset"]))
                    # Optimize for memory usage, maybe?
                    os.pwrite(fd, [0] * block["length"], block["offset"])
                else:
                    count = 0
                    while count < block["length"]:
                        length = min(block["length"] - count, MAX_PREAD_LEN)
                        offset = block["offset"] + count

                        logging.debug("Reading %d B from offset %d B" %
                                      (length, offset))
                        buf = nbd.Buffer(length)
                        nbd_handle.aio_pread(
                            buf,
                            offset,
                            lambda err, fd=fd, buf=buf, offset=offset: self.
                            _write_data(fd, buf, offset, err))
                        count += length

                        while nbd_handle.aio_in_flight() > MAX_AIO_IN_FLIGHT:
                            nbd_handle.poll(-1)
                        guestfs_helper.nbd_process_aio_requests(nbd_handle)

                        copied += length
                        self._state.disks[dm["source"]["id"]]["syncs"][
                            sync_index]["copied"] = copied
                        self._state.write()

            guestfs_helper.nbd_wait_for_aio_commands_to_finish(nbd_handle)

            if copied == 0:
                logging.debug("Nothing to copy for disk: %s" %
                              dm["source"]["id"])
            else:
                logging.debug("Copied %d B for disk: %s" %
                              (copied, dm["source"]["id"]))

            nbd_handle.shutdown()
            os.close(fd)

        self._remove_all_snapshots(vm_id)
Пример #9
0
def shell():
    import argparse
    import code
    import sys

    import nbd

    description = '''Network Block Device (NBD) shell'''
    epilog = '''Please read the nbdsh(1) manual page for full usage.'''
    parser = argparse.ArgumentParser(prog='nbdsh',
                                     description=description,
                                     epilog=epilog)
    short_options = []
    long_options = []

    parser.add_argument('--base-allocation',
                        action='store_true',
                        help='request the "base:allocation" meta context')
    long_options.append("--base-allocation")

    parser.add_argument('-u', '--uri', help="connect to NBD URI")
    short_options.append("-u")
    long_options.append("--uri")
    # For back-compat, provide --connect as an undocumented synonym to --uri
    parser.add_argument('--connect', dest='uri', help=argparse.SUPPRESS)

    parser.add_argument('-c',
                        '--command',
                        action='append',
                        help="run a command")
    short_options.append("-c")
    long_options.append("--command")

    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=nbd.package_name + ' ' + nbd.__version__)
    short_options.append("-V")
    long_options.append("--version")

    # These hidden options are used by bash tab completion.
    parser.add_argument("--short-options", action='store_true')
    parser.add_argument("--long-options", action='store_true')

    args = parser.parse_args()

    if args.short_options:
        short_options.sort()
        print("\n".join(short_options))
        exit(0)
    if args.long_options:
        long_options.sort()
        print("\n".join(long_options))
        exit(0)

    h = nbd.NBD()
    h.set_handle_name("nbdsh")
    sys.ps1 = "nbd> "

    banner = '''
Welcome to nbdsh, the shell for interacting with
Network Block Device (NBD) servers.

The ‘nbd’ module has already been imported and there
is an open NBD handle called ‘h’.

h.connect_tcp ("remote", "10809")   # Connect to a remote server.
h.get_size ()                       # Get size of the remote disk.
buf = h.pread (512, 0, 0)           # Read the first sector.
exit() or Ctrl-D                    # Quit the shell
help (nbd)                          # Display documentation
'''

    if args.base_allocation:
        h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION)
    if args.uri is not None:
        h.connect_uri(args.uri)
    # If there are no -c or --command parameters, go interactive,
    # otherwise we run the commands and exit.
    if not args.command:
        code.interact(banner=banner, local=locals(), exitmsg='')
    else:
        # https://stackoverflow.com/a/11754346
        d = dict(locals(), **globals())
        for c in args.command:
            if c != '-':
                exec(c, d, d)
            else:
                exec(sys.stdin.read(), d, d)
Пример #10
0
 def setUp(self):
     self.h = nbd.NBD()
Пример #11
0
            # slept in the select.
            if fd == sfd and revents & select.POLLIN and \
                    src.aio_get_direction() & nbd.AIO_DIRECTION_READ:
                src.aio_notify_read()
            elif fd == sfd and revents & select.POLLOUT and \
                    src.aio_get_direction() & nbd.AIO_DIRECTION_WRITE:
                src.aio_notify_write()
            elif fd == dfd and revents & select.POLLIN and \
                    dst.aio_get_direction() & nbd.AIO_DIRECTION_READ:
                dst.aio_notify_read()
            elif fd == dfd and revents & select.POLLOUT and \
                    dst.aio_get_direction() & nbd.AIO_DIRECTION_WRITE:
                dst.aio_notify_write()


src = nbd.NBD()
src.set_handle_name("src")
dst = nbd.NBD()
dst.set_handle_name("dst")
src.connect_command([
    "nbdkit", "-s", "--exit-with-parent", "-r", "pattern",
    "size=%d" % disk_size
])
dst.connect_command(
    ["nbdkit", "-s", "--exit-with-parent", "memory",
     "size=%d" % disk_size])
asynch_copy(src, dst)

print("bytes read: %d written: %d size: %d" %
      (bytes_read, bytes_written, disk_size))
assert bytes_read == disk_size
Пример #12
0
def shell():
    import argparse
    import code
    import os
    import sys

    import libnbdmod
    import nbd

    description = '''Network Block Device (NBD) shell'''
    epilog = '''Please read the nbdsh(1) manual page for full usage.'''
    parser = argparse.ArgumentParser(prog='nbdsh', description=description,
                                     epilog=epilog)
    short_options = []
    long_options = []

    parser.add_argument('--base-allocation', action='store_true',
                        help='request the "base:allocation" meta context')
    long_options.append("--base-allocation")

    parser.add_argument('-c', '--command', action='append',
                        help="run a Python statement "
                        "(may be used multiple times)")
    short_options.append("-c")
    long_options.append("--command")

    parser.add_argument('-n', action='store_true',
                        help="do not create the implicit handle 'h'")
    short_options.append("-n")

    parser.add_argument('--opt-mode', action='store_true',
                        help='request opt mode during connection')
    long_options.append("--opt-mode")

    parser.add_argument('-u', '--uri', help="connect to NBD URI")
    short_options.append("-u")
    long_options.append("--uri")
    # For back-compat, provide --connect as an undocumented synonym to --uri
    parser.add_argument('--connect', dest='uri', help=argparse.SUPPRESS)

    parser.add_argument('-v', '--verbose', action='store_true')
    short_options.append("-v")
    long_options.append("--verbose")

    parser.add_argument('-V', '--version', action='store_true')
    short_options.append("-V")
    long_options.append("--version")

    # These hidden options are used by bash tab completion.
    parser.add_argument("--short-options", action='store_true',
                        help=argparse.SUPPRESS)
    parser.add_argument("--long-options", action='store_true',
                        help=argparse.SUPPRESS)

    args = parser.parse_args()

    # It's an error if -n is passed with certain other options.
    if args.n and (args.base_allocation or
                   args.opt_mode or
                   args.uri is not None):
        print("error: -n option cannot be used with " +
              "--base-allocation, --opt-mode or --uri",
              file=sys.stderr)
        exit(1)

    # Handle the informational options which exit.
    if args.version:
        libnbdmod.display_version("nbdsh")
        exit(0)
    if args.short_options:
        short_options.sort()
        print("\n".join(short_options))
        exit(0)
    if args.long_options:
        long_options.sort()
        print("\n".join(long_options))
        exit(0)

    # Create the banner and prompt.
    banner = make_banner(args)
    sys.ps1 = "nbd> "

    # If verbose, set LIBNBD_DEBUG=1
    if args.verbose:
        os.environ["LIBNBD_DEBUG"] = "1"

    # Create the handle.
    if not args.n:
        h = nbd.NBD()
        h.set_handle_name("nbdsh")

        # Set other attributes in the handle.
        if args.base_allocation:
            h.add_meta_context(nbd.CONTEXT_BASE_ALLOCATION)
        if args.opt_mode:
            h.set_opt_mode(True)

        # Parse the URI.
        if args.uri is not None:
            try:
                h.connect_uri(args.uri)
            except nbd.Error as ex:
                print("nbdsh: unable to connect to uri '%s': %s" %
                      (args.uri, ex.string), file=sys.stderr)
                sys.exit(1)

    # If there are no -c or --command parameters, go interactive,
    # otherwise we run the commands and exit.
    if not args.command:
        code.interact(banner=banner, local=locals(), exitmsg='')
    else:
        # https://stackoverflow.com/a/11754346
        d = dict(locals(), **globals())
        try:
            for c in args.command:
                if c != '-':
                    exec(c, d, d)
                else:
                    exec(sys.stdin.read(), d, d)
        except nbd.Error as ex:
            if nbd.NBD().get_debug():
                traceback.print_exc()
            else:
                print("nbdsh: command line script failed: %s" % ex.string,
                      file=sys.stderr)
            sys.exit(1)