my ansible modules which are stock in pull request
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
7.7KB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # Copyright: (c) 2019, Markus Bergholz (markuman@gmail.com)
  4. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
  5. from __future__ import absolute_import, division, print_function
  6. __metaclass__ = type
  7. ANSIBLE_METADATA = {'metadata_version': '1.1',
  8. 'status': ['preview'],
  9. 'supported_by': 'community'}
  10. DOCUMENTATION = '''
  11. module: gitlab_project_variable
  12. short_description: Creates/updates/deletes GitLab Projects Variables
  13. description:
  14. - When a project variable does not exist, it will be created.
  15. - When a project variable does exist, its value will be updated when the values are different.
  16. - Variables which are untouched in the playbook, but are not untouched in the GitLab project,
  17. they stay untouched (I(purge) is C(false)) or will be deleted (I(purge) is C(true)).
  18. version_added: "2.9"
  19. author:
  20. - "Markus Bergholz (@markuman)"
  21. requirements:
  22. - python >= 2.7
  23. - python-gitlab python module
  24. extends_documentation_fragment:
  25. - auth_basic
  26. options:
  27. state:
  28. description:
  29. - Create or delete project variable.
  30. - Possible values are present and absent.
  31. default: present
  32. type: str
  33. choices: ["present", "absent"]
  34. api_token:
  35. description:
  36. - GitLab access token with API permissions.
  37. required: true
  38. type: str
  39. project:
  40. description:
  41. - The path and name of the project.
  42. required: true
  43. type: str
  44. purge:
  45. description:
  46. - When set to true, all variables which are not untoucheded in the task will be deleted.
  47. default: false
  48. type: bool
  49. vars:
  50. description:
  51. - A list of key value pairs.
  52. default: {}
  53. type: dict
  54. '''
  55. EXAMPLES = '''
  56. - name: Set or update some CI/CD variables
  57. gitlab_project_variable:
  58. api_url: https://gitlab.com
  59. api_token: secret_access_token
  60. project: markuman/dotfiles
  61. purge: false
  62. vars:
  63. ACCESS_KEY_ID: abc123
  64. SECRET_ACCESS_KEY: 321cba
  65. - name: Delete one variable
  66. gitlab_project_variable:
  67. api_url: https://gitlab.com
  68. api_token: secret_access_token
  69. project: markuman/dotfiles
  70. state: absent
  71. vars:
  72. ACCESS_KEY_ID: abc123
  73. '''
  74. RETURN = '''
  75. project_variable:
  76. description: Four lists of the variablenames which were added, updated, removed or exist.
  77. returned: always
  78. type: dict
  79. contains:
  80. added:
  81. description: A list of variables which were created.
  82. returned: always
  83. type: list
  84. sample: "['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']"
  85. untouched:
  86. description: A list of variables which exist.
  87. returned: always
  88. type: list
  89. sample: "['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']"
  90. removed:
  91. description: A list of variables which were deleted.
  92. returned: always
  93. type: list
  94. sample: "['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']"
  95. updated:
  96. description: A list of variables whose values were changed.
  97. returned: always
  98. type: list
  99. sample: "['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']"
  100. '''
  101. import traceback
  102. from ansible.module_utils.basic import AnsibleModule, missing_required_lib
  103. from ansible.module_utils._text import to_native
  104. from ansible.module_utils.api import basic_auth_argument_spec
  105. GITLAB_IMP_ERR = None
  106. try:
  107. import gitlab
  108. HAS_GITLAB_PACKAGE = True
  109. except Exception:
  110. GITLAB_IMP_ERR = traceback.format_exc()
  111. HAS_GITLAB_PACKAGE = False
  112. class GitlabProjectVariables(object):
  113. def __init__(self, module, gitlab_instance):
  114. self.repo = gitlab_instance
  115. self.project = self.get_project(module.params['project'])
  116. self._module = module
  117. def get_project(self, project_name):
  118. return self.repo.projects.get(project_name)
  119. def list_all_project_variables(self):
  120. return self.project.variables.list()
  121. def create_variable(self, key, value):
  122. if self._module.check_mode:
  123. return
  124. return self.project.variables.create({"key": key, "value": value})
  125. def update_variable(self, var, value):
  126. if var.value == value:
  127. return False
  128. if self._module.check_mode:
  129. return True
  130. var.value = value
  131. var.save()
  132. return True
  133. def delete_variable(self, key):
  134. if self._module.check_mode:
  135. return
  136. return self.project.variables.delete(key)
  137. def native_python_main(this_gitlab, purge, var_list, state):
  138. change = False
  139. return_value = dict(added=list(), updated=list(), removed=list(), untouched=list())
  140. gitlab_keys = this_gitlab.list_all_project_variables()
  141. existing_variables = [x.get_id() for x in gitlab_keys]
  142. for key in var_list:
  143. if key in existing_variables:
  144. index = existing_variables.index(key)
  145. existing_variables[index] = None
  146. if state == 'present':
  147. single_change = this_gitlab.update_variable(
  148. gitlab_keys[index], var_list[key])
  149. change = single_change or change
  150. if single_change:
  151. return_value['updated'].append(key)
  152. else:
  153. return_value['untouched'].append(key)
  154. elif state == 'absent':
  155. this_gitlab.delete_variable(key)
  156. change = True
  157. return_value['removed'].append(key)
  158. elif key not in existing_variables and state == 'present':
  159. this_gitlab.create_variable(key, var_list[key])
  160. change = True
  161. return_value['added'].append(key)
  162. existing_variables = list(filter(None, existing_variables))
  163. if purge:
  164. for item in existing_variables:
  165. this_gitlab.delete_variable(item)
  166. change = True
  167. return_value['removed'].append(item)
  168. else:
  169. return_value['untouched'].extend(existing_variables)
  170. return change, return_value
  171. def main():
  172. argument_spec = basic_auth_argument_spec()
  173. argument_spec.update(
  174. api_token=dict(type='str', required=True, no_log=True),
  175. project=dict(type='str', required=True),
  176. purge=dict(type='bool', required=False, default=False),
  177. vars=dict(type='dict', required=False, default=dict()),
  178. state=dict(type='str', default="present", choices=["absent", "present"])
  179. )
  180. module = AnsibleModule(
  181. argument_spec=argument_spec,
  182. mutually_exclusive=[
  183. ['api_username', 'api_token'],
  184. ['api_password', 'api_token'],
  185. ],
  186. required_together=[
  187. ['api_username', 'api_password'],
  188. ],
  189. required_one_of=[
  190. ['api_username', 'api_token']
  191. ],
  192. supports_check_mode=True
  193. )
  194. api_url = module.params['api_url']
  195. gitlab_token = module.params['api_token']
  196. purge = module.params['purge']
  197. var_list = module.params['vars']
  198. state = module.params['state']
  199. if not HAS_GITLAB_PACKAGE:
  200. module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
  201. try:
  202. gitlab_instance = gitlab.Gitlab(url=api_url, private_token=gitlab_token)
  203. gitlab_instance.auth()
  204. except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:
  205. module.fail_json(msg="Failed to connect to GitLab server: %s" % to_native(e))
  206. except (gitlab.exceptions.GitlabHttpError) as e:
  207. module.fail_json(msg="Failed to connect to Gitlab server: %s. \
  208. Gitlab remove Session API now that private tokens are removed from user API endpoints since version 10.2" % to_native(e))
  209. this_gitlab = GitlabProjectVariables(module=module, gitlab_instance=gitlab_instance)
  210. change, return_value = native_python_main(this_gitlab, purge, var_list, state)
  211. module.exit_json(changed=change, project_variable=return_value)
  212. if __name__ == '__main__':
  213. main()