예제 #1
0
def fake_datastore_obj(*args, **kwargs):
    dc_obj = oslo_datacenter.Datacenter(ref='fake-ref',
                                        name='fake-name')
    dc_obj.path = args[0]
    return oslo_datastore.Datastore(ref='fake-ref',
                                    datacenter=dc_obj,
                                    name=args[1])
예제 #2
0
    def test_enlist_image(self,
                          mock_get_ds_browser,
                          mock_timestamp_cleanup,
                          mock_timestamp_folder_get):
        image_id = "fake_image_id"
        dc_ref = "fake_dc_ref"
        fake_ds_ref = mock.Mock()
        ds = ds_obj.Datastore(
                ref=fake_ds_ref, name='fake_ds',
                capacity=1,
                freespace=1)

        ds_browser = mock.Mock()
        mock_get_ds_browser.return_value = ds_browser
        timestamp_folder_path = mock.Mock()
        mock_timestamp_folder_get.return_value = timestamp_folder_path

        self._imagecache.enlist_image(image_id, ds, dc_ref)

        cache_root_folder = ds.build_path("fake-base-folder")
        mock_get_ds_browser.assert_called_once_with(
                ds.ref)
        mock_timestamp_folder_get.assert_called_once_with(
                cache_root_folder, "fake_image_id")
        mock_timestamp_cleanup.assert_called_once_with(
                dc_ref, ds_browser, timestamp_folder_path)
예제 #3
0
    def test_list_base_images(self):
        def fake_get_dynamic_property(vim, mobj, type, property_name):
            return 'fake-ds-browser'

        def fake_get_sub_folders(session, ds_browser, ds_path):
            files = set()
            files.add('image-ref-uuid')
            return files

        with contextlib.nested(
            mock.patch.object(vim_util, 'get_dynamic_property',
                              fake_get_dynamic_property),
            mock.patch.object(ds_util, 'get_sub_folders',
                              fake_get_sub_folders)
        ) as (_get_dynamic, _get_sub_folders):
            fake_ds_ref = fake.ManagedObjectReference('fake-ds-ref')
            datastore = ds_obj.Datastore(name='ds', ref=fake_ds_ref)
            ds_path = datastore.build_path('base_folder')
            images = self._imagecache._list_datastore_images(
                    ds_path, datastore)
            originals = set()
            originals.add('image-ref-uuid')
            self.assertEqual({'originals': originals,
                              'unexplained_images': []},
                             images)
    def test_filter_datastores_specific_match(self):

        data = [
            ['VMFS', 'os-some-name', True, 'normal', 987654321, 1234678],
            ['NFS', 'another-name', True, 'normal', 9876543210, 123467890],
            ['BAD', 'some-name-bad', True, 'normal', 98765432100, 1234678900],
            ['VMFS', 'some-name-good', True, 'normal', 987654321, 12346789],
            ['VMFS', 'some-other-good', False, 'normal', 987654321000,
             12346789000],
            ['VMFS', 'new-name', True, 'inMaintenance', 987654321000,
             12346789000]
        ]
        # only the DS some-name-good is accessible and matches the regex
        datastores = self.create_result_iterator(data)
        datastore_regex = re.compile('.*-good$')

        best_match = ds_obj.Datastore(ref='fake_ref', name='ds',
                              capacity=0, freespace=0)
        rec = ds_util._select_datastore(None, datastores,
                                        best_match,
                                        datastore_regex)

        self.assertIsNotNone(rec, "could not find datastore!")
        self.assertEqual('ds-003', rec.ref.value,
                         "didn't find the right datastore!")
        self.assertNotEqual('ds-004', rec.ref.value,
                            "accepted an unreachable datastore!")
        self.assertEqual('some-name-good', rec.name)
        self.assertEqual(12346789, rec.freespace,
                         "did not obtain correct freespace!")
        self.assertEqual(987654321, rec.capacity,
                         "did not obtain correct capacity!")
예제 #5
0
 def test_ds(self):
     ds = datastore.Datastore("fake_ref", "ds_name", 2 * units.Gi,
                              1 * units.Gi)
     self.assertEqual('ds_name', ds.name)
     self.assertEqual('fake_ref', ds.ref)
     self.assertEqual(2 * units.Gi, ds.capacity)
     self.assertEqual(1 * units.Gi, ds.freespace)
    def test_filter_datastores_empty(self):
        data = []
        datastores = self.create_result_iterator(data)

        best_match = ds_obj.Datastore(ref='fake_ref', name='ds',
                              capacity=0, freespace=0)
        rec = ds_util._select_datastore(None, datastores, best_match)

        self.assertEqual(best_match, rec)
예제 #7
0
def get_datastore_by_ref(session, ds_ref):
    lst_properties = ["summary.type", "summary.name",
                      "summary.capacity", "summary.freeSpace"]
    props = session._call_method(vim_util, "get_object_properties",
                                 None, ds_ref, "Datastore", lst_properties)
    query = vm_util.get_values_from_object_properties(session, props)
    return ds_obj.Datastore(ds_ref, query["summary.name"],
                            capacity=query["summary.capacity"],
                            freespace=query["summary.freeSpace"])
예제 #8
0
 def test_build_url(self):
     ds = datastore.Datastore("fake_ref", "ds_name")
     path = 'images/ubuntu.vmdk'
     self.assertRaises(ValueError, ds.build_url, 'https', '10.0.0.2', path)
     ds.datacenter = mock.Mock()
     ds.datacenter.name = "dc_path"
     ds_url = ds.build_url('https', '10.0.0.2', path)
     self.assertEqual(ds_url.datastore_name, "ds_name")
     self.assertEqual(ds_url.datacenter_path, "dc_path")
     self.assertEqual(ds_url.path, path)
    def test_filter_datastores_no_match(self):
        datastores = self.create_result_iterator(self.data)
        datastore_regex = re.compile('no_match.*')

        best_match = ds_obj.Datastore(ref='fake_ref', name='ds',
                              capacity=0, freespace=0)
        rec = ds_util._select_datastore(None, datastores,
                                        best_match,
                                        datastore_regex)

        self.assertEqual(best_match, rec, "did not match datastore properly")
예제 #10
0
    def test_age_cached_images(self):
        def fake_get_ds_browser(ds_ref):
            return 'fake-ds-browser'

        def fake_get_timestamp(ds_browser, ds_path):
            self._get_timestamp_called += 1
            path = str(ds_path)
            if path == '[fake-ds] fake-path/fake-image-1':
                # No time stamp exists
                return
            if path == '[fake-ds] fake-path/fake-image-2':
                # Timestamp that will be valid => no deletion
                return 'ts-2012-11-22-10-00-00'
            if path == '[fake-ds] fake-path/fake-image-3':
                # Timestamp that will be invalid => deletion
                return 'ts-2012-11-20-12-00-00'
            self.fail()

        def fake_mkdir(session, ts_path, dc_ref):
            self.assertEqual(
                    '[fake-ds] fake-path/fake-image-1/ts-2012-11-22-12-00-00',
                    str(ts_path))

        def fake_file_delete(session, ds_path, dc_ref):
            self.assertEqual('[fake-ds] fake-path/fake-image-3', str(ds_path))

        def fake_timestamp_cleanup(dc_ref, ds_browser, ds_path):
            self.assertEqual('[fake-ds] fake-path/fake-image-4', str(ds_path))

        with contextlib.nested(
            mock.patch.object(self._imagecache, '_get_ds_browser',
                              fake_get_ds_browser),
            mock.patch.object(self._imagecache, '_get_timestamp',
                              fake_get_timestamp),
            mock.patch.object(ds_util, 'mkdir',
                              fake_mkdir),
            mock.patch.object(ds_util, 'file_delete',
                              fake_file_delete),
            mock.patch.object(self._imagecache, 'timestamp_cleanup',
                              fake_timestamp_cleanup),
        ) as (_get_ds_browser, _get_timestamp, _mkdir, _file_delete,
              _timestamp_cleanup):
            timeutils.set_time_override(override_time=self._time)
            datastore = ds_obj.Datastore(name='ds', ref='fake-ds-ref')
            dc_info = vmops.DcInfo(ref='dc_ref', name='name',
                                   vmFolder='vmFolder')
            self._get_timestamp_called = 0
            self._imagecache.originals = set(['fake-image-1', 'fake-image-2',
                                              'fake-image-3', 'fake-image-4'])
            self._imagecache.used_images = set(['fake-image-4'])
            self._imagecache._age_cached_images(
                    'fake-context', datastore, dc_info,
                    ds_obj.DatastorePath('fake-ds', 'fake-path'))
            self.assertEqual(3, self._get_timestamp_called)
    def test_filter_datastores_simple(self):
        datastores = self.create_result_iterator(self.data)
        best_match = ds_obj.Datastore(ref='fake_ref', name='ds',
                              capacity=0, freespace=0)
        rec = ds_util._select_datastore(None, datastores, best_match)

        self.assertIsNotNone(rec.ref, "could not find datastore!")
        self.assertEqual('ds-001', rec.ref.value,
                         "didn't find the right datastore!")
        self.assertEqual(123467890, rec.freespace,
                         "did not obtain correct freespace!")
