Exemple #1
0
    def convert_string_containing_expressions(cls, match, **kwargs):
        expr = match.group('expr')
        converter = ExpressionConverter.get_converter(expr)
        if converter:
            expr = converter.unwrap_expression(expr)
            expr = converter.convert_string(expr, **kwargs)
            expr = converter.wrap_expression(expr)

        return expr
Exemple #2
0
    def replace_immediately_referenced_variables(self, task_name, when_expr, publish_dict):
        # Check for context variable references that are used in the 'when'
        # expression
        variables_in_when = self.extract_context_variables(when_expr)

        variables_in_publish = set(publish_dict.keys())

        immediately_referenced_variables = variables_in_when & variables_in_publish

        # Replace the context variable references in the 'when'
        # expression with their expression from the 'publish' block
        for variable in immediately_referenced_variables:
            # First off, make sure they are the same type of expression,
            # we don't want to inject a Jinja expression in the middle
            # of a YAQL expression
            when_expr_type = ExpressionConverter.expression_type(when_expr)
            publish_expr_type = ExpressionConverter.expression_type(publish_dict[variable])

            if when_expr_type == publish_expr_type:
                # Grab the variable expression
                converter = ExpressionConverter.get_converter(publish_dict[variable])
                unwrapped_expr = converter.unwrap_expression(publish_dict[variable])

                # Replace double parentheses
                # ((ctx().variable))    ->  (result().result['variable'] + 1)
                variable_reference_dp = r'\(\(ctx\(\).{var}\)\)'.format(var=variable)
                when_expr = re.sub(variable_reference_dp, "({})".format(unwrapped_expr), when_expr)

                # Don't add in parentheses if they already exist
                # (ctx().variable)      ->  (result().result['variable'] + 1)
                variable_reference_dp = r'\(ctx\(\).{var}\)'.format(var=variable)
                when_expr = re.sub(variable_reference_dp, "({})".format(unwrapped_expr), when_expr)

                # Keep surrounding context and add surrounding parentheses
                # (ctx().variable ...   ->  ((result().result['variable'] + 1) ...
                # ... ctx().variable)   ->  ... (result().result['variable'] + 1))
                # ...ctx().variable...  ->  ...(result().result['variable'] + 1)...
                variable_reference_ep = r'(.)\bctx\(\).{var}\b(.)'.format(var=variable)
                when_expr = re.sub(variable_reference_ep, r"\1({})\2".format(unwrapped_expr), when_expr)

                # Keep double enclosing internal parentheses
                # (ctx(variable))  ->  (result().result['variable'] + 1)
                variable_reference_eip = r'\(ctx\({var}\)\)'.format(var=variable)
                when_expr = re.sub(variable_reference_eip, "({})".format(unwrapped_expr), when_expr)

            else:
                warnings.warn("The transition \"{when_expr}\" in {task_name} "
                              "references the '{variable}' context variable, "
                              "which is published in the same transition. You "
                              "will need to manually convert the {variable} "
                              "expression in the transition."
                              .format(when_expr=when_expr,
                                      task_name=task_name,
                                      variable=variable)),
        return when_expr
