Skip to content
This repository has been archived by the owner on Oct 19, 2023. It is now read-only.

Working with transactions #26

Open
sebbbastien opened this issue Jul 12, 2018 · 5 comments
Open

Working with transactions #26

sebbbastien opened this issue Jul 12, 2018 · 5 comments

Comments

@sebbbastien
Copy link

sebbbastien commented Jul 12, 2018

Hi David,

Is it possible to manage "transactions", sets of instructions that must all be executed, or none?

For example, I want to create a "site": a firewall, a router, and add the router as the firewall's default route.
Is it possible to define these three operations as one and the same transaction, if one of them fails, none should be taken into account?

Sometimes it is more coherent to do nothing at all if one fails, rather than managing the partial states.

Do you know if something "native" is available? If not, do you have tracks/ideas to do that in a different way?

Best regards,

--
Sébastien

@gabstopper
Copy link
Owner

gabstopper commented Jul 15, 2018 via email

@gabstopper
Copy link
Owner

gabstopper commented Jul 16, 2018

Here is a prototype that may work but needs more thought behind it.

Basically I've added a context manager that you can use to decorate a function or to use the 'with ....' statement.
Anything create operations that are performed in that block or decorated function will be considered 'transactions'. In the case of a failure, any existing transactions are rolled back (i.e. deleted) in the order they were added.

from smc.base import transaction
     
@transaction.atomic()
def mytasks():
    for name in range(1, 10):
        Host.create(name='host%s' % name, address='1.1.1.1')
     
    Network.create(name='mynet2', ipv4_network='1.1.1.0/24')
     
    print("Now fail")
    Host.create(name='host2', address='1.1.1.1')
     
 
with transaction.atomic():
    for name in range(1, 10):
        Host.create(name='host%s' % name, address='1.1.1.1')
     
    Network.create(name='mynet2', ipv4_network='1.1.1.0/24')
     
    print("Now fail")
    Host.create(name='host2', address='1.1.1.1')

In addition to these two models, I would opt to implement "savepoints" where you could nest context managers which would then trigger a 'savepoint'. In the example below, the top level context manager creates a bunch of hosts.
If the next operation in the nested context manager fails (creating the network element), the host elements will be preserved (i.e. not rolled back) due to the context manager nesting.
So treat a nested context manager as a 'savepoint' where all previous changes will be preserved.

When the Host.create(name='grace2') is run, only the inner element (the Network) is rolled back because of the inner savepoint logic.

with transaction.atomic():
    for name in range(1, 10):
        Host.create(name='host%s' % name, address='1.1.1.1')
        
    with transaction.atomic(): # <-- Nested context manager, saves all previous actions
        Network.create(name='mynet3', ipv4_network='1.1.1.0/24')
         
    print("Now fail")
    Host.create(name='host2', address='1.1.1.1')

@sebbbastien
Copy link
Author

sebbbastien commented Jul 22, 2018

Thanks a lot, I'll try this right now.

I'll keep you informed.

@sebbbastien
Copy link
Author

sebbbastien commented Jul 23, 2018

Hi David,

I can't use from smc.base import transaction, neither from master nor from develop.

Can you help me to test this solution?

--
Sébastien

@gabstopper
Copy link
Owner

Hi Sebastien,
I haven't pushed upstream yet, will need a couple more days as I've got some other updates for the session API as well. Will post back here once the post is up.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants