-
Notifications
You must be signed in to change notification settings - Fork 32
Add new model flags #87
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
Conversation
The |
diffsync/enum.py
Outdated
|
||
SKIP_UNMATCHED_BOTH = SKIP_UNMATCHED_SRC | SKIP_UNMATCHED_DST | ||
|
||
CRUD_NO_UPDATE = 0b10000 |
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.
Shouldn't we have a CRUD_NO_CREATE flag (to be set on the "source" side) as well?
Relatedly, should we allow for CRUD_NO_UPDATE to be set on either the "source" or "target" model instances, and prevent changes in either case?
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 thought about it too but I'm not sure if this is possible to have flags defined on the source side currently because we are only passing the dest model to the sync_model
method.
I think it would require us to retrieve the src_model
from the src_diffsync
and pass it to sync_model()
. I can give it a try but if it turns out to be too complicated I might change my mind
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've made the changes mentioned previously, I think it's cleaner overall
|
||
exception_backend_a.sync_from(backend_a) | ||
assert "nyc-spine1" in exception_backend_a.get(exception_backend_a.site, "nyc").devices | ||
assert "nyc-spine1__eth0" not in exception_backend_a.get(exception_backend_a.device, "nyc-spine1").interfaces |
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.
It's a little surprising to me that CRUD_NO_DELETE
by itself doesn't prevent deletion of child objects. I can sort of understand requiring to also set SKIP_CHILDREN_ON_DELETE
but it would be good to document this really clearly.
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.
Doc update
| CRUD_NO_DELETE | Do not delete and do not call delete() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff. This flag do not impact the children of this object, it's recommended to either set the flag on all objects individually or set the flag SKIP_CHILDREN_ON_DELETE | 0b1000000 |
@glennmatthews I've made all the suggested changes and I've updated the doc, should be good for a final review, thanks |
diff = backend_a.diff_from(backend_a_with_extra_models) | ||
assert diff.summary() == {"create": 1, "update": 0, "delete": 0, "no-change": 23} | ||
|
||
# Check that only the parent object is affected by the flag not the children |
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.
Don't we need some diffs on the child objects for this to actually test what the comment is saying? Also, this statement seems at odds with the behavior of SKIP_UNMATCHED_DST (which does result in child objects being skipped as well).
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.
Good point, the comment wasn't clear nor useful, I removed it
docs/source/core_engine/01-flags.md
Outdated
| SKIP_UNMATCHED_BOTH | Convenience value combining both SKIP_UNMATCHED_SRC and SKIP_UNMATCHED_DST into a single flag | 0b1100 | | ||
| CRUD_NO_CREATE | Do not create and do not call create() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff. Because the destination model doesn't exist before calling create(), the flag need to be positioned on the source object. | 0b10000 | | ||
| CRUD_NO_UPDATE | Do not update and do not call update() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff. This flag can be positioned on both source and destination objects | 0b100000 | | ||
| CRUD_NO_DELETE | Do not delete and do not call delete() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff. This flag do not impact the children of this object, it's recommended to either set the flag on all objects individually or set the flag SKIP_CHILDREN_ON_DELETE | 0b1000000 | |
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.
Looking at these flags side by side, it seems like there's some overlap. Is the only difference between SKIP_UNMATCHED_DST
and CRUD_NO_DELETE
that the former applies to both diff and sync while the latter applies only to sync? (If so, that would probably be helpful to state explicitly.) Same question for SKIP_UNMATCHED_SRC
versus CRUD_NO_CREATE
?
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.
Yes that's correct, good point
it might be best to rename these flags
CRUD_NO_DELETE
>SKIP_SYNC_UNMATCHED_DST
CRUD_NO_CREATE
>SKIP_SYNC_UNMATCHED_SRC
CRUD_NO_UPDATE
>SKIP_SYNC_UPDATE
CRUD_NO_UPDATE_DELETE
change toSKIP_SYNC_ALL
and addSKIP_SYNC_UNMATCHED_SRC
to
what do you think ? happy to use different names if you have something better
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.
After more discussion we decided to remove all CRUD_* flags for now.
the same behavior can be achieve by setting different flags during a diff or a sync
@@ -175,11 +175,29 @@ def set_status(self, status: DiffSyncStatus, message: Text = ""): | |||
self._status = status | |||
self._status_message = message | |||
|
|||
@classmethod | |||
def create_base(cls, diffsync: "DiffSync", ids: Mapping, attrs: Mapping) -> Optional["DiffSyncModel"]: |
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.
With the latest changes I'm back to not seeing why we need to have these _base
methods added at all. If the subclass overrides create()
then by default this method won't be called unless they call super().create()
, which is now exactly identical to calling super().create_base()
- so why have two different methods that do the same thing?
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 can remove them if you really want but I know if would have solved a situation for one of my project we had 3 layers of classes, like this
- DiffSyncModel
- NetworkImporterModel
- CustomerDefinedNetworkImporterModel
In this scenario, the goal was to redefine NetworkImporterModel.update()
with CustomerDefinedNetworkImporterModel.update()
to change it's behavior so calling super() wasn't possible but we still have to call DiffSyncModel.update()
We solved it by calling DiffSyncModel.update()
directly but I think this isn't ideal either.
I think., having the base method provides a clean way to identify the code that must be executed.
Again, happy to remove if you prefer ... I'm not gonna fall on my sword for this one
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 actually ran into something similar with the ssot-servicenow plugin and the create()
method, where I didn't want to call the immediate superclass's create()
but still needed to call the base DiffSyncModel.create()
. This would have been potentially useful there as well; I'm just not entirely persuaded that needing to do this is a sign of a good code smell. :-)
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.
Agreed, I think it would be redesign the API for 2.0 to manage this situation better
def sync_model( | ||
self, model: Optional["DiffSyncModel"], ids: Mapping, attrs: Mapping | ||
def sync_model( # pylint: disable=too-many-branches | ||
self, src_model: Optional["DiffSyncModel"], dst_model: Optional["DiffSyncModel"], ids: Mapping, attrs: Mapping |
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.
Looks like src_model
is an unused variable now, so can we revert the changes to this function?
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.
My preference would be to keep it in case we want to make a decision on a source flag in the future.
I think it was a miss in the design of this function
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.
Fair point.
152c2a6
to
4466bbe
Compare
Fixes #85 & #49
This PR adds 6 new model flags
SKIP_UNMATCHED_SRC
: Ignore the model if it only exists in the source/"from" DiffSync when determining diffs and syncing.SKIP_UNMATCHED_DST
: Ignore the model if it only exists in the target/"to" DiffSync when determining diffs and syncing.SKIP_UNMATCHED_BOTH
:SKIP_UNMATCHED_SRC
|SKIP_UNMATCHED_DST
CRUD_NO_UPDATE
: Do not call update() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff.CRUD_NO_DELETE
: Do not call delete() on the DiffSyncModel during sync(), the model and the changes will still be visible in the diff.CRUD_NO_UPDATE_DELETE
=CRUD_NO_UPDATE
|CRUD_NO_DELETE
The new model flags
SKIP_UNMATCHED_*
provide the same behavior as the global flags with the same name.The
CRUD_*
model flags provide a way to disable some CURD method selectively.Since, in the current design the
create
/update
/delete
method must execute the base methods withsuper()
I had to move the logic in the base methods into a new methodcreate|update|delete_base()
in order to not execute the user code but still keep the same behavior internally. Not sure if we should recommend the user to call new base methods now or if it's best to keep usingsuper()
Also one of the unit test file got too long (1000 lines) so I had to split it into 2 files
TODO