class CloudifyClient(object):
    @specs.parameter('app', dsl.MuranoObjectParameter('io.murano.Application'))
    def __init__(self, app):
        cloudify_manager = self.CONF.cloudify_manager
        self._client = cloudify_rest_client.CloudifyClient(cloudify_manager)
        self._blueprint_id = '{0}-{1}'.format(app.type.name, app.type.version)
        self._deployment_id = app.id
        self._application_package = app.package

    @specs.parameter('entry_point', yaqltypes.String())
    def publish_blueprint(self, entry_point):
        global archive_upload_lock

        if self._check_blueprint_exists():
            return
        path = self._application_package.get_resource(entry_point)
        with archive_upload_lock:
            try:
                self._client.blueprints.upload(
                    path, self._blueprint_id)
            except cloudify_exceptions.CloudifyClientError as e:
                if e.status_code != 409:
                    raise

    def _check_blueprint_exists(self):
        try:
            self._client.blueprints.get(self._blueprint_id)
            return True
        except cloudify_exceptions.CloudifyClientError as e:
            if e.status_code == 404:
                return False
            raise

    @specs.parameter('parameters', dict)
    def create_deployment(self, parameters=None):
        self._client.deployments.create(
            self._blueprint_id, self._deployment_id, parameters)

    def delete_deployment(self):
        self._client.deployments.delete(self._deployment_id)

    def wait_deployment_ready(self):
        while True:
            executions = self._client.executions.list(self._deployment_id)
            if any(t.status in ('pending', 'started') for t in executions):
                time.sleep(3)
            else:
                deployment = self._client.deployments.get(self._deployment_id)
                return deployment.outputs

    @specs.parameter('name', yaqltypes.String())
    @specs.parameter('parameters', dict)
    def execute_workflow(self, name, parameters=None):
        self._client.executions.start(self._deployment_id, name, parameters)

    @classmethod
    def init_plugin(cls):
        cls.CONF = cfg.init_config(CONF)
Exemple #2
0
def _create_instance_mpl_stub(murano_method):
    def payload(__context, __receiver, *args, **kwargs):
        return murano_method.invoke(__receiver, args, kwargs, __context, True)

    fd = _create_basic_mpl_stub(murano_method, 1, payload, False)

    receiver_type = dsl.MuranoObjectParameter(weakref.proxy(
        murano_method.declaring_type),
                                              decorate=False)
    fd.set_parameter(specs.ParameterDefinition('__receiver', receiver_type, 1))
    return fd
Exemple #3
0
def get_function_definition(func, murano_method, original_name):
    cls = murano_method.declaring_type.extension_class

    def param_type_func(name):
        return None if not cls else _infer_parameter_type(name, cls.__name__)

    body = func
    if (cls is None or helpers.inspect_is_method(cls, original_name)
            or helpers.inspect_is_classmethod(cls, original_name)):
        body = helpers.function(func)
    fd = specs.get_function_definition(body,
                                       convention=CONVENTION,
                                       parameter_type_func=param_type_func)
    fd.is_method = True
    fd.is_function = False
    if not cls or helpers.inspect_is_method(cls, original_name):
        fd.set_parameter(0,
                         dsl.MuranoObjectParameter(
                             murano_method.declaring_type),
                         overwrite=True)
    if cls and helpers.inspect_is_classmethod(cls, original_name):
        _remove_first_parameter(fd)
        body = func
    name = getattr(func, '__murano_name', None)
    if name:
        fd.name = name
    fd.insert_parameter(specs.ParameterDefinition('?1', yaqltypes.Context(),
                                                  0))
    is_static = cls and (helpers.inspect_is_static(cls, original_name)
                         or helpers.inspect_is_classmethod(cls, original_name))
    if is_static:
        fd.insert_parameter(
            specs.ParameterDefinition('?2', yaqltypes.PythonType(object), 1))

    def payload(__context, __self, *args, **kwargs):
        with helpers.contextual(__context):
            __context[constants.CTX_NAMES_SCOPE] = \
                murano_method.declaring_type
            return body(__self.extension, *args, **kwargs)

    def static_payload(__context, __receiver, *args, **kwargs):
        with helpers.contextual(__context):
            __context[constants.CTX_NAMES_SCOPE] = \
                murano_method.declaring_type
            return body(*args, **kwargs)

    if is_static:
        fd.payload = static_payload
    else:
        fd.payload = payload
    fd.meta[constants.META_MURANO_METHOD] = murano_method
    return fd
