139 lines
5.6 KiB
Python
139 lines
5.6 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.
|
|
|
|
from cinderclient import exceptions
|
|
from os_brick.initiator import connector
|
|
from oslo_concurrency import processutils
|
|
|
|
from freezer.engine.osbrick import brick_utils
|
|
from freezer.engine.osbrick import volume_actions as actions
|
|
|
|
|
|
class Client(object):
|
|
version = '1.1.0'
|
|
|
|
def __init__(self, volumes_client=None):
|
|
self.volumes_client = volumes_client
|
|
|
|
def _brick_get_connector(self, protocol, driver=None,
|
|
execute=processutils.execute,
|
|
use_multipath=False,
|
|
device_scan_attempts=3,
|
|
*args, **kwargs):
|
|
"""Wrapper to get a brick connector object.
|
|
|
|
This automatically populates the required protocol as well
|
|
as the root_helper needed to execute commands.
|
|
"""
|
|
return connector.InitiatorConnector.factory(
|
|
protocol,
|
|
brick_utils.get_root_helper(),
|
|
driver=driver,
|
|
execute=execute,
|
|
use_multipath=use_multipath,
|
|
device_scan_attempts=device_scan_attempts,
|
|
*args, **kwargs)
|
|
|
|
def get_connector(self, multipath=False, enforce_multipath=False):
|
|
conn_prop = connector.get_connector_properties(
|
|
brick_utils.get_root_helper(),
|
|
brick_utils.get_my_ip(),
|
|
multipath=multipath,
|
|
enforce_multipath=(enforce_multipath),
|
|
execute=processutils.execute)
|
|
return conn_prop
|
|
|
|
def attach(self, volume_id, hostname, mountpoint=None, mode='rw',
|
|
multipath=False, enforce_multipath=False):
|
|
|
|
# Check protocol type of storage backend.
|
|
with actions.VerifyProtocol(self.volumes_client, volume_id) as cmd:
|
|
# Retrieve vol-host attribute of volume.
|
|
volume_info = self.volumes_client.volumes.get(volume_id)
|
|
volume_capabilities = self.volumes_client.capabilities.get(
|
|
volume_info.__dict__['os-vol-host-attr:host'])
|
|
# Retrieve storage_protocol from storage backend capabilities.
|
|
protocol = volume_capabilities.storage_protocol.upper()
|
|
cmd.verify(protocol)
|
|
|
|
# Reserve volume before attachment
|
|
with actions.Reserve(self.volumes_client, volume_id) as cmd:
|
|
cmd.reserve()
|
|
|
|
with actions.InitializeConnection(
|
|
self.volumes_client, volume_id) as cmd:
|
|
connection = cmd.initialize(self, multipath, enforce_multipath)
|
|
|
|
with actions.ConnectVolume(self.volumes_client, volume_id) as cmd:
|
|
brick_connector = self._brick_get_connector(
|
|
protocol, do_local_attach=True)
|
|
device_info = cmd.connect(brick_connector,
|
|
connection['data'],
|
|
mountpoint, mode, hostname)
|
|
return device_info
|
|
|
|
def detach(self, volume_id, attachment_uuid=None, multipath=False,
|
|
enforce_multipath=False, device_info=None):
|
|
|
|
with actions.BeginDetach(self.volumes_client, volume_id) as cmd:
|
|
cmd.reserve()
|
|
|
|
with actions.InitializeConnectionForDetach(
|
|
self.volumes_client, volume_id) as cmd:
|
|
connection = cmd.initialize(self, multipath, enforce_multipath)
|
|
|
|
brick_connector = self._brick_get_connector(
|
|
connection['driver_volume_type'], do_local_attach=True)
|
|
|
|
with actions.DisconnectVolume(self.volumes_client, volume_id) as cmd:
|
|
cmd.disconnect(brick_connector, connection['data'], device_info)
|
|
|
|
with actions.DetachVolume(self.volumes_client, volume_id) as cmd:
|
|
cmd.detach(self, attachment_uuid, multipath, enforce_multipath)
|
|
|
|
def get_volume_paths(self, volume_id, use_multipath=False):
|
|
"""Gets volume paths on the system for a specific volume."""
|
|
conn_props = self.get_connector(multipath=use_multipath)
|
|
vols = self.volumes_client.volumes.list()
|
|
vol_in_use = False
|
|
vol_found = False
|
|
for vol in vols:
|
|
if (volume_id == vol.id or volume_id == vol.name):
|
|
vol_found = True
|
|
if vol.status == "in-use":
|
|
vol_in_use = True
|
|
# Make sure the volume ID is used and not the name
|
|
volume_id = vol.id
|
|
break
|
|
|
|
if not vol_found:
|
|
msg = "No volume with a name or ID of '%s' exists." % volume_id
|
|
raise exceptions.CommandError(msg)
|
|
|
|
paths = []
|
|
if vol_in_use:
|
|
conn_info = self.volumes_client.volumes.initialize_connection(
|
|
volume_id, conn_props)
|
|
protocol = conn_info['driver_volume_type']
|
|
conn = self._brick_get_connector(protocol,
|
|
use_multipath=use_multipath)
|
|
paths = conn.get_volume_paths(conn_info['data'])
|
|
|
|
return paths
|
|
|
|
def get_all_volume_paths(self, protocol, use_multipath=False):
|
|
"""Gets all volume paths on the system for a given protocol."""
|
|
conn = self._brick_get_connector(protocol, use_multipath=use_multipath)
|
|
paths = conn.get_all_available_volumes()
|
|
|
|
return paths
|