Skip to content

Commit

Permalink
1.1.0 Move to services architecture
Browse files Browse the repository at this point in the history
  • Loading branch information
dlopes7 committed Mar 28, 2021
1 parent 218402f commit c45021a
Show file tree
Hide file tree
Showing 12 changed files with 446 additions and 659 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,25 @@ dt = Dynatrace("environment_url", "api_token")


# Get all hosts and some properties
for entity in dt.get_entities('type("HOST")', fields="properties.memoryTotal,properties.monitoringMode"):
for entity in dt.entities.list('type("HOST")', fields="properties.memoryTotal,properties.monitoringMode"):
print(entity.entity_id, entity.display_name, entity.properties)

# Get idle CPU for all hosts
for metric in dt.query_metrics("builtin:host.cpu.idle", page_size=5000, resolution="Inf"):
for metric in dt.metrics.query("builtin:host.cpu.idle", page_size=5000, resolution="Inf"):
print(metric)

# Get all ActiveGates
for ag in dt.get_activegates():
for ag in dt.activegates.list():
print(ag)

# Get metric descriptions for all host metrics
for m in dt.get_metrics("builtin:host.*"):
for m in dt.metrics.list("builtin:host.*"):
print(m)

# Delete endpoints that contain the word test
for plugin in dt.get_plugins():
for plugin in dt.plugins.list():

# This could also be dt.get_endpoints(plugin.id)
# This could also be dt.get_endpoints(plugin.id)
for endpoint in plugin.endpoints:
if "test" in endpoint.name:
endpoint.delete(plugin.id)
Expand Down
61 changes: 61 additions & 0 deletions dynatrace/activegate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from dynatrace.dynatrace_object import DynatraceObject
from dynatrace.entity import EntityShortRepresentation
from dynatrace.http_client import HttpClient
from dynatrace.pagination import PaginatedList

OS_TYPE_LINUX = "LINUX"
OS_TYPE_WINDOWS = "WINDOWS"
Expand All @@ -25,6 +27,65 @@
VERSION_COMPARE_TYPE_LOWER_EQUAL = "LOWER_EQUAL"


class ActiveGateService:
def __init__(self, http_client: HttpClient):
self.__http_client = http_client

def list(
self,
hostname: str = None,
os_type: str = None,
network_address: str = None,
activegate_type: str = None,
network_zone: str = None,
update_status: str = None,
version_compare_type: str = None,
version: str = None,
) -> PaginatedList["ActiveGate"]:
"""
Lists all available ActiveGates
:param hostname: Filters the resulting set of ActiveGates by the name of the host it's running on.
You can specify a partial name. In that case, the CONTAINS operator is used.
:param os_type: Filters the resulting set of ActiveGates by the OS type of the host it's running on.
Available values : LINUX, WINDOWS
:param network_address: Filters the resulting set of ActiveGates by the network address.
You can specify a partial address. In that case, the CONTAINS operator is used.
:param activegate_type: Filters the resulting set of ActiveGates by the ActiveGate type.
Available values : ENVIRONMENT, ENVIRONMENT_MULTI
:param network_zone: Filters the resulting set of ActiveGates by the network zone.
You can specify a partial name. In that case, the CONTAINS operator is used.
:param update_status: Filters the resulting set of ActiveGates by the auto-update status.
Available values : INCOMPATIBLE, OUTDATED, SUPPRESSED, UNKNOWN, UP2DATE, UPDATE_IN_PROGRESS, UPDATE_PENDING, UPDATE_PROBLEM
:param version_compare_type: Filters the resulting set of ActiveGates by the specified version.
Specify the comparison operator here.
Available values : EQUAL, GREATER, GREATER_EQUAL, LOWER, LOWER_EQUAL
Default value : EQUAL
:param version: Filters the resulting set of ActiveGates by the specified version.
Specify the version in <major>.<minor>.<revision> format (for example, 1.195.0) here.
:return: A list of ActiveGates.
"""
params = {
"hostname": hostname,
"osType": os_type,
"networkAddress": network_address,
"ActivegateType": activegate_type,
"networkZone": network_zone,
"updateStatus": update_status,
"versionCompareType": version_compare_type,
"version": version,
}
return PaginatedList(ActiveGate, self.__http_client, "/api/v2/activeGates", params, list_item="activeGates")


class ActiveGate(EntityShortRepresentation):
@property
def id(self) -> str:
Expand Down
57 changes: 42 additions & 15 deletions dynatrace/custom_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@


from dynatrace.dynatrace_object import DynatraceObject
from dynatrace.http_client import HttpClient


class CustomDeviceService:
def __init__(self, http_client: HttpClient):
self.__http_client = http_client

def create(
self,
device_id: str,
display_name: Optional[str] = None,
group: Optional[str] = None,
ip_addresses: Optional[List[str]] = None,
listen_ports: Optional[List[int]] = None,
technology: Optional[str] = None,
favicon: Optional[str] = None,
config_url: Optional[str] = None,
properties: Optional[Dict[str, str]] = None,
tags: Optional[List[str]] = None,
series: Optional[List] = None,
host_names: Optional[List[str]] = None,
) -> "CustomDevicePushMessage":
return CustomDevicePushMessage(
self.__http_client,
device_id=device_id,
display_name=display_name,
group=group,
ip_addresses=ip_addresses,
listen_ports=listen_ports,
technology=technology,
favicon=favicon,
config_url=config_url,
properties=properties,
tags=tags,
series=series,
host_names=host_names,
)


class Series(MutableSequence):
Expand Down Expand Up @@ -95,24 +132,18 @@ def series(self, series: Series):

def post(self, only_valid_data_points=False):
try:
response = self._http_client.make_request(
f"/api/v1/entity/infrastructure/custom/{self.device_id}", params=self._raw_element, method="POST"
)
response = self._http_client.make_request(f"/api/v1/entity/infrastructure/custom/{self.device_id}", params=self._raw_element, method="POST")
return response
except Exception as e:
if only_valid_data_points and (
"configuration.Creation timestamp is:" in f"{e}" or "Data point timestamp is too far in the past" in f"{e}"
):
if only_valid_data_points and ("configuration.Creation timestamp is:" in f"{e}" or "Data point timestamp is too far in the past" in f"{e}"):
if "configuration.Creation timestamp" in f"{e}":
max_timestamp = int(f"{e}".split("configuration.Creation timestamp is:")[1].split('"')[0].strip())
max_timestamp = datetime.fromtimestamp(max_timestamp / 1000, tz=timezone.utc)
else:
max_timestamp = datetime.now(tz=timezone.utc) - timedelta(minutes=59)
self._http_client.log.warning(f"Some data points were invalid, removing data points older than {max_timestamp}")
for s in self.series:
s.data_points = [
d for d in s.data_points if d.timestamp.replace(tzinfo=max_timestamp.tzinfo) >= max_timestamp
]
s.data_points = [d for d in s.data_points if d.timestamp.replace(tzinfo=max_timestamp.tzinfo) >= max_timestamp]
self._raw_element["series"] = [s._raw_element for s in self.series]
return self.post()
else:
Expand All @@ -125,9 +156,7 @@ def absolute(self, key: str, value: float, timestamp: Optional[datetime] = None,


class EntityTimeseriesData(DynatraceObject):
def __init__(
self, http_client, timeseries_id: str, data_points: List["DataPoint"], dimensions: Optional[Dict[str, str]] = None
):
def __init__(self, http_client, timeseries_id: str, data_points: List["DataPoint"], dimensions: Optional[Dict[str, str]] = None):
self.timeseries_id: str = timeseries_id
self.dimensions = dimensions
self.__data_points: List["DataPoint"] = data_points
Expand All @@ -148,9 +177,7 @@ def data_points(self) -> List["DataPoint"]:
@data_points.setter
def data_points(self, data_points: List["DataPoint"]):
self.__data_points = data_points
self._raw_element["dataPoints"] = [
[int(data_point.timestamp.timestamp() * 1000), data_point.value] for data_point in self.__data_points
]
self._raw_element["dataPoints"] = [[int(data_point.timestamp.timestamp() * 1000), data_point.value] for data_point in self.__data_points]


class DataPoint:
Expand Down
36 changes: 35 additions & 1 deletion dynatrace/entity.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
from datetime import datetime
from typing import List
from typing import List, Optional

from dynatrace.entity_type import EntityType
from dynatrace.http_client import HttpClient
from dynatrace.management_zone import ManagementZone
from dynatrace.metag import METag
from dynatrace.dynatrace_object import DynatraceObject
from dynatrace.pagination import PaginatedList


class EntityService:
def __init__(self, http_client: HttpClient):
self.__http_client = http_client

def list(
self,
entity_selector: str,
time_from: str = "now-2h",
time_to: str = "now",
fields: Optional[str] = None,
page_size=50,
) -> PaginatedList["Entity"]:
"""
:return: A list of monitored entities along with their properties.
"""
params = {"pageSize": page_size, "entitySelector": entity_selector, "from": time_from, "to": time_to, "fields": fields}
return PaginatedList(Entity, self.__http_client, "/api/v2/entities", params, list_item="entities")

def list_types(self, page_size=50) -> PaginatedList[EntityType]:
"""
Gets a list of properties for all entity types
:param page_size: The desired amount of entities in a single response payload.
The maximal allowed page size is 500.
If not set, 50 is used.
:return: A list of properties of all available entity types.
"""
params = {"pageSize": page_size}
return PaginatedList("EntityType", self.__http_client, "/api/v2/entityTypes", params, list_item="types")


class Entity(DynatraceObject):
Expand Down
41 changes: 41 additions & 0 deletions dynatrace/event.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from datetime import datetime
from typing import Optional, List

from requests import Response

from dynatrace.dynatrace_object import DynatraceObject
from dynatrace.http_client import HttpClient

EVENT_TYPE_AVAILABILITY_EVENT = "AVAILABILITY_EVENT"
EVENT_TYPE_CUSTOM_ALERT = "CUSTOM_ALERT"
Expand All @@ -15,6 +18,44 @@
EVENT_TYPE_RESOURCE_CONTENTION = "RESOURCE_CONTENTION"


class EventService:
def __init__(self, http_client: HttpClient):
self.__http_client = http_client

def create_event(
self,
event_type: str,
entity_id: str,
source: str,
start: Optional[datetime] = None,
end: Optional[datetime] = None,
timeout_minutes: Optional[int] = None,
annotation_type: Optional[str] = None,
annotation_description: Optional[str] = None,
description: Optional[str] = None,
title: Optional[str] = None,
custom_properties: Optional[str] = None,
allow_davis_merge: Optional[bool] = None,
) -> Response:

attach_rules = PushEventAttachRules(entity_ids=[entity_id], tag_rule=None)
return EventCreation(
self.__http_client,
event_type=event_type,
attach_rules=attach_rules,
source=source,
start=start,
end=end,
timeout_minutes=timeout_minutes,
annotation_type=annotation_type,
annotation_description=annotation_description,
description=description,
title=title,
custom_properties=custom_properties,
allow_davis_merge=allow_davis_merge,
).post()


class EventCreation(DynatraceObject):
def __init__(
self,
Expand Down
63 changes: 60 additions & 3 deletions dynatrace/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,69 @@

from dynatrace.configuration import ConfigurationMetadata
from dynatrace.dynatrace_object import DynatraceObject
from dynatrace.endpoint import EndpointShortRepresentation
from dynatrace.entity import EntityShortRepresentation
from dynatrace.http_client import HttpClient
from dynatrace.pagination import PaginatedList


class ExtensionService:
def __init__(self, http_client: HttpClient):
self.__http_client = http_client
pass

def list_endpoints(self, plugin_id: str) -> PaginatedList[EndpointShortRepresentation]:
"""
Lists endpoints of the specified ActiveGate plugin
"""
return PaginatedList("EndpointShortRepresentation", self.__http_client, f"/api/config/v1/plugins/{plugin_id}/endpoints", list_item="values")

def list(self, page_size: int = 200) -> PaginatedList["ExtensionDto"]:
"""
List all uploaded extensions
:param page_size: The number of results per result page. Must be between 1 and 500
Default value : 200
"""
params = {"pageSize": page_size}
return PaginatedList(ExtensionDto, self.__http_client, f"/api/config/v1/extensions", params, list_item="extensions")

def get(self, extension_id: str):
response = self.__http_client.make_request(f"/api/config/v1/extensions/{extension_id}").json()
return Extension(self.__http_client, None, response)

def list_instances(self, extension_id: str, page_size: int = 200) -> PaginatedList["ExtensionShortRepresentation"]:
params = {"pageSize": page_size}
return PaginatedList(
ExtensionShortRepresentation,
self.__http_client,
f"/api/config/v1/extensions/{extension_id}/instances",
list_item="configurationsList",
target_params=params,
)

def get_instance(self, extension_id: str, configuration_id: str):
response = self.__http_client.make_request(f"/api/config/v1/extensions/{extension_id}/instances/{configuration_id}").json()
return ExtensionConfigurationDto(self.__http_client, None, response)

def post_instance(self, extension_configuration: "ExtensionConfigurationDto"):
return extension_configuration.post()

def create_instance(
self,
extension_id: str,
enabled: bool = True,
use_global: bool = True,
properties: dict = None,
host_id: str = None,
active_gate: EntityShortRepresentation = None,
endpoint_id: str = None,
endpoint_name: str = None,
) -> "ExtensionConfigurationDto":

return ExtensionConfigurationDto(self.__http_client, extension_id, enabled, use_global, properties, host_id, active_gate, endpoint_id, endpoint_name)


class ExtensionProperty(DynatraceObject):
@property
def key(self) -> str:
Expand Down Expand Up @@ -59,9 +118,7 @@ def __init__(
super().__init__(http_client, None, raw_element)

def post(self):
return self._http_client.make_request(
f"/api/config/v1/extensions/{self.extension_id}/instances", params=self._raw_element, method="POST"
)
return self._http_client.make_request(f"/api/config/v1/extensions/{self.extension_id}/instances", params=self._raw_element, method="POST")

@property
def extension_id(self) -> str:
Expand Down
Loading

0 comments on commit c45021a

Please sign in to comment.