We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Check for file paths outside of /etc/origin/master in master's config fails on auditConfig.policyConfiguratio
#### Description

The openshift_control_plane "Check for file paths outside of /etc/origin/master in master's config" fails on auditConfig policyConfiguration that includes nonResourceURLs specifications by interpreting these as file paths.

##### Version



```
ansible 2.7.5
  config file = /home/ansible/openshift-provision-demo/ansible.cfg
  configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
$ git describe 
openshift-ansible-3.11.69-1-4-g0964a5f
```

##### Steps To Reproduce

1. Start with a master with /etc/origin/master/master-config.yaml containing:

```
auditConfig:
  auditFilePath: /var/log/origin/audit.log
  enabled: true
  logFormat: json
  policyConfiguration:
    apiVersion: audit.k8s.io/v1beta1
    omitStages:
    - RequestReceived
    rules:
    - level: Metadata
      nonResourceURLs:
      - /login*
      - /oauth*
```

2. Run openshift-ansible deploy

##### Expected Results

This check should not choke on the auditConfig policyConfiguration.

##### Observed Results

```
TASK [openshift_control_plane : Check for file paths outside of /etc/origin/master in master's config] ************************************************************************************************************
fatal: [demo-sbx-okd-v3-11-master-0.c.openshift-provision.internal]: FAILED! => {"msg": "A string value that appears to be a file path located outside of\n/dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin has been found in /etc/origin/master/master-config.yaml.\nIn 3.10 and newer, all files needed by the master must reside inside of\nthose directories or a subdirectory or it will not be readable by the\nmaster process. Please migrate all files needed by the master into\none of /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin or a subdirectory and update your master configs before\nproceeding. The string found was: /login*\n***********************\nNOTE: the following items do not need to be migrated, they will be migrated\nfor you: oauthConfig.identityProviders"}

NO MORE HOSTS LEFT ************************************************************************************************************************************************************************************************
	to retry, use: --limit @/home/ansible/openshift-provision-demo/provision-cluster/bootstrap.retry

PLAY RECAP ********************************************************************************************************************************************************************************************************
demo-sbx-okd-v3-11-image.c.openshift-provision.internal : ok=25   changed=0    unreachable=0    failed=0   
demo-sbx-okd-v3-11-master-0.c.openshift-provision.internal : ok=28   changed=0    unreachable=0    failed=1   
localhost                  : ok=59   changed=0    unreachable=0    failed=0   


INSTALLER STATUS **************************************************************************************************************************************************************************************************
Initialization  : In Progress (0:00:07)


Failure summary:


  1. Hosts:    demo-sbx-okd-v3-11-master-0.c.openshift-provision.internal
     Play:     Retrieve existing master configs and validate
     Task:     Check for file paths outside of /etc/origin/master in master's config
     Message:  A string value that appears to be a file path located outside of
               /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin has been found in /etc/origin/master/master-config.yaml.
               In 3.10 and newer, all files needed by the master must reside inside of
               those directories or a subdirectory or it will not be readable by the
               master process. Please migrate all files needed by the master into
               one of /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin or a subdirectory and update your master configs before
               proceeding. The string found was: /login*
               ***********************
               NOTE: the following items do not need to be migrated, they will be migrated
               for you: oauthConfig.identityProviders
```

##### Additional Information