Exemple #4
0
class Agent(object):
    def __init__(self, host):
        self._enabled = False
        if CONF.engine.disable_murano_agent:
            LOG.debug('Use of murano-agent is disallowed '
                      'by the server configuration')
            return

        self._environment = host.find_owner('io.murano.Environment')
        self._enabled = True
        self._queue = str('e%s-h%s' % (self._environment.id, host.id)).lower()

    @property
    def enabled(self):
        return self._enabled

    def prepare(self):
        # (sjmc7) - turn this into a no-op if agents are disabled
        if CONF.engine.disable_murano_agent:
            LOG.debug('Use of murano-agent is disallowed '
                      'by the server configuration')
            return

        with common.create_rmq_client() as client:
            client.declare(self._queue, enable_ha=True, ttl=86400000)

    def queue_name(self):
        return self._queue

    def _check_enabled(self):
        if CONF.engine.disable_murano_agent:
            raise exceptions.PolicyViolationException(
                'Use of murano-agent is disallowed '
                'by the server configuration')

    def _prepare_message(self, template, msg_id):
        msg = message.Message()
        msg.body = template
        msg.id = msg_id
        return msg

    def _send(self, template, wait_results, timeout):
        """Send a message over the MQ interface."""
        msg_id = template.get('ID', uuid.uuid4().hex)
        if wait_results:
            event = eventlet.event.Event()
            listener = self._environment['agentListener']
            listener().subscribe(msg_id, event)

        msg = self._prepare_message(template, msg_id)
        with common.create_rmq_client() as client:
            client.send(message=msg, key=self._queue)

        if wait_results:
            try:
                with eventlet.Timeout(timeout):
                    result = event.wait()

            except eventlet.Timeout:
                listener().unsubscribe(msg_id)
                raise exceptions.TimeoutException(
                    'The murano-agent did not respond '
                    'within {0} seconds'.format(timeout))

            if not result:
                return None

            if result.get('FormatVersion', '1.0.0').startswith('1.'):
                return self._process_v1_result(result)

            else:
                return self._process_v2_result(result)

        else:
            return None

    @specs.parameter('resources',
                     dsl.MuranoObjectParameter('io.murano.system.Resources'))
    def call(self, template, resources, timeout=None):
        if timeout is None:
            timeout = CONF.engine.agent_timeout
        self._check_enabled()
        plan = self.build_execution_plan(template, resources())
        return self._send(plan, True, timeout)

    @specs.parameter('resources',
                     dsl.MuranoObjectParameter('io.murano.system.Resources'))
    def send(self, template, resources):
        self._check_enabled()
        plan = self.build_execution_plan(template, resources())
        return self._send(plan, False, 0)

    def call_raw(self, plan, timeout=None):
        if timeout is None:
            timeout = CONF.engine.agent_timeout
        self._check_enabled()
        return self._send(plan, True, timeout)

    def send_raw(self, plan):
        self._check_enabled()
        return self._send(plan, False, 0)

    def is_ready(self, timeout=100):
        try:
            self.wait_ready(timeout)
        except exceptions.TimeoutException:
            return False
        else:
            return True

    def wait_ready(self, timeout=100):
        self._check_enabled()
        template = {'Body': 'return', 'FormatVersion': '2.0.0', 'Scripts': {}}
        self.call(template, False, timeout)

    def _process_v1_result(self, result):
        if result['IsException']:
            raise AgentException(
                dict(self._get_exception_info(result.get('Result', [])),
                     source='execution_plan'))
        else:
            results = result.get('Result', [])
            if not result:
                return None
            value = results[-1]
            if value['IsException']:
                raise AgentException(
                    dict(self._get_exception_info(value.get('Result', [])),
                         source='command'))
            else:
                return value.get('Result')

    def _process_v2_result(self, result):
        error_code = result.get('ErrorCode', 0)
        if not error_code:
            return result.get('Body')
        else:
            body = result.get('Body') or {}
            err = {
                'message': body.get('Message'),
                'details': body.get('AdditionalInfo'),
                'errorCode': error_code,
                'time': result.get('Time')
            }
            for attr in ('Message', 'AdditionalInfo'):
                if attr in body:
                    del body[attr]
            err['extra'] = body if body else None
            raise AgentException(err)

    def _get_array_item(self, array, index):
        return array[index] if len(array) > index else None

    def _get_exception_info(self, data):
        data = data or []
        return {
            'type': self._get_array_item(data, 0),
            'message': self._get_array_item(data, 1),
            'command': self._get_array_item(data, 2),
            'details': self._get_array_item(data, 3),
            'timestamp': datetime.datetime.now().isoformat()
        }

    def build_execution_plan(self, template, resources):
        template = copy.deepcopy(template)
        if not isinstance(template, dict):
            raise ValueError('Incorrect execution plan ')
        format_version = template.get('FormatVersion')
        if not format_version or format_version.startswith('1.'):
            return self._build_v1_execution_plan(template, resources)
        else:
            return self._build_v2_execution_plan(template, resources)

    def _build_v1_execution_plan(self, template, resources):
        scripts_folder = 'scripts'
        script_files = template.get('Scripts', [])
        scripts = []
        for script in script_files:
            script_path = os.path.join(scripts_folder, script)
            scripts.append(resources.string(script_path).encode('base64'))
        template['Scripts'] = scripts
        return template

    def _build_v2_execution_plan(self, template, resources):
        scripts_folder = 'scripts'
        plan_id = uuid.uuid4().hex
        template['ID'] = plan_id
        if 'Action' not in template:
            template['Action'] = 'Execute'
        if 'Files' not in template:
            template['Files'] = {}

        files = {}
        for file_id, file_descr in template['Files'].items():
            files[file_descr['Name']] = file_id

        for name, script in template.get('Scripts', {}).items():
            if 'EntryPoint' not in script:
                raise ValueError('No entry point in script ' + name)

            if 'Application' == script['Type']:
                if script['EntryPoint'] not in files:
                    script['EntryPoint'] = self._place_file(
                        scripts_folder, script['EntryPoint'], template,
                        resources, files)
                else:
                    script['EntryPoint'] = files[script['EntryPoint']]
            if 'Files' in script:
                for i, file in enumerate(script['Files']):
                    if self._get_name(file) not in files:
                        script['Files'][i] = self._place_file(
                            scripts_folder, file, template, resources, files)
                    else:
                        script['Files'][i] = files[file]
        return template

    def _is_url(self, file):
        file = self._get_url(file)
        parts = six.moves.urllib.parse.urlsplit(file)
        if not parts.scheme or not parts.netloc:
            return False
        else:
            return True

    def _get_url(self, file):
        if isinstance(file, dict):
            return list(file.values())[0]
        else:
            return file

    def _get_name(self, file):
        if isinstance(file, dict):
            name = list(file.keys())[0]
        else:
            name = file

        if self._is_url(name):
            name = name[name.rindex('/') + 1:len(name)]
        elif name.startswith('<') and name.endswith('>'):
            name = name[1:-1]
        return name

    def _get_file_value(self, file):
        if isinstance(file, dict):
            file = list(file.values())[0]
        return file

    def _get_body(self, file, resources, folder):
        use_base64 = self._is_base64(file)
        if use_base64 and file.startswith('<') and file.endswith('>'):
            file = file[1:-1]
        body = resources.string(os.path.join(folder, file))
        if use_base64:
            body = body.encode('base64')
        return body

    def _is_base64(self, file):
        return file.startswith('<') and file.endswith('>')

    def _get_body_type(self, file):
        return 'Base64' if self._is_base64(file) else 'Text'

    def _place_file(self, folder, file, template, resources, files):
        file_value = self._get_file_value(file)
        name = self._get_name(file)
        file_id = uuid.uuid4().hex

        if self._is_url(file_value):
            template['Files'][file_id] = self._get_file_des_downloadable(file)
            files[name] = file_id

        else:
            template['Files'][file_id] = self._get_file_description(
                file, resources, folder)
            files[name] = file_id
        return file_id

    def _get_file_des_downloadable(self, file):
        name = self._get_name(file)
        file = self._get_file_value(file)
        return {'Name': str(name), 'URL': file, 'Type': 'Downloadable'}

    def _get_file_description(self, file, resources, folder):
        name = self._get_name(file)
        file_value = self._get_file_value(file)

        body_type = self._get_body_type(file_value)
        body = self._get_body(file_value, resources, folder)
        return {'Name': name, 'BodyType': body_type, 'Body': body}
