예제 #1
0
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var')
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = list()
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    if 'references' in value:
                        ref_list.extend([
                            self._find_resource_from_name(ref)
                            for ref in value['references']
                            if not ref.startswith(invalid_references)
                        ])

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type',
                                           {}).get('constant_value', {})

                    if not ref_type and not resource.startswith(('data')):
                        resource_type, resource_id = resource.split('.')
                        ref_type = resource_type

                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source_resources,
                                          flatten_list(ref_list), ref_type)
예제 #2
0
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = []
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    if 'references' in value:
                        ref_list.extend([
                            self._find_resource_from_name(ref)
                            for ref in value['references']
                            if not ref.startswith(invalid_references)
                        ])

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type',
                                           {}).get('constant_value', {})

                    if not ref_type and not resource.startswith(('data')):
                        resource_type, resource_id = resource.split('.')
                        ref_type = resource_type

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source_resources,
                                          flatten_list(ref_list), ref_type)

                    # Mounting B->A
                    for source_resource in flatten_list(ref_list):
                        if not source_resource.startswith(
                            ('var', 'data', 'module', 'provider')):
                            ref_type = source_resource.split('.',
                                                             maxsplit=1)[0]

                            self._mount_resources([source_resource],
                                                  source_resources, ref_type)
예제 #3
0
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var.')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = {}
                for key, value in self.configuration['resources'][resource]['expressions'].items():
                    if 'references' in value:
                        for ref in value['references']:
                            if not ref.startswith(invalid_references):
                                if key not in ref_list:
                                    ref_list[key] = self._find_resource_from_name(ref)
                                else:
                                    ref_list[key].extend(self._find_resource_from_name(ref))

                if ref_list:
                    ref_type = self.configuration['resources'][resource]['expressions'].get('type',
                                                                                            {}).get('constant_value',
                                                                                                    {})

                    if not ref_type and not self.is_type(resource, 'data'):
                        resource_type, resource_id = resource.split('.')
                        ref_type = resource_type

                    for k, v in ref_list.items():
                        v = flatten_list(v)

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(self.configuration['resources'][resource]['address'])
                    self._mount_resources(source=source_resources,
                                          target=ref_list,
                                          ref_type=ref_type)
                    
                    # Mounting B->A
                    for parameter, target_resources in ref_list.items():
                        for target_resource in target_resources:
                            if not self.is_type(resource, 'data') and not self.is_type(resource, 'var') and not self.is_type(resource, 'provider'):
                                ref_type = target_resource.split('.', maxsplit=1)[0]

                                self._mount_resources(source=[target_resource],
                                                      target={parameter: source_resources},
                                                      ref_type=ref_type)
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var.', 'each.')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = {}
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    references = seek_key_in_dict(
                        value, 'references') if isinstance(
                            value, (dict, list)) else []

                    valid_references = []
                    for ref in references:
                        if isinstance(ref, dict) and ref.get('references'):
                            valid_references = [
                                r for r in ref['references']
                                if not r.startswith(invalid_references)
                            ]

                    for ref in valid_references:
                        # if ref is not in the correct format, handle it
                        if len(ref.split('.')) < 3 and ref.startswith(
                                'module'):

                            # Using for_each and modules together may introduce an issue where the plan.out.json won't include the necessary third part of the reference
                            # It is partially resolved by mounting the reference to all instances belonging to the module
                            if 'for_each_expression' in self.configuration[
                                    'resources'][resource]:

                                # extract source resources
                                assumed_source_resources = [
                                    k for k in self.resources.keys()
                                    if k.startswith(resource)
                                ]
                                # extract for_each keys
                                assumed_for_each_keys = [
                                    k[len(resource):].split('.')[0]
                                    for k in assumed_source_resources
                                ]
                                # combine ref with for each keys
                                assumed_refs = [
                                    '{}{}'.format(ref, key)
                                    for key in assumed_for_each_keys
                                ]
                                # get all the resources that start with updated ref
                                ambigious_references = []
                                for r in self.resources.keys():
                                    for assumed_ref in assumed_refs:
                                        if r.startswith(assumed_ref):
                                            if key in ref_list:
                                                ref_list[key].append(r)
                                            else:
                                                ref_list[key] = [r]

                                            ambigious_references.append(r)

                                # throw a warning
                                defaults = Defaults()
                                console_write('{} {}: {}'.format(
                                    defaults.warning_icon,
                                    defaults.warning_colour(
                                        'WARNING (Mounting)'),
                                    defaults.info_colour(
                                        'The reference "{}" in resource {} is ambigious.'
                                        ' It will be mounted to the following resources:'
                                    ).format(ref, resource)))
                                for i, r in enumerate(ambigious_references, 1):
                                    console_write(
                                        defaults.info_colour('{}. {}'.format(
                                            i, r)))

                            # if the reference can not be resolved, warn the user and continue.
                            else:
                                console_write('{} {}: {}'.format(
                                    Defaults().warning_icon,
                                    Defaults().warning_colour(
                                        'WARNING (Mounting)'),
                                    Defaults().info_colour(
                                        'The reference "{}" in resource {} is ambigious. It will not be mounted.'
                                        .format(ref, resource))))
                                continue
                        elif key not in ref_list:
                            ref_list[key] = self._find_resource_from_name(ref)
                        else:
                            ref_list[key].extend(
                                self._find_resource_from_name(ref))

                    # This is where we synchronise constant_value in the configuration section with the resource
                    # for filling up the missing elements that hasn't been defined in the resource due to provider
                    # implementation.
                    target_resource = [
                        t for t in
                        [self.resources.get(resource, {}).get('address')]
                        if t is not None
                    ]
                    if not target_resource:
                        target_resource = [
                            k for k in self.resources.keys()
                            if k.startswith(resource)
                        ]

                    for t_r in target_resource:
                        if type(value) is type(
                                self.resources[t_r]['values'].get(key)
                        ) and self.resources[t_r]['values'].get(key) != value:
                            if isinstance(value, (list, dict)):
                                merge_dicts(self.resources[t_r]['values'][key],
                                            value)

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type', {})

                    if 'references' in ref_type:
                        ref_type = resource.split('.')[0]

                    if not ref_type and not self.is_type(resource, 'data'):
                        ref_type = self.extract_resource_type_from_address(
                            resource)

                    for k, v in ref_list.items():
                        v = flatten_list(v)

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source=source_resources,
                                          target=ref_list,
                                          ref_type=ref_type)

                    # Mounting B->A
                    for parameter, target_resources in ref_list.items():
                        for target_resource in target_resources:
                            if not self.is_type(
                                    resource, 'data') and not self.is_type(
                                        resource, 'var') and not self.is_type(
                                            resource, 'provider'):
                                ref_type = self.extract_resource_type_from_address(
                                    target_resource)

                                self._mount_resources(
                                    source=[target_resource],
                                    target={parameter: source_resources},
                                    ref_type=ref_type)
