Beispiel #1
0
 def test_two_vols_different_domains(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol', 'vol1', 'mode', log),
         FakeGuardedLock('01_dom', 'dom2', 'mode', log),
         FakeGuardedLock('02_img', 'img2', 'mode', log),
         FakeGuardedLock('03_vol', 'vol2', 'mode', log)]
     expected = [
         ('acquire', '01_dom', 'dom1', 'mode'),
         ('acquire', '01_dom', 'dom2', 'mode'),
         ('acquire', '02_img', 'img1', 'mode'),
         ('acquire', '02_img', 'img2', 'mode'),
         ('acquire', '03_vol', 'vol1', 'mode'),
         ('acquire', '03_vol', 'vol2', 'mode'),
         ('release', '03_vol', 'vol2', 'mode'),
         ('release', '03_vol', 'vol1', 'mode'),
         ('release', '02_img', 'img2', 'mode'),
         ('release', '02_img', 'img1', 'mode'),
         ('release', '01_dom', 'dom2', 'mode'),
         ('release', '01_dom', 'dom1', 'mode')]
     with guarded.context(locks):
         self.assertEqual(expected[:6], log)
     self.assertEqual(expected, log)
Beispiel #2
0
 def _run(self):
     with guarded.context(self._vol_info.locks):
         self._validate()
         with self._vol_info.prepare():
             with self._vol_info.volume_operation():
                 qemuimg.amend(self._vol_info.path,
                               self._vol_attr.compat)
Beispiel #3
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        dstQcow2Compat=self._dest.qcow2_compat,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format)
                    with utils.closing(self._operation):
                        self._operation.wait_for_completion()
Beispiel #4
0
def prepare(subchain):
    log.info("Preparing subchain %s for merge", subchain)
    with guarded.context(subchain.locks):
        with subchain.prepare():
            _update_base_capacity(subchain.base_vol,
                                  subchain.top_vol)
            _extend_base_allocation(subchain.base_vol,
                                    subchain.top_vol)
Beispiel #5
0
 def _run(self):
     self.log.info("Merging subchain %s", self.subchain)
     with guarded.context(self.subchain.locks):
         self.subchain.validate()
         with self.subchain.prepare(), self.subchain.volume_operation():
             self.operation = qemuimg.commit(
                 self.subchain.top_vol.getVolumePath(),
                 topFormat=sc.fmt2str(self.subchain.top_vol.getFormat()),
                 base=self.subchain.base_vol.getVolumePath())
             self.operation.run()
Beispiel #6
0
 def _run(self):
     self.log.info("Merging subchain %s", self.subchain)
     with guarded.context(self.subchain.locks):
         self.subchain.validate()
         with self.subchain.prepare(), self.subchain.volume_operation():
             self.operation = qemuimg.commit(
                 self.subchain.top_vol.getVolumePath(),
                 topFormat=sc.fmt2str(self.subchain.top_vol.getFormat()),
                 base=self.subchain.base_vol.getVolumePath())
             self.operation.run()
Beispiel #7
0
def finalize(subchain):
    """
    During finalize we distunguish between leaf merge and internal merge.

    In case of leaf merge, we only upate vdsm metadata, i.e. we call
    syncVolumeChain that marks the top volume as ILLEGAL. If the operation
    succeeds, the top volume is marked as ILLEGAL and will be removed by the
    engine. In case of failure, if the top volume is LEGAL, the user can
    recover by retrying cold merge. If the top volume is ILLEGAL, and the
    engine fails to delete the volume, a manual recovery is required.

    In case of internal merge, we need to update qcow metadata and vdsm
    metadata. For qcow metadata, we rebase top's child on base, and for vdsm
    metadata, we invoke syncVolumeChain that changes the child of the top to
    point to the base as its parent.  As we would like to minimize the window
    where the top volume is ILLEGAL, we set it to ILLEGAL just before calling
    qemuimg rebase.

    After finalize internal merge, there are three possible states:
    1. top volume illegal, qemu and vdsm chains updated. The operation will be
       finished by the engine deleting the top volume.
    2. top volume is ILLEGAL but not rebased, both qemu chain and vdsm chain
       are synchronized. Manual recovery is possible by inspecting the chains
       and setting the top volume to legal.
    3. top volume is ILLEGAL, qemu chain rebased, but vdsm chain wasn't
       modified or partly modified. Manual recovery is possible by updating
       vdsm chain.
    """
    log.info("Finalizing subchain after merge: %s", subchain)
    with guarded.context(subchain.locks):
        # TODO: As each cold merge step - prepare, merge and finalize -
        # requires different volumes to be prepared, we will add a prepare
        # helper for each step.
        with subchain.prepare():
            subchain.validate()
            dom = sdCache.produce_manifest(subchain.sd_id)
            if subchain.top_vol.isLeaf():
                _finalize_leaf_merge(dom, subchain)
            else:
                _finalize_internal_merge(dom, subchain)

            if subchain.base_vol.can_reduce():
                # If the top volume is leaf, the base volume will become a leaf
                # after the top volume is deleted.
                optimal_size = subchain.base_vol.optimal_size(
                    as_leaf=subchain.top_vol.isLeaf())
                actual_size = subchain.base_vol.getVolumeSize()

        # Optimal size must be computed while the image is prepared, but
        # reducing with the volume still active will issue a warning from LVM.
        # Thus, reduce after having teardown the volume.
        if subchain.base_vol.can_reduce() and optimal_size < actual_size:
            _shrink_base_volume(subchain, optimal_size)
