Leverage Idempotent, Declarative Profiles with the NSX-ALB (Avi) REST API

Nick Schmidt
3 min readJan 4, 2022

Idempotence and Declarative Methods — not just buzzwords

Idempotence

Coined by Benjamin Peirce, this term indicates that a mathematical operation will produce a consistent result, even with repetition.

Idempotence is much more complicated subject in mathematics and computer science. IT and DevOps use a simplified version of this concept, commonly leveraging flow logic instead of Masters-level Algebra.

Typically, an idempotent function in DevOps-land adds a few other requirements to the mix:

  • If a change is introduced, convergence (the act of making an object match what the consumer asked for) should be non-invasive and safe
  • Provide a “What If?” function of some kind, indicating how far off from desired state a system is

Ansible’s modules are a good example of idempotent functions, but Ansible doesn’t require that everything be idempotent. Some good examples exist of methods that cannot be idempotent, re-defining it to add the “do no harm” requirement:

  • Restarting a service
  • Deleting and re-adding a file

As a result, many contributed modules are not pressured to be idempotent when they should be. It’s the responsibility of the consumer (probably you) to verify things don’t cause harmful change.

Declarative Methods

Lori MacVittie (F5 Networks) provides an excellent detailed explanation of Declarative Models here:

https://www.f5.com/company/blog/why-is-a-declarative-model-important-for-netops-automation

Declarative Methods provide a system interface that can be leveraged by a non-Expert, by allowing a consumer to specify what the consumer wants instead of how to build it ( an Imperative method).

This is a huge issue in the IT industry in general, because we (incorrectly) conflate rote memorization of individual imperative methods with capability. In the future, the IT industry will be forced to transform away from this highly negative cultural pattern.

  • Find a way to somehow teach fundamental concepts without imperative methods
  • Teach others to value the ability to effectively define what they desire in a complete and comprehensive way

We as professionals need to solve two major problems to assist in this transition:

If you’ve ever been frustrated by an IT support ticket that has some specific steps and a completely vague definition of success, declarative methods are for you.The single most important aspect of declarative methods is that the user/consumer’s intent is captured in a complete and comprehensive way. If a user fails to define their intent in modern systems like Kubernetes, the service will fail to build. In my experience, problem #1 feeds into problem #2, and some people just think they’re being helpful by requesting imperative things.

Obviously the IT industry won’t accept that a computer system is allowed to deny them if they failed to define everything they need to. This is where expertise comes in.

# Recursively converge application profiles def converge_app_profile(app_profile_dict): # First, grab a copy of the existing application profile before_app_profile = json.loads( cogitation_interface.namshub( "get_app_profile", namshub_variables={"id": app_profile_dict["uuid"]} ) ) # Fastest and cheapest compare operation first if not app_profile_dict["profile"] == before_app_profile: # Build a deep difference of the two dictionaries, removing attributes that are not part of the profile, but the API generates diff_app_profile = deepdiff.DeepDiff( before_app_profile, app_profile_dict["profile"], exclude_paths=[ "root['uuid']", "root['url']", "root['uuid']", "root['_last_modified']", "root['tenant_ref']", ], ) # If there are differences, try to fix them at least 3 times if len(diff_app_profile) > 0 and app_profile_dict["retries"] < 3: print("Difference between dictionaries found: " + str(diff_app_profile)) print( "Converging " + app_profile_dict["profile"]["name"] + " attempt # " + str(app_profile_dict["retries"] + 1) ) # Increment retry counter app_profile_dict["retries"] += 1 # Then perform Update verb on profile cogitation_interface.namshub( "update_app_profile", namshub_payload=app_profile_dict["profile"], namshub_variables={"id": app_profile_dict["uuid"]}, ) # Perform recursion converge_app_profile(app_profile_dict) else: return before_app_profile

Originally published at https://blog.engyak.co.

--

--

Nick Schmidt

I am a network engineer based out of Alaska, pursuing various methods of achieving SRE/NRE