Exemplo n.º 1
0
    def snapshot(self, context, instance, image_id, update_task_state):
        """Snapshots the specified instance.

        :param context: security context
        :param instance: nova.objects.instance.Instance
        :param image_id: Reference to a pre-created image that will hold the
                         snapshot.
        :param update_task_state: Callback function to update the task_state
            on the instance while the snapshot operation progresses. The
            function takes a task_state argument and an optional
            expected_task_state kwarg which defaults to
            nova.compute.task_states.IMAGE_SNAPSHOT. See
            nova.objects.instance.Instance.save for expected_task_state usage.
        """

        if not self.disk_dvr.capabilities.get('snapshot'):
            raise exc.NotSupportedWithOption(
                message=_("The snapshot operation is not supported in "
                          "conjunction with a [powervm]/disk_driver setting "
                          "of %s.") % CONF.powervm.disk_driver)

        self._log_operation('snapshot', instance)

        # Define the flow.
        flow = tf_lf.Flow("snapshot")

        # Notify that we're starting the process.
        flow.add(
            tf_img.UpdateTaskState(update_task_state,
                                   task_states.IMAGE_PENDING_UPLOAD))

        # Connect the instance's boot disk to the management partition, and
        # scan the scsi bus and bring the device into the management partition.
        flow.add(tf_stg.InstanceDiskToMgmt(self.disk_dvr, instance))

        # Notify that the upload is in progress.
        flow.add(
            tf_img.UpdateTaskState(
                update_task_state,
                task_states.IMAGE_UPLOADING,
                expected_state=task_states.IMAGE_PENDING_UPLOAD))

        # Stream the disk to glance.
        flow.add(
            tf_img.StreamToGlance(context, self.image_api, image_id, instance))

        # Disconnect the boot disk from the management partition and delete the
        # device.
        flow.add(tf_stg.RemoveInstanceDiskFromMgmt(self.disk_dvr, instance))

        # Run the flow.
        tf_base.run(flow, instance=instance)
Exemplo n.º 2
0
    def snapshot(self, context, instance, image_id, update_task_state):
        """Snapshots the specified instance.

        :param context: security context
        :param instance: nova.objects.instance.Instance
        :param image_id: Reference to a pre-created image that will hold the
                         snapshot.
        :param update_task_state: Callback function to update the task_state
            on the instance while the snapshot operation progresses. The
            function takes a task_state argument and an optional
            expected_task_state kwarg which defaults to
            nova.compute.task_states.IMAGE_SNAPSHOT. See
            nova.objects.instance.Instance.save for expected_task_state usage.
        """
        # TODO(esberglu) Add check for disk driver snapshot capability when
        # additional disk drivers are implemented.
        self._log_operation('snapshot', instance)

        # Define the flow.
        flow = tf_lf.Flow("snapshot")

        # Notify that we're starting the process.
        flow.add(
            tf_img.UpdateTaskState(update_task_state,
                                   task_states.IMAGE_PENDING_UPLOAD))

        # Connect the instance's boot disk to the management partition, and
        # scan the scsi bus and bring the device into the management partition.
        flow.add(tf_stg.InstanceDiskToMgmt(self.disk_dvr, instance))

        # Notify that the upload is in progress.
        flow.add(
            tf_img.UpdateTaskState(
                update_task_state,
                task_states.IMAGE_UPLOADING,
                expected_state=task_states.IMAGE_PENDING_UPLOAD))

        # Stream the disk to glance.
        flow.add(
            tf_img.StreamToGlance(context, self.image_api, image_id, instance))

        # Disconnect the boot disk from the management partition and delete the
        # device.
        flow.add(tf_stg.RemoveInstanceDiskFromMgmt(self.disk_dvr, instance))

        # Run the flow.
        tf_base.run(flow, instance=instance)