Beispiel #8
0
 def test_deadlock(self):
     log = []
     locks = [
         FakeGuardedLock('00_storage', 'dom', 'shared', log),
         # Attemting to lock next locks will deadlock in resourceManager.
         FakeGuardedLock('02_img.dom', 'img', 'exclusive', log),
         FakeGuardedLock('02_img.dom', 'img', 'shared', log),
         FakeGuardedLock('03_vol.dom', 'vol', 'exclusive', log),
     ]
     # Creating a context should raise
     with self.assertRaises(guarded.Deadlock):
         with guarded.context(locks):
             pass
     # Without locking any of the locks
     self.assertEqual([], log)
Beispiel #9
0
 def test_deadlock(self):
     log = []
     locks = [
         FakeGuardedLock('00_storage', 'dom', 'shared', log),
         # Attemting to lock next locks will deadlock in resourceManager.
         FakeGuardedLock('02_img.dom', 'img', 'exclusive', log),
         FakeGuardedLock('02_img.dom', 'img', 'shared', log),
         FakeGuardedLock('03_vol.dom', 'vol', 'exclusive', log),
     ]
     # Creating a context should raise
     with self.assertRaises(guarded.Deadlock):
         with guarded.context(locks):
             pass
     # Without locking any of the locks
     self.assertEqual([], log)
Beispiel #10
0
 def test_one_vol(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom', 'mode', log),
         FakeGuardedLock('02_img', 'img', 'mode', log),
         FakeGuardedLock('03_vol', 'vol', 'mode', log)]
     expected = [
         ('acquire', '01_dom', 'dom', 'mode'),
         ('acquire', '02_img', 'img', 'mode'),
         ('acquire', '03_vol', 'vol', 'mode'),
         ('release', '03_vol', 'vol', 'mode'),
         ('release', '02_img', 'img', 'mode'),
         ('release', '01_dom', 'dom', 'mode')]
     with guarded.context(locks):
         self.assertEqual(expected[:3], log)
     self.assertEqual(expected, log)
Beispiel #11
0
 def test_aquire_failure_then_release_failure(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log,
                         release=InjectedFailure),
         FakeGuardedLock('03_vol', 'vol1', 'mode', log,
                         acquire=InjectedFailure)]
     expected = [
         ('acquire', '01_dom', 'dom1', 'mode'),
         ('acquire', '02_img', 'img1', 'mode'),
         ('release', '01_dom', 'dom1', 'mode')]
     with self.assertRaises(InjectedFailure):
         with guarded.context(locks):
             pass
     self.assertEqual(expected, log)
Beispiel #12
0
 def test_one_vol(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom', 'mode', log),
         FakeGuardedLock('02_img', 'img', 'mode', log),
         FakeGuardedLock('03_vol', 'vol', 'mode', log)
     ]
     expected = [('acquire', '01_dom', 'dom', 'mode'),
                 ('acquire', '02_img', 'img', 'mode'),
                 ('acquire', '03_vol', 'vol', 'mode'),
                 ('release', '03_vol', 'vol', 'mode'),
                 ('release', '02_img', 'img', 'mode'),
                 ('release', '01_dom', 'dom', 'mode')]
     with guarded.context(locks):
         self.assertEqual(expected[:3], log)
     self.assertEqual(expected, log)
