Skip to content
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
2 changes: 1 addition & 1 deletion atlasapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
# __init__.py

# Version of the realpython-reader package
__version__ = "2.0.3"
__version__ = "2.0.7"
108 changes: 106 additions & 2 deletions atlasapi/atlas.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
from dateutil.relativedelta import relativedelta
from atlasapi.specs import Host, ListOfHosts, DatabaseUsersUpdatePermissionsSpecs, DatabaseUsersPermissionsSpecs, \
ReplicaSetTypes
from atlasapi.measurements import AtlasMeasurementTypes, AtlasMeasurementValue, AtlasMeasurement, OptionalAtlasMeasurement
from atlasapi.measurements import AtlasMeasurementTypes, AtlasMeasurementValue, AtlasMeasurement, \
OptionalAtlasMeasurement
from typing import Union, Iterator, List, Optional
from atlasapi.atlas_types import OptionalInt, OptionalBool, ListofDict
from atlasapi.clusters import ClusterConfig, ShardedClusterConfig, AtlasBasicReplicaSet, \
InstanceSizeName, AdvancedOptions, TLSProtocols
from atlasapi.events import atlas_event_factory, ListOfEvents
from atlasapi.events import atlas_event_factory, ListOfEvents, AtlasEventTypes, AtlasEvent
import logging
from typing import Union, Iterable, Set, BinaryIO, Generator, Iterator
from atlasapi.errors import ErrAtlasUnauthorized, ErrAtlasBadRequest
Expand Down Expand Up @@ -943,6 +944,62 @@ def _get_all_project_events(self, since_datetime: datetime = None, pageNum: int
return_val = self.atlas.network.get(Settings.BASE_URL + uri)
return return_val

def _get_project_events_by_type(self, event_type: AtlasEventTypes, since_datetime: datetime = None,
pageNum: int = Settings.pageNum,
itemsPerPage: int = Settings.itemsPerPage,
iterable: bool = False) -> Union[List[dict], Iterable[AtlasEvent]]:
"""Get All Project Events For A Single type

Internal use only, actual data retrieval comes from properties all
url: https://docs.atlas.mongodb.com/reference/api/events-projects-get-all/

Keyword Args:
event_type (AtlasEventType):
since_datetime (datetime):
pageNum (int): Page number
itemsPerPage (int): Number of Users per Page
iterable (bool): To return an iterable high level object instead of a low level API response

Returns:
ListOfEvents or dict: Iterable object representing this function OR Response payload

Raises:
ErrPaginationLimits: Out of limits
:rtype: Union[ListOfEvents, dict]
:type iterable: OptionalBool
:type itemsPerPage: OptionalInt
:type pageNum: OptionalInt

"""

# Check limits and raise an Exception if needed
ErrPaginationLimits.checkAndRaise(pageNum, itemsPerPage)

if iterable:
item_list = list(EventsGetForProjectAndType(self.atlas, event_type, since_datetime,
pageNum, itemsPerPage))
obj_list: ListOfEvents = list()
for item in item_list:
obj_list.append(atlas_event_factory(item))
return obj_list

if since_datetime:
uri = Settings.api_resources["Events"]["Get Project Events Since Date"].format(
min_date=since_datetime.isoformat(),
group_id=self.atlas.group,
page_num=pageNum,
items_per_page=itemsPerPage) + f'&eventType={event_type.name}'

return_val = self.atlas.network.get(Settings.BASE_URL + uri)

else:
uri = Settings.api_resources["Events"]["Get All Project Events"].format(
group_id=self.atlas.group,
page_num=pageNum,
items_per_page=itemsPerPage) + f'&eventType={event_type.name}'
return_val = self.atlas.network.get(Settings.BASE_URL + uri)
return return_val

@property
def all(self) -> ListOfEvents:
"""
Expand All @@ -954,6 +1011,18 @@ def all(self) -> ListOfEvents:
"""
return self._get_all_project_events(iterable=True)

def all_by_type(self, event_type: AtlasEventTypes) -> Iterable[AtlasEvent]:
"""Returns all events for the passed AtlasEventType

Args:
event_type (AtlasEventTypes):

Returns:
Iterable[AtlasEvent]

"""
return self._get_project_events_by_type(event_type=event_type, iterable=True)

def since(self, since_datetime: datetime) -> ListOfEvents:
"""
Returns all events since the passed datetime. (UTC)
Expand All @@ -963,6 +1032,18 @@ def since(self, since_datetime: datetime) -> ListOfEvents:
"""
return self._get_all_project_events(iterable=True, since_datetime=since_datetime)

def since_by_type(self, since_datetime: datetime, event_type: AtlasEventTypes):
"""Returns all events since the passed detetime (UTC) for the passed AtlasEvent Type

Args:
since_datetime (datetime):
event_type (AtlasEventTypes):

Returns:

"""
return self._get_project_events_by_type(event_type=event_type, since_datetime=since_datetime, iterable=True)

class _DatabaseUsers:
"""Database Users API

Expand Down Expand Up @@ -2156,6 +2237,29 @@ def fetch(self, pageNum, itemsPerPage):
return self._get_all_project_events(self.since_datetime, pageNum, itemsPerPage)


# noinspection PyProtectedMember
class EventsGetForProjectAndType(AtlasPagination):

def __init__(self, atlas: Atlas, event_type: AtlasEventTypes, since_datetime: datetime,
pageNum: int, itemsPerPage: int):
super().__init__(atlas, self.fetch, pageNum, itemsPerPage)
self._get_project_events_by_type = atlas.Events._get_project_events_by_type
self.since_datetime = since_datetime
self.event_type = event_type

def fetch(self, pageNum, itemsPerPage):
"""Intermediate fetching

Args:
pageNum (int): Page number
itemsPerPage (int): Number of Events per Page

Returns:
dict: Response payload
"""
return self._get_project_events_by_type(self.event_type, self.since_datetime, pageNum, itemsPerPage)


class DatabaseUsersGetAll(AtlasPagination):
"""Pagination for Database User : Get All"""

Expand Down
7 changes: 5 additions & 2 deletions atlasapi/clusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,10 @@ def __init__(self, backup_enabled: bool = False,
srv_address: Optional[str] = None,
providerSettings: Optional[ProviderSettings] = None,
links: list = None,
id: Optional[str] = None
id: Optional[str] = None,
create_date: Optional[datetime] = None
) -> None:
self.create_date: Optional[datetime] = create_date
self.id: Optional[str] = id
self.providerSettings: Optional[ProviderSettings] = providerSettings
self.backup_enabled: bool = backup_enabled
Expand Down Expand Up @@ -341,10 +343,11 @@ def fill_from_dict(cls, data_dict: dict):
providerSettings = ProviderSettings.from_dict(provider_settings_dict)
links = data_dict.get('links', [])
id = data_dict.get('id', None)
create_date = datetime.strptime(data_dict.get('createDate', None), FORMAT).astimezone(tz=pytz.UTC)
return cls(backup_enabled, cluster_type, disk_size_gb, name, mongodb_major_version, mongodb_version,
num_shards, mongo_uri, mongo_uri_updated, mongo_uri_with_options, paused, pit_enabled,
replication_factor, state_name, autoscaling, replication_specs,
srv_address, providerSettings, links,id)
srv_address, providerSettings, links,id, create_date)

def as_dict(self) -> dict:
return_dict = self.__dict__
Expand Down
8 changes: 8 additions & 0 deletions atlasapi/events_event_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ class AtlasEventTypes(Enum):
ATLAS_MAINTENANCE_AUTO_DEFER_DISABLED = 'Atlas Maintenance Auto Defer Disabled'
ATLAS_MAINTENANCE_START_ASAP = 'Atlas Maintenance Start Asap'
ATLAS_MAINTENANCE_SCHEDULED_FOR_NEXT_WINDOW = 'Atlas Maintenance Scheduled For Next Window'
MAINTENANCE_WINDOW_ADDED = 'Atlas Maintenance Window Added'
MAINTENANCE_WINDOW_MODIFIED = 'Atlas Maintenance Window Modified'
MAINTENANCE_WINDOW_REMOVED = 'Atlas Maintenance Window Removed'
MAINTENANCE_DEFERRED = 'Atlas Maintenance Deferred'
MAINTENANCE_AUTO_DEFER_ENABLED = 'Atlas Maintenance Auto Defer Enabled'
MAINTENANCE_AUTO_DEFER_DISABLED = 'Atlas Maintenance Auto Defer Disabled'
MAINTENANCE_START_ASAP = 'Atlas Maintenance Start Asap'
MAINTENANCE_SCHEDULED_FOR_NEXT_WINDOW = 'Atlas Maintenance Scheduled For Next Window'
COMPUTE_AUTO_SCALE_UNNECESSARY = 'Compute Auto Scale Unnecessary'
COMPUTE_AUTO_SCALE_TRIGGERED = 'Compute Auto Scale Triggered'
COMPUTE_AUTO_SCALE_SKIPPED = 'Compute Auto Scale Skipped'
Expand Down
13 changes: 7 additions & 6 deletions atlasapi/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
def merge(dict1, dict2):
return dict2.update(dict1)


class Network:
"""Network constructor

Expand Down Expand Up @@ -112,7 +113,7 @@ def get_file(self, uri):
for chunk in r.iter_content(chunk_size=1024):
# writing one chunk at a time to file
if chunk:
logger.warning("Writing 1 Kbyte chunk to the file like object")
logger.debug("Writing 1 Kbyte chunk to the file like object")
file_obj.write(chunk)
logger.info("---- Completed downloading the file. ----")
return self.answer(r.status_code, file_obj)
Expand Down Expand Up @@ -162,6 +163,7 @@ def get_big(self, uri, params: dict = None):
This is a temporary fix until we re-factor pagination.

Args:
params: dict of parameters that should be sent on the path
uri (str): URI

Returns:
Expand All @@ -171,16 +173,15 @@ def get_big(self, uri, params: dict = None):
Exception: Network issue
"""
r = None
print(f"Revieved the following parameters {params}")
if params:
logger.warning(f"Revieved the following parameters {params}")
merge({'itemsPerPage': Settings.itemsPerPage},params)
logger.warning(f"The parameters are now {params}")
logger.debug(f"Recieved the following parameters to the get_big method : {params}")
merge({'itemsPerPage': Settings.itemsPerPage}, params)
logger.debug(f"The parameters are now {params}")
else:
params = {'itemsPerPage': Settings.itemsPerPage}

try:
logger.warning(f"The parameters object is {params}")
logger.debug(f"The parameters object is {params}")
r = requests.get(uri,
allow_redirects=True,
params=params,
Expand Down
17 changes: 2 additions & 15 deletions atlasapi/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ def from_dict(cls, data_dict):
Returns: None

"""
created_date = isodatetime.parse_datetime(data_dict.get("created"))
return cls(id=data_dict.get("id"), name=data_dict.get("name"),
links=data_dict.get("links", []), org_id=data_dict.get("orgId"),
created_date=data_dict.get("created"), cluster_count=data_dict.get("clusterCount"))
created_date=created_date, cluster_count=data_dict.get("clusterCount"))

@property
def create_dict(self) -> dict:
Expand Down Expand Up @@ -107,17 +108,3 @@ def from_dict(cls,data_dict: dict):
bool(data_dict.get("isRealtimePerformancePanelEnabled", False)),
bool(data_dict.get("isSchemaAdvisorEnabled", False)),
)


"""
test_dict = {
"clusterCount": 2,
"created": "2016-07-14T14:19:33Z",
"id": "5a0a1e7e0f2912c554080ae6",
"links": [],
"name": "DocsFeedbackGroup",
"orgId": "5a0a1e7e0f2912c554080adc"
}

print(Project.for_create(org_id='34', name='test_project').as_create_dict)
"""
2 changes: 1 addition & 1 deletion atlasapi/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Settings:
"{host}:{port}/databases"
},
"Events": {
"Get All Project Events": URI_STUB + "/groups/{group_id}/events??includeRaw=true&pageNum={page_num}"
"Get All Project Events": URI_STUB + "/groups/{group_id}/events?includeRaw=true&pageNum={page_num}"
"&itemsPerPage={items_per_page}",
"Get Project Events Since Date": URI_STUB + "/groups/{group_id}/events?includeRaw=true&pageNum={"
"page_num}&itemsPerPage={items_per_page}&minDate={"
Expand Down
4 changes: 3 additions & 1 deletion gendocs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
sphinx-autodoc-annotation
sphinx_rtd_theme
sphinx_rtd_theme
pygments>=2.7.4 # not directly required, pinned by Snyk to avoid a vulnerability
sphinx>=3.0.4 # not directly required, pinned by Snyk to avoid a vulnerability
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

setup(
name='atlasapi',
version='2.0.3',
version='2.0.7',
python_requires='>=3.7',
packages=find_packages(exclude=("tests",)),
install_requires=['requests', 'python-dateutil', 'isodate', 'future', 'pytz','coolname', 'humanfriendly', 'nose'],
install_requires=['requests', 'python-dateutil', 'isodate', 'future', 'pytz', 'coolname', 'humanfriendly', 'nose'],
setup_requires=['wheel'],
# Metadata
author="Matthew G. Monteleone",
Expand Down Expand Up @@ -40,7 +40,6 @@
],
entry_points={
'console_scripts': [
#final script name:local package name:local function name
'atlascli=atlascli.cli:main',
]
},
Expand Down
9 changes: 9 additions & 0 deletions tests/test_clusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from atlasapi.atlas import Atlas
from atlasapi.lib import AtlasPeriods, AtlasUnits, AtlasGranularities
from json import dumps
from datetime import datetime
from atlasapi.clusters import AtlasBasicReplicaSet, ClusterConfig
from atlasapi.lib import MongoDBMajorVersion as mdb_version
from atlasapi.clusters import ClusterConfig, ProviderSettings, ReplicationSpecs, InstanceSizeName
Expand Down Expand Up @@ -179,3 +180,11 @@ def test_13_set_advanced_options(self):



def test_14_issue_154_additional_data(self):
cluster = self.a.Clusters.get_single_cluster_as_obj(self.TEST_CLUSTER_NAME)
self.assertTrue(type(cluster) is ClusterConfig)
self.assertEqual(cluster.name, self.TEST_CLUSTER_NAME)
self.assertIsInstance(cluster.create_date, datetime)
pprint(cluster.as_dict())

test_02_get_a_cluster_as_obj.basic = True
26 changes: 24 additions & 2 deletions tests/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import logging
from time import sleep
from datetime import datetime, timedelta, timezone
from atlasapi.events import AtlasEventTypes, AtlasEvent, _AtlasBaseEvent

USER = getenv('ATLAS_USER', None)
API_KEY = getenv('ATLAS_KEY', None)
Expand Down Expand Up @@ -48,7 +49,6 @@ def test_01_get_project_events_since(self):

test_01_get_project_events_since.basic = True


def test_02_since(self):
test_datetime = datetime.utcnow() - timedelta(hours=12)
verbose_logger.info(f'Events Since (public) {test_datetime.isoformat()}')
Expand All @@ -71,5 +71,27 @@ def test_04_CPS(self):
self.assertIsInstance(out, list)
for each in out:
if type(each) == events.AtlasCPSEvent:
self.assertIsInstance(each,events.AtlasCPSEvent)
self.assertIsInstance(each, events.AtlasCPSEvent)

test_04_CPS.basic = True

def test_05_All_Events_By_Type(self):
out = self.a.Events.all_by_type(event_type=AtlasEventTypes.CLUSTER_UPDATE_COMPLETED)
count = 0
for each_event in out:
count += 1
self.assertIsInstance(each_event, _AtlasBaseEvent)
pprint(f"Found {count} events.")

test_05_All_Events_By_Type.basic = True

def test_06_Events_Since_By_Type(self):
out = self.a.Events.since_by_type(event_type=AtlasEventTypes.CLUSTER_UPDATE_COMPLETED,
since_datetime=datetime(2022, 1, 1))
count = 0
for each_event in out:
count += 1
self.assertIsInstance(each_event, _AtlasBaseEvent)
pprint(f"Found {count} events.")

test_06_Events_Since_By_Type.basic = True
9 changes: 9 additions & 0 deletions tests/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


"""
import datetime
from pprint import pprint
from os import environ, getenv
from atlasapi.atlas import Atlas
Expand Down Expand Up @@ -128,3 +129,11 @@ def test_10_get_project_settings(self):
self.assertIsInstance(out, ProjectSettings, "The response must be a ProjectSettings obj")

test_10_get_project_settings.basic = True


def test_11_get_project_create_date(self):
out = self.a.Projects.project_by_id(self.a.group)
pprint(out.__dict__)
self.assertIsInstance(out.created_date, datetime.datetime, "An datetime should be returned")

test_02_get_project_by_id.basic = True