Exemplo n.º 3
0
    def test_instance_disk_to_mgmt(self, mock_rm, mock_discover, mock_find):
        mock_discover.return_value = '/dev/disk'
        mock_instance = mock.Mock()
        mock_instance.name = 'instance_name'
        mock_stg = mock.Mock()
        mock_stg.name = 'stg_name'
        mock_vwrap = mock.Mock()
        mock_vwrap.name = 'vios_name'
        mock_vwrap.uuid = 'vios_uuid'
        mock_vwrap.scsi_mappings = ['mapping1']

        disk_dvr = mock.MagicMock()
        disk_dvr.mp_uuid = 'mp_uuid'
        disk_dvr.connect_instance_disk_to_mgmt.return_value = (mock_stg,
                                                               mock_vwrap)

        def reset_mocks():
            mock_find.reset_mock()
            mock_discover.reset_mock()
            mock_rm.reset_mock()
            disk_dvr.reset_mock()

        # Good path - find_maps returns one result
        mock_find.return_value = ['one_mapping']
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        self.assertEqual('instance_disk_to_mgmt', tf.name)
        self.assertEqual((mock_stg, mock_vwrap, '/dev/disk'), tf.execute())
        disk_dvr.connect_instance_disk_to_mgmt.assert_called_with(
            mock_instance)
        mock_find.assert_called_with(['mapping1'],
                                     client_lpar_id='mp_uuid',
                                     stg_elem=mock_stg)
        mock_discover.assert_called_with('one_mapping')
        tf.revert('result', 'failures')
        disk_dvr.disconnect_disk_from_mgmt.assert_called_with(
            'vios_uuid', 'stg_name')
        mock_rm.assert_called_with('/dev/disk')

        # Good path - find_maps returns >1 result
        reset_mocks()
        mock_find.return_value = ['first_mapping', 'second_mapping']
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        self.assertEqual((mock_stg, mock_vwrap, '/dev/disk'), tf.execute())
        disk_dvr.connect_instance_disk_to_mgmt.assert_called_with(
            mock_instance)
        mock_find.assert_called_with(['mapping1'],
                                     client_lpar_id='mp_uuid',
                                     stg_elem=mock_stg)
        mock_discover.assert_called_with('first_mapping')
        tf.revert('result', 'failures')
        disk_dvr.disconnect_disk_from_mgmt.assert_called_with(
            'vios_uuid', 'stg_name')
        mock_rm.assert_called_with('/dev/disk')

        # Management Partition is VIOS and NovaLink hosted storage
        reset_mocks()
        disk_dvr._vios_uuids = ['mp_uuid']
        dev_name = '/dev/vg/fake_name'
        disk_dvr.get_bootdisk_path.return_value = dev_name
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        self.assertEqual((None, None, dev_name), tf.execute())

        # Management Partition is VIOS and not NovaLink hosted storage
        reset_mocks()
        disk_dvr._vios_uuids = ['mp_uuid']
        disk_dvr.get_bootdisk_path.return_value = None
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        tf.execute()
        disk_dvr.connect_instance_disk_to_mgmt.assert_called_with(
            mock_instance)

        # Bad path - find_maps returns no results
        reset_mocks()
        mock_find.return_value = []
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        self.assertRaises(exception.NewMgmtMappingNotFoundException,
                          tf.execute)
        disk_dvr.connect_instance_disk_to_mgmt.assert_called_with(
            mock_instance)
        # find_maps was still called
        mock_find.assert_called_with(['mapping1'],
                                     client_lpar_id='mp_uuid',
                                     stg_elem=mock_stg)
        # discover_vscsi_disk didn't get called
        self.assertEqual(0, mock_discover.call_count)
        tf.revert('result', 'failures')
        # disconnect_disk_from_mgmt got called
        disk_dvr.disconnect_disk_from_mgmt.assert_called_with(
            'vios_uuid', 'stg_name')
        # ...but remove_block_dev did not.
        self.assertEqual(0, mock_rm.call_count)

        # Bad path - connect raises
        reset_mocks()
        disk_dvr.connect_instance_disk_to_mgmt.side_effect = (
            exception.InstanceDiskMappingFailed(instance_name='inst_name'))
        tf = tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        self.assertRaises(exception.InstanceDiskMappingFailed, tf.execute)
        disk_dvr.connect_instance_disk_to_mgmt.assert_called_with(
            mock_instance)
        self.assertEqual(0, mock_find.call_count)
        self.assertEqual(0, mock_discover.call_count)
        # revert shouldn't call disconnect or remove
        tf.revert('result', 'failures')
        self.assertEqual(0, disk_dvr.disconnect_disk_from_mgmt.call_count)
        self.assertEqual(0, mock_rm.call_count)

        # Validate args on taskflow.task.Task instantiation
        with mock.patch('taskflow.task.Task.__init__') as tf:
            tf_stg.InstanceDiskToMgmt(disk_dvr, mock_instance)
        tf.assert_called_once_with(
            name='instance_disk_to_mgmt',
            provides=['stg_elem', 'vios_wrap', 'disk_path'])