Beispiel #13
0
def finalize(subchain):
    """
    During finalize we distunguish between leaf merge and internal merge.

    In case of leaf merge, we only upate vdsm metadata, i.e. we call
    syncVolumeChain that marks the top volume as ILLEGAL. If the operation
    succeeds, the top volume is marked as ILLEGAL and will be removed by the
    engine. In case of failure, if the top volume is LEGAL, the user can
    recover by retrying cold merge. If the top volume is ILLEGAL, and the
    engine fails to delete the volume, a manual recovery is required.

    In case of internal merge, we need to update qcow metadata and vdsm
    metadata. For qcow metadata, we rebase top's child on base, and for vdsm
    metadata, we invoke syncVolumeChain that changes the child of the top to
    point to the base as its parent.  As we would like to minimize the window
    where the top volume is ILLEGAL, we set it to ILLEGAL just before calling
    qemuimg rebase.

    After finalize internal merge, there are three possible states:
    1. top volume illegal, qemu and vdsm chains updated. The operation will be
       finished by the engine deleting the top volume.
    2. top volume is ILLEGAL but not rebased, both qemu chain and vdsm chain
       are synchronized. Manual recovery is possible by inspecting the chains
       and setting the top volume to legal.
    3. top volume is ILLEGAL, qemu chain rebased, but vdsm chain wasn't
       modified or partly modified. Manual recovery is possible by updating
       vdsm chain.
    """
    log.info("Finalizing subchain after merge: %s", subchain)
    with guarded.context(subchain.locks):
        # TODO: As each cold merge step - prepare, merge and finalize -
        # requires different volumes to be prepared, we will add a prepare
        # helper for each step.
        with subchain.prepare():
            subchain.validate()
            dom = sdCache.produce_manifest(subchain.sd_id)
            if subchain.top_vol.isLeaf():
                _finalize_leaf_merge(dom, subchain)
            else:
                _finalize_internal_merge(dom, subchain)

            if subchain.base_vol.chunked():
                # optimal_size must be called when the volume is prepared
                optimal_size = subchain.base_vol.optimal_size()

        if subchain.base_vol.chunked():
            _shrink_base_volume(subchain, optimal_size)
Beispiel #14
0
 def test_fail_inside_context(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol', 'vol1', 'mode', log)
     ]
     expected = [('acquire', '01_dom', 'dom1', 'mode'),
                 ('acquire', '02_img', 'img1', 'mode'),
                 ('acquire', '03_vol', 'vol1', 'mode'),
                 ('release', '03_vol', 'vol1', 'mode'),
                 ('release', '02_img', 'img1', 'mode'),
                 ('release', '01_dom', 'dom1', 'mode')]
     with self.assertRaises(InjectedFailure):
         with guarded.context(locks):
             raise InjectedFailure()
     self.assertEqual(expected, log)
Beispiel #15
0
 def test_fail_inside_context_with_release_failure(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol', 'vol1', 'mode', log,
                         release=InjectedFailure)]
     expected = [
         ('acquire', '01_dom', 'dom1', 'mode'),
         ('acquire', '02_img', 'img1', 'mode'),
         ('acquire', '03_vol', 'vol1', 'mode'),
         ('release', '02_img', 'img1', 'mode'),
         ('release', '01_dom', 'dom1', 'mode')]
     with self.assertRaises(RuntimeError):
         with guarded.context(locks):
             raise RuntimeError()
     self.assertEqual(expected, log)
Beispiel #16
0
def finalize(subchain):
    log.info("Finalizing subchain after merge: %s", subchain)
    with guarded.context(subchain.locks):
        with subchain.prepare():
            subchain.validate()

            # Base volume must be ILLEGAL. Otherwise, VM could be run while
            # performing cold merge.
            base_legality = subchain.base_vol.getLegality()
            if base_legality == sc.LEGAL_VOL:
                raise se.UnexpectedVolumeState(
                    subchain.base_id, sc.ILLEGAL_VOL, base_legality)

            dom = sdCache.produce_manifest(subchain.sd_id)
            _update_qemu_metadata(dom, subchain)
            _update_vdsm_metadata(dom, subchain)
            subchain.base_vol.setLegality(sc.LEGAL_VOL)
Beispiel #17
0
    def _run(self):
        self.log.info("Merging subchain %s", self.subchain)
        with guarded.context(self.subchain.locks):
            self.subchain.validate()
            # Base volume must be ILLEGAL. Otherwise, VM could be run while
            # performing cold merge.
            base_legality = self.subchain.base_vol.getLegality()
            if base_legality == sc.LEGAL_VOL:
                raise se.UnexpectedVolumeState(self.subchain.base_id,
                                               sc.ILLEGAL_VOL,
                                               base_legality)

            with self.subchain.prepare(), self.subchain.volume_operation():
                self.operation = qemuimg.commit(
                    self.subchain.top_vol.getVolumePath(),
                    topFormat=sc.fmt2str(self.subchain.top_vol.getFormat()),
                    base=self.subchain.base_vol.getVolumePath())
                with utils.closing(self.operation):
                    self.operation.wait_for_completion()
Beispiel #18
0
 def test_release_failure(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol',
                         'vol1',
                         'mode',
                         log,
                         release=InjectedFailure)
     ]
     expected = [('acquire', '01_dom', 'dom1', 'mode'),
                 ('acquire', '02_img', 'img1', 'mode'),
                 ('acquire', '03_vol', 'vol1', 'mode'),
                 ('release', '02_img', 'img1', 'mode'),
                 ('release', '01_dom', 'dom1', 'mode')]
     with self.assertRaises(guarded.ReleaseError):
         with guarded.context(locks):
             pass
     self.assertEqual(expected, log)
