oc_adm_policy_user.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. # pylint: skip-file
  2. # flake8: noqa
  3. class PolicyUserException(Exception):
  4. ''' PolicyUser exception'''
  5. pass
  6. class PolicyUserConfig(OpenShiftCLIConfig):
  7. ''' PolicyUserConfig is a DTO for user related policy. '''
  8. def __init__(self, namespace, kubeconfig, policy_options):
  9. super(PolicyUserConfig, self).__init__(policy_options['name']['value'],
  10. namespace, kubeconfig, policy_options)
  11. self.kind = self.get_kind()
  12. self.namespace = namespace
  13. def get_kind(self):
  14. ''' return the kind we are working with '''
  15. if self.config_options['resource_kind']['value'] == 'role':
  16. return 'rolebinding'
  17. elif self.config_options['resource_kind']['value'] == 'cluster-role':
  18. return 'clusterrolebinding'
  19. elif self.config_options['resource_kind']['value'] == 'scc':
  20. return 'scc'
  21. return None
  22. # pylint: disable=too-many-return-statements
  23. class PolicyUser(OpenShiftCLI):
  24. ''' Class to handle attaching policies to users '''
  25. def __init__(self,
  26. config,
  27. verbose=False):
  28. ''' Constructor for PolicyUser '''
  29. super(PolicyUser, self).__init__(config.namespace, config.kubeconfig, verbose)
  30. self.config = config
  31. self.verbose = verbose
  32. self._rolebinding = None
  33. self._scc = None
  34. self._cluster_role_bindings = None
  35. self._role_bindings = None
  36. @property
  37. def rolebindings(self):
  38. if self._role_bindings is None:
  39. results = self._get('rolebindings', None)
  40. if results['returncode'] != 0:
  41. raise OpenShiftCLIError('Could not retrieve rolebindings')
  42. self._role_bindings = results['results'][0]['items']
  43. return self._role_bindings
  44. @property
  45. def clusterrolebindings(self):
  46. if self._cluster_role_bindings is None:
  47. results = self._get('clusterrolebindings', None)
  48. if results['returncode'] != 0:
  49. raise OpenShiftCLIError('Could not retrieve clusterrolebindings')
  50. self._cluster_role_bindings = results['results'][0]['items']
  51. return self._cluster_role_bindings
  52. @property
  53. def role_binding(self):
  54. ''' role_binding property '''
  55. return self._rolebinding
  56. @role_binding.setter
  57. def role_binding(self, binding):
  58. ''' setter for role_binding property '''
  59. self._rolebinding = binding
  60. @property
  61. def security_context_constraint(self):
  62. ''' security_context_constraint property '''
  63. return self._scc
  64. @security_context_constraint.setter
  65. def security_context_constraint(self, scc):
  66. ''' setter for security_context_constraint property '''
  67. self._scc = scc
  68. def get(self):
  69. '''fetch the desired kind
  70. This is only used for scc objects.
  71. The {cluster}rolebindings happen in exists.
  72. '''
  73. resource_name = self.config.config_options['name']['value']
  74. if resource_name == 'cluster-reader':
  75. resource_name += 's'
  76. return self._get(self.config.kind, resource_name)
  77. def exists_role_binding(self):
  78. ''' return whether role_binding exists '''
  79. bindings = None
  80. if self.config.config_options['resource_kind']['value'] == 'cluster-role':
  81. bindings = self.clusterrolebindings
  82. else:
  83. bindings = self.rolebindings
  84. if bindings is None:
  85. return False
  86. for binding in bindings:
  87. if binding['roleRef']['name'] == self.config.config_options['name']['value'] and \
  88. binding['userNames'] is not None and \
  89. self.config.config_options['user']['value'] in binding['userNames']:
  90. self.role_binding = binding
  91. return True
  92. return False
  93. def exists_scc(self):
  94. ''' return whether scc exists '''
  95. results = self.get()
  96. if results['returncode'] == 0:
  97. self.security_context_constraint = SecurityContextConstraints(results['results'][0])
  98. if self.security_context_constraint.find_user(self.config.config_options['user']['value']) != None:
  99. return True
  100. return False
  101. return results
  102. def exists(self):
  103. '''does the object exist?'''
  104. if self.config.config_options['resource_kind']['value'] == 'cluster-role':
  105. return self.exists_role_binding()
  106. elif self.config.config_options['resource_kind']['value'] == 'role':
  107. return self.exists_role_binding()
  108. elif self.config.config_options['resource_kind']['value'] == 'scc':
  109. return self.exists_scc()
  110. return False
  111. def perform(self):
  112. '''perform action on resource'''
  113. cmd = ['policy',
  114. self.config.config_options['action']['value'],
  115. self.config.config_options['name']['value'],
  116. self.config.config_options['user']['value']]
  117. if self.config.config_options['role_namespace']['value'] is not None:
  118. cmd.extend(['--role-namespace', self.config.config_options['role_namespace']['value']])
  119. return self.openshift_cmd(cmd, oadm=True)
  120. @staticmethod
  121. def run_ansible(params, check_mode):
  122. '''run the idempotent ansible code'''
  123. state = params['state']
  124. action = None
  125. if state == 'present':
  126. action = 'add-' + params['resource_kind'] + '-to-user'
  127. else:
  128. action = 'remove-' + params['resource_kind'] + '-from-user'
  129. nconfig = PolicyUserConfig(params['namespace'],
  130. params['kubeconfig'],
  131. {'action': {'value': action, 'include': False},
  132. 'user': {'value': params['user'], 'include': False},
  133. 'resource_kind': {'value': params['resource_kind'], 'include': False},
  134. 'name': {'value': params['resource_name'], 'include': False},
  135. 'role_namespace': {'value': params['role_namespace'], 'include': False},
  136. })
  137. policyuser = PolicyUser(nconfig, params['debug'])
  138. # Run the oc adm policy user related command
  139. ########
  140. # Delete
  141. ########
  142. if state == 'absent':
  143. if not policyuser.exists():
  144. return {'changed': False, 'state': 'absent'}
  145. if check_mode:
  146. return {'changed': False, 'msg': 'CHECK_MODE: would have performed a delete.'}
  147. api_rval = policyuser.perform()
  148. if api_rval['returncode'] != 0:
  149. return {'msg': api_rval}
  150. return {'changed': True, 'results' : api_rval, state:'absent'}
  151. if state == 'present':
  152. ########
  153. # Create
  154. ########
  155. results = policyuser.exists()
  156. if isinstance(results, dict) and 'returncode' in results and results['returncode'] != 0:
  157. return {'msg': results}
  158. if not results:
  159. if check_mode:
  160. return {'changed': False, 'msg': 'CHECK_MODE: would have performed a create.'}
  161. api_rval = policyuser.perform()
  162. if api_rval['returncode'] != 0:
  163. return {'msg': api_rval}
  164. return {'changed': True, 'results': api_rval, state: 'present'}
  165. return {'changed': False, state: 'present'}
  166. return {'failed': True, 'changed': False, 'results': 'Unknown state passed. %s' % state, state: 'unknown'}