9.6 KiB
Ansible OpenStack Collection and its branches
Our codebase has been split into two separate release series, 2.x.x and 1.x.x:
2.x.xreleases of Ansible OpenStack collection are compatible with OpenStack SDK1.x.xand its release candidates0.99.0and later only (OpenStack Zed and later). Ourmasterbranch tracks our2.x.xreleases.1.x.xreleases of Ansible OpenStack collection are compatible with OpenStack SDK0.x.xprior to0.99.0only (OpenStack Yoga and earlier). Ourstable/1.0.0branch tracks our1.x.xreleases.2.x.xreleases of Ansible OpenStack collection are not backward compatible to1.x.xreleases ⚠️
Both branches will be developed in parallel for the time being. Patches from master will be backported to
stable/1.0.0 on a best effort basis but expect new features to be introduced in our master branch only.
Contributions are welcome for both branches!
Our decision to break backward compatibility was not taken lightly. OpenStack SDK's first major release (1.0.0 and its
release candidates >=0.99.0) has streamlined and improved large parts of its codebase. For example, its Connection
interface now consistently uses the Resource interfaces under the hood. This required breaking changes from older SDK
releases though. The Ansible OpenStack collection is heavily based on OpenStack SDK.
With OpenStack SDK becoming backward incompatible, so does our Ansible OpenStack collection. For example, with
openstacksdk >=0.99.0 most Ansible modules return dictionaries instead Munch objects and many of their keys have
been renamed. We simply lack the development resources to maintain a backward compatible interface in Ansible OpenStack
collection across several SDK releases.
Notable changes between release series 2.x.x and 1.x.x
When we ported our collection to openstacksdk >=0.99.0, a series of changes were applied to our
master branch. We went through each module in our collection and did the following:
- Identify function calls which use openstacksdk's cloud layer, e.g.
self.conn.get_network(). Change these calls to functions from openstacksdk's resource proxies, e.g.self.conn.network.find_network(), if possible. As a guideline use this decision tree:- If a functionality requires a single api call (to the OpenStack API), then use functions from openstacksdk's resource proxies.
- If a functionality requires multiple api calls (to the OpenStack API), e.g. when creating and attaching a floating ip to a server, then use functions from openstacksdk's cloud layer.
- When unsure which of openstacksdk's layers to use, then first go to resource proxies and then to its cloud layer.
Mainly this applies to functions retrieving information, i.e. all calls where we get info about cloud resources
should be changed to openstacksdk functions which return proxy resources.
Note: Using openstacksdk's cloud layer for functionality which is not provided by openstacksdk's proxy layer is
acceptable. openstacksdk's cloud layer is not going away. For example, listing
functions in openstacksdk's cloud layer such as
search_users()often allow to filter results with function parameterfilters. openstacksdk's proxy layer does not provide an equivalent and thus usingsearch_users()is fine.
- Functions in openstacksdk's cloud layer often have different return values then pre-0.99.0 releases. When return
values have changed in any of the functions which a module uses, update
RETURNvariable. If a module has noRETURNvariable, define it. - Only return data types such as lists or dictionaries to Ansible. For example, the return statement
self.exit_json(changed=False, floating_ips=floating_ips)in modulefloating_ip_infoshall return a list ofdict's. Use openstacksdk'sto_dictfunction to convert resources to dictionaries. Setting its parameters such ascomputedtoFalsewill drop computed attributes from the resulting dict. Readto_dict's docstring for more parameters. Usingto_dictmight change the return values of your Ansible module. Please document changes to return values inRETURN. - Older openstacksdk releases did not provide the
to_dictfunction. We decided to allow breaking backward compatibility with release2.x.x, so workarounds such as(o.to_dict() if hasattr(o, 'to_dict') else dict(o))are not required anymore and shall be avoided. - Manually dropping attributes such as
locationorlinkfrom openstacksdk resources is no longer necessary. Workarounds such asare no longer necessary and can be removed.for raw in self.conn.block_storage.backups(**attrs): dt = raw.to_dict() dt.pop('location') data.append(dt) - Add tests to ci/run-collection.yml and ci/roles. Each module has a
dedicated Ansible role with tests in
ci/roles. Create one if no such directory exist. - With release of openstacksdk 0.99.0 most of our CI tests in ci/ failed. To prove that module patches
actually fix issues all CI tests for unrelated broken modules have to be skipped. To run CI tests for patched modules
only, temporarily list the Ansible tags of all CI tests which should run in
vars: { tox_extra_args: ... }of jobansible-collections-openstack-functional-devstack-ansiblein.zuul.yaml(example) and send the patch for review. Once all CI tests are passing in Zuul CI, undo changes to.zuul.yaml, i.e. revert changes totox_extra_argsand submit final patch for review. Cherry-pick or backport patches forBackporting patches frommasterbranch tostable/1.0.0branch. Both branches should divert only if necessary in order to keep maintainence of two separate branches simple. When applying patches to thestable/1.0.0branch, it is often necessary to make changes to not break backward compatibility on thestable/1.0.0branch. Onmasterwe use.to_dict(computed=False)which we have to change to.to_dict(computed=True)onstable/1.0.0. For example, this patch formasterbranch has been tweaked and cherry-picked tostable/1.0.0branch.mastertostable/1.0.0branch have been abandoned due to lack of time and resources ⚠️- Version checks in modules are no longer necessary because we require openstacksdk >=0.99.0 globally. For example,
drop
min_ver/max_verconstraints on module arguments. - Rename module parameter names to the attribute names that openstacksdk uses, e.g.
sharedbecomesis_shared. Keep old names as aliases for input backward compatibility. - Some modules have if-else branches for handling cases where a
nameis given. For most modules these can be dropped safely because names can be passed as a query parameter. - Some modules do not use
nameas module parameters for resource names. For example,portmodule had an attribute calledportinstead ofname. Rename those attributes tonameto be consistent with other modules and because openstacksdk is doing the same. Add old attribute names as aliases to keep input backward compatibility. - Replacing
self.conn.get_*withself.conn.*.find_*functions provide aignore_missing=Falseparameter. This allows to dropself.fail_json()calls in modules. Less code means less to maintain. - Some modules pass
ignore_missing=Truetoself.conn.*.find_*functions and then fail if the return value isNone. Often this code can be simplified by changingignore_missingtoFalseand dropping the if-else branches. - When module attribute that have choices, always doubt its values. The module code was probably written long ago and
the choices given might be outdated. It might also make sense to drop the
choicesparameter completely when choices are to narrow and might soon be outdated again. - Check comments whether they are still relevant.
- Sanity check existing integration tests. For example, return values of module calls should be tested else running a test could be useless in the first place.
- Most functions in openstacksdk's cloud layer no longer return
Munchobjects. Instead they return resources which should be converted to dictionaries. UpdateRETURNdocs in modules, e.g. change fromtype: complextotype: dict. - Move list of expected module results to role defaults, e.g. define a variable
expected_fields. This enables easier reuse. - Following and applying our development guide and review guide