Beispiel #19
0
 def test_two_vols_same_image(self):
     log = []
     locks = [
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol', 'vol1', 'mode', log),
         FakeGuardedLock('01_dom', 'dom1', 'mode', log),
         FakeGuardedLock('02_img', 'img1', 'mode', log),
         FakeGuardedLock('03_vol', 'vol2', 'mode', log)
     ]
     expected = [('acquire', '01_dom', 'dom1', 'mode'),
                 ('acquire', '02_img', 'img1', 'mode'),
                 ('acquire', '03_vol', 'vol1', 'mode'),
                 ('acquire', '03_vol', 'vol2', 'mode'),
                 ('release', '03_vol', 'vol2', 'mode'),
                 ('release', '03_vol', 'vol1', 'mode'),
                 ('release', '02_img', 'img1', 'mode'),
                 ('release', '01_dom', 'dom1', 'mode')]
     with guarded.context(locks):
         self.assertEqual(expected[:4], log)
     self.assertEqual(expected, log)
Beispiel #20
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                self._validate_copy_bitmaps(src_format, dst_format)

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        dstQcow2Compat=self._dest.qcow2_compat,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format,
                        unordered_writes=self._dest.
                        recommends_unordered_writes,
                        create=self._dest.requires_create,
                        bitmaps=self._copy_bitmaps,
                        target_is_zero=self._dest.zero_initialized,
                    )
                    with utils.stopwatch("Copy volume {}".format(
                            self._source.path),
                                         level=logging.INFO,
                                         log=log):
                        self._operation.run()
Beispiel #21
0
    def _run(self):
        with guarded.context(self._source.locks + self._dest.locks):
            with self._source.prepare(), self._dest.prepare():
                # Do not start copying if we have already been aborted
                if self._status == jobs.STATUS.ABORTED:
                    return

                # Workaround for volumes containing VM configuration info that
                # were created with invalid vdsm metadata.
                if self._source.is_invalid_vm_conf_disk():
                    src_format = dst_format = qemuimg.FORMAT.RAW
                else:
                    src_format = self._source.qemu_format
                    dst_format = self._dest.qemu_format

                with self._dest.volume_operation():
                    self._operation = qemuimg.convert(
                        self._source.path,
                        self._dest.path,
                        srcFormat=src_format,
                        dstFormat=dst_format,
                        backing=self._dest.backing_path,
                        backingFormat=self._dest.backing_qemu_format)
                    self._operation.wait_for_completion()
Beispiel #22
0
 def _run(self):
     with guarded.context(self._vol_info.locks):
         self._validate()
         with self._vol_info.prepare():
             with self._vol_info.volume_operation():
                 virtsparsify.sparsify_inplace(self._vol_info.path)
Beispiel #23
0
 def _run(self):
     with guarded.context(self._vol_info.locks):
         self._validate()
         with self._vol_info.prepare():
             with self._vol_info.volume_operation():
                 bitmaps.clear_bitmaps(self._vol_info.path)
Beispiel #24
0
 def test_empty(self):
     with guarded.context([]):
         pass
Beispiel #25
0
 def test_empty(self):
     with guarded.context([]):
         pass
Beispiel #26
0
 def _run(self):
     with guarded.context(self._endpoint.locks):
         self._endpoint.volume.set_generation(self._endpoint.generation,
                                              self._new_gen)
Beispiel #27
0
 def _run(self):
     with guarded.context(self._endpoint.locks):
         self._endpoint.volume.update_attributes(self._endpoint.generation,
                                                 self._vol_attr)
Beispiel #28
0
 def _run(self):
     with guarded.context(self._endpoint.locks):
         self._endpoint.volume.update_attributes(self._endpoint.generation,
                                                 self._vol_attr)
Beispiel #29
0
 def _run(self):
     with guarded.context(self._vol_info.locks):
         self._validate()
         with self._vol_info.prepare():
             with self._vol_info.volume_operation():
                 qemuimg.amend(self._vol_info.path, self._qcow2_attr.compat)
Beispiel #30
0
def prepare(subchain):
    log.info("Preparing subchain %s for merge", subchain)
    with guarded.context(subchain.locks):
        with subchain.prepare():
            _update_base_capacity(subchain.base_vol, subchain.top_vol)
            _extend_base_allocation(subchain.base_vol, subchain.top_vol)
Beispiel #31
0
 def _run(self):
     with guarded.context(self._vol_info.locks):
         self._validate()
         with self._vol_info.prepare():
             with self._vol_info.volume_operation():
                 virtsparsify.sparsify_inplace(self._vol_info.path)