Exemple #5
0
@specs.yaql_property(dsl_types.MuranoProperty)
@specs.name('usage')
def property_usage(murano_property):
    return murano_property.usage


@specs.yaql_property(dsl_types.MuranoProperty)
@specs.name('declaring_type')
def property_owner(murano_property):
    return murano_property.declaring_type


@specs.name('get_value')
@specs.parameter('property_', dsl_types.MuranoProperty)
@specs.parameter('object_',
                 dsl.MuranoObjectParameter(nullable=True, decorate=False))
@specs.method
def property_get_value(context, property_, object_):
    if object_ is None:
        return helpers.get_executor().get_static_property(
            property_.declaring_type, name=property_.name, context=context)
    return object_.cast(property_.declaring_type).get_property(
        name=property_.name, context=context)


@specs.name('set_value')
@specs.parameter('property_', dsl_types.MuranoProperty)
@specs.parameter('object_',
                 dsl.MuranoObjectParameter(nullable=True, decorate=False))
@specs.method
def property_set_value(context, property_, object_, value):
Exemple #6
0
import eventlet
from yaql.language import expressions
from yaql.language import specs
from yaql.language import utils
from yaql.language import yaqltypes

from murano.dsl import constants
from murano.dsl import dsl
from murano.dsl import dsl_types
from murano.dsl import helpers
from murano.dsl import reflection
from murano.dsl import serializer


