New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed lookup search path #16630
fixed lookup search path #16630
Conversation
@@ -101,3 +102,19 @@ def run(self, terms, variables=None, **kwargs): | |||
result_string = to_unicode(result_string) | |||
""" | |||
pass | |||
|
|||
def find_needle(self, myvars, subdir, needle): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe 'def find_file_in_expected_search_path()' or 'find_file_in_search_path()' ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And maybe a
def find_file_in_search_paths(self, myvars, subdirs, target_name):
results = []
for subdir in subdirs:
try:
result.append(self.find_file_in_search_path(myvars, subdir, target_name))
# could use a more specific exception here. Or let find_needle/find_file_in_search_path() return results as []
except AnsibleError:
continue
return results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And/or, throw some variety of IGotTooManyAnswersException if find_file_in_search_paths end up with len(result) > 1
something like:
def find_file_in_search_paths(self, myvars, subdirs, target_name):
results = []
for subdir in subdirs:
try:
result.append(self.find_file_in_search_path(myvars, subdir, target_name))
# could use a more specific exception here. Or let find_needle/find_file_in_search_path() return results as []
except AnsibleError:
continue
if not results:
raise NoFilesFoundInSearchPathException(target_file=target_name, subdir=subdir)
if len(results) > 1:
raise TooManyFilesException(target_file=target_name, subdir=subdir, results=results)
return results
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it cannot, as it always returns the first one found
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to rephrase, we don't care that multiple files can match, it MUST return the first one it finds, that is why search path order matters.
added ansible_search_path var that contains the proper list and in order removed roledir var which was only used by first_found, rest used role_path added needle function for lookups that mirrors the action plugin one, now both types of plugins use same pathing.
mylookup = self._shared_loader_obj.lookup_loader.get(self._task.loop, loader=self._loader, templar=templar) | ||
|
||
# give lookup task 'context' for subdir (mostly needed for first_found) | ||
for subdir in ['tempalte', 'var', 'file']: #TODO: move this to constants? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
template is misspelled.
'with_first_found' lookup into {files,templates} directory so we must use relative path for vars/* (See See ansible/ansible#14454) $ ansible --version ansible 2.2.0
Hi, with this change no files in role/vars are looked up anymore. I've to rename the vars directory inside each role to files. Is this expected or a bug? |
* fixed lookup search path added ansible_search_path var that contains the proper list and in order removed roledir var which was only used by first_found, rest used role_path added needle function for lookups that mirrors the action plugin one, now both types of plugins use same pathing. * added missing os import * renamed as per feedback * fixed missing rename in first_found * also fixed first_found * fixed import to match new error class * fixed getattr ref
PR ansible#16630 broke globbing in with_fileglob for globbed path components by changing from path_dwim_relative to path_dwim_relative_stack. While the former does something like this (for a path specification like "/tmp/*/some.conf", see Issue ansible#17136 for an example playbook) search = ["/tmp/*"] for candidate in search: if os.path.exists(candidate): break return candidate the check inside path_dwim_relative_stack works slightly differently: result = None if os.path.exists("/tmp/*"): result = "/tmp/*" return result The way the loop in the former example works makes path_dwim_relative return the last element from the 'search' list even if os.path.exists never returned True, while path_dwim_relative_stack returns None in the same case. This ultimately makes the fileglob plugin fail because find_file_in_search_path returns None now. To allow asterisks in paths again, this change breaks the search for potential targets out of path_dwim_relative_stack. This function can then be called from the fileglob plugin to find all potential target directories without checking if these dirs (like "/tmp/*") actually exist. fileglob will now apply globbing first and check for the actual existence of the files _after_ globbing.
PR ansible#16630 broke globbing in with_fileglob for globbed path components by changing from path_dwim_relative to path_dwim_relative_stack. While the former does something like this (for a path specification like "/tmp/*/some.conf", see Issue ansible#17136 for an example playbook) search = ["/tmp/*"] for candidate in search: if os.path.exists(candidate): break return candidate the check inside path_dwim_relative_stack works slightly differently: result = None if os.path.exists("/tmp/*"): result = "/tmp/*" return result The way the loop in the former example works makes path_dwim_relative return the last element from the 'search' list even if os.path.exists never returned True, while path_dwim_relative_stack returns None in the same case. This ultimately makes the fileglob plugin fail because find_file_in_search_path returns None now. To allow asterisks in paths again, this change breaks the search for potential targets out of path_dwim_relative_stack. This function can then be called from the fileglob plugin to find all potential target directories without checking if these dirs (like "/tmp/*") actually exist. fileglob will now apply globbing first and check for the actual existence of the files _after_ globbing. Additionally, fileglob now calls os.path.normpath() on the results of glob.glob and eliminates duplicate results.
ISSUE TYPE
ANSIBLE VERSION
SUMMARY
added ansible_search_path var that contains the proper list and in order
removed roledir var which was only used by first_found, rest used role_path
added needle function for lookups that mirrors the action plugin one, now
both types of plugins use same pathing.
Also fixes first_found in particular, to be 'aware' of task subdir requirements, this info is now available to all
with_<lookup>
.fixes #16630