Skip to content

Commit

Permalink
Chore/update device settings (#410)
Browse files Browse the repository at this point in the history
* add class to manage incydr device settings
  • Loading branch information
tora-kozic committed Mar 30, 2022
1 parent 1d48b4d commit 96d0a2b
Show file tree
Hide file tree
Showing 41 changed files with 606 additions and 183 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/cla.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheckcla' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Alpha Release
uses: cla-assistant/github-action@v2.0.1-alpha
uses: cla-assistant/github-action@v2.13.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
Expand All @@ -22,7 +22,7 @@ jobs:
path-to-cla-document: 'https://code42.github.io/code42-cla/Code42_Individual_Contributor_License_Agreement'
# branch should not be protected
branch: 'main'
allowlist: alang13,unparalleled-js,kiran-chaudhary,ceciliastevens,DiscoRiver,annie-payseur,amoravec,patelsagar192,peterbriggs42
allowlist: alang13,unparalleled-js,kiran-chaudhary,ceciliastevens,DiscoRiver,annie-payseur,amoravec,patelsagar192,peterbriggs42,tora-kozic,timabrmsn

#below are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repos:
- id: reorder-python-imports
args: ["--application-directories", "src"]
- repo: https://github.com/psf/black
rev: 19.10b0
rev: 22.3.0
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
The intended audience of this file is for py42 consumers -- as such, changes that don't affect
how a consumer would use the library (e.g. adding unit tests, updating documentation, etc) are not captured here.

## Unreleased

### Added
- `IncydrDeviceSettings` class to allow users to manage the settings on individual Incydr devices.

## 1.21.1 - 2022-02-22

### Fixed
Expand Down
6 changes: 6 additions & 0 deletions docs/methoddocs/devicesettings.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Device Settings

```{eval-rst}
.. autoclass:: py42.clients.settings.device_settings.IncydrDeviceSettings
:members:
:show-inheritance:
```

```{eval-rst}
.. autoclass:: py42.clients.settings.device_settings.DeviceSettings
:members:
Expand Down
52 changes: 31 additions & 21 deletions docs/userguides/devicesettings.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# View or Modify device settings

Use py42 to easily view and update the settings for devices with the `DeviceSettings` object.
Use py42 to easily view and update the settings for devices with the `DeviceSettings` and `IncydrDeviceSettings` objects for Crashplan and Incydr customers, respectively.

The `DeviceSettings` object is a wrapper around the complex nested dict that the Code42 `Computer` API endpoint expects,
The [Device Settings](../methoddocs/devicesettings.md) objects are wrappers around the complex nested dict that the Code42 `Computer` API endpoint expects,
providing helper properties that can be used to get/set values, without having to know the underlying nested structure.

To get started, create a `DeviceSettings` object for a given device guid:
To get started, create a `DeviceSettings` or `IncydrDeviceSettings` object for a given device guid. The `get_settings()` method will create the appropriate object automatically based on the corresponding service running on the device:

```python
device_settings = sdk.devices.get_settings(908765043021)
```

Some common non-modifiable details about the device are accessible as read-only properties:
Details on which settings can be updated and which are non-modifiable can be found in the method documentation [Device Settings](../methoddocs/devicesettings.md). These may differ between services.
Some common non-modifiable settings fields are accessible as read-only properties on the object:

```python
>>> device_settings.computer_id
Expand All @@ -24,28 +25,16 @@ Some common non-modifiable details about the device are accessible as read-only
494842
>>> device_settings.version
1525200006800
>>> device_settings.available_destinations
{'632540230984925185': 'PROe Cloud, US - West', '43': 'PROe Cloud, US'}
```

And to change settings, in most cases you can just assign new values to the corresponding attribute:

```python
>>> device_settings.name
"Admin's Computer"
>>> device_settings.name = "Bob's Laptop"
```

Because device backup settings are tied to a given "Backup Set", of which there could be more than one, the `DeviceSettings.backup_sets`
property returns a list of `BackupSet` wrapper classes that help manage backup configuration settings.

```python
>>> device_settings.backup_sets
[<BackupSet: id: 1, name: 'Primary - Backup Set'>, <BackupSet: id: 298010138, name: 'Secondary (large files) - Backup Set'>]
>>> device_settings.notes
"A note on this device."
>>> device_settings.notes = "A note on this device."
```

See the [Configuring Backup Sets](backupsets.md) guide for details on managing backup set settings.

The below section provides more detail on managing backup settings for Crashplan customers.

For convenience and logging purposes, all changes are tracked in the `.changes` property of the `DeviceSettings` objects.

Expand All @@ -62,7 +51,28 @@ with the server response:
<Py42Response [status=200, data={'active': True, 'address': '192.168.74.144:4247', 'alertState': 0, 'alertStates': ['OK'], ...}]>
```

## Advanced Usage

## Crashplan

### Backup settings

The available backup destinations for a device can be found on the read-only `availableDestinations` property:
```python
>>> device_settings.available_destinations
{'632540230984925185': 'PROe Cloud, US - West', '43': 'PROe Cloud, US'}
```

Because device backup settings are tied to a given "Backup Set", of which there could be more than one, the `DeviceSettings.backup_sets`
property returns a list of `BackupSet` wrapper classes that help manage backup configuration settings.

```python
>>> device_settings.backup_sets
[<BackupSet: id: 1, name: 'Primary - Backup Set'>, <BackupSet: id: 298010138, name: 'Secondary (large files) - Backup Set'>]
```

See the [Configuring Backup Sets](backupsets.md) guide for details on managing backup set settings.

### Advanced usage

Because `DeviceSettings` is a subclass of `UserDict` with added attributes/methods to help easily access/modify setting values,
the underlying dict that ultimately gets posted to the server is stored on the `.data` attribute of `DeviceSettings` instances,
Expand Down
11 changes: 9 additions & 2 deletions src/py42/clients/_archiveaccess/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ class ArchiveContentStreamer(ArchiveExplorer):
"""A class with methods for restoring files from backup."""

def stream_from_backup(
self, backup_set_id, file_paths, file_size_calc_timeout=None, show_deleted=None,
self,
backup_set_id,
file_paths,
file_size_calc_timeout=None,
show_deleted=None,
):
file_selections = self.create_file_selections(
backup_set_id, file_paths, file_size_calc_timeout
Expand Down Expand Up @@ -173,7 +177,10 @@ def _create_file_selections(file_paths, metadata_list, file_sizes=None):
"selected": True,
}
selection = FileSelection(
file, size_info["numFiles"], size_info["numDirs"], size_info["size"],
file,
size_info["numFiles"],
size_info["numDirs"],
size_info["size"],
)
file_selections.append(selection)
return file_selections
Expand Down
18 changes: 14 additions & 4 deletions src/py42/clients/_archiveaccess/accessorfactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ def create_archive_accessor(
restore_job_manager,
file_size_poller,
) = self._create_archive_accessor_dependencies(
storage_archive_service, device_guid, private_password, encryption_key,
storage_archive_service,
device_guid,
private_password,
encryption_key,
)
return accessor_class(
device_guid,
Expand Down Expand Up @@ -66,7 +69,10 @@ def create_archive_content_pusher(
restore_job_manager,
file_size_poller,
) = self._create_archive_accessor_dependencies(
push_service, device_guid, private_password, encryption_key,
push_service,
device_guid,
private_password,
encryption_key,
)
destination_guid = (
destination_guid
Expand All @@ -87,13 +93,17 @@ def _create_archive_accessor_dependencies(
self, storage_archive_service, device_guid, private_password, encryption_key
):
decryption_keys = self._get_decryption_keys(
device_guid, private_password, encryption_key,
device_guid,
private_password,
encryption_key,
)
session_id = self._create_restore_session(
storage_archive_service, device_guid, **decryption_keys
)
restore_job_manager = create_restore_job_manager(
storage_archive_service, device_guid, session_id,
storage_archive_service,
device_guid,
session_id,
)
file_size_poller = create_file_size_poller(storage_archive_service, device_guid)
return decryption_keys, session_id, restore_job_manager, file_size_poller
Expand Down
6 changes: 5 additions & 1 deletion src/py42/clients/_archiveaccess/restoremanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
def create_restore_job_manager(
storage_archive_service, device_guid, archive_session_id
):
return RestoreJobManager(storage_archive_service, device_guid, archive_session_id,)
return RestoreJobManager(
storage_archive_service,
device_guid,
archive_session_id,
)


def create_file_size_poller(storage_archive_service, device_guid):
Expand Down
4 changes: 2 additions & 2 deletions src/py42/clients/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
class CaseStatus(Choices):
"""Constants available for setting the status of a case.
* ``OPEN``
* ``CLOSED``
* ``OPEN``
* ``CLOSED``
"""

OPEN = "OPEN"
Expand Down
4 changes: 3 additions & 1 deletion src/py42/clients/securitydata.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ def _get_stored_file(self, version):
version["storageNodeURL"]
)
token = pds.get_download_token(
version["archiveGuid"], version["fileId"], version["versionTimestamp"],
version["archiveGuid"],
version["fileId"],
version["versionTimestamp"],
)
return pds.get_file(str(token))

Expand Down
4 changes: 2 additions & 2 deletions src/py42/clients/settings/_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def minutes_to_days(minutes):
def bytes_to_gb(bytes):
if bytes == -1: # special "unlimited" value
return bytes
gb = bytes / 1000 ** 3
gb = bytes / 1000**3
if isinstance(gb, float) and gb.is_integer():
return int(gb)
return gb
Expand All @@ -58,6 +58,6 @@ def gb_to_bytes(gb):
if gb == -1: # special "unlimited" value
return gb
try:
return gb * 1000 ** 3
return gb * 1000**3
except ValueError:
raise AttributeError("value must be numeric.")
54 changes: 54 additions & 0 deletions src/py42/clients/settings/device_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,60 @@
)


class IncydrDeviceSettings(UserDict):
"""Class used to manage individual Incydr devices. These devices have no backup settings and only the **notes** and **external reference** fields are modifiable."""

def __init__(self, settings_dict):
self.changes = {}
self.data = settings_dict

@property
def name(self):
"""Name of this device. Read-only."""
return self.data["name"]

@property
def computer_id(self):
"""Identifier of this device. Read-only."""
return self.data["computerId"]

@property
def device_id(self):
"""Identifier of this device (alias of `.computer_id`). Read only."""
return self.computer_id

@property
def guid(self):
"""Globally unique identifier of this device. Read-only."""
return self.data["guid"]

@property
def org_id(self):
"""Identifier of the organization this device belongs to. Read-only."""
return self.data["orgId"]

@property
def user_id(self):
"""Identifier of the user this device belongs to. Read-only."""
return self.data["userId"]

@property
def version(self):
"""Latest reported Code42 client version number for this device. Read-only."""
return self.data["version"]

external_reference = SettingProperty(
name="external_reference", location=["computerExtRef"]
)
"""External reference field for this device."""

notes = SettingProperty(name="notes", location=["notes"])
"""Notes field for this device."""

def __repr__(self):
return f"<IncydrDeviceSettings: guid: {self.data['guid']}, name: {self.data['name']}>"


class DeviceSettingsDefaults(UserDict):
"""Class used for managing an Organization's Device Default settings. Also acts as a
base class for `DeviceSettings` to manage individual device settings."""
Expand Down
6 changes: 4 additions & 2 deletions src/py42/clients/settings/org_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ def registration_key(self):
"""Notes field for this Org."""

quota_settings_inherited = SettingProperty(
"quota_settings_inherited", ["settings", "isUsingQuotaDefaults"],
"quota_settings_inherited",
["settings", "isUsingQuotaDefaults"],
)
"""Determines if Org Quota settings (`maximum_user_subscriptions`, `org_backup_quota`,
`user_backup_quota`, `archive_hold_days`) are inherited from parent organization.
Expand Down Expand Up @@ -105,7 +106,8 @@ def registration_key(self):
"""Limit (in MB) to amount of data restorable by non-admin users via web restore."""

reporting_settings_inherited = SettingProperty(
"reporting_settings_inherited", ["settings", "isUsingReportingDefaults"],
"reporting_settings_inherited",
["settings", "isUsingReportingDefaults"],
)
"""Determines if Org Reporting settings (`backup_warning_email_days`,
`backup_critical_email_days', `backup_alert_recipient_emails`) are inherited from
Expand Down
4 changes: 2 additions & 2 deletions src/py42/clients/trustedactivities.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
class TrustedActivityType(Choices):
"""Constants available for setting the type of a trusted activity.
* ``DOMAIN``
* ``SLACK``
* ``DOMAIN``
* ``SLACK``
"""

DOMAIN = "DOMAIN"
Expand Down
4 changes: 2 additions & 2 deletions src/py42/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
class SortDirection(Choices):
"""Constants available to set Code42 request `sort_direction` when sorting returned lists in responses.
* ``ASC``
* ``DESC``
* ``ASC``
* ``DESC``
"""

DESC = "DESC"
Expand Down

0 comments on commit 96d0a2b

Please sign in to comment.