diff options
Diffstat (limited to 'roles/lib_openshift/src')
| -rw-r--r-- | roles/lib_openshift/src/ansible/oc_adm_policy_group.py | 34 | ||||
| -rw-r--r-- | roles/lib_openshift/src/ansible/oc_adm_policy_user.py | 34 | ||||
| -rw-r--r-- | roles/lib_openshift/src/class/oc_adm_policy_group.py | 195 | ||||
| -rw-r--r-- | roles/lib_openshift/src/class/oc_adm_policy_user.py | 194 | ||||
| -rw-r--r-- | roles/lib_openshift/src/doc/policy_group | 74 | ||||
| -rw-r--r-- | roles/lib_openshift/src/doc/policy_user | 74 | ||||
| -rw-r--r-- | roles/lib_openshift/src/lib/scc.py | 218 | ||||
| -rw-r--r-- | roles/lib_openshift/src/sources.yml | 24 | 
8 files changed, 847 insertions, 0 deletions
diff --git a/roles/lib_openshift/src/ansible/oc_adm_policy_group.py b/roles/lib_openshift/src/ansible/oc_adm_policy_group.py new file mode 100644 index 000000000..cf6691b03 --- /dev/null +++ b/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() diff --git a/roles/lib_openshift/src/ansible/oc_adm_policy_user.py b/roles/lib_openshift/src/ansible/oc_adm_policy_user.py new file mode 100644 index 000000000..a22496866 --- /dev/null +++ b/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() diff --git a/roles/lib_openshift/src/class/oc_adm_policy_group.py b/roles/lib_openshift/src/class/oc_adm_policy_group.py new file mode 100644 index 000000000..1d6b2450a --- /dev/null +++ b/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'} diff --git a/roles/lib_openshift/src/class/oc_adm_policy_user.py b/roles/lib_openshift/src/class/oc_adm_policy_user.py new file mode 100644 index 000000000..8d2c5eadf --- /dev/null +++ b/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'} diff --git a/roles/lib_openshift/src/doc/policy_group b/roles/lib_openshift/src/doc/policy_group new file mode 100644 index 000000000..343413269 --- /dev/null +++ b/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 +''' diff --git a/roles/lib_openshift/src/doc/policy_user b/roles/lib_openshift/src/doc/policy_user new file mode 100644 index 000000000..351c9af65 --- /dev/null +++ b/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 +''' diff --git a/roles/lib_openshift/src/lib/scc.py b/roles/lib_openshift/src/lib/scc.py new file mode 100644 index 000000000..3e2aa08d7 --- /dev/null +++ b/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 diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml index a48fdf0c2..a0e200d0a 100644 --- a/roles/lib_openshift/src/sources.yml +++ b/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  | 
