14df0c7721
TrivialFix Change-Id: I2dde2430011a777bffc1f0d25886784c9ed04b68
115 lines
4.1 KiB
Python
115 lines
4.1 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""
|
|
Generic SheepDog Connection Utilities.
|
|
|
|
"""
|
|
import eventlet
|
|
import io
|
|
from oslo_concurrency import processutils
|
|
|
|
from os_brick import exception
|
|
from os_brick.i18n import _
|
|
|
|
|
|
class SheepdogVolumeIOWrapper(io.RawIOBase):
|
|
"""File-like object with Sheepdog backend."""
|
|
|
|
def __init__(self, addr, port, volume, snapshot_name=None):
|
|
self._addr = addr
|
|
self._port = port
|
|
self._vdiname = volume
|
|
self._snapshot_name = snapshot_name
|
|
self._offset = 0
|
|
# SheepdogVolumeIOWrapper instance becomes invalid
|
|
# if a write error occurs.
|
|
self._valid = True
|
|
|
|
def _execute(self, cmd, data=None):
|
|
try:
|
|
# NOTE(yamada-h): processutils.execute causes busy waiting
|
|
# under eventlet.
|
|
# To avoid wasting CPU resources, it should not be used for
|
|
# the command which takes long time to execute.
|
|
# For workaround, we replace a subprocess module with
|
|
# the original one while only executing a read/write command.
|
|
_processutils_subprocess = processutils.subprocess
|
|
processutils.subprocess = eventlet.patcher.original('subprocess')
|
|
return processutils.execute(*cmd, process_input=data)[0]
|
|
except (processutils.ProcessExecutionError, OSError):
|
|
self._valid = False
|
|
raise exception.VolumeDriverException(name=self._vdiname)
|
|
finally:
|
|
processutils.subprocess = _processutils_subprocess
|
|
|
|
def read(self, length=None):
|
|
if not self._valid:
|
|
raise exception.VolumeDriverException(name=self._vdiname)
|
|
|
|
cmd = ['dog', 'vdi', 'read', '-a', self._addr, '-p', self._port]
|
|
if self._snapshot_name:
|
|
cmd.extend(('-s', self._snapshot_name))
|
|
cmd.extend((self._vdiname, self._offset))
|
|
if length:
|
|
cmd.append(length)
|
|
data = self._execute(cmd)
|
|
self._offset += len(data)
|
|
return data
|
|
|
|
def write(self, data):
|
|
if not self._valid:
|
|
raise exception.VolumeDriverException(name=self._vdiname)
|
|
|
|
length = len(data)
|
|
cmd = ('dog', 'vdi', 'write', '-a', self._addr, '-p', self._port,
|
|
self._vdiname, self._offset, length)
|
|
self._execute(cmd, data)
|
|
self._offset += length
|
|
return length
|
|
|
|
def seek(self, offset, whence=0):
|
|
if not self._valid:
|
|
raise exception.VolumeDriverException(name=self._vdiname)
|
|
|
|
if whence == 0:
|
|
# SEEK_SET or 0 - start of the stream (the default);
|
|
# offset should be zero or positive
|
|
new_offset = offset
|
|
elif whence == 1:
|
|
# SEEK_CUR or 1 - current stream position; offset may be negative
|
|
new_offset = self._offset + offset
|
|
else:
|
|
# SEEK_END or 2 - end of the stream; offset is usually negative
|
|
# TODO(yamada-h): Support SEEK_END
|
|
raise IOError(_("Invalid argument - whence=%s not supported.") %
|
|
whence)
|
|
|
|
if new_offset < 0:
|
|
raise IOError(_("Invalid argument - negative seek offset."))
|
|
|
|
self._offset = new_offset
|
|
|
|
def tell(self):
|
|
return self._offset
|
|
|
|
def flush(self):
|
|
pass
|
|
|
|
def fileno(self):
|
|
"""Sheepdog does not have support for fileno so we raise IOError.
|
|
|
|
Raising IOError is recommended way to notify caller that interface is
|
|
not supported - see http://docs.python.org/2/library/io.html#io.IOBase
|
|
"""
|
|
raise IOError(_("fileno is not supported by SheepdogVolumeIOWrapper"))
|