This has behavior has been observed with OKD 3.11 and OCP 3.11 deployments.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `roles/lib_utils/action_plugins/master_check_paths_in_config.py`
Content:
```
1 """
2 Ansible action plugin to ensure inventory variables are set
3 appropriately and no conflicting options have been provided.
4 """
5 import collections
6 import six
7 
8 from ansible.plugins.action import ActionBase
9 from ansible import errors
10 
11 
12 FAIL_MSG = """A string value that appears to be a file path located outside of
13 {} has been found in /etc/origin/master/master-config.yaml.
14 In 3.10 and newer, all files needed by the master must reside inside of
15 those directories or a subdirectory or it will not be readable by the
16 master process. Please migrate all files needed by the master into
17 one of {} or a subdirectory and update your master configs before
18 proceeding. The string found was: {}
19 ***********************
20 NOTE: the following items do not need to be migrated, they will be migrated
21 for you: {}"""
22 
23 
24 ITEMS_TO_POP = (
25     ('oauthConfig', 'identityProviders'),
26 )
27 # Create csv string of dot-separated dictionary keys:
28 # eg: 'oathConfig.identityProviders, something.else.here'
29 MIGRATED_ITEMS = ", ".join([".".join(x) for x in ITEMS_TO_POP])
30 
31 ALLOWED_DIRS = (
32     '/dev/null',
33     '/etc/origin/master/',
34     '/var/lib/origin',
35     '/etc/origin/cloudprovider',
36     '/etc/origin/kubelet-plugins',
37     '/usr/libexec/kubernetes/kubelet-plugins',
38     '/var/log/origin',
39 )
40 
41 ALLOWED_DIRS_STRING = ', '.join(ALLOWED_DIRS)
42 
43 
44 def pop_migrated_fields(mastercfg):
45     """Some fields do not need to be searched because they will be migrated
46     for users automatically"""
47     # Walk down the tree and pop the specific item we migrate / don't care about
48     for item in ITEMS_TO_POP:
49         field = mastercfg
50         for sub_field in item:
51             parent_field = field
52             field = field[sub_field]
53         parent_field.pop(item[len(item) - 1])
54 
55 
56 def do_item_check(val, strings_to_check):
57     """Check type of val, append to strings_to_check if string, otherwise if
58     it's a dictionary-like object call walk_mapping, if it's a list-like
59     object call walk_sequence, else ignore."""
60     if isinstance(val, six.string_types):
61         strings_to_check.append(val)
62     elif isinstance(val, collections.Sequence):
63         # A list-like object
64         walk_sequence(val, strings_to_check)
65     elif isinstance(val, collections.Mapping):
66         # A dictionary-like object
67         walk_mapping(val, strings_to_check)
68     # If it's not a string, list, or dictionary, we're not interested.
69 
70 
71 def walk_sequence(items, strings_to_check):
72     """Walk recursively through a list, items"""
73     for item in items:
74         do_item_check(item, strings_to_check)
75 
76 
77 def walk_mapping(map_to_walk, strings_to_check):
78     """Walk recursively through map_to_walk dictionary and add strings to
79     strings_to_check"""
80     for _, val in map_to_walk.items():
81         do_item_check(val, strings_to_check)
82 
83 
84 def check_strings(strings_to_check):
85     """Check the strings we found to see if they look like file paths and if
86     they are, fail if not start with /etc/origin/master"""
87     for item in strings_to_check:
88         if item.startswith('/') or item.startswith('../'):
89             matches = 0
90             for allowed in ALLOWED_DIRS:
91                 if item.startswith(allowed):
92                     matches += 1
93             if matches == 0:
94                 raise errors.AnsibleModuleError(
95                     FAIL_MSG.format(ALLOWED_DIRS_STRING,
96                                     ALLOWED_DIRS_STRING,
97                                     item, MIGRATED_ITEMS))
98 
99 
100 # pylint: disable=R0903
101 class ActionModule(ActionBase):
102     """Action plugin to validate no files are needed by master that reside
103     outside of /etc/origin/master as masters will now run as pods and cannot
104     utilize files outside of that path as they will not be mounted inside the
105     containers."""
106     def run(self, tmp=None, task_vars=None):
107         """Run this action module"""
108         result = super(ActionModule, self).run(tmp, task_vars)
109 
110         # self.task_vars holds all in-scope variables.
111         # Ignore settting self.task_vars outside of init.
112         # pylint: disable=W0201
113         self.task_vars = task_vars or {}
114 
115         # mastercfg should be a dictionary from scraping an existing master's
116         # config yaml file.
117         mastercfg = self._task.args.get('mastercfg')
118 
119         # We migrate some paths for users automatically, so we pop those.
120         pop_migrated_fields(mastercfg)
121 
122         # Create an empty list to append strings from our config file to to check
123         # later.
124         strings_to_check = []
125 
126         walk_mapping(mastercfg, strings_to_check)
127 
128         check_strings(strings_to_check)
129 
130         result["changed"] = False
131         result["failed"] = False
132         result["msg"] = "Aight, configs looking good"
133         return result
134
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/roles/lib_utils/action_plugins/master_check_paths_in_config.py b/roles/lib_utils/action_plugins/master_check_paths_in_config.py
--- a/roles/lib_utils/action_plugins/master_check_paths_in_config.py
+++ b/roles/lib_utils/action_plugins/master_check_paths_in_config.py
@@ -22,6 +22,7 @@
 
 
 ITEMS_TO_POP = (
+    ('auditConfig', 'policyConfiguration'),
     ('oauthConfig', 'identityProviders'),
 )
 # Create csv string of dot-separated dictionary keys:
@@ -45,12 +46,19 @@
     """Some fields do not need to be searched because they will be migrated
     for users automatically"""
     # Walk down the tree and pop the specific item we migrate / don't care about
-    for item in ITEMS_TO_POP:
-        field = mastercfg
-        for sub_field in item:
-            parent_field = field
-            field = field[sub_field]
-        parent_field.pop(item[len(item) - 1])
+    for field_path in ITEMS_TO_POP:
+        pop_migrated_field(mastercfg, field_path)
+
+
+def pop_migrated_field(mastercfg, field_path):
+    """Remove field at given path from config"""
+    field = mastercfg
+    for sub_field in field_path:
+        parent_field = field
+        if sub_field not in field:
+            return
+        field = field[sub_field]
+    parent_field.pop(field_path[-1])
 
 
 def do_item_check(val, strings_to_check):

{"golden_diff": "diff --git a/roles/lib_utils/action_plugins/master_check_paths_in_config.py b/roles/lib_utils/action_plugins/master_check_paths_in_config.py\n--- a/roles/lib_utils/action_plugins/master_check_paths_in_config.py\n+++ b/roles/lib_utils/action_plugins/master_check_paths_in_config.py\n@@ -22,6 +22,7 @@\n \n \n ITEMS_TO_POP = (\n+    ('auditConfig', 'policyConfiguration'),\n     ('oauthConfig', 'identityProviders'),\n )\n # Create csv string of dot-separated dictionary keys:\n@@ -45,12 +46,19 @@\n     \"\"\"Some fields do not need to be searched because they will be migrated\n     for users automatically\"\"\"\n     # Walk down the tree and pop the specific item we migrate / don't care about\n-    for item in ITEMS_TO_POP:\n-        field = mastercfg\n-        for sub_field in item:\n-            parent_field = field\n-            field = field[sub_field]\n-        parent_field.pop(item[len(item) - 1])\n+    for field_path in ITEMS_TO_POP:\n+        pop_migrated_field(mastercfg, field_path)\n+\n+\n+def pop_migrated_field(mastercfg, field_path):\n+    \"\"\"Remove field at given path from config\"\"\"\n+    field = mastercfg\n+    for sub_field in field_path:\n+        parent_field = field\n+        if sub_field not in field:\n+            return\n+        field = field[sub_field]\n+    parent_field.pop(field_path[-1])\n \n \n def do_item_check(val, strings_to_check):\n", "issue": "Check for file paths outside of /etc/origin/master in master's config fails on auditConfig.policyConfiguratio\n#### Description\r\n\r\nThe openshift_control_plane \"Check for file paths outside of /etc/origin/master in master's config\" fails on auditConfig policyConfiguration that includes nonResourceURLs specifications by interpreting these as file paths.\r\n\r\n##### Version\r\n\r\n\r\n\r\n```\r\nansible 2.7.5\r\n  config file = /home/ansible/openshift-provision-demo/ansible.cfg\r\n  configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']\r\n  ansible python module location = /usr/lib/python2.7/site-packages/ansible\r\n  executable location = /usr/bin/ansible\r\n  python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]\r\n$ git describe \r\nopenshift-ansible-3.11.69-1-4-g0964a5f\r\n```\r\n\r\n##### Steps To Reproduce\r\n\r\n1. Start with a master with /etc/origin/master/master-config.yaml containing:\r\n\r\n```\r\nauditConfig:\r\n  auditFilePath: /var/log/origin/audit.log\r\n  enabled: true\r\n  logFormat: json\r\n  policyConfiguration:\r\n    apiVersion: audit.k8s.io/v1beta1\r\n    omitStages:\r\n    - RequestReceived\r\n    rules:\r\n    - level: Metadata\r\n      nonResourceURLs:\r\n      - /login*\r\n      - /oauth*\r\n```\r\n\r\n2. Run openshift-ansible deploy\r\n\r\n##### Expected Results\r\n\r\nThis check should not choke on the auditConfig policyConfiguration.\r\n\r\n##### Observed Results\r\n\r\n```\r\nTASK [openshift_control_plane : Check for file paths outside of /etc/origin/master in master's config] ************************************************************************************************************\r\nfatal: [demo-sbx-okd-v3-11-master-0.c.openshift-provision.internal]: FAILED! => {\"msg\": \"A string value that appears to be a file path located outside of\\n/dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin has been found in /etc/origin/master/master-config.yaml.\\nIn 3.10 and newer, all files needed by the master must reside inside of\\nthose directories or a subdirectory or it will not be readable by the\\nmaster process. Please migrate all files needed by the master into\\none of /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin or a subdirectory and update your master configs before\\nproceeding. The string found was: /login*\\n***********************\\nNOTE: the following items do not need to be migrated, they will be migrated\\nfor you: oauthConfig.identityProviders\"}\r\n\r\nNO MORE HOSTS LEFT ************************************************************************************************************************************************************************************************\r\n\tto retry, use: --limit @/home/ansible/openshift-provision-demo/provision-cluster/bootstrap.retry\r\n\r\nPLAY RECAP ********************************************************************************************************************************************************************************************************\r\ndemo-sbx-okd-v3-11-image.c.openshift-provision.internal : ok=25   changed=0    unreachable=0    failed=0   \r\ndemo-sbx-okd-v3-11-master-0.c.openshift-provision.internal : ok=28   changed=0    unreachable=0    failed=1   \r\nlocalhost                  : ok=59   changed=0    unreachable=0    failed=0   \r\n\r\n\r\nINSTALLER STATUS **************************************************************************************************************************************************************************************************\r\nInitialization  : In Progress (0:00:07)\r\n\r\n\r\nFailure summary:\r\n\r\n\r\n  1. Hosts:    demo-sbx-okd-v3-11-master-0.c.openshift-provision.internal\r\n     Play:     Retrieve existing master configs and validate\r\n     Task:     Check for file paths outside of /etc/origin/master in master's config\r\n     Message:  A string value that appears to be a file path located outside of\r\n               /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin has been found in /etc/origin/master/master-config.yaml.\r\n               In 3.10 and newer, all files needed by the master must reside inside of\r\n               those directories or a subdirectory or it will not be readable by the\r\n               master process. Please migrate all files needed by the master into\r\n               one of /dev/null, /etc/origin/master/, /var/lib/origin, /etc/origin/cloudprovider, /etc/origin/kubelet-plugins, /usr/libexec/kubernetes/kubelet-plugins, /var/log/origin or a subdirectory and update your master configs before\r\n               proceeding. The string found was: /login*\r\n               ***********************\r\n               NOTE: the following items do not need to be migrated, they will be migrated\r\n               for you: oauthConfig.identityProviders\r\n```\r\n\r\n##### Additional Information\r\n\r\nThis has behavior has been observed with OKD 3.11 and OCP 3.11 deployments.\n", "before_files": [{"content": "\"\"\"\nAnsible action plugin to ensure inventory variables are set\nappropriately and no conflicting options have been provided.\n\"\"\"\nimport collections\nimport six\n\nfrom ansible.plugins.action import ActionBase\nfrom ansible import errors\n\n\nFAIL_MSG = \"\"\"A string value that appears to be a file path located outside of\n{} has been found in /etc/origin/master/master-config.yaml.\nIn 3.10 and newer, all files needed by the master must reside inside of\nthose directories or a subdirectory or it will not be readable by the\nmaster process. Please migrate all files needed by the master into\none of {} or a subdirectory and update your master configs before\nproceeding. The string found was: {}\n***********************\nNOTE: the following items do not need to be migrated, they will be migrated\nfor you: {}\"\"\"\n\n\nITEMS_TO_POP = (\n    ('oauthConfig', 'identityProviders'),\n)\n# Create csv string of dot-separated dictionary keys:\n# eg: 'oathConfig.identityProviders, something.else.here'\nMIGRATED_ITEMS = \", \".join([\".\".join(x) for x in ITEMS_TO_POP])\n\nALLOWED_DIRS = (\n    '/dev/null',\n    '/etc/origin/master/',\n    '/var/lib/origin',\n    '/etc/origin/cloudprovider',\n    '/etc/origin/kubelet-plugins',\n    '/usr/libexec/kubernetes/kubelet-plugins',\n    '/var/log/origin',\n)\n\nALLOWED_DIRS_STRING = ', '.join(ALLOWED_DIRS)\n\n\ndef pop_migrated_fields(mastercfg):\n    \"\"\"Some fields do not need to be searched because they will be migrated\n    for users automatically\"\"\"\n    # Walk down the tree and pop the specific item we migrate / don't care about\n    for item in ITEMS_TO_POP:\n        field = mastercfg\n        for sub_field in item:\n            parent_field = field\n            field = field[sub_field]\n        parent_field.pop(item[len(item) - 1])\n\n\ndef do_item_check(val, strings_to_check):\n    \"\"\"Check type of val, append to strings_to_check if string, otherwise if\n    it's a dictionary-like object call walk_mapping, if it's a list-like\n    object call walk_sequence, else ignore.\"\"\"\n    if isinstance(val, six.string_types):\n        strings_to_check.append(val)\n    elif isinstance(val, collections.Sequence):\n        # A list-like object\n        walk_sequence(val, strings_to_check)\n    elif isinstance(val, collections.Mapping):\n        # A dictionary-like object\n        walk_mapping(val, strings_to_check)\n    # If it's not a string, list, or dictionary, we're not interested.\n\n\ndef walk_sequence(items, strings_to_check):\n    \"\"\"Walk recursively through a list, items\"\"\"\n    for item in items:\n        do_item_check(item, strings_to_check)\n\n\ndef walk_mapping(map_to_walk, strings_to_check):\n    \"\"\"Walk recursively through map_to_walk dictionary and add strings to\n    strings_to_check\"\"\"\n    for _, val in map_to_walk.items():\n        do_item_check(val, strings_to_check)\n\n\ndef check_strings(strings_to_check):\n    \"\"\"Check the strings we found to see if they look like file paths and if\n    they are, fail if not start with /etc/origin/master\"\"\"\n    for item in strings_to_check:\n        if item.startswith('/') or item.startswith('../'):\n            matches = 0\n            for allowed in ALLOWED_DIRS:\n                if item.startswith(allowed):\n                    matches += 1\n            if matches == 0:\n                raise errors.AnsibleModuleError(\n                    FAIL_MSG.format(ALLOWED_DIRS_STRING,\n                                    ALLOWED_DIRS_STRING,\n                                    item, MIGRATED_ITEMS))\n\n\n# pylint: disable=R0903\nclass ActionModule(ActionBase):\n    \"\"\"Action plugin to validate no files are needed by master that reside\n    outside of /etc/origin/master as masters will now run as pods and cannot\n    utilize files outside of that path as they will not be mounted inside the\n    containers.\"\"\"\n    def run(self, tmp=None, task_vars=None):\n        \"\"\"Run this action module\"\"\"\n        result = super(ActionModule, self).run(tmp, task_vars)\n\n        # self.task_vars holds all in-scope variables.\n        # Ignore settting self.task_vars outside of init.\n        # pylint: disable=W0201\n        self.task_vars = task_vars or {}\n\n        # mastercfg should be a dictionary from scraping an existing master's\n        # config yaml file.\n        mastercfg = self._task.args.get('mastercfg')\n\n        # We migrate some paths for users automatically, so we pop those.\n        pop_migrated_fields(mastercfg)\n\n        # Create an empty list to append strings from our config file to to check\n        # later.\n        strings_to_check = []\n\n        walk_mapping(mastercfg, strings_to_check)\n\n        check_strings(strings_to_check)\n\n        result[\"changed\"] = False\n        result[\"failed\"] = False\n        result[\"msg\"] = \"Aight, configs looking good\"\n        return result\n", "path": "roles/lib_utils/action_plugins/master_check_paths_in_config.py"}], "after_files": [{"content": "\"\"\"\nAnsible action plugin to ensure inventory variables are set\nappropriately and no conflicting options have been provided.\n\"\"\"\nimport collections\nimport six\n\nfrom ansible.plugins.action import ActionBase\nfrom ansible import errors\n\n\nFAIL_MSG = \"\"\"A string value that appears to be a file path located outside of\n{} has been found in /etc/origin/master/master-config.yaml.\nIn 3.10 and newer, all files needed by the master must reside inside of\nthose directories or a subdirectory or it will not be readable by the\nmaster process. Please migrate all files needed by the master into\none of {} or a subdirectory and update your master configs before\nproceeding. The string found was: {}\n***********************\nNOTE: the following items do not need to be migrated, they will be migrated\nfor you: {}\"\"\"\n\n\nITEMS_TO_POP = (\n    ('auditConfig', 'policyConfiguration'),\n    ('oauthConfig', 'identityProviders'),\n)\n# Create csv string of dot-separated dictionary keys:\n# eg: 'oathConfig.identityProviders, something.else.here'\nMIGRATED_ITEMS = \", \".join([\".\".join(x) for x in ITEMS_TO_POP])\n\nALLOWED_DIRS = (\n    '/dev/null',\n    '/etc/origin/master/',\n    '/var/lib/origin',\n    '/etc/origin/cloudprovider',\n    '/etc/origin/kubelet-plugins',\n    '/usr/libexec/kubernetes/kubelet-plugins',\n    '/var/log/origin',\n)\n\nALLOWED_DIRS_STRING = ', '.join(ALLOWED_DIRS)\n\n\ndef pop_migrated_fields(mastercfg):\n    \"\"\"Some fields do not need to be searched because they will be migrated\n    for users automatically\"\"\"\n    # Walk down the tree and pop the specific item we migrate / don't care about\n    for field_path in ITEMS_TO_POP:\n        pop_migrated_field(mastercfg, field_path)\n\n\ndef pop_migrated_field(mastercfg, field_path):\n    \"\"\"Remove field at given path from config\"\"\"\n    field = mastercfg\n    for sub_field in field_path:\n        parent_field = field\n        if sub_field not in field:\n            return\n        field = field[sub_field]\n    parent_field.pop(field_path[-1])\n\n\ndef do_item_check(val, strings_to_check):\n    \"\"\"Check type of val, append to strings_to_check if string, otherwise if\n    it's a dictionary-like object call walk_mapping, if it's a list-like\n    object call walk_sequence, else ignore.\"\"\"\n    if isinstance(val, six.string_types):\n        strings_to_check.append(val)\n    elif isinstance(val, collections.Sequence):\n        # A list-like object\n        walk_sequence(val, strings_to_check)\n    elif isinstance(val, collections.Mapping):\n        # A dictionary-like object\n        walk_mapping(val, strings_to_check)\n    # If it's not a string, list, or dictionary, we're not interested.\n\n\ndef walk_sequence(items, strings_to_check):\n    \"\"\"Walk recursively through a list, items\"\"\"\n    for item in items:\n        do_item_check(item, strings_to_check)\n\n\ndef walk_mapping(map_to_walk, strings_to_check):\n    \"\"\"Walk recursively through map_to_walk dictionary and add strings to\n    strings_to_check\"\"\"\n    for _, val in map_to_walk.items():\n        do_item_check(val, strings_to_check)\n\n\ndef check_strings(strings_to_check):\n    \"\"\"Check the strings we found to see if they look like file paths and if\n    they are, fail if not start with /etc/origin/master\"\"\"\n    for item in strings_to_check:\n        if item.startswith('/') or item.startswith('../'):\n            matches = 0\n            for allowed in ALLOWED_DIRS:\n                if item.startswith(allowed):\n                    matches += 1\n            if matches == 0:\n                raise errors.AnsibleModuleError(\n                    FAIL_MSG.format(ALLOWED_DIRS_STRING,\n                                    ALLOWED_DIRS_STRING,\n                                    item, MIGRATED_ITEMS))\n\n\n# pylint: disable=R0903\nclass ActionModule(ActionBase):\n    \"\"\"Action plugin to validate no files are needed by master that reside\n    outside of /etc/origin/master as masters will now run as pods and cannot\n    utilize files outside of that path as they will not be mounted inside the\n    containers.\"\"\"\n    def run(self, tmp=None, task_vars=None):\n        \"\"\"Run this action module\"\"\"\n        result = super(ActionModule, self).run(tmp, task_vars)\n\n        # self.task_vars holds all in-scope variables.\n        # Ignore settting self.task_vars outside of init.\n        # pylint: disable=W0201\n        self.task_vars = task_vars or {}\n\n        # mastercfg should be a dictionary from scraping an existing master's\n        # config yaml file.\n        mastercfg = self._task.args.get('mastercfg')\n\n        # We migrate some paths for users automatically, so we pop those.\n        pop_migrated_fields(mastercfg)\n\n        # Create an empty list to append strings from our config file to to check\n        # later.\n        strings_to_check = []\n\n        walk_mapping(mastercfg, strings_to_check)\n\n        check_strings(strings_to_check)\n\n        result[\"changed\"] = False\n        result[\"failed\"] = False\n        result[\"msg\"] = \"Aight, configs looking good\"\n        return result\n", "path": "roles/lib_utils/action_plugins/master_check_paths_in_config.py"}]}