f86345f777
* basic plugin loading working (with many hacks) * task collections working * play/block-level collection module/action working * implement PEP302 loader * implicit package support (no need for __init.py__ in collections) * provides future options for secure loading of content that shouldn't execute inside controller (eg, actively ignore __init__.py on content/module paths) * provide hook for synthetic collection setup (eg ansible.core pseudo-collection for specifying built-in plugins without legacy path, etc) * synthetic package support * ansible.core.plugins mapping works, others don't * synthetic collections working for modules/actions * fix direct-load legacy * change base package name to ansible_collections * note * collection role loading * expand paths from installed content root vars * feature complete? * rename ansible.core to ansible.builtin * and various sanity fixes * sanity tweaks * unittest fixes * less grabby error handler on has_plugin * probably need to replace with a or harden callers * fix win_ping test * disable module test with explicit file extension; might be able to support in some scenarios, but can't see any other tests that verify that behavior... * fix unicode conversion issues on py2 * attempt to keep things working-ish on py2.6 * python2.6 test fun round 2 * rename dirs/configs to "collections" * add wrapper dir for content-adjacent * fix pythoncheck to use localhost * unicode tweaks, native/bytes string prefixing * rename COLLECTION_PATHS to COLLECTIONS_PATHS * switch to pathspec * path handling cleanup * change expensive `all` back to or chain * unused import cleanup * quotes tweak * use wrapped iter/len in Jinja proxy * var name expansion * comment seemingly overcomplicated playbook_paths resolution * drop unnecessary conditional nesting * eliminate extraneous local * zap superfluous validation function * use slice for rolespec NS assembly * misc naming/unicode fixes * collection callback loader asks if valid FQ name instead of just '.' * switch collection role resolution behavior to be internally `text` as much as possible * misc fixmes * to_native in exception constructor * (slightly) detangle tuple accumulation mess in module_utils __init__ walker * more misc fixmes * tighten up action dispatch, add unqualified action test * rename Collection mixin to CollectionSearch * (attempt to) avoid potential confusion/conflict with builtin collections, etc * stale fixmes * tighten up pluginloader collections determination * sanity test fixes * ditch regex escape * clarify comment * update default collections paths config entry * use PATH format instead of list * skip integration tests on Python 2.6 ci_complete
280 lines
9.7 KiB
YAML
280 lines
9.7 KiB
YAML
- hosts: testhost
|
|
tasks:
|
|
# basic test of FQ module lookup and that we got the right one (user-dir hosted)
|
|
- name: exec FQ module in a user-dir testns collection
|
|
testns.testcoll.testmodule:
|
|
register: testmodule_out
|
|
|
|
# verifies that distributed collection subpackages are visible under a multi-location namespace (testns exists in user and sys locations)
|
|
- name: exec FQ module in a sys-dir testns collection
|
|
testns.coll_in_sys.systestmodule:
|
|
register: systestmodule_out
|
|
|
|
# verifies that content-adjacent collections were automatically added to the installed content roots
|
|
- name: exec FQ module from content-adjacent collection
|
|
testns.content_adj.contentadjmodule:
|
|
register: contentadjmodule_out
|
|
|
|
# content should only be loaded from the first visible instance of a collection
|
|
- name: attempt to look up FQ module in a masked collection
|
|
testns.testcoll.plugin_lookup:
|
|
type: module
|
|
name: testns.testcoll.maskedmodule
|
|
register: maskedmodule_out
|
|
|
|
# module with a granular module_utils import (from (this collection).module_utils.leaf import thingtocall)
|
|
- name: exec module with granular module utils import from this collection
|
|
testns.testcoll.uses_leaf_mu_granular_import:
|
|
register: granular_out
|
|
|
|
# module with a granular nested module_utils import (from (this collection).module_utils.base import thingtocall,
|
|
# where base imports secondary from the same collection's module_utils)
|
|
- name: exec module with nested module utils from this collection
|
|
testns.testcoll.uses_base_mu_granular_nested_import:
|
|
register: granular_nested_out
|
|
|
|
# module with a flat module_utils import (import (this collection).module_utils.leaf)
|
|
- name: exec module with flat module_utils import from this collection
|
|
testns.testcoll.uses_leaf_mu_flat_import:
|
|
register: flat_out
|
|
|
|
# FIXME: this one doesn't work yet
|
|
# module with a full-module module_utils import using 'from' (from (this collection).module_utils import leaf)
|
|
- name: exec module with full-module module_utils import using 'from' from this collection
|
|
testns.testcoll.uses_leaf_mu_module_import_from:
|
|
ignore_errors: true
|
|
register: from_out
|
|
|
|
- assert:
|
|
that:
|
|
- testmodule_out.source == 'user'
|
|
- systestmodule_out.source == 'sys'
|
|
- contentadjmodule_out.source == 'content_adj'
|
|
- not maskedmodule_out.plugin_path
|
|
- granular_out.mu_result == 'thingtocall in leaf'
|
|
- granular_nested_out.mu_result == 'thingtocall in base called thingtocall in secondary'
|
|
- flat_out.mu_result == 'thingtocall in leaf'
|
|
- from_out is failed # FIXME: switch back once this import is fixed --> from_out.mu_result == 'thingtocall in leaf'
|
|
|
|
- name: exercise filters/tests/lookups
|
|
assert:
|
|
that:
|
|
- "'data' | testns.testcoll.testfilter == 'data_from_userdir'"
|
|
- "'from_user' is testns.testcoll.testtest"
|
|
- lookup('testns.testcoll.mylookup') == 'lookup_from_user_dir'
|
|
|
|
# ensure that the synthetic ansible.builtin collection limits to builtin plugins, that ansible.legacy loads overrides
|
|
# from legacy plugin dirs, and that a same-named plugin loaded from a real collection is not masked by the others
|
|
- hosts: testhost
|
|
tasks:
|
|
- name: test unqualified ping from library dir
|
|
ping:
|
|
register: unqualified_ping_out
|
|
|
|
- name: test legacy-qualified ping from library dir
|
|
ansible.legacy.ping:
|
|
register: legacy_ping_out
|
|
|
|
- name: test builtin ping
|
|
ansible.builtin.ping:
|
|
register: builtin_ping_out
|
|
|
|
- name: test collection-based ping
|
|
testns.testcoll.ping:
|
|
register: collection_ping_out
|
|
|
|
- assert:
|
|
that:
|
|
- unqualified_ping_out.source == 'legacy_library_dir'
|
|
- legacy_ping_out.source == 'legacy_library_dir'
|
|
- builtin_ping_out.ping == 'pong'
|
|
- collection_ping_out.source == 'user'
|
|
|
|
# verify the default value for the collections list is empty
|
|
- hosts: testhost
|
|
tasks:
|
|
- name: sample default collections value
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_default_out
|
|
|
|
- assert:
|
|
that:
|
|
# in original release, collections defaults to empty, which is mostly equivalent to ansible.legacy
|
|
- not coll_default_out.collection_list
|
|
|
|
|
|
# ensure that inheritance/masking works as expected, that the proper default values are injected when missing,
|
|
# and that the order is preserved if one of the magic values is explicitly specified
|
|
- name: verify collections keyword play/block/task inheritance and magic values
|
|
hosts: testhost
|
|
collections:
|
|
- bogus.fromplay
|
|
tasks:
|
|
- name: sample play collections value
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_play_out
|
|
|
|
- name: collections override block-level
|
|
collections:
|
|
- bogus.fromblock
|
|
block:
|
|
- name: sample block collections value
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_block_out
|
|
|
|
- name: sample task collections value
|
|
collections:
|
|
- bogus.fromtask
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_task_out
|
|
|
|
- name: sample task with explicit core
|
|
collections:
|
|
- ansible.builtin
|
|
- bogus.fromtaskexplicitcore
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_task_core
|
|
|
|
- name: sample task with explicit legacy
|
|
collections:
|
|
- ansible.legacy
|
|
- bogus.fromtaskexplicitlegacy
|
|
testns.testcoll.plugin_lookup:
|
|
register: coll_task_legacy
|
|
|
|
- assert:
|
|
that:
|
|
# ensure that parent value inheritance is masked properly by explicit setting
|
|
- coll_play_out.collection_list == ['bogus.fromplay', 'ansible.legacy']
|
|
- coll_block_out.collection_list == ['bogus.fromblock', 'ansible.legacy']
|
|
- coll_task_out.collection_list == ['bogus.fromtask', 'ansible.legacy']
|
|
- coll_task_core.collection_list == ['ansible.builtin', 'bogus.fromtaskexplicitcore']
|
|
- coll_task_legacy.collection_list == ['ansible.legacy', 'bogus.fromtaskexplicitlegacy']
|
|
|
|
- name: verify unqualified plugin resolution behavior
|
|
hosts: testhost
|
|
collections:
|
|
- testns.testcoll
|
|
- testns.coll_in_sys
|
|
- testns.contentadj
|
|
tasks:
|
|
# basic test of unqualified module lookup and that we got the right one (user-dir hosted, there's another copy of
|
|
# this one in the same-named collection in sys dir that should be masked
|
|
- name: exec unqualified module in a user-dir testns collection
|
|
testmodule:
|
|
register: testmodule_out
|
|
|
|
# use another collection to verify that we're looking in all collections listed on the play
|
|
- name: exec unqualified module in a sys-dir testns collection
|
|
systestmodule:
|
|
register: systestmodule_out
|
|
|
|
# ensure we're looking up actions properly
|
|
- name: unqualified action test
|
|
plugin_lookup:
|
|
register: pluginlookup_out
|
|
|
|
- assert:
|
|
that:
|
|
- testmodule_out.source == 'user'
|
|
- systestmodule_out.source == 'sys'
|
|
- pluginlookup_out.collection_list == ['testns.testcoll', 'testns.coll_in_sys', 'testns.contentadj', 'ansible.legacy']
|
|
|
|
# FIXME: this won't work until collections list gets passed through task templar
|
|
# - name: exercise unqualified filters/tests/lookups
|
|
# assert:
|
|
# that:
|
|
# - "'data' | testfilter == 'data_from_userdir'"
|
|
# - "'from_user' is testtest"
|
|
# - lookup('mylookup') == 'lookup_from_user_dir'
|
|
|
|
|
|
# test keyword-static execution of a FQ collection-backed role
|
|
- name: verify collection-backed role execution (keyword static)
|
|
hosts: testhost
|
|
collections:
|
|
# set to ansible.builtin only to ensure that roles function properly without inheriting the play's collections config
|
|
- ansible.builtin
|
|
vars:
|
|
test_role_input: keyword static
|
|
roles:
|
|
- role: testns.testcoll.testrole
|
|
tasks:
|
|
- name: ensure role executed
|
|
assert:
|
|
that:
|
|
- test_role_output.msg == test_role_input
|
|
|
|
|
|
# test dynamic execution of a FQ collection-backed role
|
|
- name: verify collection-backed role execution (dynamic)
|
|
hosts: testhost
|
|
collections:
|
|
# set to ansible.builtin only to ensure that roles function properly without inheriting the play's collections config
|
|
- ansible.builtin
|
|
vars:
|
|
test_role_input: dynamic
|
|
tasks:
|
|
- include_role:
|
|
name: testns.testcoll.testrole
|
|
- name: ensure role executed
|
|
assert:
|
|
that:
|
|
- test_role_output.msg == test_role_input
|
|
|
|
|
|
# test task-static execution of a FQ collection-backed role
|
|
- name: verify collection-backed role execution (task static)
|
|
hosts: testhost
|
|
collections:
|
|
- ansible.builtin
|
|
vars:
|
|
test_role_input: task static
|
|
tasks:
|
|
- import_role:
|
|
name: testns.testcoll.testrole
|
|
- name: ensure role executed
|
|
assert:
|
|
that:
|
|
- test_role_output.msg == test_role_input
|
|
|
|
|
|
# test a legacy playbook-adjacent role, ensure that play collections config is not inherited
|
|
- name: verify legacy playbook-adjacent role behavior
|
|
hosts: testhost
|
|
collections:
|
|
- bogus.bogus
|
|
vars:
|
|
test_role_input: legacy playbook-adjacent
|
|
roles:
|
|
- testrole
|
|
# FIXME: this should technically work to look up a playbook-adjacent role
|
|
# - ansible.legacy.testrole
|
|
tasks:
|
|
- name: ensure role executed
|
|
assert:
|
|
that:
|
|
- test_role_output.msg == test_role_input
|
|
|
|
|
|
- name: test a collection-hosted connection plugin against a host from a collection-hosted inventory plugin
|
|
hosts: dynamic_host_a
|
|
vars:
|
|
ansible_connection: testns.testcoll.localconn
|
|
ansible_localconn_connectionvar: from_play
|
|
tasks:
|
|
- raw: echo 'hello world'
|
|
register: connection_out
|
|
|
|
- assert:
|
|
that:
|
|
- connection_out.stdout == "localconn ran echo 'hello world'"
|
|
# ensure that the connection var we overrode above made it into the running config
|
|
- connection_out.stderr == "connectionvar is from_play"
|
|
|
|
- hosts: testhost
|
|
tasks:
|
|
- assert:
|
|
that:
|
|
- hostvars['dynamic_host_a'] is defined
|
|
- hostvars['dynamic_host_a'].connection_out.stdout == "localconn ran echo 'hello world'"
|