Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pagination extension to monitors #1633

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .apigentools-info
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
"spec_versions": {
"v1": {
"apigentools_version": "1.6.5",
"regenerated": "2023-08-30 07:29:22.537461",
"spec_repo_commit": "febdee32"
"regenerated": "2023-08-30 08:42:52.326487",
"spec_repo_commit": "fee86b40"
},
"v2": {
"apigentools_version": "1.6.5",
"regenerated": "2023-08-30 07:29:22.557428",
"spec_repo_commit": "febdee32"
"regenerated": "2023-08-30 08:42:52.374431",
"spec_repo_commit": "fee86b40"
}
}
}
4 changes: 4 additions & 0 deletions .generator/schemas/v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24896,6 +24896,7 @@ paths:
name: page_size
required: false
schema:
default: 100
example: 20
format: int32
maximum: 1000
Expand Down Expand Up @@ -24931,6 +24932,9 @@ paths:
summary: Get all monitor details
tags:
- Monitors
x-pagination:
limitParam: page_size
pageParam: page
post:
description: 'Create a monitor using the specified options.

Expand Down
4 changes: 3 additions & 1 deletion .generator/src/generator/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ def get_api_models(operations):
yield name

if "x-pagination" in operation:
name = get_type_at_path(operation, operation["x-pagination"]["resultsPath"])
name = get_type_at_path(operation, operation["x-pagination"].get("resultsPath"))
if name and name not in seen:
seen.add(name)
yield name
Expand Down Expand Up @@ -629,6 +629,8 @@ def get_type_at_path(operation, attribute_path):
if content is None:
raise RuntimeError("Default response not found")
content = content["schema"]
if not attribute_path:
return get_type_for_items(content)
for attr in attribute_path.split("."):
content = content["properties"][attr]
return get_type_for_items(content)
5 changes: 5 additions & 0 deletions .generator/src/generator/templates/api.j2
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,19 @@ class {{ classname }}:
set_attribute_from_path(kwargs, "{{ pagination.limitParam|attribute_path }}", local_page_size, endpoint.params_map)
pagination = {
"limit_value": local_page_size,
{%- if pagination.resultsPath %}
"results_path": "{{ pagination.resultsPath|attribute_path }}",
{%- endif %}
{%- if pagination.cursorParam %}
"cursor_param": "{{ pagination.cursorParam|attribute_path }}",
"cursor_path": "{{ pagination.cursorPath }}",
{%- endif %}
{%- if pagination.pageOffsetParam %}
"page_offset_param": "{{ pagination.pageOffsetParam|attribute_path }}",
{%- endif %}
{%- if pagination.pageParam %}
"page_param": "{{ pagination.pageParam|attribute_path }}",
{%- endif %}
"endpoint": endpoint,
"kwargs": kwargs,
}
Expand Down
22 changes: 18 additions & 4 deletions .generator/src/generator/templates/api_client.j2
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,13 @@ class ApiClient:
host: Optional[str] = None,
check_type: Optional[bool] = None,
):
if "page_param" in pagination:
set_attribute_from_path(
pagination["kwargs"],
pagination["page_param"],
0,
pagination["endpoint"].params_map,
)
params = pagination["endpoint"].gather_params(pagination["kwargs"])
while True:
response = self.call_api(
Expand All @@ -365,9 +372,9 @@ class ApiClient:
host=host,
collection_formats=params["collection_format"],
)
for item in get_attribute_from_path(response, pagination["results_path"]):
for item in get_attribute_from_path(response, pagination.get("results_path")):
yield item
if len(get_attribute_from_path(response, pagination["results_path"])) < pagination["limit_value"]:
if len(get_attribute_from_path(response, pagination.get("results_path"))) < pagination["limit_value"]:
break

