def list_log_streams(self, next_token: str = None): """ List image builder's logs. :param next_token: Token for paginated requests. :returns ListLogsResponse """ try: log_streams = [] if AWSApi.instance().logs.log_group_exists(self._log_group_name): LOGGER.debug("Listing log streams from log group %s", self._log_group_name) log_stream_resp = AWSApi.instance().logs.describe_log_streams( log_group_name=self._log_group_name, next_token=next_token ) log_streams.extend(log_stream_resp["logStreams"]) next_token = log_stream_resp.get("nextToken") else: LOGGER.debug("Log Group %s doesn't exist.", self._log_group_name) raise NotFoundImageBuilderActionError( ("Unable to find image logs, please double check if image id=" f"{self.image_id} is correct.") ) return LogStreams(log_streams, next_token) except AWSClientError as e: raise ImageBuilderActionError(f"Unexpected error when retrieving image's logs: {e}")
def list_log_streams(self, filters: List[str] = None, next_token: str = None): """ List cluster's logs. :param next_token: Token for paginated requests. :param filters: Filters in the format Name=name,Values=value1,value2 Accepted filters are: private_dns_name, node_type==HeadNode :returns a dict with the structure {"logStreams": [], "stackEventsStream": {}} """ try: # check stack if not AWSApi.instance().cfn.stack_exists(self.stack_name): raise NotFoundClusterActionError( f"Cluster {self.name} does not exist.") log_streams = [] LOGGER.debug("Listing log streams from log group %s", self.stack.log_group_name) if self.stack.log_group_name: list_logs_filters = self._init_list_logs_filters(filters) log_stream_resp = AWSApi.instance().logs.describe_log_streams( log_group_name=self.stack.log_group_name, log_stream_name_prefix=list_logs_filters.log_stream_prefix, next_token=next_token, ) log_streams.extend(log_stream_resp["logStreams"]) next_token = log_stream_resp.get("nextToken") else: LOGGER.debug( "CloudWatch logging is not enabled for cluster %s.", self.name) raise BadRequestClusterActionError( f"CloudWatch logging is not enabled for cluster {self.name}." ) return LogStreams(log_streams, next_token) except AWSClientError as e: raise _cluster_error_mapper( e, f"Unexpected error when retrieving cluster's logs: {e}")
def test_execute(self, mocker, set_env, args): logs = LogStreams() logs.log_streams = [ { "logStreamName": "ip-10-0-0-102.i-0717e670ad2549e72.cfn-init", "creationTime": 1622802842228, "firstEventTimestamp": 1622802790248, "lastEventTimestamp": 1622802893126, "lastIngestionTime": 1622802903119, "uploadSequenceToken": "4961...", "arn": ("arn:aws:logs:eu-west-1:111:log-group:/aws/parallelcluster/" "test22-202106041223:log-stream:ip-10-0-0-102.i-0717e670ad2549e72.cfn-init" ), "storedBytes": 0, }, { "logStreamName": "ip-10-0-0-102.i-0717e670ad2549e72.chef-client", "creationTime": 1622802842207, "firstEventTimestamp": 1622802837114, "lastEventTimestamp": 1622802861226, "lastIngestionTime": 1622802897558, "uploadSequenceToken": "4962...", "arn": ("arn:aws:logs:eu-west-1:111:log-group:/aws/parallelcluster/" "test22-202106041223:log-stream:ip-10-0-0-102.i-0717e670ad2549e72.chef-client" ), "storedBytes": 0, }, ] logs.next_token = "123-456" list_log_streams_mock = mocker.patch( "pcluster.api.controllers.image_logs_controller.ImageBuilder.list_log_streams", return_value=logs) set_env("AWS_DEFAULT_REGION", "us-east-1") base_args = ["list-image-log-streams"] command = base_args + self._build_cli_args({**REQUIRED_ARGS, **args}) out = run(command) # cfn stack events are not displayed if next-token is passed expected_out = [ { "logStreamName": "ip-10-0-0-102.i-0717e670ad2549e72.cfn-init", "firstEventTimestamp": to_iso_timestr(to_utc_datetime(1622802790248)), "lastEventTimestamp": to_iso_timestr(to_utc_datetime(1622802893126)), }, { "logStreamName": "ip-10-0-0-102.i-0717e670ad2549e72.chef-client", "firstEventTimestamp": to_iso_timestr(to_utc_datetime(1622802837114)), "lastEventTimestamp": to_iso_timestr(to_utc_datetime(1622802861226)), }, ] assert_that(out["nextToken"]).is_equal_to(logs.next_token) for i in range(len(logs.log_streams)): select_keys = { "logStreamName", "firstEventTimestamp", "lastEventTimestamp" } out_select = { k: v for k, v in out["logStreams"][i].items() if k in select_keys } assert_that(out_select).is_equal_to(expected_out[i]) assert_that(list_log_streams_mock.call_args).is_length(2) # verify arguments kwargs = {"next_token": None} kwargs.update(args) list_log_streams_mock.assert_called_with(**kwargs)