mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
bitbucket: Support Basic Auth (#2045)
* bitbucket: Support Basic Auth
* Rename username to user
* Document user/password options
* Rename username to workspace
* Deprecate username
* Fix credentials_required error_message
* Fix credentials_required error_message
* Test user/password/workspace options and env vars
* Update a test to use user/password/workspace for each module
* Fix check auth arguments
* Use required_one_of/required_together
* Fix required typo
* Fix fetch_access_token
* Fix tests 🤞
* Switch things up in test_bitbucket_access_key
* Fix username/password are None
* Remove username/password properties, use params directly
* Update plugins/doc_fragments/bitbucket.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/module_utils/source_control/bitbucket.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/module_utils/source_control/bitbucket.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/module_utils/source_control/bitbucket.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_access_key.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_key_pair.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_known_host.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_known_host.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_variable.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_variable.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_access_key.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update plugins/modules/source_control/bitbucket/bitbucket_pipeline_key_pair.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Document OAuth/Basic Auth precedence
* Apply suggestions from code review
Co-authored-by: Felix Fontein <felix@fontein.de>
* Remove no_log=False from user argument
* Add changelog fragment
* Correct wording and formatting in changelog
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update changelogs/fragments/2045-bitbucket_support_basic_auth.yaml
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
2324f350bc
commit
aaa0f39f72
11 changed files with 187 additions and 134 deletions
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
minor_changes:
|
||||
- bitbucket_* modules - add ``user`` and ``password`` options for Basic authentication (https://github.com/ansible-collections/community.general/pull/2045).
|
||||
deprecated_features:
|
||||
- bitbucket_* modules - ``username`` options have been deprecated in favor of ``workspace`` and will be removed in community.general 6.0.0 (https://github.com/ansible-collections/community.general/pull/2045).
|
||||
major_changes:
|
||||
- "bitbucket_* modules - ``client_id`` is no longer marked as ``no_log=true``. If you relied on its value not showing up in logs and output, please mark the whole tasks with ``no_log: true`` (https://github.com/ansible-collections/community.general/pull/2045)."
|
41
plugins/doc_fragments/bitbucket.py
Normal file
41
plugins/doc_fragments/bitbucket.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2019, Evgeniy Krysanov <evgeniy.krysanov@gmail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- The OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- The OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
user:
|
||||
description:
|
||||
- The username.
|
||||
- If not set the environment variable C(BITBUCKET_USERNAME) will be used.
|
||||
type: str
|
||||
version_added: 4.0.0
|
||||
password:
|
||||
description:
|
||||
- The App password.
|
||||
- If not set the environment variable C(BITBUCKET_PASSWORD) will be used.
|
||||
type: str
|
||||
version_added: 4.0.0
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Bitbucket App password can be created from Bitbucket profile -> Personal Settings -> App passwords.
|
||||
- If both OAuth and Basic Auth credentials are passed, OAuth credentials take precedence.
|
||||
'''
|
|
@ -15,13 +15,6 @@ from ansible.module_utils.urls import fetch_url, basic_auth_header
|
|||
class BitbucketHelper:
|
||||
BITBUCKET_API_URL = 'https://api.bitbucket.org'
|
||||
|
||||
error_messages = {
|
||||
'required_client_id': '`client_id` must be specified as a parameter or '
|
||||
'BITBUCKET_CLIENT_ID environment variable',
|
||||
'required_client_secret': '`client_secret` must be specified as a parameter or '
|
||||
'BITBUCKET_CLIENT_SECRET environment variable',
|
||||
}
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.access_token = None
|
||||
|
@ -29,35 +22,40 @@ class BitbucketHelper:
|
|||
@staticmethod
|
||||
def bitbucket_argument_spec():
|
||||
return dict(
|
||||
client_id=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_CLIENT_ID'])),
|
||||
client_id=dict(type='str', fallback=(env_fallback, ['BITBUCKET_CLIENT_ID'])),
|
||||
client_secret=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_CLIENT_SECRET'])),
|
||||
# TODO:
|
||||
# - Rename user to username once current usage of username is removed
|
||||
# - Alias user to username and deprecate it
|
||||
user=dict(type='str', fallback=(env_fallback, ['BITBUCKET_USERNAME'])),
|
||||
password=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_PASSWORD'])),
|
||||
)
|
||||
|
||||
def check_arguments(self):
|
||||
if self.module.params['client_id'] is None:
|
||||
self.module.fail_json(msg=self.error_messages['required_client_id'])
|
||||
@staticmethod
|
||||
def bitbucket_required_one_of():
|
||||
return [['client_id', 'client_secret', 'user', 'password']]
|
||||
|
||||
if self.module.params['client_secret'] is None:
|
||||
self.module.fail_json(msg=self.error_messages['required_client_secret'])
|
||||
@staticmethod
|
||||
def bitbucket_required_together():
|
||||
return [['client_id', 'client_secret'], ['user', 'password']]
|
||||
|
||||
def fetch_access_token(self):
|
||||
self.check_arguments()
|
||||
if self.module.params['client_id'] and self.module.params['client_secret']:
|
||||
headers = {
|
||||
'Authorization': basic_auth_header(self.module.params['client_id'], self.module.params['client_secret']),
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Authorization': basic_auth_header(self.module.params['client_id'], self.module.params['client_secret'])
|
||||
}
|
||||
info, content = self.request(
|
||||
api_url='https://bitbucket.org/site/oauth2/access_token',
|
||||
method='POST',
|
||||
data='grant_type=client_credentials',
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
info, content = self.request(
|
||||
api_url='https://bitbucket.org/site/oauth2/access_token',
|
||||
method='POST',
|
||||
data='grant_type=client_credentials',
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
if info['status'] == 200:
|
||||
self.access_token = content['access_token']
|
||||
else:
|
||||
self.module.fail_json(msg='Failed to retrieve access token: {0}'.format(info))
|
||||
if info['status'] == 200:
|
||||
self.access_token = content['access_token']
|
||||
else:
|
||||
self.module.fail_json(msg='Failed to retrieve access token: {0}'.format(info))
|
||||
|
||||
def request(self, api_url, method, data=None, headers=None):
|
||||
headers = headers or {}
|
||||
|
@ -66,6 +64,10 @@ class BitbucketHelper:
|
|||
headers.update({
|
||||
'Authorization': 'Bearer {0}'.format(self.access_token),
|
||||
})
|
||||
elif self.module.params['user'] and self.module.params['password']:
|
||||
headers.update({
|
||||
'Authorization': basic_auth_header(self.module.params['user'], self.module.params['password']),
|
||||
})
|
||||
|
||||
if isinstance(data, dict):
|
||||
data = self.module.jsonify(data)
|
||||
|
|
|
@ -15,27 +15,21 @@ description:
|
|||
- Manages Bitbucket repository access keys (also called deploy keys).
|
||||
author:
|
||||
- Evgeniy Krysanov (@catcombo)
|
||||
extends_documentation_fragment:
|
||||
- community.general.bitbucket
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- The OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- The OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
repository:
|
||||
description:
|
||||
- The repository name.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
workspace:
|
||||
description:
|
||||
- The repository owner.
|
||||
- Alias I(username) has been deprecated and will become an alias of I(user) in community.general 6.0.0.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ username ]
|
||||
key:
|
||||
description:
|
||||
- The SSH public key.
|
||||
|
@ -52,8 +46,7 @@ options:
|
|||
required: true
|
||||
choices: [ absent, present ]
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Bitbucket OAuth consumer should have permissions to read and administrate account repositories.
|
||||
- Bitbucket OAuth consumer or App password should have permissions to read and administrate account repositories.
|
||||
- Check mode is supported.
|
||||
'''
|
||||
|
||||
|
@ -61,7 +54,7 @@ EXAMPLES = r'''
|
|||
- name: Create access key
|
||||
community.general.bitbucket_access_key:
|
||||
repository: 'bitbucket-repo'
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
key: '{{lookup("file", "bitbucket.pub") }}'
|
||||
label: 'Bitbucket'
|
||||
state: present
|
||||
|
@ -69,7 +62,7 @@ EXAMPLES = r'''
|
|||
- name: Delete access key
|
||||
community.general.bitbucket_access_key:
|
||||
repository: bitbucket-repo
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
label: Bitbucket
|
||||
state: absent
|
||||
'''
|
||||
|
@ -82,13 +75,13 @@ from ansible_collections.community.general.plugins.module_utils.source_control.b
|
|||
error_messages = {
|
||||
'required_key': '`key` is required when the `state` is `present`',
|
||||
'required_permission': 'OAuth consumer `client_id` should have permissions to read and administrate the repository',
|
||||
'invalid_username_or_repo': 'Invalid `repository` or `username`',
|
||||
'invalid_workspace_or_repo': 'Invalid `repository` or `workspace`',
|
||||
'invalid_key': 'Invalid SSH key or key is already in use',
|
||||
}
|
||||
|
||||
BITBUCKET_API_ENDPOINTS = {
|
||||
'deploy-key-list': '%s/2.0/repositories/{username}/{repo_slug}/deploy-keys/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'deploy-key-detail': '%s/2.0/repositories/{username}/{repo_slug}/deploy-keys/{key_id}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'deploy-key-list': '%s/2.0/repositories/{workspace}/{repo_slug}/deploy-keys/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'deploy-key-detail': '%s/2.0/repositories/{workspace}/{repo_slug}/deploy-keys/{key_id}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,7 +131,7 @@ def get_existing_deploy_key(module, bitbucket):
|
|||
"""
|
||||
content = {
|
||||
'next': BITBUCKET_API_ENDPOINTS['deploy-key-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
)
|
||||
}
|
||||
|
@ -151,7 +144,7 @@ def get_existing_deploy_key(module, bitbucket):
|
|||
)
|
||||
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg=error_messages['invalid_username_or_repo'])
|
||||
module.fail_json(msg=error_messages['invalid_workspace_or_repo'])
|
||||
|
||||
if info['status'] == 403:
|
||||
module.fail_json(msg=error_messages['required_permission'])
|
||||
|
@ -170,7 +163,7 @@ def get_existing_deploy_key(module, bitbucket):
|
|||
def create_deploy_key(module, bitbucket):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['deploy-key-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
),
|
||||
method='POST',
|
||||
|
@ -181,7 +174,7 @@ def create_deploy_key(module, bitbucket):
|
|||
)
|
||||
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg=error_messages['invalid_username_or_repo'])
|
||||
module.fail_json(msg=error_messages['invalid_workspace_or_repo'])
|
||||
|
||||
if info['status'] == 403:
|
||||
module.fail_json(msg=error_messages['required_permission'])
|
||||
|
@ -199,7 +192,7 @@ def create_deploy_key(module, bitbucket):
|
|||
def delete_deploy_key(module, bitbucket, key_id):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['deploy-key-detail'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
key_id=key_id,
|
||||
),
|
||||
|
@ -207,7 +200,7 @@ def delete_deploy_key(module, bitbucket, key_id):
|
|||
)
|
||||
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg=error_messages['invalid_username_or_repo'])
|
||||
module.fail_json(msg=error_messages['invalid_workspace_or_repo'])
|
||||
|
||||
if info['status'] == 403:
|
||||
module.fail_json(msg=error_messages['required_permission'])
|
||||
|
@ -223,7 +216,10 @@ def main():
|
|||
argument_spec = BitbucketHelper.bitbucket_argument_spec()
|
||||
argument_spec.update(
|
||||
repository=dict(type='str', required=True),
|
||||
username=dict(type='str', required=True),
|
||||
workspace=dict(
|
||||
type='str', aliases=['username'], required=True,
|
||||
deprecated_aliases=[dict(name='username', version='6.0.0', collection_name='community.general')],
|
||||
),
|
||||
key=dict(type='str', no_log=False),
|
||||
label=dict(type='str', required=True),
|
||||
state=dict(type='str', choices=['present', 'absent'], required=True),
|
||||
|
@ -231,6 +227,8 @@ def main():
|
|||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=BitbucketHelper.bitbucket_required_one_of(),
|
||||
required_together=BitbucketHelper.bitbucket_required_together(),
|
||||
)
|
||||
|
||||
bitbucket = BitbucketHelper(module)
|
||||
|
|
|
@ -15,27 +15,21 @@ description:
|
|||
- Manages Bitbucket pipeline SSH key pair.
|
||||
author:
|
||||
- Evgeniy Krysanov (@catcombo)
|
||||
extends_documentation_fragment:
|
||||
- community.general.bitbucket
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
repository:
|
||||
description:
|
||||
- The repository name.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
workspace:
|
||||
description:
|
||||
- The repository owner.
|
||||
- Alias I(username) has been deprecated and will become an alias of I(user) in community.general 6.0.0.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ username ]
|
||||
public_key:
|
||||
description:
|
||||
- The public key.
|
||||
|
@ -51,7 +45,6 @@ options:
|
|||
required: true
|
||||
choices: [ absent, present ]
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Check mode is supported.
|
||||
'''
|
||||
|
||||
|
@ -59,7 +52,7 @@ EXAMPLES = r'''
|
|||
- name: Create or update SSH key pair
|
||||
community.general.bitbucket_pipeline_key_pair:
|
||||
repository: 'bitbucket-repo'
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
public_key: '{{lookup("file", "bitbucket.pub") }}'
|
||||
private_key: '{{lookup("file", "bitbucket") }}'
|
||||
state: present
|
||||
|
@ -67,7 +60,7 @@ EXAMPLES = r'''
|
|||
- name: Remove SSH key pair
|
||||
community.general.bitbucket_pipeline_key_pair:
|
||||
repository: bitbucket-repo
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
state: absent
|
||||
'''
|
||||
|
||||
|
@ -82,7 +75,7 @@ error_messages = {
|
|||
}
|
||||
|
||||
BITBUCKET_API_ENDPOINTS = {
|
||||
'ssh-key-pair': '%s/2.0/repositories/{username}/{repo_slug}/pipelines_config/ssh/key_pair' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'ssh-key-pair': '%s/2.0/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/key_pair' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,7 +97,7 @@ def get_existing_ssh_key_pair(module, bitbucket):
|
|||
}
|
||||
"""
|
||||
api_url = BITBUCKET_API_ENDPOINTS['ssh-key-pair'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
)
|
||||
|
||||
|
@ -123,7 +116,7 @@ def get_existing_ssh_key_pair(module, bitbucket):
|
|||
def update_ssh_key_pair(module, bitbucket):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['ssh-key-pair'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
),
|
||||
method='PUT',
|
||||
|
@ -143,7 +136,7 @@ def update_ssh_key_pair(module, bitbucket):
|
|||
def delete_ssh_key_pair(module, bitbucket):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['ssh-key-pair'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
),
|
||||
method='DELETE',
|
||||
|
@ -160,7 +153,10 @@ def main():
|
|||
argument_spec = BitbucketHelper.bitbucket_argument_spec()
|
||||
argument_spec.update(
|
||||
repository=dict(type='str', required=True),
|
||||
username=dict(type='str', required=True),
|
||||
workspace=dict(
|
||||
type='str', aliases=['username'], required=True,
|
||||
deprecated_aliases=[dict(name='username', version='6.0.0', collection_name='community.general')],
|
||||
),
|
||||
public_key=dict(type='str'),
|
||||
private_key=dict(type='str', no_log=True),
|
||||
state=dict(type='str', choices=['present', 'absent'], required=True),
|
||||
|
@ -168,6 +164,8 @@ def main():
|
|||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=BitbucketHelper.bitbucket_required_one_of(),
|
||||
required_together=BitbucketHelper.bitbucket_required_together(),
|
||||
)
|
||||
|
||||
bitbucket = BitbucketHelper(module)
|
||||
|
|
|
@ -16,29 +16,23 @@ description:
|
|||
- The host fingerprint will be retrieved automatically, but in case of an error, one can use I(key) field to specify it manually.
|
||||
author:
|
||||
- Evgeniy Krysanov (@catcombo)
|
||||
extends_documentation_fragment:
|
||||
- community.general.bitbucket
|
||||
requirements:
|
||||
- paramiko
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- The OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- The OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
repository:
|
||||
description:
|
||||
- The repository name.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
workspace:
|
||||
description:
|
||||
- The repository owner.
|
||||
- Alias I(username) has been deprecated and will become an alias of I(user) in community.general 6.0.0.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ username ]
|
||||
name:
|
||||
description:
|
||||
- The FQDN of the known host.
|
||||
|
@ -55,7 +49,6 @@ options:
|
|||
required: true
|
||||
choices: [ absent, present ]
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Check mode is supported.
|
||||
'''
|
||||
|
||||
|
@ -63,7 +56,7 @@ EXAMPLES = r'''
|
|||
- name: Create known hosts from the list
|
||||
community.general.bitbucket_pipeline_known_host:
|
||||
repository: 'bitbucket-repo'
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
name: '{{ item }}'
|
||||
state: present
|
||||
with_items:
|
||||
|
@ -73,14 +66,14 @@ EXAMPLES = r'''
|
|||
- name: Remove known host
|
||||
community.general.bitbucket_pipeline_known_host:
|
||||
repository: bitbucket-repo
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
name: bitbucket.org
|
||||
state: absent
|
||||
|
||||
- name: Specify public key file
|
||||
community.general.bitbucket_pipeline_known_host:
|
||||
repository: bitbucket-repo
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
name: bitbucket.org
|
||||
key: '{{lookup("file", "bitbucket.pub") }}'
|
||||
state: absent
|
||||
|
@ -105,8 +98,8 @@ error_messages = {
|
|||
}
|
||||
|
||||
BITBUCKET_API_ENDPOINTS = {
|
||||
'known-host-list': '%s/2.0/repositories/{username}/{repo_slug}/pipelines_config/ssh/known_hosts/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'known-host-detail': '%s/2.0/repositories/{username}/{repo_slug}/pipelines_config/ssh/known_hosts/{known_host_uuid}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'known-host-list': '%s/2.0/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/known_hosts/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'known-host-detail': '%s/2.0/repositories/{workspace}/{repo_slug}/pipelines_config/ssh/known_hosts/{known_host_uuid}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,7 +130,7 @@ def get_existing_known_host(module, bitbucket):
|
|||
"""
|
||||
content = {
|
||||
'next': BITBUCKET_API_ENDPOINTS['known-host-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
)
|
||||
}
|
||||
|
@ -150,7 +143,7 @@ def get_existing_known_host(module, bitbucket):
|
|||
)
|
||||
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg='Invalid `repository` or `username`.')
|
||||
module.fail_json(msg='Invalid `repository` or `workspace`.')
|
||||
|
||||
if info['status'] != 200:
|
||||
module.fail_json(msg='Failed to retrieve list of known hosts: {0}'.format(info))
|
||||
|
@ -214,7 +207,7 @@ def create_known_host(module, bitbucket):
|
|||
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['known-host-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
),
|
||||
method='POST',
|
||||
|
@ -240,7 +233,7 @@ def create_known_host(module, bitbucket):
|
|||
def delete_known_host(module, bitbucket, known_host_uuid):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['known-host-detail'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
known_host_uuid=known_host_uuid,
|
||||
),
|
||||
|
@ -261,7 +254,10 @@ def main():
|
|||
argument_spec = BitbucketHelper.bitbucket_argument_spec()
|
||||
argument_spec.update(
|
||||
repository=dict(type='str', required=True),
|
||||
username=dict(type='str', required=True),
|
||||
workspace=dict(
|
||||
type='str', aliases=['username'], required=True,
|
||||
deprecated_aliases=[dict(name='username', version='6.0.0', collection_name='community.general')],
|
||||
),
|
||||
name=dict(type='str', required=True),
|
||||
key=dict(type='str', no_log=False),
|
||||
state=dict(type='str', choices=['present', 'absent'], required=True),
|
||||
|
@ -269,6 +265,8 @@ def main():
|
|||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=BitbucketHelper.bitbucket_required_one_of(),
|
||||
required_together=BitbucketHelper.bitbucket_required_together(),
|
||||
)
|
||||
|
||||
if (module.params['key'] is None) and (not HAS_PARAMIKO):
|
||||
|
|
|
@ -15,27 +15,21 @@ description:
|
|||
- Manages Bitbucket pipeline variables.
|
||||
author:
|
||||
- Evgeniy Krysanov (@catcombo)
|
||||
extends_documentation_fragment:
|
||||
- community.general.bitbucket
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- The OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- The OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
repository:
|
||||
description:
|
||||
- The repository name.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
workspace:
|
||||
description:
|
||||
- The repository owner.
|
||||
- Alias I(username) has been deprecated and will become an alias of I(user) in community.general 6.0.0.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ username ]
|
||||
name:
|
||||
description:
|
||||
- The pipeline variable name.
|
||||
|
@ -57,7 +51,6 @@ options:
|
|||
required: true
|
||||
choices: [ absent, present ]
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Check mode is supported.
|
||||
- For secured values return parameter C(changed) is always C(True).
|
||||
'''
|
||||
|
@ -66,7 +59,7 @@ EXAMPLES = r'''
|
|||
- name: Create or update pipeline variables from the list
|
||||
community.general.bitbucket_pipeline_variable:
|
||||
repository: 'bitbucket-repo'
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
name: '{{ item.name }}'
|
||||
value: '{{ item.value }}'
|
||||
secured: '{{ item.secured }}'
|
||||
|
@ -78,7 +71,7 @@ EXAMPLES = r'''
|
|||
- name: Remove pipeline variable
|
||||
community.general.bitbucket_pipeline_variable:
|
||||
repository: bitbucket-repo
|
||||
username: bitbucket_username
|
||||
workspace: bitbucket_workspace
|
||||
name: AWS_ACCESS_KEY
|
||||
state: absent
|
||||
'''
|
||||
|
@ -93,8 +86,8 @@ error_messages = {
|
|||
}
|
||||
|
||||
BITBUCKET_API_ENDPOINTS = {
|
||||
'pipeline-variable-list': '%s/2.0/repositories/{username}/{repo_slug}/pipelines_config/variables/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'pipeline-variable-detail': '%s/2.0/repositories/{username}/{repo_slug}/pipelines_config/variables/{variable_uuid}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'pipeline-variable-list': '%s/2.0/repositories/{workspace}/{repo_slug}/pipelines_config/variables/' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
'pipeline-variable-detail': '%s/2.0/repositories/{workspace}/{repo_slug}/pipelines_config/variables/{variable_uuid}' % BitbucketHelper.BITBUCKET_API_URL,
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,7 +113,7 @@ def get_existing_pipeline_variable(module, bitbucket):
|
|||
The `value` key in dict is absent in case of secured variable.
|
||||
"""
|
||||
variables_base_url = BITBUCKET_API_ENDPOINTS['pipeline-variable-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
)
|
||||
# Look through the all response pages in search of variable we need
|
||||
|
@ -133,7 +126,7 @@ def get_existing_pipeline_variable(module, bitbucket):
|
|||
)
|
||||
|
||||
if info['status'] == 404:
|
||||
module.fail_json(msg='Invalid `repository` or `username`.')
|
||||
module.fail_json(msg='Invalid `repository` or `workspace`.')
|
||||
|
||||
if info['status'] != 200:
|
||||
module.fail_json(msg='Failed to retrieve the list of pipeline variables: {0}'.format(info))
|
||||
|
@ -153,7 +146,7 @@ def get_existing_pipeline_variable(module, bitbucket):
|
|||
def create_pipeline_variable(module, bitbucket):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['pipeline-variable-list'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
),
|
||||
method='POST',
|
||||
|
@ -174,7 +167,7 @@ def create_pipeline_variable(module, bitbucket):
|
|||
def update_pipeline_variable(module, bitbucket, variable_uuid):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['pipeline-variable-detail'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
variable_uuid=variable_uuid,
|
||||
),
|
||||
|
@ -195,7 +188,7 @@ def update_pipeline_variable(module, bitbucket, variable_uuid):
|
|||
def delete_pipeline_variable(module, bitbucket, variable_uuid):
|
||||
info, content = bitbucket.request(
|
||||
api_url=BITBUCKET_API_ENDPOINTS['pipeline-variable-detail'].format(
|
||||
username=module.params['username'],
|
||||
workspace=module.params['workspace'],
|
||||
repo_slug=module.params['repository'],
|
||||
variable_uuid=variable_uuid,
|
||||
),
|
||||
|
@ -221,7 +214,10 @@ def main():
|
|||
argument_spec = BitbucketHelper.bitbucket_argument_spec()
|
||||
argument_spec.update(
|
||||
repository=dict(type='str', required=True),
|
||||
username=dict(type='str', required=True),
|
||||
workspace=dict(
|
||||
type='str', aliases=['username'], required=True,
|
||||
deprecated_aliases=[dict(name='username', version='6.0.0', collection_name='community.general')],
|
||||
),
|
||||
name=dict(type='str', required=True),
|
||||
value=dict(type='str'),
|
||||
secured=dict(type='bool', default=False),
|
||||
|
@ -230,6 +226,8 @@ def main():
|
|||
module = BitBucketPipelineVariable(
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
required_one_of=BitbucketHelper.bitbucket_required_one_of(),
|
||||
required_together=BitbucketHelper.bitbucket_required_together(),
|
||||
)
|
||||
|
||||
bitbucket = BitbucketHelper(module)
|
||||
|
|
|
@ -29,15 +29,14 @@ class TestBucketAccessKeyModule(ModuleTestCase):
|
|||
|
||||
self.assertEqual(exec_info.exception.args[0]['msg'], self.module.error_messages['required_key'])
|
||||
|
||||
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
|
||||
@patch.object(bitbucket_access_key, 'get_existing_deploy_key', return_value=None)
|
||||
def test_create_deploy_key(self, *args):
|
||||
with patch.object(self.module, 'create_deploy_key') as create_deploy_key_mock:
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
set_module_args({
|
||||
'client_id': 'ABC',
|
||||
'client_secret': 'XXX',
|
||||
'username': 'name',
|
||||
'user': 'ABC',
|
||||
'password': 'XXX',
|
||||
'workspace': 'name',
|
||||
'repository': 'repo',
|
||||
'key': 'public_key',
|
||||
'label': 'key name',
|
||||
|
|
|
@ -28,15 +28,14 @@ class TestBucketPipelineKeyPairModule(ModuleTestCase):
|
|||
|
||||
self.assertEqual(exec_info.exception.args[0]['msg'], self.module.error_messages['required_keys'])
|
||||
|
||||
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
|
||||
@patch.object(bitbucket_pipeline_key_pair, 'get_existing_ssh_key_pair', return_value=None)
|
||||
def test_create_keys(self, *args):
|
||||
with patch.object(self.module, 'update_ssh_key_pair') as update_ssh_key_pair_mock:
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
set_module_args({
|
||||
'client_id': 'ABC',
|
||||
'client_secret': 'XXX',
|
||||
'username': 'name',
|
||||
'user': 'ABC',
|
||||
'password': 'XXX',
|
||||
'workspace': 'name',
|
||||
'repository': 'repo',
|
||||
'public_key': 'public',
|
||||
'private_key': 'PRIVATE',
|
||||
|
|
|
@ -37,16 +37,15 @@ class TestBucketPipelineKnownHostModule(ModuleTestCase):
|
|||
self.assertEqual(create_known_host_mock.call_count, 1)
|
||||
self.assertEqual(exec_info.exception.args[0]['changed'], True)
|
||||
|
||||
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
|
||||
@patch.object(BitbucketHelper, 'request', return_value=(dict(status=201), dict()))
|
||||
@patch.object(bitbucket_pipeline_known_host, 'get_existing_known_host', return_value=None)
|
||||
def test_create_known_host_with_key(self, *args):
|
||||
with patch.object(self.module, 'get_host_key') as get_host_key_mock:
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
set_module_args({
|
||||
'client_id': 'ABC',
|
||||
'client_secret': 'XXX',
|
||||
'username': 'name',
|
||||
'user': 'ABC',
|
||||
'password': 'XXX',
|
||||
'workspace': 'name',
|
||||
'repository': 'repo',
|
||||
'name': 'bitbucket.org',
|
||||
'key': 'ssh-rsa public',
|
||||
|
|
|
@ -25,7 +25,7 @@ class TestBucketPipelineVariableModule(ModuleTestCase):
|
|||
})
|
||||
self.module.main()
|
||||
|
||||
self.assertEqual(exec_info.exception.args[0]['msg'], BitbucketHelper.error_messages['required_client_id'])
|
||||
self.assertEqual(exec_info.exception.args[0]['failed'], True)
|
||||
|
||||
def test_missing_value_with_present_state(self):
|
||||
with self.assertRaises(AnsibleFailJson) as exec_info:
|
||||
|
@ -47,7 +47,7 @@ class TestBucketPipelineVariableModule(ModuleTestCase):
|
|||
})
|
||||
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
|
||||
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
|
||||
def test_env_vars_params(self, *args):
|
||||
def test_oauth_env_vars_params(self, *args):
|
||||
with self.assertRaises(AnsibleExitJson):
|
||||
set_module_args({
|
||||
'username': 'name',
|
||||
|
@ -57,15 +57,29 @@ class TestBucketPipelineVariableModule(ModuleTestCase):
|
|||
})
|
||||
self.module.main()
|
||||
|
||||
@patch.object(BitbucketHelper, 'fetch_access_token', return_value='token')
|
||||
@patch.dict('os.environ', {
|
||||
'BITBUCKET_USERNAME': 'ABC',
|
||||
'BITBUCKET_PASSWORD': 'XXX',
|
||||
})
|
||||
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
|
||||
def test_basic_auth_env_vars_params(self, *args):
|
||||
with self.assertRaises(AnsibleExitJson):
|
||||
set_module_args({
|
||||
'workspace': 'name',
|
||||
'repository': 'repo',
|
||||
'name': 'PIPELINE_VAR_NAME',
|
||||
'state': 'absent',
|
||||
})
|
||||
self.module.main()
|
||||
|
||||
@patch.object(bitbucket_pipeline_variable, 'get_existing_pipeline_variable', return_value=None)
|
||||
def test_create_variable(self, *args):
|
||||
with patch.object(self.module, 'create_pipeline_variable') as create_pipeline_variable_mock:
|
||||
with self.assertRaises(AnsibleExitJson) as exec_info:
|
||||
set_module_args({
|
||||
'client_id': 'ABC',
|
||||
'client_secret': 'XXX',
|
||||
'username': 'name',
|
||||
'user': 'ABC',
|
||||
'password': 'XXX',
|
||||
'workspace': 'name',
|
||||
'repository': 'repo',
|
||||
'name': 'PIPELINE_VAR_NAME',
|
||||
'value': '42',
|
||||
|
|
Loading…
Reference in a new issue