params = self._update_paginated_params(pagination, response)
Expand All @@ -381,6 +388,13 @@ class ApiClient:
+ pagination["limit_value"],
pagination["endpoint"].params_map,
)
elif "page_param" in pagination:
set_attribute_from_path(
pagination["kwargs"],
pagination["page_param"],
get_attribute_from_path(pagination["kwargs"], pagination["page_param"], 0) + 1,
pagination["endpoint"].params_map,
)
else:
set_attribute_from_path(
pagination["kwargs"],
Expand Down Expand Up @@ -635,9 +649,9 @@ class AsyncApiClient(ApiClient):
host=host,
collection_formats=params["collection_format"],
)
for item in get_attribute_from_path(response, pagination["results_path"]):
for item in get_attribute_from_path(response, pagination.get("results_path")):
yield item
if len(get_attribute_from_path(response, pagination["results_path"])) < pagination["limit_value"]:
if len(get_attribute_from_path(response, pagination.get("results_path"))) < pagination["limit_value"]:
break

params = self._update_paginated_params(pagination, response)
Expand Down
2 changes: 2 additions & 0 deletions .generator/src/generator/templates/model_utils.j2
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,8 @@ class UnparsedObject(ModelNormal):

def get_attribute_from_path(obj, path, default=None):
"""Return an attribute at `path` from the passed object."""
if not path:
return obj
for elt in path.split("."):
try:
obj = obj[elt]
Expand Down
15 changes: 15 additions & 0 deletions examples/v1/monitors/ListMonitors_2966492814.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
Get all monitor details returns "OK" response with pagination
"""

from datadog_api_client import ApiClient, Configuration
from datadog_api_client.v1.api.monitors_api import MonitorsApi

configuration = Configuration()
with ApiClient(configuration) as api_client:
api_instance = MonitorsApi(api_client)
items = api_instance.list_monitors_with_pagination(
page_size=2,
)
for item in items:
print(item)
22 changes: 18 additions & 4 deletions src/datadog_api_client/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,13 @@ def call_api_paginated(
host: Optional[str] = None,
check_type: Optional[bool] = None,
):
if "page_param" in pagination:
set_attribute_from_path(
pagination["kwargs"],
pagination["page_param"],
0,
pagination["endpoint"].params_map,
)
params = pagination["endpoint"].gather_params(pagination["kwargs"])
while True:
response = self.call_api(
Expand All @@ -365,9 +372,9 @@ def call_api_paginated(
host=host,
collection_formats=params["collection_format"],
)
for item in get_attribute_from_path(response, pagination["results_path"]):
for item in get_attribute_from_path(response, pagination.get("results_path")):
yield item
if len(get_attribute_from_path(response, pagination["results_path"])) < pagination["limit_value"]:
if len(get_attribute_from_path(response, pagination.get("results_path"))) < pagination["limit_value"]:
break

params = self._update_paginated_params(pagination, response)
Expand All @@ -381,6 +388,13 @@ def _update_paginated_params(self, pagination, response):
+ pagination["limit_value"],
pagination["endpoint"].params_map,
)
elif "page_param" in pagination:
set_attribute_from_path(
pagination["kwargs"],
pagination["page_param"],
get_attribute_from_path(pagination["kwargs"], pagination["page_param"], 0) + 1,
pagination["endpoint"].params_map,
)
else:
set_attribute_from_path(
pagination["kwargs"],
Expand Down Expand Up @@ -633,9 +647,9 @@ async def call_api_paginated(
host=host,
collection_formats=params["collection_format"],
)
for item in get_attribute_from_path(response, pagination["results_path"]):
for item in get_attribute_from_path(response, pagination.get("results_path")):
yield item
if len(get_attribute_from_path(response, pagination["results_path"])) < pagination["limit_value"]:
if len(get_attribute_from_path(response, pagination.get("results_path"))) < pagination["limit_value"]:
break

params = self._update_paginated_params(pagination, response)
Expand Down
2 changes: 2 additions & 0 deletions src/datadog_api_client/model_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,8 @@ def __init__(self, **kwargs):

def get_attribute_from_path(obj, path, default=None):
"""Return an attribute at `path` from the passed object."""
if not path:
return obj
for elt in path.split("."):
try:
obj = obj[elt]
Expand Down
78 changes: 78 additions & 0 deletions src/datadog_api_client/v1/api/monitors_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
# Copyright 2019-Present Datadog, Inc.
from __future__ import annotations

import collections
from typing import Any, Dict, List, Union

from datadog_api_client.api_client import ApiClient, Endpoint as _Endpoint
from datadog_api_client.configuration import Configuration
from datadog_api_client.model_utils import (
set_attribute_from_path,
get_attribute_from_path,
UnsetType,
unset,
)
Expand Down Expand Up @@ -693,6 +696,81 @@ def list_monitors(

return self._list_monitors_endpoint.call_with_http_info(**kwargs)

def list_monitors_with_pagination(
self,
*,
group_states: Union[str, UnsetType] = unset,
name: Union[str, UnsetType] = unset,
tags: Union[str, UnsetType] = unset,
monitor_tags: Union[str, UnsetType] = unset,
with_downtimes: Union[bool, UnsetType] = unset,
id_offset: Union[int, UnsetType] = unset,
page: Union[int, UnsetType] = unset,
page_size: Union[int, UnsetType] = unset,
) -> collections.abc.Iterable[Monitor]:
"""Get all monitor details.