Exemple #3
0
    def convert_task_transition_expr(self, task_name, expression_list, publish, orquesta_expr):
        # group all complex expressions by their common expression
        # this way we can keep all of the transitions with the same
        # expressions in the same `when:` condition
        #
        # on-success:
        #   - do_thing_a: "{{ _.x }}"
        #   - do_thing_b: "{{ _.x }}"
        #   - do_thing_c: "{{ not _.x }}"
        #
        # should produce the following in orquesta
        #
        # next:
        #   - when: "{{ succeeded() and _.x }}"
        #     do:
        #       - do_thing_a
        #       - do_thing_b
        #   - when: "{{ succeeded() and not _.x }}"
        #     do:
        #       - do_thing_c
        transitions = []
        for expr, task_list in six.iteritems(expression_list):
            expr_transition = ruamel.yaml.comments.CommentedMap()
            expr_converted = ExpressionConverter.convert(expr)

            # for some transitions (on-complete) the orquesta_expr may be empty
            # so only add it in, if it's necessary
            if orquesta_expr:
                converter = ExpressionConverter.get_converter(expr_converted)
                expr_converted = converter.unwrap_expression(expr_converted)
                o_expr = '{} and ({})'.format(orquesta_expr, expr_converted)
                o_expr = converter.wrap_expression(o_expr)
            else:
                o_expr = expr_converted

            expr_transition['when'] = o_expr
            if publish:
                converted_publish = ExpressionConverter.convert_dict(publish)
                expr_transition['publish'] = [{k: v} for k, v in converted_publish.items()]

                expr_transition['when'] = self.replace_immediately_referenced_variables(task_name,
                                                                                        expr_transition['when'],
                                                                                        converted_publish)

            expr_transition['do'] = task_list
            transitions.append(expr_transition)
        return transitions
Exemple #4
0
    def convert_with_items(self, m_task_spec, expr_converter):
        with_items = m_task_spec['with-items']

        with_attr = {
            'items': self.convert_with_items_expr(with_items, expr_converter),
        }

        if m_task_spec.get('concurrency'):
            concurrency_expr = m_task_spec['concurrency']

            # Only try to convert the concurrency expression if it's a str
            if isinstance(concurrency_expr, six.string_types):
                converter = ExpressionConverter.get_converter(concurrency_expr)
                if converter:
                    concurrency_expr = converter.unwrap_expression(concurrency_expr)
                    concurrency_expr = converter.convert_string(concurrency_expr)
                    concurrency_expr = converter.wrap_expression(concurrency_expr)
            with_attr['concurrency'] = concurrency_expr

        return with_attr
Exemple #5
0
    def convert_with_items_expr(self, expression, expr_converter):
        # Convert all with-items attributes
        #
        # with-items:
        #   - i in <% $.yaql_data %>
        #
        # with-items:
        #   - i in <% $.yaql_data %>
        #   - j in <% $.more_data %>
        #   - k in <% $.all_the_data %>
        #
        # with-items: i in <% $.yaql_data %>
        # concurrency: 2
        #
        # with-items: i in {{ _.jinja_data }}
        #
        # with-items: i in [0, 1, 2, 3]
        #
        # should produce the following in orquesta
        #
        # with:
        #   items: i in <% ctx().yaql_data %>
        #
        # with:
        #   items: i, j, k in <% zip($.yaql_data, $.more_data, $.all_the_data) %>
        #
        # with:
        #   items: i in <% $.yaql_data %>
        #   concurrency: 2
        #
        # with:
        #   items: i in {{ ctx().jinja_data }}
        #
        # with:
        #   items: i in <% [0, 1, 2, 3] %>
        converter = None
        var_list = []
        expr_list = []
        if isinstance(expression, list):
            expression_list = expression
        else:
            # Create a list with a single element
            expression_list = [expression]

        for expr_item in expression_list:
            m = WITH_ITEMS_EXPR_RGX.match(expr_item)
            if m:
                var = m.group('var')
                expr = m.group('expr')
                converter = ExpressionConverter.get_converter(expr)
                if converter:
                    expr = converter.unwrap_expression(expr)
                    expr = converter.convert_string(expr)
                var_list.append(var)
                expr_list.append(expr)
            else:
                raise NotImplementedError("Unrecognized with-items expression: '{}'".
                                          format(expr_item))

        # If we have a list of expressions, we need to join them with commas
        # and feed that into 'zip()'
        # If we only have one expression in the list, we don't need to join
        # them or use 'zip()', we just use it directly
        if len(expr_list) > 1:
            expr_list_string = 'zip({expr})'.format(expr=', '.join(expr_list))
        else:
            expr_list_string = expr_list[0]

        # Default to the global expression converter if we could not determine one
        converter = converter if converter else expr_converter

        # We need to save the list of expression variables for when we convert
        # item access to item() instead of ctx()
        self.task_with_item_vars.extend(var_list)

        return "{vars} in {wrapped_expr}".format(
            vars=', '.join(var_list),
            wrapped_expr=converter.wrap_expression(expr_list_string))
