-
Notifications
You must be signed in to change notification settings - Fork 32
Add core engine section in docs and rename example directories #71
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
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
04890dc
Merge pull request #53 from networktocode/dga-examples-nautobot
dgarros b2d92db
Add core engine section in docs and rename example directories
dgarros 6ef651c
Update docs/source/core_engine/01-flags.md
dgarros 93e36b4
Update docs/source/core_engine/02-customize-diff-class.md
dgarros 4b76360
Update docs/source/core_engine/01-flags.md
dgarros 827cefc
Update docs/source/core_engine/02-customize-diff-class.md
dgarros f29a4fd
Fix example directory names in unit tests
dgarros 7ab6a00
Add skip state
dgarros 81d6838
Fix pylint
dgarros 54f6b3b
Update docs/source/core_engine/01-flags.md
dgarros 6b13497
Update docs/source/core_engine/01-flags.md
dgarros d2bbd57
Update docs/source/core_engine/01-flags.md
dgarros 54839fe
Update docs/source/core_engine/02-customize-diff-class.md
dgarros c28f405
Update docs/source/core_engine/01-flags.md
dgarros 503a751
Update docs/source/core_engine/01-flags.md
dgarros 6e38ea1
Remove Change the rendering of the result of the diff section from doc
dgarros aa88e88
Convert link to ReST format
dgarros 6591f73
Update docs/source/core_engine/01-flags.md
dgarros a8e22a1
Update docs/source/core_engine/01-flags.md
dgarros 066f742
Update docs/source/core_engine/01-flags.md
dgarros 1566714
Update docs/source/core_engine/01-flags.md
dgarros 8d937cc
Feedback from glenn
dgarros File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
|
||
# Global and Model Flags | ||
|
||
These flags offer a powerful way to instruct the core engine how to handle some specific situation without changing the data. One way to think of the flags is to represent them as configuration for the core engine. Currently 2 sets of flags are supported: | ||
- **global flags**: applicable to all data. | ||
- **model flags**: applicable to a specific model or to individual instances of a model. | ||
|
||
> *The flags are stored in binary format which allows storing multiple flags in a single variable. See the section below [Working with flags](#working-with-flags) to learn how to manage them.* | ||
|
||
The list of supported flags is expected to grow over time as more use cases are identified. If you think some additional flags should be supported, please reach out via Github to start a discussion. | ||
|
||
## Global flags | ||
|
||
Global flags can be defined at runtime when calling one of these functions : `diff_to` ,`diff_from`, `sync_to` or `sync_from` | ||
|
||
```python | ||
from diffsync.enum import DiffSyncFlags | ||
flags = DiffSyncFlags.SKIP_UNMATCHED_DST | ||
diff = nautobot.diff_from(local, flags=flags) | ||
``` | ||
|
||
### Supported Global Flags | ||
|
||
| Name | Description | Binary Value | | ||
|---|---|---| | ||
| CONTINUE_ON_FAILURE | Continue synchronizing even if failures are encountered when syncing individual models. | 0b1 | | ||
| SKIP_UNMATCHED_SRC | Ignore objects that only exist in the source/"from" DiffSync when determining diffs and syncing. If this flag is set, no new objects will be created in the target/"to" DiffSync. | 0b10 | | ||
| SKIP_UNMATCHED_DST | Ignore objects that only exist in the target/"to" DiffSync when determining diffs and syncing. If this flag is set, no objects will be deleted from the target/"to" DiffSync. | 0b100 | | ||
| SKIP_UNMATCHED_BOTH | Convenience value combining both SKIP_UNMATCHED_SRC and SKIP_UNMATCHED_DST into a single flag | 0b110 | | ||
| LOG_UNCHANGED_RECORDS | If this flag is set, a log message will be generated during synchronization for each model, even unchanged ones. | 0b1000 | | ||
|
||
## Model flags | ||
|
||
Model flags are stored in the attribute `model_flags` of each model and are usually set when the data is being loaded into the adapter. | ||
|
||
```python | ||
from diffsync import DiffSync | ||
from diffsync.enum import DiffSyncModelFlags | ||
from model import MyDeviceModel | ||
|
||
class MyAdapter(DiffSync): | ||
|
||
device = MyDeviceModel | ||
|
||
def load(self, data): | ||
"""Load all devices into the adapter and add the flag IGNORE to all firewall devices.""" | ||
for device in data.get("devices"): | ||
obj = self.device(name=device["name"]) | ||
if "firewall" in device["name"]: | ||
obj.model_flags = DiffSyncModelFlags.IGNORE | ||
self.add(obj) | ||
``` | ||
|
||
### Supported Model Flags | ||
|
||
| Name | Description | Binary Value | | ||
|---|---|---| | ||
| IGNORE | Do not render diffs containing this model; do not make any changes to this model when synchronizing. Can be used to indicate a model instance that exists but should not be changed by DiffSync. | 0b1 | | ||
| SKIP_CHILDREN_ON_DELETE | When deleting this model, do not recursively delete its children. Can be used for the case where deletion of a model results in the automatic deletion of all its children. | 0b10 | | ||
|
||
## Working with flags | ||
|
||
Flags are stored in binary format. In binary format, each bit of a variable represents 1 flag which allow us to have up to many flags stored in a single variable. Using binary flags provides more flexibility to add support for more flags in the future without redefining the current interfaces and the current DiffSync API. | ||
|
||
### Enable a flag (Bitwise OR) | ||
|
||
Enabling a flag is possible with the bitwise OR operator `|=`. It's important to use the bitwise operator OR when enabling a flags to ensure that the value of other flags remains unchanged. | ||
|
||
```python | ||
>>> from diffsync.enum import DiffSyncFlags | ||
>>> flags = DiffSyncFlags.CONTINUE_ON_FAILURE | ||
>>> flags | ||
<DiffSyncFlags.CONTINUE_ON_FAILURE: 1> | ||
>>> bin(flags.value) | ||
'0b1' | ||
>>> flags |= DiffSyncFlags.SKIP_UNMATCHED_DST | ||
>>> flags | ||
<DiffSyncFlags.SKIP_UNMATCHED_DST|CONTINUE_ON_FAILURE: 5> | ||
>>> bin(flags.value) | ||
'0b101' | ||
``` | ||
|
||
### Checking the value of a specific flag (bitwise AND) | ||
|
||
Validating if a flag is enabled is possible with the bitwise operator AND: `&`. The AND operator will return 0 if the flag is not set and the binary value of the flag if it's enabled. To convert the result of the test into a proper conditional it's possible to wrap the bitwise AND operator into a `bool` function. | ||
|
||
```python | ||
>>> from diffsync.enum import DiffSyncFlags | ||
>>> flags = DiffSyncFlags.NONE | ||
>>> bool(flags & DiffSyncFlags.CONTINUE_ON_FAILURE) | ||
False | ||
>>> flags |= DiffSyncFlags.CONTINUE_ON_FAILURE | ||
>>> bool(flags & DiffSyncFlags.CONTINUE_ON_FAILURE) | ||
True | ||
``` | ||
|
||
### Disable a flag (bitwise NOT) | ||
|
||
After a flag has been enabled, it's possible to disable it with a bitwise AND NOT operator : `&= ~` | ||
|
||
```python | ||
>>> from diffsync.enum import DiffSyncFlags | ||
>>> flags = DiffSyncFlags.NONE | ||
# Setting the flags SKIP_UNMATCHED_DST and CONTINUE_ON_FAILURE | ||
>>> flags |= DiffSyncFlags.SKIP_UNMATCHED_DST | DiffSyncFlags.CONTINUE_ON_FAILURE | ||
>>> flags | ||
<DiffSyncFlags.SKIP_UNMATCHED_DST|CONTINUE_ON_FAILURE: 5> | ||
>>> bool(flags & DiffSyncFlags.SKIP_UNMATCHED_DST) | ||
True | ||
# Unsetting the flag SKIP_UNMATCHED_DST; CONTINUE_ON_FAILURE remains set | ||
>>> flags &= ~DiffSyncFlags.SKIP_UNMATCHED_DST | ||
>>> flags | ||
<DiffSyncFlags.CONTINUE_ON_FAILURE: 1> | ||
>>> bool(flags & DiffSyncFlags.SKIP_UNMATCHED_DST) | ||
False | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
|
||
# Custom Diff Class | ||
|
||
When performing a diff or a sync operation, a diff object is generated. A diff object is itself composed of DiffElement objects representing the different elements of the original datasets with their differences. | ||
|
||
The diff object helps to access all the DiffElements. It's possible to provide your own Diff class in order to customize some of its capabilities the main one being the order in which the elements are processed. | ||
|
||
## Using your own Diff class | ||
|
||
To use your own diff class, you need to provide it at runtime when calling one of these functions : `diff_to`, `diff_from`, `sync_to` or `sync_from`. | ||
|
||
```python | ||
>>> from diffsync.enum import DiffSyncFlags | ||
>>> from diff import AlphabeticalOrderDiff | ||
>>> diff = remote_adapter.diff_from(local_adapter, diff_class=AlphabeticalOrderDiff) | ||
>>> type(diff) | ||
<class 'AlphabeticalOrderDiff'> | ||
``` | ||
|
||
## Change the order in which the element are being processed | ||
|
||
By default, all objects of the same type will be stored in a dictionary and as such the order in which they will be processed during a diff or a sync operation is not guaranteed (although in most cases, it will match the order in which they were initially loaded and added to the adapter). When the order in which a given group of object should be processed is important, it's possible to define your own ordering inside a custom Diff class. | ||
|
||
When iterating over a list of objects, either at the top level or as a group of children of a given object, the core engine is looking for a function named after the type of the object `order_children_<type>` and if none is found it will rely on the default function `order_children_default`. Either function need to be present and need to return an Iterator of DiffElement. | ||
|
||
In the example below, by default all devices will be sorted per type of CRUD operations (`order_children_device`) while all other objects will be sorted alphabetically (`order_children_default`) | ||
|
||
```python | ||
class MixedOrderingDiff(Diff): | ||
"""Alternate diff class to list children in alphabetical order, except devices to be ordered by CRUD action.""" | ||
|
||
@classmethod | ||
def order_children_default(cls, children): | ||
"""Simple diff to return all children in alphabetical order.""" | ||
for child_name, child in sorted(children.items()): | ||
yield children[child_name] | ||
|
||
@classmethod | ||
def order_children_device(cls, children): | ||
"""Return a list of device sorted by CRUD action and alphabetically.""" | ||
children_by_type = defaultdict(list) | ||
|
||
# Organize the children's name by action create, update or delete | ||
for child_name, child in children.items(): | ||
action = child.action or "skip" | ||
children_by_type[action].append(child_name) | ||
|
||
# Create a global list, organized per action | ||
sorted_children = sorted(children_by_type["create"]) | ||
sorted_children += sorted(children_by_type["update"]) | ||
sorted_children += sorted(children_by_type["delete"]) | ||
sorted_children += sorted(children_by_type["skip"]) | ||
|
||
for name in sorted_children: | ||
yield children[name] | ||
``` | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Core Engine | ||
=========== | ||
|
||
The core engine of DiffSync is meant to be transparent for most users but in some cases it's important to have the ability to change its behavior to adjust to some specific use cases. For these use cases, there are several ways to customize its behavior: | ||
|
||
- Global and Model Flags | ||
- Diff class | ||
|
||
.. mdinclude:: 01-flags.md | ||
.. mdinclude:: 02-customize-diff-class.md | ||
|
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 3 additions & 1 deletion
4
examples/example1/README.md → examples/01-multiple-data-sources/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a huge fan of mixing-and-matching Markdown and ReST in the same docs. Which one is our standard for newly created documentation files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we have it clearly defined yet, I'll open a new issue to track that