Provide a paginated version of :meth:`list_monitors`, returning all items.

:param group_states: When specified, shows additional information about the group states.
Choose one or more from ``all`` , ``alert`` , ``warn`` , and ``no data``.
:type group_states: str, optional
:param name: A string to filter monitors by name.
:type name: str, optional
:param tags: A comma separated list indicating what tags, if any, should be used to filter the list of monitors by scope.
For example, ``host:host0``.
:type tags: str, optional
:param monitor_tags: A comma separated list indicating what service and/or custom tags, if any, should be used to filter the list of monitors.
Tags created in the Datadog UI automatically have the service key prepended. For example, ``service:my-app``.
:type monitor_tags: str, optional
:param with_downtimes: If this argument is set to true, then the returned data includes all current active downtimes for each monitor.
:type with_downtimes: bool, optional
:param id_offset: Use this parameter for paginating through large sets of monitors. Start with a value of zero, make a request, set the value to the last ID of result set, and then repeat until the response is empty.
:type id_offset: int, optional
:param page: The page to start paginating from. If this argument is not specified, the request returns all monitors without pagination.
:type page: int, optional
:param page_size: The number of monitors to return per page. If the page argument is not specified, the default behavior returns all monitors without a ``page_size`` limit. However, if page is specified and ``page_size`` is not, the argument defaults to 100.
:type page_size: int, optional

