예제 #1
0
 def test_flag_update(self):
     """flag_update=False avoids update even if Subtask returns True."""
     txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))
     tx1 = tx.WrapperTask('tx1', self.getter)
     tx1.add_functor_subtask(lambda x: True, flag_update=False)
     tx1.execute()
     self.assertEqual(0, txfx.patchers['update'].mock.call_count)
     # But if there's another Subtask that returns True without
     # flag_update=False, it does trigger an update.
     tx1.add_functor_subtask(lambda x: True)
     tx1.execute()
     self.assertEqual(1, txfx.patchers['update'].mock.call_count)
예제 #2
0
    def test_logspec(self):
        txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))
        tx1 = tx.WrapperTask('tx1', self.getter)
        mock_log = mock.Mock()
        mock_log.side_effect = lambda *args: txfx.log('log')

        def functor(wrp):
            txfx.log('functor')

        # "False" logspec ignored
        tx1.add_functor_subtask(functor, logspec=[])
        # logspec must have at least two args
        self.assertRaises(ValueError,
                          tx1.add_functor_subtask,
                          functor,
                          logspec=[1])
        # First arg must be callable
        self.assertRaises(ValueError,
                          tx1.add_functor_subtask,
                          functor,
                          logspec=[1, 2])
        # Valid call with just a string
        tx1.add_functor_subtask(functor, logspec=[mock_log, "string"])
        # Valid call with a format string and args
        tx1.add_functor_subtask(functor,
                                logspec=[mock_log, "one %s two %s", 1, 2])
        # Valid call with named args
        tx1.add_functor_subtask(functor,
                                logspec=[
                                    mock_log, "three %(three)s four %(four)s",
                                    {
                                        'three': 3,
                                        'four': 4
                                    }
                                ])

        tx1.execute()
        self.assertEqual([
            'lock', 'get', 'functor', 'log', 'functor', 'log', 'functor',
            'log', 'functor', 'unlock'
        ], txfx.get_log())
        mock_log.assert_has_calls([
            mock.call("string"),
            mock.call("one %s two %s", 1, 2),
            mock.call("three %(three)s four %(four)s", {
                'three': 3,
                'four': 4
            })
        ])
예제 #3
0
    def _attach_vopt(self, instance, lpar_uuid, vopt, stg_ftsk=None):
        """Will attach the vopt to the VIOS.

        If the stg_ftsk is provided, adds the mapping to the stg_ftsk, but
        won't attach until the stg_ftsk is independently executed.

        :param instance: The VM instance from OpenStack.
        :param lpar_uuid: The UUID of the client LPAR
        :param vopt: The virtual optical device to add.
        :param stg_ftsk: (Optional) If provided, the tasks to create the
                         storage mappings to connect the Media to the VM will
                         be deferred on to the FeedTask passed in.  The execute
                         can be done all in one method (batched together).  If
                         None (the default), the media will be attached
                         immediately.
        """
        # If no transaction manager, build locally so that we can run
        # immediately
        if stg_ftsk is None:
            wtsk = pvm_tx.WrapperTask(
                'media_attach',
                pvm_vios.VIOS.getter(self.adapter,
                                     entry_uuid=self.vios_uuid,
                                     xag=[pvm_const.XAG.VIO_SMAP]))
        else:
            wtsk = stg_ftsk.wrapper_tasks[self.vios_uuid]

        # Define the function to build and add the mapping
        def add_func(vios_w):
            LOG.info(_LI("Adding cfg drive mapping for instance %(inst)s for "
                         "Virtual I/O Server %(vios)s"), {
                             'inst': instance.name,
                             'vios': vios_w.name
                         },
                     instance=instance)
            mapping = tsk_map.build_vscsi_mapping(self.host_uuid, vios_w,
                                                  lpar_uuid, vopt)
            return tsk_map.add_map(vios_w, mapping)

        wtsk.add_functor_subtask(add_func)

        # If built locally, then execute
        if stg_ftsk is None:
            wtsk.execute()
