def _get_docker_volume(self, docker_volume_name): search_opts = { 'name': docker_volume_name, 'metadata': { consts.VOLUME_FROM: CONF.volume_from } } try: docker_shares = self.manilaclient.shares.list( search_opts=search_opts) except manila_exception.ClientException as e: LOG.error("Could not retrieve Manila share list. Error: %s", e) raise if not docker_shares: raise exceptions.NotFound("Could not find share with " "search_opts: {0}".format(search_opts)) elif len(docker_shares) > 1: raise exceptions.TooManyResources( "Find too many shares with search_opts: {0}, while " "for Fuxi, should get only one share with provided " "search_opts".format(docker_shares)) docker_share = docker_shares[0] if self.connector.check_access_allowed(docker_share): return docker_share, ATTACH_TO_THIS else: return docker_share, NOT_ATTACH
def show(self, docker_volume_name): cinder_volume, state = self._get_docker_volume(docker_volume_name) LOG.info(_LI("Get docker volume {0} {1} with state " "{2}").format(docker_volume_name, cinder_volume, state)) if state == ATTACH_TO_THIS: devpath = os.path.realpath( self._get_connector().get_device_path(cinder_volume)) mp = self._get_mountpoint(docker_volume_name) LOG.info("Expected devpath: {0} and mountpoint: {1} for volume: " "{2} {3}".format(devpath, mp, docker_volume_name, cinder_volume)) mounter = mount.Mounter() return {"Name": docker_volume_name, "Mountpoint": mp if mp in mounter.get_mps_by_device( devpath) else ''} elif state in (NOT_ATTACH, ATTACH_TO_OTHER): return {'Name': docker_volume_name, 'Mountpoint': ''} elif state == UNKNOWN: msg = _LW("Can't find this volume '{0}' in " "OpenSDS").format(docker_volume_name) LOG.warning(msg) raise exceptions.NotFound(msg) else: msg = _LE("Volume '{0}' exists, but not attached to this volume," "and current state is {1}").format(docker_volume_name, state) raise exceptions.NotMatchedState(msg)
def test_check_exist(self): with mock.patch('fuxi.volumeprovider.manila.Manila._get_docker_volume', side_effect=exceptions.NotFound()): self.assertFalse(self.provider.check_exist('fake-vol')) with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_object.FakeManilaShare(), consts.ATTACH_TO_THIS)): self.assertTrue(self.provider.check_exist('fake-vol'))
def test_volumedriver_get_with_volume_not_exist(self): self.volume_providers_setup(['cinder']) fake_docker_volume_name = u'test-vol' fake_request = {u'Name': fake_docker_volume_name} for provider in app.volume_providers.values(): provider.show = mock.MagicMock(side_effect=exceptions.NotFound()) response = self.app.post('/VolumeDriver.Get', content_type='application/json', data=jsonutils.dumps(fake_request)) fake_response = {u'Err': u'Volume Not Found'} self.assertEqual(200, response.status_code) self.assertEqual(fake_response, jsonutils.loads(response.data))
def show(self, docker_volume_name): cinder_volume, state = self._get_docker_volume(docker_volume_name) LOG.info(_LI("Get docker volume %(d_v)s %(vol)s with state %(st)s"), { 'd_v': docker_volume_name, 'vol': cinder_volume, 'st': state }) if state == ATTACH_TO_THIS: devpath = os.path.realpath( self._get_connector().get_device_path(cinder_volume)) mp = self._get_mountpoint(docker_volume_name) LOG.info( _LI("Expected devpath: %(dp)s and mountpoint: %(mp)s for" " volume: %(d_v)s %(vol)s"), { 'dp': devpath, 'mp': mp, 'd_v': docker_volume_name, 'vol': cinder_volume }) mounter = mount.Mounter() return { "Name": docker_volume_name, "Mountpoint": mp if mp in mounter.get_mps_by_device(devpath) else '' } elif state in (NOT_ATTACH, ATTACH_TO_OTHER): return {'Name': docker_volume_name, 'Mountpoint': ''} elif state == UNKNOWN: msg = _LW("Can't find this volume '{0}' in " "Cinder").format(docker_volume_name) LOG.warning(msg) raise exceptions.NotFound(msg) else: msg = _LE("Volume '{0}' exists, but not attached to this volume," "and current state is {1}").format( docker_volume_name, state) raise exceptions.NotMatchedState(msg)
def connect_volume(self, volume, **connect_opts): bdm = blockdevice.BlockerDeviceManager() ori_devices = bdm.device_scan() # Do volume-attach try: server_id = connect_opts.get('server_id', None) if not server_id: server_id = utils.get_instance_uuid() LOG.info("Start to connect to volume %s", volume) nova_volume = self.novaclient.volumes.create_server_volume( server_id=server_id, volume_id=volume.id, device=None) volume_monitor = state_monitor.StateMonitor( self.cinderclient, nova_volume, 'in-use', ( 'available', 'attaching', )) attached_volume = volume_monitor.monitor_cinder_volume() except nova_exception.ClientException as ex: LOG.error( "Attaching volume %(vol)s to server %(s)s " "failed. Error: %(err)s", { 'vol': volume.id, 's': server_id, 'err': ex }) raise # Get all devices on host after do volume-attach, # and then find attached device. LOG.info("After connected to volume, scan the added " "block device on host") curr_devices = bdm.device_scan() start_time = time.time() delta_devices = list(set(curr_devices) - set(ori_devices)) while not delta_devices: time.sleep(consts.DEVICE_SCAN_TIME_DELAY) curr_devices = bdm.device_scan() delta_devices = list(set(curr_devices) - set(ori_devices)) if time.time() - start_time > consts.DEVICE_SCAN_TIMEOUT: msg = _("Could not detect added device with " "limited time") raise exceptions.FuxiException(msg) LOG.info("Get extra added block device %s", delta_devices) for device in delta_devices: if bdm.get_device_size(device) == volume.size: device = device.replace('/sys/block', '/dev') LOG.info( "Find attached device %(dev)s" " for volume %(at)s %(vol)s", { 'dev': device, 'at': attached_volume.name, 'vol': volume }) link_path = os.path.join(consts.VOLUME_LINK_DIR, volume.id) try: utils.execute('ln', '-s', device, link_path, run_as_root=True) except processutils.ProcessExecutionError as e: LOG.error( "Error happened when create link file for" " block device attached by Nova." " Error: %s", e) raise return {'path': link_path} LOG.warning("Could not find matched device") raise exceptions.NotFound("Not Found Matched Device")
class TestManila(base.TestCase): def setUp(self): super(TestManila, self).setUp() self._set_up_provider() @mock.patch.object(utils, 'get_manilaclient', return_value=fake_client.FakeManilaClient()) def _set_up_provider(self, mock_client): self.provider = manila.Manila() self.provider.manilaclient = fake_client.FakeManilaClient() self.provider.connector = FakeManilaConnector() def test_create_exist(self): fake_share = fake_object.FakeManilaShare(name='fake-vol', id='fake-id', export_location='fake-el') for status in [consts.NOT_ATTACH, consts.ATTACH_TO_THIS]: with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_share, status)): self.assertEqual('fake-el', self.provider.create('fake-vol', {})['path']) @mock.patch('fuxi.volumeprovider.manila.Manila._get_docker_volume', side_effect=exceptions.NotFound()) def test_create_from_id(self, mock_docker_volume): fake_vol_opts = {'volume_id': 'fake-id'} fake_share = fake_object.FakeManilaShare(name='fake-vol', id='fake-id', export_location='fake-el', status='available', metadata={}) with mock.patch.object(fake_client.FakeManilaClient.Shares, 'get', return_value=fake_share): self.assertEqual( 'fake-el', self.provider.create('fake-vol', fake_vol_opts)['path']) @mock.patch('fuxi.volumeprovider.manila.Manila._get_docker_volume', side_effect=exceptions.NotFound()) def test_create_not_exist(self, mock_docker_volume): fake_vol_opts = {'share_network': 'fake-share-network'} fake_share = fake_object.FakeManilaShare(name='fake-vol', id='fake-id', export_location='fake-el', status='creating') with mock.patch.object(fake_client.FakeManilaClient.Shares, 'create', return_value=fake_share): fake_share.status = 'available' with mock.patch.object(state_monitor.StateMonitor, 'monitor_manila_share', return_value=fake_share): self.assertEqual( 'fake-el', self.provider.create('fake-vol', fake_vol_opts)['path']) @mock.patch.object(utils, 'execute') @mock.patch.object(mount.Mounter, 'get_mps_by_device', return_value=[]) def test_delete(self, mock_execute, mock_mps): fake_share = fake_object.FakeManilaShare(name='fake-vol', id='fake-id', export_location='fake-el') with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_share, consts.ATTACH_TO_THIS)): with mock.patch.object(manila.Manila, '_delete_share'): self.assertTrue(self.provider.delete('fake-vol')) def test_mount(self): fake_share = fake_object.FakeManilaShare(name='fake-vol', id='fake-id', export_location='fake-el', share_proto='nfs') with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_share, consts.ATTACH_TO_THIS)): self.assertEqual('fake-vol', self.provider.mount('fake-vol')) def test_unmount(self): self.assertIsNone(self.provider.unmount('fake-vol')) def test_show(self): fake_vol = fake_object.DEFAULT_VOLUME_NAME with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_object.FakeManilaShare(), consts.ATTACH_TO_THIS)): self.assertEqual({ 'Name': fake_vol, 'Mountpoint': fake_vol }, self.provider.show(fake_vol)) @mock.patch('fuxi.tests.unit.fake_client.FakeManilaClient.Shares.list', side_effect=manila_exception.ClientException(500)) def test_show_list_failed(self, mock_list): self.assertRaises(manila_exception.ClientException, self.provider.show, 'fake-vol') @mock.patch.object(fake_client.FakeManilaClient.Shares, 'list', return_value=[]) def test_show_no_share(self, mock_list): self.assertRaises(exceptions.NotFound, self.provider.show, 'fake-vol') @mock.patch.object(fake_client.FakeManilaClient.Shares, 'list', return_value=[ fake_object.FakeManilaShare(id='1'), fake_object.FakeManilaShare(id='2') ]) def test_show_too_many_shares(self, mock_list): self.assertRaises(exceptions.TooManyResources, self.provider.show, 'fake-vol') @mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_object.FakeManilaShare(), consts.NOT_ATTACH)) def test_show_not_attach(self, mock_docker_volume): fake_vol = fake_object.DEFAULT_VOLUME_NAME self.assertEqual({ 'Name': fake_vol, 'Mountpoint': fake_vol }, self.provider.show(fake_vol)) @mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_object.FakeManilaShare(), consts.ATTACH_TO_THIS)) def test_show_not_mount(self, mock_dokcer_volume): fake_vol = fake_object.DEFAULT_VOLUME_NAME self.assertEqual({ 'Name': fake_vol, 'Mountpoint': fake_vol }, self.provider.show(fake_vol)) def test_list(self): share_dict = [{ 'id': 'fake-id1', 'name': 'fake-name1', 'export_location': 'fake-el1' }, { 'id': 'fake-id2', 'name': 'fake-name2', 'export_location': 'fake-el2' }] fake_shares = [fake_object.FakeManilaShare(**s) for s in share_dict] fake_volumes = [{ 'Name': 'fake-name1', 'Mountpoint': 'fake-name1' }, { 'Name': 'fake-name2', 'Mountpoint': 'fake-name2' }] with mock.patch.object(fake_client.FakeManilaClient.Shares, 'list', return_value=fake_shares): with mock.patch.object(mount.Mounter, 'get_mps_by_device', return_value=[]): self.assertEqual(fake_volumes, self.provider.list()) def test_list_failed(self): with mock.patch( 'fuxi.tests.unit.fake_client.FakeManilaClient' '.Shares.list', side_effect=manila_exception.ClientException): self.assertRaises(manila_exception.ClientException, self.provider.list) def test_check_exist(self): with mock.patch('fuxi.volumeprovider.manila.Manila._get_docker_volume', side_effect=exceptions.NotFound()): self.assertFalse(self.provider.check_exist('fake-vol')) with mock.patch.object(manila.Manila, '_get_docker_volume', return_value=(fake_object.FakeManilaShare(), consts.ATTACH_TO_THIS)): self.assertTrue(self.provider.check_exist('fake-vol'))