예제 #1
0
    def parse(self, data: Dict[str, Any], context: Dict[str,
                                                        Any]) -> List[Link]:
        """Parse this field and return a list of Links.

        Args:
            data: data to parse
            context: contains data from higher level parsing code.

        Returns:
            List of Link objects. At most one link will be returned.
        """
        if isinstance(self._resource_spec_class, str):
            resource_spec_class: Type[
                ResourceSpec] = ResourceSpec.get_by_class_name(
                    self._resource_spec_class)
        else:
            resource_spec_class = self._resource_spec_class
        if not self.alti_key:
            self.alti_key = resource_spec_class.type_name
        short_resource_id = data.get(self.source_key)
        if not short_resource_id:
            if self.optional:
                return []
            raise ResourceLinkFieldSourceKeyNotFoundException(
                f"Expected key '{self.source_key}' with non-empty/zero value in {data}"
            )
        if self.value_is_id:
            resource_id = short_resource_id
        else:
            resource_id = resource_spec_class.generate_id(
                short_resource_id, context)
        return [TransientResourceLinkLink(pred=self.alti_key, obj=resource_id)]
예제 #2
0
def dedupe_resources(resources: Iterable[Resource]) -> Tuple[Resource, ...]:
    """Resolve any duplicate resource ids.  In general duplicate resource ids can
    have their Resource objects merged if they are of the same type and all fields
    are identical or additive only across the resources or if one of the Resources
    allows a special merge via its ResourceSpec class' `allow_clobber` attribute."""
    resource_ids_resources: DefaultDict[str,
                                        List[Resource]] = defaultdict(list)
    for resource in resources:
        resource_ids_resources[resource.resource_id].append(resource)
    merged_resources: List[Resource] = []
    for resource_id, candidate_resources in resource_ids_resources.items():
        if len(candidate_resources) > 1:
            merged_resource = ResourceSpec.merge_resources(
                resource_id=resource_id, resources=candidate_resources)
            merged_resources.append(merged_resource)
    for merged_resource in merged_resources:
        resource_ids_resources[merged_resource.resource_id] = [merged_resource]
    # at this point all values in resource_ids_resources should be single-value lists.
    # validate that and build a list of deduped_resources from those single-values
    deduped_resources = []
    for resource_id, resource_list in resource_ids_resources.items():
        if len(resource_list) != 1:
            raise Exception(
                f"More than one resource found for {resource_id}: {resource_list}"
            )
        deduped_resources.append(resource_list[0])
    return tuple(deduped_resources)
예제 #3
0
    def parse(self, data: str, context: Dict[str, Any]) -> List[Link]:
        """Parse this field and return a list of Links.

        Args:
            data: data to parse
            context: contains data from higher level parsing code.

        Returns:
            List of Link objects. At most one link will be returned.
        """
        if isinstance(self._resource_spec_class, str):
            resource_spec_class: Type[
                ResourceSpec] = ResourceSpec.get_by_class_name(
                    self._resource_spec_class)
        else:
            resource_spec_class = self._resource_spec_class
        if not self.alti_key:
            self.alti_key = resource_spec_class.type_name

        short_resource_id = data
        if self.value_is_id:
            resource_id = short_resource_id
        else:
            resource_id = resource_spec_class.generate_id(
                short_resource_id, context)
        return [ResourceLinkLink(pred=self.alti_key, obj=resource_id)]
    def parse(self, data: str, context: Dict[str, Any]) -> LinkCollection:
        """Parse this field and return a LinkCollection.

        Args:
            data: data to parse
            context: contains data from higher level parsing code.

        Returns:
            LinkCollection
        """
        if isinstance(self._resource_spec_class, str):
            resource_spec_class: Type[
                ResourceSpec] = ResourceSpec.get_by_class_name(
                    self._resource_spec_class)
        else:
            resource_spec_class = self._resource_spec_class
        if not self.alti_key:
            self.alti_key = resource_spec_class.type_name

        short_resource_id = data
        if self.value_is_id:
            resource_id = short_resource_id
        else:
            resource_id = resource_spec_class.generate_id(
                short_resource_id, context)
        return LinkCollection(
            resource_links=[ResourceLink(pred=self.alti_key,
                                         obj=resource_id)], )
    def test(self):
        account_id = "012345678901"
        errors = ["foo", "boo"]
        unscanned_account_resource = UnscannedAccountResourceSpec.create_resource(
            account_id=account_id, errors=errors)
        resource = ResourceSpec.merge_resources("foo",
                                                [unscanned_account_resource])

        self.assertEqual(resource.resource_id, "foo")
        self.assertEqual(resource.type, "aws:unscanned-account")
        self.assertEqual(len(resource.link_collection.simple_links), 2)
        self.assertEqual(
            resource.link_collection.simple_links[0],
            SimpleLink(pred="account_id", obj="012345678901"),
        )
        self.assertEqual(resource.link_collection.simple_links[1].pred,
                         "error")
        self.assertTrue(
            resource.link_collection.simple_links[1].obj.startswith(
                "foo\nboo - "))