예제 #4
0
    def test_wrapper_task2(self):
        # Now:
        # o Fake like update forces retry
        # o Test add_functor_subtask, including chaining
        # o Ensure GET is deferred when .wrapper() is not called ahead of time.
        # o Make sure subtask args are getting to the subtask.
        txfx = fx.WrapperTaskFx(self.dwrap)

        def _update_retries_twice(timeout=-1):
            self.assertEqual(123, timeout)
            return self.retry_twice(self.dwrap, self.tracker, txfx)

        txfx.patchers['update'].side_effect = _update_retries_twice

        self.useFixture(txfx)

        def functor(wrapper, arg1, arg2, kwarg3=None, kwarg4=None):
            txfx.log('functor')
            # Make sure args are getting here
            self.assertEqual(['arg', 1], arg1)
            self.assertEqual('arg2', arg2)
            self.assertIsNone(kwarg3)
            self.assertEqual('kwarg4', kwarg4)
            return wrapper, True

        # Instantiate-add-execute chain
        tx.WrapperTask(
            'tx2', self.getter,
            update_timeout=123).add_functor_subtask(functor, ['arg', 1],
                                                    'arg2',
                                                    kwarg4='kwarg4').execute()
        # Check the overall order.  Update should have been called thrice (two
        # retries)
        self.assertEqual(3, txfx.patchers['update'].mock.call_count)
        self.assertEqual([
            'lock', 'get', 'functor', 'update 1', 'refresh', 'functor',
            'update 2', 'refresh', 'functor', 'update 3', 'unlock'
        ], txfx.get_log())
예제 #5
0
    def test_subtask_provides(self):
        self.useFixture(fx.WrapperTaskFx(self.dwrap))
        test_case = self

        class ChainSubtask(tx.Subtask):
            def __init__(self, val, *args, **kwargs):
                self.val = val
                super(ChainSubtask, self).__init__(*args, **kwargs)

            def execute(self, *args, **kwargs):
                test_case.assertEqual(test_case.dwrap, args[0])
                # If execute accepts **kwargs, 'provided' is provided.
                test_case.assertIn('provided', kwargs)
                test_case.assertEqual(kwargs['expected_provided'],
                                      kwargs['provided'])
                return self.val

        class ChainSubtask2(tx.Subtask):
            def execute(self, wrp, provided, expected_provided):
                test_case.assertEqual(test_case.dwrap, wrp)
                # Able to get 'provided' as a named parameter
                test_case.assertEqual(expected_provided, provided)

        wtsk = tx.WrapperTask('name', self.getter)
        wtsk.add_subtask(ChainSubtask(1, provides='one', expected_provided={}))
        # Can't add another Subtask with the same 'provides'
        self.assertRaises(ValueError, wtsk.add_subtask,
                          ChainSubtask(2, provides='one'))
        # Next subtask should see the result from the first.
        wtsk.add_subtask(
            ChainSubtask(2, provides='two', expected_provided={'one': 1}))
        # Add one that doesn't provide.  Its return shouldn't show up in
        # 'provided'.
        wtsk.add_subtask(
            ChainSubtask(3, expected_provided={
                'one': 1,
                'two': 2
            }))
        # 'provided' works implicitly when it's a named parameter on execute
        wtsk.add_subtask(ChainSubtask2(expected_provided={'one': 1, 'two': 2}))
        # Even when execute doesn't return anything, we 'provide' that None
        wtsk.add_subtask(
            ChainSubtask2(provides='four',
                          expected_provided={
                              'one': 1,
                              'two': 2
                          }))

        # Make sure the same stuff works for functors
        def ret_val_kwargs(*args, **kwargs):
            self.assertEqual(self.dwrap, args[0])
            self.assertIn('provided', kwargs)
            self.assertEqual(kwargs['expected_provided'], kwargs['provided'])
            return args[1]

        def ret_val_explicit(wrp, val, provided, expected_provided):
            self.assertEqual(self.dwrap, wrp)
            self.assertEqual(expected_provided, provided)
            return val

        self.assertRaises(ValueError,
                          wtsk.add_functor_subtask,
                          int,
                          provides='one')
        wtsk.add_functor_subtask(ret_val_kwargs,
                                 5,
                                 provides='five',
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None
                                 })
        wtsk.add_functor_subtask(ret_val_kwargs,
                                 6,
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5
                                 })
        wtsk.add_functor_subtask(ret_val_explicit,
                                 7,
                                 provides='seven',
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5
                                 })
        wtsk.add_functor_subtask(ret_val_explicit,
                                 8,
                                 expected_provided={
                                     'one': 1,
                                     'two': 2,
                                     'four': None,
                                     'five': 5,
                                     'seven': 7
                                 })

        # Execute the WrapperTask, verifying assertions in ChainSubtask[2] and
        # ret_val_{kwargs|explicit)
        wrapper, subtask_rets = wtsk.execute()
        self.assertEqual(self.dwrap, wrapper)
        # Verify final form of subtask_rets returned from WrapperTask.execute()
        self.assertEqual(
            {
                'one': 1,
                'two': 2,
                'four': None,
                'five': 5,
                'seven': 7
            }, subtask_rets)
