Skip to content
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

Add .load() class-method to DiffSyncModel #257

Open
jamesharr opened this issue Nov 20, 2023 · 0 comments
Open

Add .load() class-method to DiffSyncModel #257

jamesharr opened this issue Nov 20, 2023 · 0 comments

Comments

@jamesharr
Copy link
Contributor

Environment

  • DiffSync version: 1.9.0

Proposed Functionality

This change proposes to 1) add a load() class-method to DiffSyncModel and 2) augments DiffSync.load() such that it will call each model's .load() method with whatever is passed in.

Key benefits:

  1. DiffSyncModel has always felt incomplete with only create/update/delete.
  2. It's a common pattern in code that I have written to have a .from_xyz() class-method to transform data. Adding it to diffsync would give it a more official location.
  3. The design of this API would support both two methods of loading data: a) each model calls an API to load code it needs b) there is one large call to load ALL the data, and each model handles interpreting the data, such as with GraphQL.
  4. Additional parameters, such as filtering criteria, could be passed to DiffSyncModel.load()

Use Case

# DiffSync modifications
class DiffSyncModel:
    @classmethod
    def load(cls, diffsync: DiffSyncModel, *args, **kwargs):
        pass
        # no-op

class DiffSync:
    def load(self, *args, **kwargs):
        # Pass all arguments to per-model flags
        for model_name in self.store.get_all_model_names():
            model_cls = getattr(self, model_name)
            model_cls.load(*args, diffsync=self, **kwargs)



# Example user-code 1 - each model loads its own data
class Location(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, nb: pynautobot.api):
        for nb_location in nb.dcim.locations.filter():
             diffsync.add(cls(name=nb_location.name, ...))

class Device(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, nb: pynautobot.api):
        for nb_device in nb.dcim.devices.all():
             diffsync.add(cls(name=nb_device.name, ...))

class MyBackend(DiffSync):
    ... utilizes default backend

def main():
    be1 = MyBackend()
    be1.load(nb=pynautobot.api(...))



# Example user-code 2 - each model loads its own data, with filter criteria being passed along
class Location(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, nb: pynautobot.api, tags: List[str]):
        for nb_location in nb.dcim.locations.filter(tags=tags):
             diffsync.add(cls(name=nb_location.name, ...))

class Device(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, nb: pynautobot.api, tags: List[str]):
        for nb_device in nb.dcim.devices.filter(tags=tags):
             diffsync.add(cls(name=nb_device.name, ...))

class MyBackend(DiffSync):
    ... utilizes default backend

def main():
    be1 = MyBackend()
    be1.load(nb=pynautobot.api(...), tags=["US", "Europe"])



# Example user-code 3 - Backend handles data retrieval, models handle transformation
class Location(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, graphql: GraphQLRecord):
        for nb_location in graphql.json["data"]["locations"]
             diffsync.add(cls(name=nb_location["name"], ...))

class Device(DiffSyncModel):
    ...
    @classmethod
    def load(cls, diffsync: DiffSyncModel, graphql: GraphQLRecord):
        for nb_device in graphql.json["data"]["devices"]
             diffsync.add(cls(name=nb_device["name"], ...))

class MyBackend(DiffSync):
    def load(self):
        nb = pynautobot.api(...)
        result = nb.graphql.query("query { devices { name } locations { name } }")
        super().load(graphql=result)

def main():
    be1 = MyBackend()
    be1.load()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant