The import block¶
The next section of the module is the block of code where the imports happen.
This code usually just involves importing the module_utils
helper libraries, but may
also include imports of other libraries if you are working with legacy code.
For this module, the import block is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.six import iteritems
try:
# Sideband repository used for dev
from library.module_utils.network.f5.bigip import HAS_F5SDK
from library.module_utils.network.f5.bigip import F5RestClient
from library.module_utils.network.f5.common import F5ModuleError
from library.module_utils.network.f5.common import AnsibleF5Parameters
from library.module_utils.network.f5.common import cleanup_tokens
from library.module_utils.network.f5.common import fq_name
from library.module_utils.network.f5.common import f5_argument_spec
except ImportError:
# Upstream Ansible
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
from ansible.module_utils.network.f5.bigip import F5RestClient
from ansible.module_utils.network.f5.common import F5ModuleError
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
from ansible.module_utils.network.f5.common import cleanup_tokens
from ansible.module_utils.network.f5.common import fq_name
from ansible.module_utils.network.f5.common import f5_argument_spec
|
In 90% of cases, this code is boilerplate and you can ignore it when writing a module.
The inv
command takes care of this for you.
Let’s take a moment to walk through some of the things you see here and explain their purpose.
AnsibleModule import¶
This import is at line #1 above.
from ansible.module_utils.basic import AnsibleModule
This import makes available to the module all of the utilities and convenience functions that Ansible provides to modules written in Python.
This module is defined in Ansible here. This code will change over time, so you may need
to visit the file location itself on Ansible’s devel
branch.
All F5 modules should include this line because it is used in the body of the main()
method of the module. Its purpose is to consume the module’s ArgumentSpec
class and
provide back to the module a list of parameters that have been parsed and verified to meet
the spec.
env_fallback import¶
This import is at line #2 above.
This import is used by any modules that support a partition
argument. Its purpose is to
provide access to environment variables for parameters to “fall back” to in the event that
the parameter is not provided directly to the module.
Normally, all of these environment fallbacks are defined in the F5 common.py
module util
file. The partition one is the exception though, because it is not a common parameter.
Consider APIs of the BIG-IP that change system-level resources, like SSHD configuration or the
management IP of the BIG-IP. Modules like these have no reason to offer a partition
parameter to the user. Therefore, partition
is not common across all modules, and is
not included in the common.py
module utils. Each module that can use a partition is
expected to define that parameter in its ArgumentSpec
.
Various helper import¶
These imports are the other imports that remain outside of the import try
block. In this
module, that means line #3.
Modules can make use of a number of helper libraries that ship with Ansible. This module
makes use of the iteritems
function to provide dictionary iteration that is compatible
across both Python 2.x and 3.x.
This illustrates another concern that modules have; that they should support older and newer Python versions.
This commitment enables the users of F5 modules to gradually move off of older Python versions over time.
The dev/prod import try block¶
This series of imports start at, or around, line #7 and continues for some time. In this module’s case, it starts at line #7 and continues to line #33.
This large block of imports is actually a couple of things.
First, remember back to the previous section where the HAS_DEVEL_IMPORTS
was first
defined. The first set of imports in this try
block is the module’s attempts to load
those.
The reason that the modules tries its development libraries first is that, were the developers to try to import the second block, the second block would always succeed. This is because the second block’s imports are always defined; they are part of Ansible.
However, the developers need to test and do their development. So the module tries to import the development code (part of the side-band repository) first. This allows the developers to do their work without messing up anything in their installed copy of Ansible. It also allows them to do work in their own side-band source repository. Otherwise, they would need to do development directly in the Ansible repository.
When Ansible ships, this code will fail to import, but that’s not a problem. The module will catch this failing behavior, and instead, try to import what it considers to be the production imports. In other words, what comes installed with Ansible. This is nearly always guaranteed to succeed.
Note
This may fail when a newer copy of the module is run on an older copy of Ansible. In this case, the older copy may be missing things that were defined in the newer Ansible. The F5 modules should always be run on the newest version of Ansible to prevent this from occurring.
What is imported in the try block?¶
These try blocks are a mixture of support libraries that the Ansible module will use. Most of these libraries are standard across all F5 modules. Also, you’ll notice that the actual imported things are nearly identical, except for the path leading up to them.
For example:
from library.module_utils.network.f5.common import fq_name
versus:
from ansible.module_utils.network.f5.common import fq_name
In both cases, the fq_name
function is attempted to be imported. It is the location
of this function that changes. The first attempt is in the side-band repository. The
second attempt is in Ansible core.
Key imports to recognize¶
Some of the imports that are made are crucial for the module to execute correctly. The imports and their purposes are outlined below.
Imported item | Comment |
---|---|
F5RestClient |
This variable contains a connection to your F5 device (BIG-IP, BIG-IQ, etc). |
F5ModuleError |
This is a general purpose Exception class that all F5 modules
use when something “bad” happens in them. It is raised for
situations when F5 is aware that something troubling can happen.
F5 does not catch, nor raise, Python’s base Exception exception
because this may suppress problems that occur that we are not
aware of. The developers want to be identified of those unknowns. |
AnsibleF5Parameters |
This is a base class for the Parameters class that is used by
all modules. This class includes methods for handling common F5
things such as the method by which the Parameters class
auto-creates properties for you. |
cleanup_tokens |
This method is used by all modules to clean up the authentication tokens that are created during a module’s run. If token cleanup is not done, this can wedge your BIG-IP after hundreds of tokens have accumulated. |
fq_name |
This is a convenience method. Give a partition and a name .
It will return a name that is “fully qualified,” i.e., includes
the partition. This is helpful in situations where users can
specify a name which, itself, is a fully qualified name. For
example, inputs of foo and /Common/foo would both return
/Common/foo . |
f5_argument_spec |
This returns the base set of arguments that all modules can consume.
This is usually combined with module specific arguments to form the
final ArgumentSpec . |
Conclusion¶
The import block at the top of each module has a number of useful things injected into the module.
The next section skips down to the bottom of the file and begins exploring some of the common classes
of a module. ArgumentSpec
will be the first class we visit.