예제 #6
0
    def test(self):
        account_id = "012345678901"
        errors = ["foo", "boo"]
        unscanned_account_resource = UnscannedAccountResourceSpec.create_resource(
            account_id=account_id, errors=errors)
        resource = ResourceSpec.merge_resources("foo",
                                                [unscanned_account_resource])

        resource_dict = resource.to_dict()
        self.assertEqual(resource_dict["type"], "aws:unscanned-account")
        self.assertEqual(len(resource_dict["links"]), 2)
        self.assertEqual(resource_dict["links"][0], {
            'pred': 'account_id',
            'obj': '012345678901',
            'type': 'simple'
        })
        self.assertEqual(resource_dict["links"][1]["pred"], "error")
        self.assertEqual(resource_dict["links"][1]["type"], "simple")
        self.assertTrue(
            resource_dict["links"][1]["obj"].startswith("foo\nboo - "))
예제 #7
0
 def _resolve_duplicates(self) -> None:
     """Resolve any duplicate resource ids.  In general duplicate resource ids can
     have their Resource objects merged if they are of the same type and all fields
     are identical or additive only across the resources or if one of the Resources
     allows a special merge via its ResourceSpec class' `allow_clobber` attribute."""
     resource_ids_resources: DefaultDict[str,
                                         List[Resource]] = defaultdict(list)
     for resource in self.resources:
         resource_ids_resources[resource.resource_id].append(resource)
     merged_resources: List[Resource] = []
     for resource_id, resources in resource_ids_resources.items():
         if len(resources) > 1:
             merged_resource = ResourceSpec.merge_resources(
                 resource_id=resource_id, resources=resources)
             merged_resources.append(merged_resource)
     for merged_resource in merged_resources:
         self.resources = [
             resource for resource in self.resources
             if resource.resource_id != merged_resource.resource_id
         ]
         self.resources.append(merged_resource)
    def parse(self, data: Dict[str, Any],
              context: Dict[str, Any]) -> LinkCollection:
        """Parse this field and return a LinkCollection

        Args:
            data: data to parse
            context: contains data from higher level parsing code.

        Returns:
             LinkCollection
        """
        if isinstance(self._resource_spec_class, str):
            resource_spec_class: Type[
                ResourceSpec] = ResourceSpec.get_by_class_name(
                    self._resource_spec_class)
        else:
            resource_spec_class = self._resource_spec_class
        if not self.alti_key:
            self.alti_key = resource_spec_class.type_name
        short_resource_id = data.get(self.source_key)
        if not short_resource_id:
            if self.optional:
                return LinkCollection()
            raise ResourceLinkFieldSourceKeyNotFoundException(
                f"Expected key '{self.source_key}' with non-empty/zero value in {data}"
            )
        if not isinstance(short_resource_id, str):
            raise ResourceLinkFieldValueNotAStringException((
                f"ResourceLinkField for {self.source_key} expected a string but got a "
                f"{type(short_resource_id)} : {short_resource_id}"))
        if self.value_is_id:
            resource_id = short_resource_id
        else:
            resource_id = resource_spec_class.generate_id(
                short_resource_id, context)
        return LinkCollection(
            resource_links=[ResourceLink(pred=self.alti_key,
                                         obj=resource_id)], )