Automation Principles – Atomicity

This is part of a series of posts focused on Network Automation Principles.

Atomicity in Computer Science

In simple terms, an atomic operation guarantees that an action succeeds completely or fails completely. Going a step deeper, the included quote provides context and accuracy to describe the principle, in proper terminology:

In concurrent programming, an operation (or set of operations) is atomic, linearizable, indivisible or uninterruptible if it appears to the rest of the system to occur instantaneously.

Atomicity is a guarantee of isolation from concurrent processes. Additionally, atomic operations commonly have a succeed-or-fail definition — they either successfully change the state of the system, or have no apparent effect.

Atomicity is commonly enforced by mutual exclusion, whether at the hardware level building on a cache coherency protocol, or the software level using semaphores or locks. Thus, an atomic operation does not actually occur instantaneously.

In computer science, atomicity is often associated with databases and represents the “A” in ACID, which describes a set of properties for database transactions.

Example

A common example used to illustrate the effect of the principle is transferring money from one account to another. When transferring $100 from Bob’s to Sally’s bank account, it would be disastrous if money was removed from Bob’s account but not deposited to Sally’s account for Bob and Sally, as it would result in a missing $100 to Sally. The transaction would be equally problematic if the money was added to Sally’s account without being removed from Bob’s account for the bank.

Achieving Atomicity

There are several mechanisms to achieve atomicity, but for simplicity, the focus will be on locking. A simplified view of this can be seen as:

  • Identify memory locations that will be accessed.
  • Create locks on each location.
  • Perform a linear set of transactions and save to a new memory location.
  • Wait for all transactions to complete.
  • In a single transaction, swap the memory locations.

This strategy would likely result in the inability for the operation to be multi-threaded, but as alluded to, there are other methods.

Atomic Operations in Python

In researching examples, one blog referred to two key explanations. The official Python documentation provides insight into what operations are/are not atomic. Even more to the point is Google’s styling guide on Threading which provides the below insight.

While Python’s built-in data types such as dictionaries appear to have atomic operations, there are corner cases where they aren’t atomic (e.g. if hash or eq are implemented as Python methods) and their atomicity should not be relied upon. Neither should you rely on atomic variable assignment (since this in turn depends on dictionaries).

Rather interesting to note that even variable assignment are not guaranteed to be safe and atomic.

Atomic Operation in Networking

Using a traditional Cisco IOS CLI, applying configurations in a linear fashion can be problematic. Take, for example, creating a VTY ACL. Adding a single line to the new ACL, can enforce an implicit deny and could potentially lock the the operator out. Naturally, the ability to apply configurations atomically has obvious benefits.

Luckily, since at least 2007, there has been a feature called “configure replace”, to replace an entire Cisco IOS configuration. Even better, this is used within the NAPALM Python library. In order to illustrate the effect, the first attempt will fail to push configurations and demonstrate a proper rollback, and the second attempt will work as intended.

Initially, the “intended” configuration will contain this contrived incorrect configuration.

vlan 499
 name printers
!
vlan 5000
 name users

The mistyped VLAN 5000 instead of 500 will be problematic. Let’s observe how NAPALM reacts.

>>> import getpass
>>> from napalm import get_network_driver
>>> driver = get_network_driver('ios')
>>> hostname = 'ios-sw1'
>>> username = 'ntc'
>>> password = getpass.getpass()
Password:
>>> device = driver(hostname, username, password)
>>> device.open()
>>> device.load_replace_candidate(filename='ios-sw1')
>>> device.compare_config()
'+vlan 499\n  +name printers\n+vlan 5000\n +name users'
>>> device.commit_config()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.5/dist-packages/napalm/ios/ios.py", line 533, in commit_config
    raise ReplaceConfigException(msg)
napalm.base.exceptions.ReplaceConfigException: Candidate config could not be applied
Command rejected: Bad VLAN list - character #5 (EOL) delimits a VLAN
number which is out of the range 1..4094.
Failed to apply command vlan 5000
Aborting Rollback.

Rollback failed.Reverting back to the original configuration: flash:-Dec-14-13-05-59.491-0 ...

Total number of passes: 1
Rollback Done

The original configuration has been successfully restored.

>>>

As you can see, the comparison of the configuration indicates an attempt to add VLANs 499 and 5000. However, when a configuration commit is attempted, the configuration aborts with the following message Command rejected: Bad VLAN list - character #5 (EOL) delimits a VLAN number which is out of the range 1..4094. The failure forces a rollback and ensures that both VLANs did not get created.

Updating the VLAN 5000 to the correct VLAN 500 and rerunning the process results in a successful operation.

>>> device = driver(hostname, username, password)
>>> device.open()
>>> device.load_replace_candidate(filename='ios-sw1')
>>> device.compare_config()
'+vlan 499\n  +name printers\n+vlan 500\n +name users'
>>> device.commit_config()
>>>

This can be further verified on the switch, by viewing the configuration.

vlan 499
 name printers
!
vlan 500
 name users

While the “configure replace” process likely lacks the integrity that a PostgreSQL or MySQL database will have, it is largely effective in creating an atomic operation.


Conclusion

An atomic operation is generally safer and implies your intent–outside of rare use cases. In databases, this is often handled in transactions and in practice creating your own atomic actions often requires locks. Perhaps Yoda can best describe atomicity succinctly with his quote, “do or do not. There is no try.”

Yoda Quote

-Ken



ntc img
ntc img

Contact Us to Learn More

Share details about yourself & someone from our team will reach out to you ASAP!

Author