Skip to content

Commit

Permalink
Merge pull request #438 from abafzal/backup_restore
Browse files Browse the repository at this point in the history
Add functionality to get, initiate and cancel Tamr backups and restores
  • Loading branch information
skalish committed Dec 3, 2020
2 parents aafbf97 + 7ac2601 commit 62389b5
Show file tree
Hide file tree
Showing 20 changed files with 642 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## 0.14.0-dev
**BETA**
Important: Do not use BETA features for production workflows.
- [#438](https://github.com/Datatamer/tamr-client/pull/438) Now able to get, initiate and cancel Tamr backups and restores

## 0.13.0
**BETA**
Expand Down
2 changes: 2 additions & 0 deletions docs/beta.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

* [Attribute](beta/attribute)
* [Auth](beta/auth)
* [Backup](beta/backup)
* [Categorization](beta/categorization)
* [Dataset](beta/dataset)
* [Golden Records](beta/golden_records)
Expand All @@ -19,6 +20,7 @@
* [Operation](beta/operation)
* [Primary Key](beta/primary_key)
* [Project](beta/project)
* [Restore](beta/restore)
* [Schema Mapping](beta/schema_mapping)
* [Transformations](beta/transformations)
* [Response](beta/response)
Expand Down
18 changes: 18 additions & 0 deletions docs/beta/backup.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Backup
======

.. autoclass:: tamr_client.Backup

.. autofunction:: tamr_client.backup.get_all
.. autofunction:: tamr_client.backup.by_resource_id
.. autofunction:: tamr_client.backup.initiate
.. autofunction:: tamr_client.backup.cancel
.. autofunction:: tamr_client.backup.poll

Exceptions
----------

.. autoclass:: tamr_client.backup.NotFound
:no-inherited-members:
.. autoclass:: tamr_client.backup.InvalidOperation
:no-inherited-members:
16 changes: 16 additions & 0 deletions docs/beta/restore.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Restore
=======

.. autoclass:: tamr_client.Restore

.. autofunction:: tamr_client.restore.get
.. autofunction:: tamr_client.restore.initiate
.. autofunction:: tamr_client.restore.cancel

Exceptions
----------

.. autoclass:: tamr_client.restore.NotFound
:no-inherited-members:
.. autoclass:: tamr_client.restore.InvalidOperation
:no-inherited-members:
4 changes: 4 additions & 0 deletions tamr_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
AnyDataset,
Attribute,
AttributeType,
Backup,
CategorizationProject,
Dataset,
GoldenRecordsProject,
Expand All @@ -28,6 +29,7 @@
MasteringProject,
Operation,
Project,
Restore,
SchemaMappingProject,
Session,
SubAttribute,
Expand All @@ -41,6 +43,7 @@
###############

from tamr_client import attribute
from tamr_client import backup
from tamr_client import categorization
from tamr_client import dataset
from tamr_client import golden_records
Expand All @@ -50,6 +53,7 @@
from tamr_client import primary_key
from tamr_client import project
from tamr_client import response
from tamr_client import restore
from tamr_client import schema_mapping
from tamr_client import session
from tamr_client import transformations
Expand Down
2 changes: 2 additions & 0 deletions tamr_client/_types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
SubAttribute,
)
from tamr_client._types.auth import UsernamePasswordAuth
from tamr_client._types.backup import Backup
from tamr_client._types.dataset import AnyDataset, Dataset, UnifiedDataset
from tamr_client._types.instance import Instance
from tamr_client._types.json import JsonDict
Expand All @@ -27,6 +28,7 @@
Project,
SchemaMappingProject,
)
from tamr_client._types.restore import Restore
from tamr_client._types.session import Session
from tamr_client._types.transformations import InputTransformation, Transformations
from tamr_client._types.url import URL
22 changes: 22 additions & 0 deletions tamr_client/_types/backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from tamr_client._types.url import URL


@dataclass(frozen=True)
class Backup:
"""A Tamr backup
See https://docs.tamr.com/new/docs/configuration-backup-and-restore
Args:
url
path
state
error_message
"""

url: URL
path: str
state: str
error_message: str
22 changes: 22 additions & 0 deletions tamr_client/_types/restore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from dataclasses import dataclass

from tamr_client._types.url import URL


@dataclass(frozen=True)
class Restore:
"""A Tamr restore
See https://docs.tamr.com/new/docs/configuration-backup-and-restore
Args:
url
backup_path
state
error_message
"""

url: URL
backup_path: str
state: str
error_message: str
150 changes: 150 additions & 0 deletions tamr_client/backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from copy import deepcopy
from typing import List

from tamr_client import Backup, response
from tamr_client._types import Instance, JsonDict, Session, URL
from tamr_client.exception import TamrClientException


class InvalidOperation(TamrClientException):
"""Raised when attempting an invalid operation.
"""

pass


class NotFound(TamrClientException):
"""Raised when referencing a backup that does not exist on the server.
"""

pass


def _from_json(url: URL, data: JsonDict) -> Backup:
"""Make backup from JSON data (deserialize).
Args:
url: Backup URL
data: Backup JSON data from Tamr server
"""
cp = deepcopy(data)
return Backup(
url=url,
path=cp["backupPath"],
state=cp["state"],
error_message=cp["errorMessage"],
)


def get_all(session: Session, instance: Instance) -> List[Backup]:
"""Get all backups that have been initiated for a Tamr instance.
Args:
session: Tamr session
instance: Tamr instance
Returns:
A list of Tamr backups
Raises:
backup.NotFound: If no backup found at the specified URL
"""
url = URL(instance=instance, path="backups")
r = session.get(str(url))
if r.status_code == 404:
raise NotFound(str(url))
backups = [
_from_json(URL(instance=instance, path=f'backups/{data["relativeId"]}'), data)
for data in response.successful(r).json()
]
return backups


def by_resource_id(session: Session, instance: Instance, resource_id: str) -> Backup:
"""Get information on a specific Tamr backup.
Args:
session: Tamr session
instance: Tamr instance
resource_id: Resource ID of the backup
Returns:
A Tamr backup
Raises:
backup.NotFound: If no backup found at the specified URL
"""
url = URL(instance=instance, path=f"backups/{resource_id}")
r = session.get(str(url))
if r.status_code == 404:
raise NotFound(str(url))
return _from_json(url, response.successful(r).json())


def initiate(session: Session, instance: Instance) -> Backup:
"""Initiate a Tamr backup.
Args:
session: Tamr session
instance: Tamr instance
Returns:
Initiated backup
Raises:
backup.InvalidOperation: If attempting an invalid operation
"""
url = URL(instance=instance, path="backups")
r = session.post(str(url))
if r.status_code == 400:
raise InvalidOperation(str(url), r.json()["message"])
data = response.successful(r).json()
return _from_json(
URL(instance=instance, path=f'backups/{data["relativeId"]}'), data
)


def cancel(session: Session, backup: Backup) -> Backup:
"""Cancel a Tamr backup.
Args:
session: Tamr session
backup: A Tamr backup
Returns:
Canceled backup
Raises:
backup.NotFound: If no backup found at the specified URL
backup.InvalidOperation: If attempting an invalid operation
"""
cancel_url = f"{backup.url}:cancel"
r = session.post(cancel_url)
if r.status_code == 404:
raise NotFound(cancel_url)
if r.status_code == 400:
raise InvalidOperation(cancel_url, r.json()["message"])
return _from_json(backup.url, response.successful(r).json())


def poll(session: Session, backup: Backup) -> Backup:
"""Poll this backup for server-side updates.
Does not update the :class:`~tamr_client.backup.Backup` object.
Instead, returns a new :class:`~tamr_client.backup.Backup`.
Args:
session: Tamr session
backup: Tamr backup to be polled
Returns:
A Tamr backup
Raises:
backup.NotFound: If no backup found at the specified URL
"""
url = backup.url
r = session.get(str(url))
if r.status_code == 404:
raise NotFound(str(url))
return _from_json(url, response.successful(r).json())

0 comments on commit 62389b5

Please sign in to comment.