예제 #12
0
 def test_get_summary(self):
     ds_ref = vim_util.get_moref('ds-0', 'Datastore')
     ds = datastore.Datastore(ds_ref, 'ds-name')
     summary = mock.sentinel.summary
     session = mock.Mock()
     session.invoke_api = mock.Mock()
     session.invoke_api.return_value = summary
     ret = ds.get_summary(session)
     self.assertEqual(summary, ret)
     session.invoke_api.assert_called_once_with(vim_util,
                                                'get_object_property',
                                                session.vim, ds.ref,
                                                'summary')
    def test_filter_datastores_missing_props(self):
        data = [
            ['VMFS', 'os-some-name', 987654321, 1234678],
            ['NFS', 'another-name', 9876543210, 123467890],
        ]
        # no matches are expected when 'summary.accessible' is missing
        prop_names = ['summary.type', 'summary.name',
                      'summary.capacity', 'summary.freeSpace']
        datastores = self.create_result_iterator(data, prop_names)
        best_match = ds_obj.Datastore(ref='fake_ref', name='ds',
                              capacity=0, freespace=0)

        rec = ds_util._select_datastore(None, datastores, best_match)
        self.assertEqual(best_match, rec, "no matches were expected")
예제 #14
0
def _get_allowed_datastores(datastores, datastore_regex):
    for obj_content in datastores:
        # the propset attribute "need not be set" by returning API
        if not hasattr(obj_content, 'propSet'):
            continue

        propdict = vm_util.propset_dict(obj_content.propSet)
        if _is_datastore_valid(propdict,
                               datastore_regex,
                               ALL_SUPPORTED_DS_TYPES):
            yield (ds_obj.Datastore(ref=obj_content.obj,
                                    name=propdict['summary.name'],
                                    capacity=propdict['summary.capacity'],
                                    freespace=propdict['summary.freeSpace']))
예제 #15
0
def _get_allowed_datastores(data_stores, datastore_regex):
    allowed = []
    for obj_content in data_stores.objects:
        # the propset attribute "need not be set" by returning API
        if not hasattr(obj_content, 'propSet'):
            continue

        propdict = vm_util.propset_dict(obj_content.propSet)
        if _is_datastore_valid(propdict,
                               datastore_regex,
                               ALL_SUPPORTED_DS_TYPES):
            allowed.append(ds_obj.Datastore(ref=obj_content.obj,
                                            name=propdict['summary.name']))

    return allowed
    def _test_get_connected_hosts(self,
                                  in_maintenance_mode,
                                  m1_accessible=True):
        session = mock.Mock()
        ds_ref = vim_util.get_moref('ds-0', 'Datastore')
        ds = datastore.Datastore(ds_ref, 'ds-name')
        ds.get_summary = mock.Mock()
        ds.get_summary.return_value.accessible = False
        self.assertEqual([], ds.get_connected_hosts(session))
        ds.get_summary.return_value.accessible = True
        m1 = HostMount("m1", MountInfo('readWrite', True, m1_accessible))
        m2 = HostMount("m2", MountInfo('read', True, True))
        m3 = HostMount("m3", MountInfo('readWrite', False, True))
        m4 = HostMount("m4", MountInfo('readWrite', True, False))
        ds.get_summary.assert_called_once_with(session)

        class Prop(object):
            DatastoreHostMount = [m1, m2, m3, m4]

        class HostRuntime(object):
            inMaintenanceMode = in_maintenance_mode

        class HostProp(object):
            name = 'runtime'
            val = HostRuntime()

        class Object(object):
            obj = "m1"
            propSet = [HostProp()]

        class Runtime(object):
            objects = [Object()]

        session.invoke_api = mock.Mock(side_effect=[Prop(), Runtime()])
        hosts = ds.get_connected_hosts(session)
        calls = [
            mock.call(vim_util, 'get_object_property', session.vim, ds_ref,
                      'host')
        ]
        if m1_accessible:
            calls.append(
                mock.call(vim_util,
                          'get_properties_for_a_collection_of_objects',
                          session.vim, 'HostSystem', ["m1"], ['runtime']))
        self.assertEqual(calls, session.invoke_api.mock_calls)
        return hosts
