Browse Source

oadm_policy_group/adm_policy_user module

jupierce 8 years ago
parent
commit
5e36d75d47

File diff suppressed because it is too large
+ 2092 - 0
roles/lib_openshift/library/oc_adm_policy_group.py


File diff suppressed because it is too large
+ 2091 - 0
roles/lib_openshift/library/oc_adm_policy_user.py


+ 34 - 0
roles/lib_openshift/src/ansible/oc_adm_policy_group.py

@@ -0,0 +1,34 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+def main():
+    '''
+    ansible oc adm module for group policy
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            state=dict(default='present', type='str',
+                       choices=['present', 'absent']),
+            debug=dict(default=False, type='bool'),
+            resource_name=dict(required=True, type='str'),
+            namespace=dict(default='default', type='str'),
+            kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+
+            group=dict(required=True, type='str'),
+            resource_kind=dict(required=True, choices=['role', 'cluster-role', 'scc'], type='str'),
+        ),
+        supports_check_mode=True,
+    )
+
+    results = PolicyGroup.run_ansible(module.params, module.check_mode)
+
+    if 'failed' in results:
+        module.fail_json(**results)
+
+    module.exit_json(**results)
+
+
+if __name__ == "__main__":
+    main()

+ 34 - 0
roles/lib_openshift/src/ansible/oc_adm_policy_user.py

@@ -0,0 +1,34 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+def main():
+    '''
+    ansible oc adm module for user policy
+    '''
+
+    module = AnsibleModule(
+        argument_spec=dict(
+            state=dict(default='present', type='str',
+                       choices=['present', 'absent']),
+            debug=dict(default=False, type='bool'),
+            resource_name=dict(required=True, type='str'),
+            namespace=dict(default='default', type='str'),
+            kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+
+            user=dict(required=True, type='str'),
+            resource_kind=dict(required=True, choices=['role', 'cluster-role', 'scc'], type='str'),
+        ),
+        supports_check_mode=True,
+    )
+
+    results = PolicyUser.run_ansible(module.params, module.check_mode)
+
+    if 'failed' in results:
+        module.fail_json(**results)
+
+    module.exit_json(**results)
+
+
+if __name__ == "__main__":
+    main()

+ 195 - 0
roles/lib_openshift/src/class/oc_adm_policy_group.py

@@ -0,0 +1,195 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+class PolicyGroupException(Exception):
+    ''' PolicyGroup exception'''
+    pass
+
+
+class PolicyGroupConfig(OpenShiftCLIConfig):
+    ''' PolicyGroupConfig is a DTO for group related policy.  '''
+    def __init__(self, namespace, kubeconfig, policy_options):
+        super(PolicyGroupConfig, self).__init__(policy_options['name']['value'],
+                                                namespace, kubeconfig, policy_options)
+        self.kind = self.get_kind()
+        self.namespace = namespace
+
+    def get_kind(self):
+        ''' return the kind we are working with '''
+        if self.config_options['resource_kind']['value'] == 'role':
+            return 'rolebinding'
+        elif self.config_options['resource_kind']['value'] == 'cluster-role':
+            return 'clusterrolebinding'
+        elif self.config_options['resource_kind']['value'] == 'scc':
+            return 'scc'
+
+        return None
+
+
+# pylint: disable=too-many-return-statements
+class PolicyGroup(OpenShiftCLI):
+    ''' Class to handle attaching policies to users '''
+
+
+    def __init__(self,
+                 config,
+                 verbose=False):
+        ''' Constructor for PolicyGroup '''
+        super(PolicyGroup, self).__init__(config.namespace, config.kubeconfig, verbose)
+        self.config = config
+        self.verbose = verbose
+        self._rolebinding = None
+        self._scc = None
+
+    @property
+    def role_binding(self):
+        ''' role_binding getter '''
+        return self._rolebinding
+
+    @role_binding.setter
+    def role_binding(self, binding):
+        ''' role_binding setter '''
+        self._rolebinding = binding
+
+    @property
+    def security_context_constraint(self):
+        ''' security_context_constraint getter '''
+        return self._scc
+
+    @security_context_constraint.setter
+    def security_context_constraint(self, scc):
+        ''' security_context_constraint setter '''
+        self._scc = scc
+
+    def get(self):
+        '''fetch the desired kind'''
+        resource_name = self.config.config_options['name']['value']
+        if resource_name == 'cluster-reader':
+            resource_name += 's'
+
+        # oc adm policy add-... creates policy bindings with the name
+        # "[resource_name]-binding", however some bindings in the system
+        # simply use "[resource_name]". So try both.
+
+        results = self._get(self.config.kind, resource_name)
+        if results['returncode'] == 0:
+            return results
+
+        # Now try -binding naming convention
+        return self._get(self.config.kind, resource_name + "-binding")
+
+    def exists_role_binding(self):
+        ''' return whether role_binding exists '''
+        results = self.get()
+        if results['returncode'] == 0:
+            self.role_binding = RoleBinding(results['results'][0])
+            if self.role_binding.find_group_name(self.config.config_options['group']['value']) != None:
+                return True
+
+            return False
+
+        elif '\"%s\" not found' % self.config.config_options['name']['value'] in results['stderr']:
+            return False
+
+        return results
+
+    def exists_scc(self):
+        ''' return whether scc exists '''
+        results = self.get()
+        if results['returncode'] == 0:
+            self.security_context_constraint = SecurityContextConstraints(results['results'][0])
+
+            if self.security_context_constraint.find_group(self.config.config_options['group']['value']) != None:
+                return True
+
+            return False
+
+        return results
+
+    def exists(self):
+        '''does the object exist?'''
+        if self.config.config_options['resource_kind']['value'] == 'cluster-role':
+            return self.exists_role_binding()
+
+        elif self.config.config_options['resource_kind']['value'] == 'role':
+            return self.exists_role_binding()
+
+        elif self.config.config_options['resource_kind']['value'] == 'scc':
+            return self.exists_scc()
+
+        return False
+
+    def perform(self):
+        '''perform action on resource'''
+        cmd = ['policy',
+               self.config.config_options['action']['value'],
+               self.config.config_options['name']['value'],
+               self.config.config_options['group']['value']]
+
+        return self.openshift_cmd(cmd, oadm=True)
+
+    @staticmethod
+    def run_ansible(params, check_mode):
+        '''run the idempotent ansible code'''
+
+        state = params['state']
+
+        action = None
+        if state == 'present':
+            action = 'add-' + params['resource_kind'] + '-to-group'
+        else:
+            action = 'remove-' + params['resource_kind'] + '-from-group'
+
+        nconfig = PolicyGroupConfig(params['namespace'],
+                                    params['kubeconfig'],
+                                    {'action': {'value': action, 'include': False},
+                                     'group': {'value': params['group'], 'include': False},
+                                     'resource_kind': {'value': params['resource_kind'], 'include': False},
+                                     'name': {'value': params['resource_name'], 'include': False},
+                                    })
+
+        policygroup = PolicyGroup(nconfig, params['debug'])
+
+        # Run the oc adm policy group related command
+
+        ########
+        # Delete
+        ########
+        if state == 'absent':
+            if not policygroup.exists():
+                return {'changed': False, 'state': 'absent'}
+
+            if check_mode:
+                return {'changed': False, 'msg': 'CHECK_MODE: would have performed a delete.'}
+
+            api_rval = policygroup.perform()
+
+            if api_rval['returncode'] != 0:
+                return {'msg': api_rval}
+
+            return {'changed': True, 'results' : api_rval, state:'absent'}
+
+        if state == 'present':
+            ########
+            # Create
+            ########
+            results = policygroup.exists()
+            if isinstance(results, dict) and 'returncode' in results and results['returncode'] != 0:
+                return {'msg': results}
+
+            if not results:
+
+                if check_mode:
+                    return {'changed': False, 'msg': 'CHECK_MODE: would have performed a create.'}
+
+                api_rval = policygroup.perform()
+
+                if api_rval['returncode'] != 0:
+                    return {'msg': api_rval}
+
+                return {'changed': True, 'results': api_rval, state: 'present'}
+
+            return {'changed': False, state: 'present'}
+
+        return {'failed': True, 'changed': False, 'results': 'Unknown state passed. %s' % state, state: 'unknown'}

+ 194 - 0
roles/lib_openshift/src/class/oc_adm_policy_user.py

@@ -0,0 +1,194 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+class PolicyUserException(Exception):
+    ''' PolicyUser exception'''
+    pass
+
+
+class PolicyUserConfig(OpenShiftCLIConfig):
+    ''' PolicyUserConfig is a DTO for user related policy.  '''
+    def __init__(self, namespace, kubeconfig, policy_options):
+        super(PolicyUserConfig, self).__init__(policy_options['name']['value'],
+                                               namespace, kubeconfig, policy_options)
+        self.kind = self.get_kind()
+        self.namespace = namespace
+
+    def get_kind(self):
+        ''' return the kind we are working with '''
+        if self.config_options['resource_kind']['value'] == 'role':
+            return 'rolebinding'
+        elif self.config_options['resource_kind']['value'] == 'cluster-role':
+            return 'clusterrolebinding'
+        elif self.config_options['resource_kind']['value'] == 'scc':
+            return 'scc'
+
+        return None
+
+
+# pylint: disable=too-many-return-statements
+class PolicyUser(OpenShiftCLI):
+    ''' Class to handle attaching policies to users '''
+
+    def __init__(self,
+                 policy_config,
+                 verbose=False):
+        ''' Constructor for PolicyUser '''
+        super(PolicyUser, self).__init__(policy_config.namespace, policy_config.kubeconfig, verbose)
+        self.config = policy_config
+        self.verbose = verbose
+        self._rolebinding = None
+        self._scc = None
+
+    @property
+    def role_binding(self):
+        ''' role_binding property '''
+        return self._rolebinding
+
+    @role_binding.setter
+    def role_binding(self, binding):
+        ''' setter for role_binding property '''
+        self._rolebinding = binding
+
+    @property
+    def security_context_constraint(self):
+        ''' security_context_constraint property '''
+        return self._scc
+
+    @security_context_constraint.setter
+    def security_context_constraint(self, scc):
+        ''' setter for security_context_constraint property '''
+        self._scc = scc
+
+    def get(self):
+        '''fetch the desired kind'''
+        resource_name = self.config.config_options['name']['value']
+        if resource_name == 'cluster-reader':
+            resource_name += 's'
+
+        # oc adm policy add-... creates policy bindings with the name
+        # "[resource_name]-binding", however some bindings in the system
+        # simply use "[resource_name]". So try both.
+
+        results = self._get(self.config.kind, resource_name)
+        if results['returncode'] == 0:
+            return results
+
+        # Now try -binding naming convention
+        return self._get(self.config.kind, resource_name + "-binding")
+
+    def exists_role_binding(self):
+        ''' return whether role_binding exists '''
+        results = self.get()
+        if results['returncode'] == 0:
+            self.role_binding = RoleBinding(results['results'][0])
+            if self.role_binding.find_user_name(self.config.config_options['user']['value']) != None:
+                return True
+
+            return False
+
+        elif '\"%s\" not found' % self.config.config_options['name']['value'] in results['stderr']:
+            return False
+
+        return results
+
+    def exists_scc(self):
+        ''' return whether scc exists '''
+        results = self.get()
+        if results['returncode'] == 0:
+            self.security_context_constraint = SecurityContextConstraints(results['results'][0])
+
+            if self.security_context_constraint.find_user(self.config.config_options['user']['value']) != None:
+                return True
+
+            return False
+
+        return results
+
+    def exists(self):
+        '''does the object exist?'''
+        if self.config.config_options['resource_kind']['value'] == 'cluster-role':
+            return self.exists_role_binding()
+
+        elif self.config.config_options['resource_kind']['value'] == 'role':
+            return self.exists_role_binding()
+
+        elif self.config.config_options['resource_kind']['value'] == 'scc':
+            return self.exists_scc()
+
+        return False
+
+    def perform(self):
+        '''perform action on resource'''
+        cmd = ['policy',
+               self.config.config_options['action']['value'],
+               self.config.config_options['name']['value'],
+               self.config.config_options['user']['value']]
+
+        return self.openshift_cmd(cmd, oadm=True)
+
+    @staticmethod
+    def run_ansible(params, check_mode):
+        '''run the idempotent ansible code'''
+
+        state = params['state']
+
+        action = None
+        if state == 'present':
+            action = 'add-' + params['resource_kind'] + '-to-user'
+        else:
+            action = 'remove-' + params['resource_kind'] + '-from-user'
+
+        nconfig = PolicyUserConfig(params['namespace'],
+                                   params['kubeconfig'],
+                                   {'action': {'value': action, 'include': False},
+                                    'user': {'value': params['user'], 'include': False},
+                                    'resource_kind': {'value': params['resource_kind'], 'include': False},
+                                    'name': {'value': params['resource_name'], 'include': False},
+                                   })
+
+        policyuser = PolicyUser(nconfig, params['debug'])
+
+        # Run the oc adm policy user related command
+
+        ########
+        # Delete
+        ########
+        if state == 'absent':
+            if not policyuser.exists():
+                return {'changed': False, 'state': 'absent'}
+
+            if check_mode:
+                return {'changed': False, 'msg': 'CHECK_MODE: would have performed a delete.'}
+
+            api_rval = policyuser.perform()
+
+            if api_rval['returncode'] != 0:
+                return {'msg': api_rval}
+
+            return {'changed': True, 'results' : api_rval, state:'absent'}
+
+        if state == 'present':
+            ########
+            # Create
+            ########
+            results = policyuser.exists()
+            if isinstance(results, dict) and 'returncode' in results and results['returncode'] != 0:
+                return {'msg': results}
+
+            if not results:
+
+                if check_mode:
+                    return {'changed': False, 'msg': 'CHECK_MODE: would have performed a create.'}
+
+                api_rval = policyuser.perform()
+
+                if api_rval['returncode'] != 0:
+                    return {'msg': api_rval}
+
+                return {'changed': True, 'results': api_rval, state: 'present'}
+
+            return {'changed': False, state: 'present'}
+
+        return {'failed': True, 'changed': False, 'results': 'Unknown state passed. %s' % state, state: 'unknown'}

+ 74 - 0
roles/lib_openshift/src/doc/policy_group

@@ -0,0 +1,74 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_adm_policy_group
+short_description: Module to manage openshift policy for groups
+description:
+  - Manage openshift policy for groups.
+options:
+  kubeconfig:
+    description:
+    - The path for the kubeconfig file to use for authentication
+    required: false
+    default: /etc/origin/master/admin.kubeconfig
+    aliases: []
+  namespace:
+    description:
+    - The namespace scope
+    required: false
+    default: None
+    aliases: []
+  debug:
+    description:
+    - Turn on debug output.
+    required: false
+    default: False
+    aliases: []
+  group:
+    description:
+    - The name of the group
+    required: true
+    default: None
+    aliases: []
+  resource_kind:
+    description:
+    - The kind of policy to affect
+    required: true
+    default: None
+    choices: ["role", "cluster-role", "scc"]
+    aliases: []
+  resource_name:
+    description:
+    - The name of the policy
+    required: true
+    default: None
+    aliases: []
+  state:
+    description:
+    - Desired state of the policy
+    required: true
+    default: present
+    choices: ["present", "absent"]
+    aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+- name: oc adm policy remove-scc-from-group an-scc agroup
+  oc_adm_policy_group:
+    group: agroup
+    resource_kind: scc
+    resource_name: an-scc
+    state: absent
+
+- name: oc adm policy add-cluster-role-to-group system:build-strategy-docker agroup
+  oc_adm_policy_group:
+    group: agroup
+    resource_kind: cluster-role
+    resource_name: system:build-strategy-docker
+    state: present
+'''

