freezer/freezer/engine/osbrick/client.py

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