예제 #17
0
def _select_datastore(session,
                      data_stores,
                      best_match,
                      datastore_regex=None,
                      storage_policy=None,
                      allowed_ds_types=ALL_SUPPORTED_DS_TYPES):
    """Find the most preferable datastore in a given RetrieveResult object.

    :param session: vmwareapi session
    :param data_stores: a RetrieveResult object from vSphere API call
    :param best_match: the current best match for datastore
    :param datastore_regex: an optional regular expression to match names
    :param storage_policy: storage policy for the datastore
    :param allowed_ds_types: a list of acceptable datastore type names
    :return: datastore_ref, datastore_name, capacity, freespace
    """

    if storage_policy:
        matching_ds = _filter_datastores_matching_storage_policy(
            session, data_stores, storage_policy)
        if not matching_ds:
            return best_match
    else:
        matching_ds = data_stores

    # data_stores is actually a RetrieveResult object from vSphere API call
    for obj_content in matching_ds.objects:
        # the propset attribute "need not be set" by returning API
        if not hasattr(obj_content, 'propSet'):
            continue

        propdict = vm_util.propset_dict(obj_content.propSet)
        if _is_datastore_valid(propdict, datastore_regex, allowed_ds_types):
            new_ds = ds_obj.Datastore(ref=obj_content.obj,
                                      name=propdict['summary.name'],
                                      capacity=propdict['summary.capacity'],
                                      freespace=propdict['summary.freeSpace'])
            # favor datastores with more free space
            if (best_match is None or new_ds.freespace > best_match.freespace):
                best_match = new_ds

    return best_match
    def test_filter_datastores_best_match(self):
        data = [
            ['VMFS', 'spam-good', True, 20 * units.Gi, 10 * units.Gi],
            ['NFS', 'eggs-good', True, 40 * units.Gi, 15 * units.Gi],
            ['BAD', 'some-name-bad', True, 30 * units.Gi, 20 * units.Gi],
            ['VMFS', 'some-name-good', True, 50 * units.Gi, 5 * units.Gi],
            ['VMFS', 'some-other-good', True, 10 * units.Gi, 10 * units.Gi],
        ]

        datastores = self.build_result_set(data)
        datastore_regex = re.compile('.*-good$')

        # the current best match is better than all candidates
        best_match = ds_obj.Datastore(ref='ds-100',
                                      name='best-ds-good',
                                      capacity=20 * units.Gi,
                                      freespace=19 * units.Gi)
        rec = ds_util._select_datastore(None, datastores, best_match,
                                        datastore_regex)
        self.assertEqual(rec, best_match, "did not match datastore properly")
예제 #19
0
    def test_update(self, mock_get_by_inst):
        def fake_list_datastore_images(ds_path, datastore):
            return {'unexplained_images': [], 'originals': self.images}

        def fake_age_cached_images(context, datastore, dc_info, ds_path):
            self.assertEqual('[ds] fake-base-folder', str(ds_path))
            self.assertEqual(self.images, self._imagecache.used_images)
            self.assertEqual(self.images, self._imagecache.originals)

        with contextlib.nested(
                mock.patch.object(self._imagecache, '_list_datastore_images',
                                  fake_list_datastore_images),
                mock.patch.object(
                    self._imagecache, '_age_cached_images',
                    fake_age_cached_images)) as (_list_base, _age_and_verify):
            instances = [{
                'image_ref': '1',
                'host': CONF.host,
                'name': 'inst-1',
                'uuid': '123',
                'vm_state': '',
                'task_state': ''
            }, {
                'image_ref': '2',
                'host': CONF.host,
                'name': 'inst-2',
                'uuid': '456',
                'vm_state': '',
                'task_state': ''
            }]
            all_instances = [
                fake_instance.fake_instance_obj(None, **instance)
                for instance in instances
            ]
            self.images = set(['1', '2'])
            datastore = ds_obj.Datastore(name='ds', ref='fake-ds-ref')
            dc_info = vmops.DcInfo(ref='dc_ref',
                                   name='name',
                                   vmFolder='vmFolder')
            datastores_info = [(datastore, dc_info)]
            self._imagecache.update('context', all_instances, datastores_info)
예제 #20
0
    def test_get_connected_hosts(self):
        session = mock.Mock()
        ds_ref = vim_util.get_moref('ds-0', 'Datastore')
        ds = datastore.Datastore(ds_ref, 'ds-name')
        ds.get_summary = mock.Mock()
        ds.get_summary.return_value.accessible = False
        self.assertEqual([], ds.get_connected_hosts(session))
        ds.get_summary.return_value.accessible = True
        m1 = HostMount("m1", MountInfo('readWrite', True, True))
        m2 = HostMount("m2", MountInfo('read', True, True))
        m3 = HostMount("m3", MountInfo('readWrite', False, True))
        m4 = HostMount("m4", MountInfo('readWrite', True, False))
        ds.get_summary.assert_called_once_with(session)

        class Prop(object):
            DatastoreHostMount = [m1, m2, m3, m4]

        session.invoke_api = mock.Mock()
        session.invoke_api.return_value = Prop()
        hosts = ds.get_connected_hosts(session)
        self.assertEqual(1, len(hosts))
        self.assertEqual("m1", hosts.pop())