+ 74 - 0
roles/lib_openshift/src/doc/policy_user

@@ -0,0 +1,74 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_adm_policy_user
+short_description: Module to manage openshift policy for users
+description:
+  - Manage openshift policy for users.
+options:
+  kubeconfig:
+    description:
+    - The path for the kubeconfig file to use for authentication
+    required: false
+    default: /etc/origin/master/admin.kubeconfig
+    aliases: []
+  namespace:
+    description:
+    - The namespace scope
+    required: false
+    default: None
+    aliases: []
+  debug:
+    description:
+    - Turn on debug output.
+    required: false
+    default: False
+    aliases: []
+  user:
+    description:
+    - The name of the user
+    required: true
+    default: None
+    aliases: []
+  resource_kind:
+    description:
+    - The kind of policy to affect
+    required: true
+    default: None
+    choices: ["role", "cluster-role", "scc"]
+    aliases: []
+  resource_name:
+    description:
+    - The name of the policy
+    required: true
+    default: None
+    aliases: []
+  state:
+    description:
+    - Desired state of the policy
+    required: true
+    default: present
+    choices: ["present", "absent"]
+    aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+- name: oc adm policy remove-scc-from-user an-scc ausername
+  oc_adm_policy_user:
+    user: ausername
+    resource_kind: scc
+    resource_name: an-scc
+    state: absent
+
+- name: oc adm policy add-cluster-role-to-user system:build-strategy-docker ausername
+  oc_adm_policy_user:
+    user: ausername
+    resource_kind: cluster-role
+    resource_name: system:build-strategy-docker
+    state: present
+'''

+ 218 - 0
roles/lib_openshift/src/lib/scc.py

@@ -0,0 +1,218 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+# pylint: disable=too-many-instance-attributes
+class SecurityContextConstraintsConfig(object):
+    ''' Handle scc options '''
+    # pylint: disable=too-many-arguments
+    def __init__(self,
+                 sname,
+                 kubeconfig,
+                 options=None,
+                 fs_group='MustRunAs',
+                 default_add_capabilities=None,
+                 groups=None,
+                 priority=None,
+                 required_drop_capabilities=None,
+                 run_as_user='MustRunAsRange',
+                 se_linux_context='MustRunAs',
+                 supplemental_groups='RunAsAny',
+                 users=None,
+                 annotations=None):
+        ''' constructor for handling scc options '''
+        self.kubeconfig = kubeconfig
+        self.name = sname
+        self.options = options
+        self.fs_group = fs_group
+        self.default_add_capabilities = default_add_capabilities
+        self.groups = groups
+        self.priority = priority
+        self.required_drop_capabilities = required_drop_capabilities
+        self.run_as_user = run_as_user
+        self.se_linux_context = se_linux_context
+        self.supplemental_groups = supplemental_groups
+        self.users = users
+        self.annotations = annotations
+        self.data = {}
+
+        self.create_dict()
+
+    def create_dict(self):
+        ''' assign the correct properties for a scc dict '''
+        # allow options
+        if self.options:
+            for key, value in self.options.items():
+                self.data[key] = value
+        else:
+            self.data['allowHostDirVolumePlugin'] = False
+            self.data['allowHostIPC'] = False
+            self.data['allowHostNetwork'] = False
+            self.data['allowHostPID'] = False
+            self.data['allowHostPorts'] = False
+            self.data['allowPrivilegedContainer'] = False
+            self.data['allowedCapabilities'] = None
+
+        # version
+        self.data['apiVersion'] = 'v1'
+        # kind
+        self.data['kind'] = 'SecurityContextConstraints'
+        # defaultAddCapabilities
+        self.data['defaultAddCapabilities'] = self.default_add_capabilities
+        # fsGroup
+        self.data['fsGroup']['type'] = self.fs_group
+        # groups
+        self.data['groups'] = []
+        if self.groups:
+            self.data['groups'] = self.groups
+        # metadata
+        self.data['metadata'] = {}
+        self.data['metadata']['name'] = self.name
+        if self.annotations:
+            for key, value in self.annotations.items():
+                self.data['metadata'][key] = value
+        # priority
+        self.data['priority'] = self.priority
+        # requiredDropCapabilities
+        self.data['requiredDropCapabilities'] = self.required_drop_capabilities
+        # runAsUser
+        self.data['runAsUser'] = {'type': self.run_as_user}
+        # seLinuxContext
+        self.data['seLinuxContext'] = {'type': self.se_linux_context}
+        # supplementalGroups
+        self.data['supplementalGroups'] = {'type': self.supplemental_groups}
+        # users
+        self.data['users'] = []
+        if self.users:
+            self.data['users'] = self.users
+
+
+# pylint: disable=too-many-instance-attributes,too-many-public-methods,no-member
+class SecurityContextConstraints(Yedit):
+    ''' Class to wrap the oc command line tools '''
+    default_add_capabilities_path = "defaultAddCapabilities"
+    fs_group_path = "fsGroup"
+    groups_path = "groups"
+    priority_path = "priority"
+    required_drop_capabilities_path = "requiredDropCapabilities"
+    run_as_user_path = "runAsUser"
+    se_linux_context_path = "seLinuxContext"
+    supplemental_groups_path = "supplementalGroups"
+    users_path = "users"
+    kind = 'SecurityContextConstraints'
+
+    def __init__(self, content):
+        '''SecurityContextConstraints constructor'''
+        super(SecurityContextConstraints, self).__init__(content=content)
+        self._users = None
+        self._groups = None
+
+    @property
+    def users(self):
+        ''' users property getter '''
+        if self._users is None:
+            self._users = self.get_users()
+        return self._users
+
+    @property
+    def groups(self):
+        ''' groups property getter '''
+        if self._groups is None:
+            self._groups = self.get_groups()
+        return self._groups
+
+    @users.setter
+    def users(self, data):
+        ''' users property setter'''
+        self._users = data
+
+    @groups.setter
+    def groups(self, data):
+        ''' groups property setter'''
+        self._groups = data
+
+    def get_users(self):
+        '''get scc users'''
+        return self.get(SecurityContextConstraints.users_path) or []
+
+    def get_groups(self):
+        '''get scc groups'''
+        return self.get(SecurityContextConstraints.groups_path) or []
+
+    def add_user(self, inc_user):
+        ''' add a user '''
+        if self.users:
+            self.users.append(inc_user)
+        else:
+            self.put(SecurityContextConstraints.users_path, [inc_user])
+
+        return True
+
+    def add_group(self, inc_group):
+        ''' add a group '''
+        if self.groups:
+            self.groups.append(inc_group)
+        else:
+            self.put(SecurityContextConstraints.groups_path, [inc_group])
+
+        return True
+
+    def remove_user(self, inc_user):
+        ''' remove a user '''
+        try:
+            self.users.remove(inc_user)
+        except ValueError as _:
+            return False
+
+        return True
+
+    def remove_group(self, inc_group):
+        ''' remove a group '''
+        try:
+            self.groups.remove(inc_group)
+        except ValueError as _:
+            return False
+
+        return True
+
+    def update_user(self, inc_user):
+        ''' update a user '''
+        try:
+            index = self.users.index(inc_user)
+        except ValueError as _:
+            return self.add_user(inc_user)
+
+        self.users[index] = inc_user
+
+        return True
+
+    def update_group(self, inc_group):
+        ''' update a group '''
+        try:
+            index = self.groups.index(inc_group)
+        except ValueError as _:
+            return self.add_group(inc_group)
+
+        self.groups[index] = inc_group
+
+        return True
+
+    def find_user(self, inc_user):
+        ''' find a user '''
+        index = None
+        try:
+            index = self.users.index(inc_user)
+        except ValueError as _:
+            return index
+
+        return index
+
+    def find_group(self, inc_group):
+        ''' find a group '''
+        index = None
+        try:
+            index = self.groups.index(inc_group)
+        except ValueError as _:
+            return index
+
+        return index

+ 24 - 0
roles/lib_openshift/src/sources.yml

@@ -19,6 +19,30 @@ oadm_manage_node.py:
 - class/oadm_manage_node.py
 - ansible/oadm_manage_node.py
 
+oc_adm_policy_user.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/policy_user
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- lib/rolebinding.py
+- lib/scc.py
+- class/oc_adm_policy_user.py
+- ansible/oc_adm_policy_user.py
+
+oc_adm_policy_group.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/policy_group
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- lib/rolebinding.py
+- lib/scc.py
+- class/oc_adm_policy_group.py
+- ansible/oc_adm_policy_group.py
+
 oc_adm_registry.py:
 - doc/generated
 - doc/license