예제 #6
0
    def test_wrapper_task1(self):
        txfx = self.useFixture(fx.WrapperTaskFx(self.dwrap))

        # Must supply a wrapper or getter to instantiate
        self.assertRaises(ValueError, tx.WrapperTask, 'foo', 'bar')

        # Create a valid WrapperTask
        tx1 = tx.WrapperTask('tx1', self.getter)
        self.assertEqual('tx1', tx1.name)
        self.assertIn('wrapper_getter_uuid', tx1.provides)
        self.assertIn('subtask_rets_getter_uuid', tx1.provides)
        # Nothing has been run yet
        self.assertEqual([], txfx.get_log())
        # Try running with no subtasks
        self.assertRaises(ex.WrapperTaskNoSubtasks, tx1.execute)
        # Try adding something that isn't a Subtask
        self.assertRaises(ValueError, tx1.add_subtask, 'Not a Subtask')
        # Error paths don't run anything.
        self.assertEqual([], txfx.get_log())

        # Add a subtask that doesn't change anything
        tx1.add_subtask(
            self.LparNameAndMem('z3-9-5-126-127-00000001', logger=txfx))
        # Adding a subtask does not run anything
        self.assertEqual([], txfx.get_log())

        # Get the wrapper - this should invoke GET, but *not* under lock
        self.assertEqual(self.dwrap, tx1.wrapper)
        self.assertEqual(['get'], txfx.get_log())

        # Run the transaction
        lwrap, subtask_rets = tx1.execute()
        # The name should be unchanged
        self.assertEqual('z3-9-5-126-127-00000001', lwrap.name)
        # And update should not have been called, which should be reflected in
        # the log.  Note that 'get' is NOT called a second time.
        self.assertEqual([
            'get', 'lock', 'LparNameAndMem_z3-9-5-126-127-00000001', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)

        txfx.reset_log()
        # These subtasks do change the name.
        tx1.add_subtask(self.LparNameAndMem('new_name', logger=txfx))
        tx1.add_subtask(self.LparNameAndMem('newer_name', logger=txfx))
        # But this one doesn't.  We're making sure the last 'no update needed'
        # doesn't make the overall update_needed status False.
        tx1.add_subtask(self.LparNameAndMem('newer_name', logger=txfx))
        # Get the wrapper - this should *not* reinvoke GET
        self.assertEqual(self.dwrap, tx1.wrapper)
        self.assertEqual([], txfx.get_log())
        # Now execute the transaction
        lwrap, subtask_rets = tx1.execute()
        # The last change should be the one that stuck
        self.assertEqual('newer_name', lwrap.name)
        # Check the overall order.  Update was called.
        self.assertEqual([
            'lock', 'LparNameAndMem_z3-9-5-126-127-00000001',
            'LparNameAndMem_new_name', 'LparNameAndMem_newer_name',
            'LparNameAndMem_newer_name', 'update', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)

        # Test 'cloning' the subtask list
        txfx.reset_log()
        tx2 = tx.WrapperTask('tx2', self.getter, subtasks=tx1.subtasks)
        # Add another one to make sure it goes at the end
        tx2.add_subtask(self.LparNameAndMem('newest_name', logger=txfx))
        # Add one to the original transaction to make sure it doesn't affect
        # this one.
        tx1.add_subtask(self.LparNameAndMem('bogus_name', logger=txfx))
        lwrap, subtask_rets = tx2.execute()
        # The last change should be the one that stuck
        self.assertEqual('newest_name', lwrap.name)
        # Check the overall order.  This one GETs under lock.  Update called.
        self.assertEqual([
            'lock', 'get', 'LparNameAndMem_z3-9-5-126-127-00000001',
            'LparNameAndMem_new_name', 'LparNameAndMem_newer_name',
            'LparNameAndMem_newer_name', 'LparNameAndMem_newest_name',
            'update', 'unlock'
        ], txfx.get_log())
        self.assertEqual({}, subtask_rets)
예제 #7
0
 def test_wrapper_task_allow_empty(self):
     """Test the allow_empty=True condition."""
     # No mocks - no REST calls should be run.
     tx1 = tx.WrapperTask('tx1', self.getter, allow_empty=True)
     # Does not raise, returns None
     self.assertIsNone(tx1.execute())