예제 #21
0
    def test_disconnect(self, attach_disk_to_backing, detach_disk_from_backing,
                        get_disk_device, getsize, upload_vmdk, file_open,
                        create_temp_ds_folder, get_ds_by_ref):
        ds_ref = mock.sentinel.ds_ref
        ds_name = 'datastore-1'
        dstore = datastore.Datastore(ds_ref, ds_name)
        get_ds_by_ref.return_value = dstore

        file_open_ret = mock.Mock()
        tmp_file = mock.sentinel.tmp_file
        file_open_ret.__enter__ = mock.Mock(return_value=tmp_file)
        file_open_ret.__exit__ = mock.Mock(return_value=None)
        file_open.return_value = file_open_ret

        dc_name = mock.sentinel.dc_name
        copy_task = mock.sentinel.copy_vdisk_task
        delete_file_task = mock.sentinel.delete_file_task
        session = mock.Mock()
        session.invoke_api.side_effect = [dc_name, copy_task, delete_file_task]

        getsize.return_value = units.Gi
        disk_device = mock.sentinel.disk_device
        get_disk_device.return_value = disk_device

        backing = mock.sentinel.backing
        tmp_file_path = '/tmp/foo.vmdk'
        dc_ref = mock.sentinel.dc_ref
        vmdk_path = mock.sentinel.vmdk_path
        self._connector._disconnect(backing, tmp_file_path, session, ds_ref,
                                    dc_ref, vmdk_path)

        tmp_folder_path = self._connector.TMP_IMAGES_DATASTORE_FOLDER_PATH
        ds_folder_path = '[%s] %s' % (ds_name, tmp_folder_path)
        create_temp_ds_folder.assert_called_once_with(session, ds_folder_path,
                                                      dc_ref)
        file_open.assert_called_once_with(tmp_file_path, "rb")

        self.assertEqual(
            mock.call(vim_util, 'get_object_property', session.vim, dc_ref,
                      'name'), session.invoke_api.call_args_list[0])

        exp_rel_path = '%s/foo.vmdk' % tmp_folder_path
        upload_vmdk.assert_called_once_with(
            tmp_file, self._connector._ip, self._connector._port, dc_name,
            ds_name, session.vim.client.options.transport.cookiejar,
            exp_rel_path, units.Gi, self._connector._ca_file,
            self._connector._timeout)

        get_disk_device.assert_called_once_with(session, backing)
        detach_disk_from_backing.assert_called_once_with(
            session, backing, disk_device)

        src = '[%s] %s' % (ds_name, exp_rel_path)
        disk_mgr = session.vim.service_content.virtualDiskManager
        self.assertEqual(
            mock.call(session.vim,
                      'CopyVirtualDisk_Task',
                      disk_mgr,
                      sourceName=src,
                      sourceDatacenter=dc_ref,
                      destName=vmdk_path,
                      destDatacenter=dc_ref),
            session.invoke_api.call_args_list[1])
        self.assertEqual(mock.call(copy_task),
                         session.wait_for_task.call_args_list[0])

        attach_disk_to_backing.assert_called_once_with(session, backing,
                                                       disk_device)

        file_mgr = session.vim.service_content.fileManager
        self.assertEqual(
            mock.call(session.vim,
                      'DeleteDatastoreFile_Task',
                      file_mgr,
                      name=src,
                      datacenter=dc_ref), session.invoke_api.call_args_list[2])
        self.assertEqual(mock.call(delete_file_task),
                         session.wait_for_task.call_args_list[1])
예제 #22
0
 def test_build_path(self):
     ds = datastore.Datastore("fake_ref", "ds_name")
     ds_path = ds.build_path("some_dir", "foo.vmdk")
     self.assertEqual('[ds_name] some_dir/foo.vmdk', str(ds_path))
예제 #23
0
 def test_ds_no_capacity_no_freespace(self):
     ds = datastore.Datastore("fake_ref", "ds_name")
     self.assertIsNone(ds.capacity)
     self.assertIsNone(ds.freespace)