:return: A generator of paginated results.
:rtype: collections.abc.Iterable[Monitor]
"""
kwargs: Dict[str, Any] = {}
if group_states is not unset:
kwargs["group_states"] = group_states

if name is not unset:
kwargs["name"] = name

if tags is not unset:
kwargs["tags"] = tags

if monitor_tags is not unset:
kwargs["monitor_tags"] = monitor_tags

if with_downtimes is not unset:
kwargs["with_downtimes"] = with_downtimes

if id_offset is not unset:
kwargs["id_offset"] = id_offset

if page is not unset:
kwargs["page"] = page

if page_size is not unset:
kwargs["page_size"] = page_size

local_page_size = get_attribute_from_path(kwargs, "page_size", 100)
endpoint = self._list_monitors_endpoint
set_attribute_from_path(kwargs, "page_size", local_page_size, endpoint.params_map)
pagination = {
"limit_value": local_page_size,
"page_param": "page",
"endpoint": endpoint,
"kwargs": kwargs,
}
return endpoint.call_with_http_info_paginated(pagination)

def search_monitor_groups(
self,
*,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2023-08-28T07:51:42.436Z
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
interactions:
- request:
body: null
headers:
accept:
- application/json
method: GET
uri: https://api.datadoghq.com/api/v1/monitor?page_size=2&page=0
response:
body:
string: '[{"id":34822915,"org_id":321813,"type":"query alert","name":"SLO Monitor:
aws_alb_latency_p95 for splunk","message":"Latency SLO violation for splunk
load balancer(s)","tags":["environment:test","generator:slops","release:e6a2686","sli:latency","slotype:alb","systemid:splunk","team:developer_insights"],"query":"avg(last_1m):avg:aws.applicationelb.target_response_time.p95{systemid:splunk,aws_account_type:production}
by {region} > 0.2","options":{"notify_audit":false,"locked":false,"include_tags":true,"thresholds":{"critical":0.2},"new_host_delay":300,"require_full_window":true,"notify_no_data":false,"silenced":{}},"multi":true,"created_at":1620047024000,"created":"2021-05-03T13:03:44.905085+00:00","modified":"2021-05-03T13:03:44.905085+00:00","deleted":null,"restricted_roles":null,"priority":null,"overall_state_modified":"2021-05-03T13:06:23+00:00","overall_state":"No
Data","creator":{"name":null,"handle":"frog@datadoghq.com","email":"frog@datadoghq.com","id":1445416},"matching_downtimes":[]},{"id":34822916,"org_id":321813,"type":"query
alert","name":"SLO Monitor: aws_classic_elb_latency_p99 for splunk","message":"Latency
SLO violation for splunk load balancer(s)","tags":["environment:test","generator:slops","release:e6a2686","sli:latency","slotype:elb","systemid:splunk","team:developer_insights"],"query":"avg(last_1m):avg:aws.elb.latency.p99{systemid:splunk,aws_account_type:production}
by {region} > 0.2","options":{"notify_audit":false,"locked":false,"include_tags":true,"thresholds":{"critical":0.2},"new_host_delay":300,"require_full_window":true,"notify_no_data":false,"silenced":{}},"multi":true,"created_at":1620047024000,"created":"2021-05-03T13:03:44.909928+00:00","modified":"2021-05-03T13:03:44.909928+00:00","deleted":null,"restricted_roles":null,"priority":null,"overall_state_modified":"2021-05-03T13:06:18+00:00","overall_state":"No
Data","creator":{"name":null,"handle":"frog@datadoghq.com","email":"frog@datadoghq.com","id":1445416},"matching_downtimes":[]}]

'
headers:
content-type:
- application/json
status:
code: 200
message: OK
- request:
body: null
headers:
accept:
- application/json
method: GET
uri: https://api.datadoghq.com/api/v1/monitor?page_size=2&page=1
response:
body:
string: '[{"id":34822917,"org_id":321813,"type":"query alert","name":"SLO Monitor:
aws_alb_latency_p50 for splunk","message":"Latency SLO violation for splunk
load balancer(s)","tags":["environment:test","generator:slops","release:e6a2686","sli:latency","slotype:alb","systemid:splunk","team:developer_insights"],"query":"avg(last_1m):avg:aws.applicationelb.target_response_time.p50{systemid:splunk,aws_account_type:production}
by {region} > 0.2","options":{"notify_audit":false,"locked":false,"include_tags":true,"thresholds":{"critical":0.2},"new_host_delay":300,"require_full_window":true,"notify_no_data":false,"silenced":{}},"multi":true,"created_at":1620047024000,"created":"2021-05-03T13:03:44.920644+00:00","modified":"2021-05-03T13:03:44.920644+00:00","deleted":null,"restricted_roles":null,"priority":null,"overall_state_modified":"2021-05-03T13:06:37+00:00","overall_state":"No
Data","creator":{"name":null,"handle":"frog@datadoghq.com","email":"frog@datadoghq.com","id":1445416},"matching_downtimes":[]}]

'
headers:
content-type:
- application/json
status:
code: 200
message: OK
version: 1
8 changes: 8 additions & 0 deletions tests/v1/features/monitors.feature
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ Feature: Monitors
When the request is sent
Then the response status is 200 OK

@replay-only @skip-validation @team:DataDog/monitor-app @with-pagination
Scenario: Get all monitor details returns "OK" response with pagination
Given new "ListMonitors" request
And request contains "page_size" parameter with value 2
When the request with pagination is sent
Then the response status is 200 OK
And the response has 3 items

@skip @team:DataDog/monitor-app
Scenario: Get all monitor details with tags
Given there is a valid "monitor" in the system
Expand Down
Loading