@specs.parameter('object_', dsl.MuranoObjectParameter())
def id_(object_):
    return object_.id


@specs.parameter('object_', dsl.MuranoObjectParameter())
@specs.parameter('type__', dsl.MuranoTypeParameter())
@specs.parameter('version_spec', yaqltypes.String(True))
def cast(context, object_, type__, version_spec=None):
    return helpers.cast(object_, type__.type.name, version_spec
                        or helpers.get_type(context))


@specs.parameter('__type_name', dsl.MuranoTypeParameter())
@specs.parameter('__extra', utils.MappingType)
@specs.parameter('__owner',
Exemple #7
0
        return constext


@specs.parameter('kwargs', yaqltypes.Lambda(with_context=True))
def with_original(context, **kwargs):
    new_context = context.create_child_context()

    original_context = context[constants.CTX_ORIGINAL_CONTEXT]
    for k, v in six.iteritems(kwargs):
        new_context['$' + k] = v(original_context)
    return new_context


@specs.parameter('target',
                 yaqltypes.AnyOf(dsl.MuranoTypeParameter(),
                                 dsl.MuranoObjectParameter()))
@specs.parameter('target_method', yaqltypes.String())
@specs.parameter('mock_object', dsl.MuranoObjectParameter())
@specs.parameter('mock_name', yaqltypes.String())
def inject_method_with_str(context, target, target_method, mock_object,
                           mock_name):
    ctx_manager = helpers.get_executor(context).context_manager

    current_class = helpers.get_type(context)
    mock_func = current_class.find_single_method(mock_name)
    original_class = target.type

    original_function = original_class.find_single_method(target_method)
    result_fd = original_function.instance_stub.clone()

    def payload_adapter(__context, __sender, *args, **kwargs):
Exemple #8
0
class Agent(object):
    def __init__(self, host):
        self._enabled = False
        if CONF.engine.disable_murano_agent:
            LOG.debug('Use of murano-agent is disallowed '
                      'by the server configuration')
        self._host = host
        self._enabled = not CONF.engine.disable_murano_agent
        env = host.find_owner('io.murano.Environment')
        self._queue = str('e%s-h%s' % (env.id, host.id)).lower()
        self._signing_key = None
        if CONF.engine.signing_key:
            key_path = os.path.expanduser(CONF.engine.signing_key)
            if not os.path.exists(key_path):
                LOG.warn("Key file %s does not exist. "
                         "Message signing is disabled")
            else:
                with open(key_path, "rb") as key_file:
                    key_data = key_file.read()
                    self._signing_key = serialization.load_pem_private_key(
                        key_data, password=None, backend=default_backend())
        self._last_stamp = 0
        self._initialized = False

    @property
    def enabled(self):
        return self._enabled

    @specs.parameter('line_prefix', specs.yaqltypes.String())
    def signing_key(self, line_prefix=''):
        if not self._signing_key:
            return ""
        key = self._signing_key.public_key().public_bytes(
            serialization.Encoding.PEM, serialization.PublicFormat.PKCS1)
        return line_prefix + line_prefix.join(key.splitlines(True))

    def _initialize(self):
        if self._initialized:
            return

        # (sjmc7) - turn this into a no-op if agents are disabled
        if CONF.engine.disable_murano_agent:
            LOG.debug('Use of murano-agent is disallowed '
                      'by the server configuration')
        else:
            region = dsl.MuranoObjectInterface.create(self._host().getRegion())
            with common.create_rmq_client(region) as client:
                client.declare(self._queue, enable_ha=True, ttl=86400000)
        self._initialized = True

    def queue_name(self):
        return self._queue

    def _check_enabled(self):
        if CONF.engine.disable_murano_agent:
            raise exceptions.PolicyViolationException(
                'Use of murano-agent is disallowed '
                'by the server configuration')

    def _prepare_message(self, template, msg_id):
        msg = message.Message()
        msg.body = template
        msg.id = msg_id
        return msg

    def _send(self, template, wait_results, timeout):
        """Send a message over the MQ interface."""
        self._initialize()
        region = self._host().getRegion()
        msg_id = template.get('ID', uuid.uuid4().hex)
        if wait_results:
            event = eventlet.event.Event()
            listener = region['agentListener']
            listener().subscribe(msg_id, event)

        msg = self._prepare_message(template, msg_id)
        with common.create_rmq_client(region) as client:
            client.send(message=msg, key=self._queue, signing_func=self._sign)
        if wait_results:
            try:
                with eventlet.Timeout(timeout):
                    result = event.wait()

            except eventlet.Timeout:
                listener().unsubscribe(msg_id)
                raise exceptions.TimeoutException(
                    'The murano-agent did not respond '
                    'within {0} seconds'.format(timeout))

            if not result:
                return None

            if result.get('FormatVersion', '1.0.0').startswith('1.'):
                return self._process_v1_result(result)

            else:
                return self._process_v2_result(result)

        else:
            return None

    @specs.parameter('resources',
                     dsl.MuranoObjectParameter('io.murano.system.Resources'))
    def call(self, template, resources, timeout=None):
        if timeout is None:
            timeout = CONF.engine.agent_timeout
        self._check_enabled()
        plan = self.build_execution_plan(template, resources())
        return self._send(plan, True, timeout)

    @specs.parameter('resources',
                     dsl.MuranoObjectParameter('io.murano.system.Resources'))
    def send(self, template, resources):
        self._check_enabled()
        plan = self.build_execution_plan(template, resources())
        return self._send(plan, False, 0)

    def call_raw(self, plan, timeout=None):
        if timeout is None:
            timeout = CONF.engine.agent_timeout
        self._check_enabled()
        return self._send(plan, True, timeout)

    def send_raw(self, plan):
        self._check_enabled()
        return self._send(plan, False, 0)

    def is_ready(self, timeout=100):
        try:
            self.wait_ready(timeout)
        except exceptions.TimeoutException:
            return False
        else:
            return True

    def wait_ready(self, timeout=100):
        self._check_enabled()
        template = {'Body': 'return', 'FormatVersion': '2.0.0', 'Scripts': {}}
        self.call_raw(template, timeout)

    def _sign(self, msg):
        if not self._signing_key:
            return None
        return self._signing_key.sign((self._queue + msg).encode('utf-8'),
                                      padding.PKCS1v15(), hashes.SHA256())

    def _process_v1_result(self, result):
        if result['IsException']:
            raise AgentException(
                dict(self._get_exception_info(result.get('Result', [])),
                     source='execution_plan'))
        else:
            results = result.get('Result', [])
            if not result:
                return None
            value = results[-1]
            if value['IsException']:
                raise AgentException(
                    dict(self._get_exception_info(value.get('Result', [])),
                         source='command'))
            else:
                return value.get('Result')

    def _process_v2_result(self, result):
        error_code = result.get('ErrorCode', 0)
        if not error_code:
            return result.get('Body')
        else:
            body = result.get('Body') or {}
            err = {
                'message': body.get('Message'),
                'details': body.get('AdditionalInfo'),
                'errorCode': error_code,
                'time': result.get('Time')
            }
            for attr in ('Message', 'AdditionalInfo'):
                if attr in body:
                    del body[attr]
            err['extra'] = body if body else None
            raise AgentException(err)

    def _get_array_item(self, array, index):
        return array[index] if len(array) > index else None

    def _get_exception_info(self, data):
        data = data or []
        return {
            'type': self._get_array_item(data, 0),
            'message': self._get_array_item(data, 1),
            'command': self._get_array_item(data, 2),
            'details': self._get_array_item(data, 3),
            'timestamp': datetime.datetime.now().isoformat()
        }

    def build_execution_plan(self, template, resources):
        template = copy.deepcopy(template)
        if not isinstance(template, dict):
            raise ValueError('Incorrect execution plan ')
        format_version = template.get('FormatVersion')
        if not format_version or format_version.startswith('1.'):
            return self._build_v1_execution_plan(template, resources)
        else:
            return self._build_v2_execution_plan(template, resources)

    def _generate_stamp(self):
        stamp = int(time.time() * 10000)
        if stamp <= self._last_stamp:
            stamp = self._last_stamp + 1
        self._last_stamp = stamp
        return stamp

    def _build_v1_execution_plan(self, template, resources):
        scripts_folder = 'scripts'
        script_files = template.get('Scripts', [])
        scripts = []
        for script in script_files:
            script_path = os.path.join(scripts_folder, script)
            scripts.append(
                base64.encode_as_text(resources.string(script_path,
                                                       binary=True),
                                      encoding='latin1'))
        template['Scripts'] = scripts
        template['Stamp'] = self._generate_stamp()
        return template

    def _build_v2_execution_plan(self, template, resources):
        scripts_folder = 'scripts'
        plan_id = uuid.uuid4().hex
        template['ID'] = plan_id
        template['Stamp'] = self._generate_stamp()

        if 'Action' not in template:
            template['Action'] = 'Execute'
        if 'Files' not in template:
            template['Files'] = {}

        files = {}
        for file_id, file_descr in template['Files'].items():
            files[file_descr['Name']] = file_id

        for name, script in template.get('Scripts', {}).items():
            if 'EntryPoint' not in script:
                raise ValueError('No entry point in script ' + name)

            if 'Application' == script['Type']:
                if script['EntryPoint'] not in files:
                    script['EntryPoint'] = self._place_file(
                        scripts_folder, script['EntryPoint'], template,
                        resources, files)
                else:
                    script['EntryPoint'] = files[script['EntryPoint']]
            if 'Files' in script:
                for i, file in enumerate(script['Files']):
                    if self._get_name(file) not in files:
                        script['Files'][i] = self._place_file(
                            scripts_folder, file, template, resources, files)
                    else:
                        script['Files'][i] = files[file]
        return template

    def _is_url(self, file):
        file = self._get_url(file)
        parts = urllib.parse.urlsplit(file)
        if not parts.scheme or not parts.netloc:
            return False
        else:
            return True

    def _get_url(self, file):
        if isinstance(file, dict):
            return list(file.values())[0]
        else:
            return file

    def _get_name(self, file):
        if isinstance(file, dict):
            name = list(file.keys())[0]
        else:
            name = file

        if self._is_url(name):
            name = name[name.rindex('/') + 1:len(name)]
        elif name.startswith('<') and name.endswith('>'):
            name = name[1:-1]
        return name

    def _get_file_value(self, file):
        if isinstance(file, dict):
            file = list(file.values())[0]
        return file

    def _get_body(self, file, resources, folder):
        use_base64 = self._is_base64(file)
        if use_base64:
            path = os.path.join(folder, file[1:-1])
            body = resources.string(path, binary=True)
            body = base64.encode_as_text(body) + "\n"
        else:
            path = os.path.join(folder, file)
            body = resources.string(path)
        return body

    def _is_base64(self, file):
        return file.startswith('<') and file.endswith('>')

    def _get_body_type(self, file):
        return 'Base64' if self._is_base64(file) else 'Text'

    def _place_file(self, folder, file, template, resources, files):
        file_value = self._get_file_value(file)
        name = self._get_name(file)
        file_id = uuid.uuid4().hex

        if self._is_url(file_value):
            template['Files'][file_id] = self._get_file_des_downloadable(file)
            files[name] = file_id

        else:
            template['Files'][file_id] = self._get_file_description(
                file, resources, folder)
            files[name] = file_id
        return file_id

    def _get_file_des_downloadable(self, file):
        name = self._get_name(file)
        file = self._get_file_value(file)
        return {'Name': str(name), 'URL': file, 'Type': 'Downloadable'}

    def _get_file_description(self, file, resources, folder):
        name = self._get_name(file)
        file_value = self._get_file_value(file)

        body_type = self._get_body_type(file_value)
        body = self._get_body(file_value, resources, folder)
        return {'Name': name, 'BodyType': body_type, 'Body': body}
        return constext


@specs.parameter('kwargs', yaqltypes.Lambda(with_context=True))
def with_original(context, **kwargs):
    new_context = context.create_child_context()

    original_context = context[constants.CTX_ORIGINAL_CONTEXT]
    for k, v in kwargs.items():
        new_context['$' + k] = v(original_context)
    return new_context


@specs.parameter(
    'target',
    yaqltypes.AnyOf(dsl.MuranoTypeParameter(), dsl.MuranoObjectParameter()))
@specs.parameter('target_method', yaqltypes.String())
@specs.parameter('mock_object', dsl.MuranoObjectParameter())
@specs.parameter('mock_name', yaqltypes.String())
def inject_method_with_str(context, target, target_method,
                           mock_object, mock_name):
    ctx_manager = helpers.get_executor().context_manager

    current_class = helpers.get_type(context)
    mock_func = current_class.find_single_method(mock_name)
    original_class = target.type

    original_function = original_class.find_single_method(target_method)
    result_fd = original_function.instance_stub.clone()

    def payload_adapter(__context, __sender, *args, **kwargs):
class GarbageCollector(object):
    @staticmethod
    @specs.parameter('publisher', dsl.MuranoObjectParameter(decorate=False))
    @specs.parameter('subscriber', dsl.MuranoObjectParameter(decorate=False))
    @specs.parameter('handler', yaqltypes.String(nullable=True))
    def subscribe_destruction(publisher, subscriber, handler=None):
        publisher_this = publisher.real_this
        subscriber_this = subscriber.real_this

        if handler:
            subscriber.type.find_single_method(handler)

        dependency = GarbageCollector._find_dependency(
            publisher_this, subscriber_this, handler)

        if not dependency:
            dependency = {'subscriber': helpers.weak_ref(subscriber_this),
                          'handler': handler}
            publisher_this.destruction_dependencies.append(dependency)

    @staticmethod
    @specs.parameter('publisher', dsl.MuranoObjectParameter(decorate=False))
    @specs.parameter('subscriber', dsl.MuranoObjectParameter(decorate=False))
    @specs.parameter('handler', yaqltypes.String(nullable=True))
    def unsubscribe_destruction(publisher, subscriber, handler=None):
        publisher_this = publisher.real_this
        subscriber_this = subscriber.real_this

        if handler:
            subscriber.type.find_single_method(handler)

        dds = publisher_this.destruction_dependencies
        dependency = GarbageCollector._find_dependency(
            publisher_this, subscriber_this, handler)

        if dependency:
            dds.remove(dependency)

    @staticmethod
    def _find_dependency(publisher, subscriber, handler):
        dds = publisher.destruction_dependencies
        for dd in dds:
            if dd['handler'] != handler:
                continue
            d_subscriber = dd['subscriber']
            if d_subscriber:
                d_subscriber = d_subscriber()
            if d_subscriber == subscriber:
                return dd

    @staticmethod
    def collect():
        helpers.get_executor().object_store.cleanup()

    @staticmethod
    @specs.parameter('object_', dsl.MuranoObjectParameter(decorate=False))
    def is_doomed(object_):
        return helpers.get_object_store().is_doomed(object_)

    @staticmethod
    @specs.parameter('object_', dsl.MuranoObjectParameter(decorate=False))
    def is_destroyed(object_):
        return object_.destroyed