예제 #5
0
    def test_flatten_single_dimensional_list(self):
        a = ['a', 'b', 'c']
        b = ['a', 'b', 'c']

        self.assertEqual(flatten_list(a), b)
예제 #6
0
    def test_flatten_multi_dimensional_nested_list(self):
        a = ['a', 'b', ['c', ['d', 'e'], 'f'], 'g', 'h', 'i', ['j', 'k']]
        b = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']

        self.assertEqual(flatten_list(a), b)
예제 #7
0
    def test_flatten_multi_dimensional_list(self):
        a = ['a', 'b', ['c']]
        b = ['a', 'b', 'c']

        self.assertEqual(flatten_list(a), b)
예제 #8
0
파일: terraform.py 프로젝트: sleightsec/cli
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var.', 'each.')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = {}
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    references = seek_key_in_dict(
                        value, 'references') if isinstance(
                            value, (dict, list)) else []

                    valid_references = []
                    for ref in references:
                        if isinstance(ref, dict) and ref.get('references'):
                            valid_references = [
                                r for r in ref['references']
                                if not r.startswith(invalid_references)
                            ]

                    for ref in valid_references:
                        if key not in ref_list:
                            ref_list[key] = self._find_resource_from_name(ref)
                        else:
                            ref_list[key].extend(
                                self._find_resource_from_name(ref))

                    # This is where we synchronise constant_value in the configuration section with the resource
                    # for filling up the missing elements that hasn't been defined in the resource due to provider
                    # implementation.
                    target_resource = [
                        t for t in
                        [self.resources.get(resource, {}).get('address')]
                        if t is not None
                    ]
                    if not target_resource:
                        target_resource = [
                            k for k in self.resources.keys()
                            if k.startswith(resource)
                        ]

                    for t_r in target_resource:
                        if type(value) is type(
                                self.resources[t_r]['values'].get(key)
                        ) and self.resources[t_r]['values'].get(key) != value:
                            if isinstance(value, (list, dict)):
                                merge_dicts(self.resources[t_r]['values'][key],
                                            value)

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type', {})

                    if 'references' in ref_type:
                        ref_type = resource.split('.')[0]

                    if not ref_type and not self.is_type(resource, 'data'):
                        resource_type, resource_id = resource.split('.')
                        ref_type = resource_type

                    for k, v in ref_list.items():
                        v = flatten_list(v)

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source=source_resources,
                                          target=ref_list,
                                          ref_type=ref_type)

                    # Mounting B->A
                    for parameter, target_resources in ref_list.items():
                        for target_resource in target_resources:
                            if not self.is_type(
                                    resource, 'data') and not self.is_type(
                                        resource, 'var') and not self.is_type(
                                            resource, 'provider'):
                                ref_type = target_resource.split('.',
                                                                 maxsplit=1)[0]

                                self._mount_resources(
                                    source=[target_resource],
                                    target={parameter: source_resources},
                                    ref_type=ref_type)