# 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 __future__ import print_function from cinderclient import exceptions from os_brick.initiator import connector from oslo_concurrency import processutils from brick_cinderclient_ext import brick_utils from brick_cinderclient_ext 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): # 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.VerifyProtocol(self.volumes_client, volume_id) as cmd: cmd.verify(connection['driver_volume_type']) with actions.ConnectVolume(self.volumes_client, volume_id) as cmd: brick_connector = self._brick_get_connector( connection['driver_volume_type'], 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