Exemple #6
0
    def convert_retry(self, m_retry, task_name):
        # Convert 'retry' specification
        #
        # retry:
        #   count: 10
        #   delay: 20
        #   break-on: <% $.my_var = 'break' %>
        #
        # should produce the following in orquesta
        #
        # retry:
        #   count: 10
        #   delay: 20
        #   when: <% failed() and not (ctx().my_var = 'break') %>
        #
        # (note that the 'when' expression is inverted/negated from break-on)
        #
        # and this:
        #
        # retry:
        #   count: 10
        #   delay: 20
        #   continue-on: <% $.my_var = 'continue' %>
        #
        # should produce the following in orquesta
        #
        # retry:
        #   count: 10
        #   delay: 20
        #   when: <% succeeded() and (ctx().my_var = 'continue') %>
        #
        o_retry = ruamel.yaml.comments.CommentedMap()
        if m_retry.get('count'):
            o_retry['count'] = m_retry['count']
        if m_retry.get('delay'):
            o_retry['delay'] = m_retry['delay']

        # Check for both and bail early
        with_continue = None
        with_break = None
        if m_retry.get('continue-on'):
            continue_expr = m_retry['continue-on']
            continue_converter = ExpressionConverter.get_converter(continue_expr)
            if not continue_converter:
                raise NotImplementedError("Could not convert continue-on expression: {converter} "
                                          "in task '{task_name}'"
                                          .format(converter=continue_converter,
                                                  task_name=task_name))
            continue_expr = continue_converter.unwrap_expression(continue_expr)
            continue_expr = continue_converter.convert_string(continue_expr)
            with_continue = 'succeeded() and ({continue_expr})'.format(continue_expr=continue_expr)

        if m_retry.get('break-on'):
            break_expr = m_retry['break-on']
            break_converter = ExpressionConverter.get_converter(break_expr)
            if not break_converter:
                raise NotImplementedError("Could not convert break-on expression: {converter} "
                                          "in task '{task_name}'"
                                          .format(converter=break_converter,
                                                  task_name=task_name))
            break_expr = break_converter.unwrap_expression(break_expr)
            break_expr = break_converter.convert_string(break_expr)
            with_break = 'failed() and not ({break_expr})'.format(break_expr=break_expr)

        if with_continue and with_break:
            # The converters are classes themselves
            if continue_converter is not break_converter:
                raise NotImplementedError("Cannot convert continue-on ({continue_on}) and "
                                          "break-on ({break_on}) expressions that are different "
                                          "types in task '{task_name}'"
                                          .format(continue_on=m_retry['continue-on'],
                                                  break_on=m_retry['break-on'],
                                                  task_name=task_name))

            with_expr = ('({with_continue}) or ({with_break})'
                         .format(with_continue=with_continue, with_break=with_break))

            o_retry['when'] = continue_converter.wrap_expression(with_expr)
        elif m_retry.get('continue-on'):
            o_retry['when'] = continue_converter.wrap_expression(with_continue)
        elif m_retry.get('break-on'):
            o_retry['when'] = break_converter.wrap_expression(with_break)

        return o_retry
 def test_get_converter_none(self):
     expr = "test"
     result = ExpressionConverter.get_converter(expr)
     self.assertIsNone(result)
 def test_get_converter_yaql(self):
     expr = "<% $.test %>"
     result = ExpressionConverter.get_converter(expr)
     self.assertIs(result, YaqlExpressionConverter)
 def test_get_converter_jinja(self):
     expr = "{{ _.test }}"
     result = ExpressionConverter.get_converter(expr)
     self.assertIs(result, JinjaExpressionConverter)