Example #1
0
    def delete_tag(self, key: str) -> bool:
        tag_resource_name = self.tag_resource_name()
        if tag_resource_name:
            log.debug(f"Deleting tag {key} on resource {self.id}")
            team = self._account
            credentials = get_team_credentials(team.id)
            if credentials is None:
                raise RuntimeError(
                    f"Cannot update tag on resource {self.id}, credentials not found for team {team.id}"
                )
            client = StreamingWrapper(
                credentials.api_token,
                credentials.spaces_access_key,
                credentials.spaces_secret_key,
            )

            if key not in self.tags:
                # tag does not exist, nothing to do
                return False

            tag_key = dump_tag(key, self.tags.get(key))
            untagged = client.untag_resource(tag_key, tag_resource_name,
                                             self.id)
            if not untagged:
                return False
            tag_count = client.get_tag_count(tag_key)
            if tag_count == 0:
                return client.delete("/tags", tag_key)
            return True
        else:
            raise NotImplementedError(
                f"resource {self.kind} does not support tagging")
Example #2
0
 def delete(self, graph: Graph) -> bool:
     log.debug(
         f"Deleting space {self.id} in account {self.account(graph).id} region {self.region(graph).id}"
     )
     team = self.account(graph)
     credentials = get_team_credentials(team.id)
     if credentials is None:
         raise RuntimeError(
             f"Cannot delete resource {self.id}, credentials not found for team {team.id}"
         )
     client = StreamingWrapper(
         credentials.api_token,
         credentials.spaces_access_key,
         credentials.spaces_secret_key,
     )
     return client.delete_space(self.region(graph).id, self.id)
Example #3
0
 def delete(self, graph: Graph) -> bool:
     log.debug(
         f"Deleting resource {self.id} in account {self.account(graph).id} region {self.region(graph).id}"
     )
     team = self.account(graph)
     credentials = get_team_credentials(team.id)
     if credentials is None:
         raise RuntimeError(
             f"Cannot delete resource {self.id}, credentials not found for team {team.id}"
         )
     client = StreamingWrapper(
         credentials.api_token,
         credentials.spaces_access_key,
         credentials.spaces_secret_key,
     )
     # un-assign the ip just in case it's still assigned to a droplet
     client.unassign_floating_ip(self.id)
     return client.delete("/floating_ips", self.id)
Example #4
0
    def delete(self, graph: Graph) -> bool:
        """Delete a resource in the cloud"""
        delete_uri_path = self.delete_uri_path()
        if delete_uri_path:
            log.debug(
                f"Deleting resource {self.id} in account {self.account(graph).id} region {self.region(graph).id}"
            )
            team = self.account(graph)
            credentials = get_team_credentials(team.id)
            if credentials is None:
                raise RuntimeError(
                    f"Cannot delete resource {self.id}, credentials not found for team {team.id}"
                )
            client = StreamingWrapper(
                credentials.api_token,
                credentials.spaces_access_key,
                credentials.spaces_secret_key,
            )
            return client.delete(delete_uri_path, self.id)

        raise NotImplementedError
Example #5
0
    def collect_team(self, client: StreamingWrapper) -> Optional[Graph]:
        """Collects an individual team."""
        team_id = client.get_team_id()
        team = DigitalOceanTeam(id=team_id, tags={}, urn=f"do:team:{team_id}")

        try:
            dopc = DigitalOceanTeamCollector(team, client)
            dopc.collect()
        except Exception:
            log.exception(
                f"An unhandled error occurred while collecting team {team_id}")
            return None
        else:
            return dopc.graph
Example #6
0
    def collect_team(self, client: StreamingWrapper) -> Optional[Dict]:
        """Collects an individual team."""
        projects = client.list_projects()
        team_id = str(projects[0]["owner_id"])
        team = DigitalOceanTeam(id=team_id, tags={}, urn=f"do:team:{team_id}")

        try:
            dopc = DigitalOceanTeamCollector(team, client)
            dopc.collect()
        except Exception:
            log.exception(
                f"An unhandled error occurred while collecting team {team_id}"
            )
        else:
            return dopc.graph
Example #7
0
    def collect(self) -> None:
        """This method is being called by resoto whenever the collector runs

        It is responsible for querying the cloud APIs for remote resources and adding
        them to the plugin graph.
        The graph root (self.graph.root) must always be followed by one or more
        accounts. An account must always be followed by a region.
        A region can contain arbitrary resources.
        """
        tokens = Config.digitalocean.api_tokens
        spaces_access_keys: List[str] = Config.digitalocean.spaces_access_keys
        spaces_keys: List[Tuple[Optional[str], Optional[str]]] = []

        def spaces_keys_valid(keys: List[str]) -> bool:
            return all([len(key.split(":")) == 2 for key in keys])

        if not spaces_keys_valid(spaces_access_keys):
            log.warn(
                "DigitalOcean Spaces access keys must be provided in pairs of access_key:secret_key"
            )
        else:

            def key_to_tuple(key: str) -> Tuple[str, str]:
                splitted = key.split(":")
                return splitted[0], splitted[1]

            spaces_keys = [key_to_tuple(key) for key in spaces_access_keys]

        if len(tokens) != len(spaces_access_keys):
            log.warn(
                "The number of DigitalOcean API tokens and DigitalOcean Spaces access keys must be equal."
                + "Missing or extra spaces access keys will be ignored.")
            spaces_keys = spaces_keys[:len(tokens)]
            spaces_keys.extend([(None, None)] *
                               (len(tokens) - len(spaces_keys)))

        log.info(
            f"plugin: collecting DigitalOcean resources for {len(tokens)} teams"
        )
        for token, space_key_tuple in zip(tokens, spaces_keys):
            client = StreamingWrapper(token, space_key_tuple[0],
                                      space_key_tuple[1])
            team_graph = self.collect_team(client)
            self.graph.merge(team_graph)
Example #8
0
    def update_tag(self, key: str, value: str) -> bool:

        tag_resource_name = self.tag_resource_name()
        if tag_resource_name:

            log.debug(f"Updating tag {key} on resource {self.id}")
            team = self._account
            credentials = get_team_credentials(team.id)
            if credentials is None:
                raise RuntimeError(
                    f"Cannot update tag on resource {self.id}, credentials not found for team {team.id}"
                )
            client = StreamingWrapper(
                credentials.api_token,
                credentials.spaces_access_key,
                credentials.spaces_secret_key,
            )

            if key in self.tags:
                # resotocore knows about the tag. Therefore we need to clean it first
                tag_key = dump_tag(key, self.tags.get(key))
                client.untag_resource(tag_key, tag_resource_name, self.id)

            # we tag the resource using the key-value formatted tag
            tag_kv = dump_tag(key, value)
            tag_ready: bool = True
            tag_count = client.get_tag_count(tag_kv)
            # tag count call failed irrecoverably, we can't continue
            if isinstance(tag_count, str):
                raise RuntimeError(f"Tag update failed. Reason: {tag_count}")
            # tag does not exist, create it
            if tag_count is None:
                tag_ready = client.create_tag(tag_kv)

            return tag_ready and client.tag_resource(tag_kv, tag_resource_name,
                                                     self.id)
        else:
            raise NotImplementedError(
                f"resource {self.kind} does not support tagging")