mirror of
https://github.com/ansible/awx.git
synced 2026-09-04 19:08:30 -02:30
Merge pull request #4436 from jbradberry/webhook-receivers
Webhook receivers Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -154,12 +154,12 @@ def mk_job_template(name, job_type='run',
|
||||
organization=None, inventory=None,
|
||||
credential=None, network_credential=None,
|
||||
cloud_credential=None, persisted=True, extra_vars='',
|
||||
project=None, spec=None):
|
||||
project=None, spec=None, webhook_service=''):
|
||||
if extra_vars:
|
||||
extra_vars = json.dumps(extra_vars)
|
||||
|
||||
jt = JobTemplate(name=name, job_type=job_type, extra_vars=extra_vars,
|
||||
playbook='helloworld.yml')
|
||||
webhook_service=webhook_service, playbook='helloworld.yml')
|
||||
|
||||
jt.inventory = inventory
|
||||
if jt.inventory is None:
|
||||
@@ -200,11 +200,13 @@ def mk_workflow_job(status='new', workflow_job_template=None, extra_vars={},
|
||||
return job
|
||||
|
||||
|
||||
def mk_workflow_job_template(name, extra_vars='', spec=None, organization=None, persisted=True):
|
||||
def mk_workflow_job_template(name, extra_vars='', spec=None, organization=None, persisted=True,
|
||||
webhook_service=''):
|
||||
if extra_vars:
|
||||
extra_vars = json.dumps(extra_vars)
|
||||
|
||||
wfjt = WorkflowJobTemplate(name=name, extra_vars=extra_vars, organization=organization)
|
||||
wfjt = WorkflowJobTemplate(name=name, extra_vars=extra_vars, organization=organization,
|
||||
webhook_service=webhook_service)
|
||||
|
||||
wfjt.survey_spec = spec
|
||||
if wfjt.survey_spec:
|
||||
|
||||
@@ -197,7 +197,7 @@ def create_survey_spec(variables=None, default_type='integer', required=True, mi
|
||||
#
|
||||
|
||||
|
||||
def create_job_template(name, roles=None, persisted=True, **kwargs):
|
||||
def create_job_template(name, roles=None, persisted=True, webhook_service='', **kwargs):
|
||||
Objects = generate_objects(["job_template", "jobs",
|
||||
"organization",
|
||||
"inventory",
|
||||
@@ -252,11 +252,10 @@ def create_job_template(name, roles=None, persisted=True, **kwargs):
|
||||
else:
|
||||
spec = None
|
||||
|
||||
jt = mk_job_template(name, project=proj,
|
||||
inventory=inv, credential=cred,
|
||||
jt = mk_job_template(name, project=proj, inventory=inv, credential=cred,
|
||||
network_credential=net_cred, cloud_credential=cloud_cred,
|
||||
job_type=job_type, spec=spec, extra_vars=extra_vars,
|
||||
persisted=persisted)
|
||||
persisted=persisted, webhook_service=webhook_service)
|
||||
|
||||
if 'jobs' in kwargs:
|
||||
for i in kwargs['jobs']:
|
||||
@@ -401,7 +400,7 @@ def generate_workflow_job_template_nodes(workflow_job_template,
|
||||
|
||||
|
||||
# TODO: Implement survey and jobs
|
||||
def create_workflow_job_template(name, organization=None, persisted=True, **kwargs):
|
||||
def create_workflow_job_template(name, organization=None, persisted=True, webhook_service='', **kwargs):
|
||||
Objects = generate_objects(["workflow_job_template",
|
||||
"workflow_job_template_nodes",
|
||||
"survey",], kwargs)
|
||||
@@ -418,7 +417,8 @@ def create_workflow_job_template(name, organization=None, persisted=True, **kwar
|
||||
organization=organization,
|
||||
spec=spec,
|
||||
extra_vars=extra_vars,
|
||||
persisted=persisted)
|
||||
persisted=persisted,
|
||||
webhook_service=webhook_service)
|
||||
|
||||
|
||||
|
||||
|
||||
260
awx/main/tests/functional/api/test_webhooks.py
Normal file
260
awx/main/tests/functional/api/test_webhooks.py
Normal file
@@ -0,0 +1,260 @@
|
||||
import pytest
|
||||
|
||||
from awx.api.versioning import reverse
|
||||
from awx.main.models.mixins import WebhookTemplateMixin
|
||||
from awx.main.models.credential import Credential, CredentialType
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"user_role, expect", [
|
||||
('superuser', 200),
|
||||
('org admin', 200),
|
||||
('jt admin', 200),
|
||||
('jt execute', 403),
|
||||
('org member', 403),
|
||||
]
|
||||
)
|
||||
def test_get_webhook_key_jt(organization_factory, job_template_factory, get, user_role, expect):
|
||||
objs = organization_factory("org", superusers=['admin'], users=['user'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
if user_role == 'superuser':
|
||||
user = objs.superusers.admin
|
||||
else:
|
||||
user = objs.users.user
|
||||
grant_obj = objs.organization if user_role.startswith('org') else jt
|
||||
getattr(grant_obj, '{}_role'.format(user_role.split()[1])).members.add(user)
|
||||
|
||||
url = reverse('api:webhook_key', kwargs={'model_kwarg': 'job_templates', 'pk': jt.pk})
|
||||
response = get(url, user=user, expect=expect)
|
||||
if expect < 400:
|
||||
assert response.data == {'webhook_key': ''}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"user_role, expect", [
|
||||
('superuser', 200),
|
||||
('org admin', 200),
|
||||
('jt admin', 200),
|
||||
('jt execute', 403),
|
||||
('org member', 403),
|
||||
]
|
||||
)
|
||||
def test_get_webhook_key_wfjt(organization_factory, workflow_job_template_factory, get, user_role, expect):
|
||||
objs = organization_factory("org", superusers=['admin'], users=['user'])
|
||||
wfjt = workflow_job_template_factory("wfjt", organization=objs.organization).workflow_job_template
|
||||
if user_role == 'superuser':
|
||||
user = objs.superusers.admin
|
||||
else:
|
||||
user = objs.users.user
|
||||
grant_obj = objs.organization if user_role.startswith('org') else wfjt
|
||||
getattr(grant_obj, '{}_role'.format(user_role.split()[1])).members.add(user)
|
||||
|
||||
url = reverse('api:webhook_key', kwargs={'model_kwarg': 'workflow_job_templates', 'pk': wfjt.pk})
|
||||
response = get(url, user=user, expect=expect)
|
||||
if expect < 400:
|
||||
assert response.data == {'webhook_key': ''}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"user_role, expect", [
|
||||
('superuser', 201),
|
||||
('org admin', 201),
|
||||
('jt admin', 201),
|
||||
('jt execute', 403),
|
||||
('org member', 403),
|
||||
]
|
||||
)
|
||||
def test_post_webhook_key_jt(organization_factory, job_template_factory, post, user_role, expect):
|
||||
objs = organization_factory("org", superusers=['admin'], users=['user'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
if user_role == 'superuser':
|
||||
user = objs.superusers.admin
|
||||
else:
|
||||
user = objs.users.user
|
||||
grant_obj = objs.organization if user_role.startswith('org') else jt
|
||||
getattr(grant_obj, '{}_role'.format(user_role.split()[1])).members.add(user)
|
||||
|
||||
url = reverse('api:webhook_key', kwargs={'model_kwarg': 'job_templates', 'pk': jt.pk})
|
||||
response = post(url, {}, user=user, expect=expect)
|
||||
if expect < 400:
|
||||
assert bool(response.data.get('webhook_key'))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"user_role, expect", [
|
||||
('superuser', 201),
|
||||
('org admin', 201),
|
||||
('jt admin', 201),
|
||||
('jt execute', 403),
|
||||
('org member', 403),
|
||||
]
|
||||
)
|
||||
def test_post_webhook_key_wfjt(organization_factory, workflow_job_template_factory, post, user_role, expect):
|
||||
objs = organization_factory("org", superusers=['admin'], users=['user'])
|
||||
wfjt = workflow_job_template_factory("wfjt", organization=objs.organization).workflow_job_template
|
||||
if user_role == 'superuser':
|
||||
user = objs.superusers.admin
|
||||
else:
|
||||
user = objs.users.user
|
||||
grant_obj = objs.organization if user_role.startswith('org') else wfjt
|
||||
getattr(grant_obj, '{}_role'.format(user_role.split()[1])).members.add(user)
|
||||
|
||||
url = reverse('api:webhook_key', kwargs={'model_kwarg': 'workflow_job_templates', 'pk': wfjt.pk})
|
||||
response = post(url, {}, user=user, expect=expect)
|
||||
if expect < 400:
|
||||
assert bool(response.data.get('webhook_key'))
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service", [s for s, _ in WebhookTemplateMixin.SERVICES]
|
||||
)
|
||||
def test_set_webhook_service(organization_factory, job_template_factory, patch, service):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert (jt.webhook_service, jt.webhook_key) == ('', '')
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
patch(url, {'webhook_service': service}, user=admin, expect=200)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service", [s for s, _ in WebhookTemplateMixin.SERVICES]
|
||||
)
|
||||
def test_unset_webhook_service(organization_factory, job_template_factory, patch, service):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization, webhook_service=service,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
patch(url, {'webhook_service': ''}, user=admin, expect=200)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert (jt.webhook_service, jt.webhook_key) == ('', '')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service", [s for s, _ in WebhookTemplateMixin.SERVICES]
|
||||
)
|
||||
def test_set_webhook_credential(organization_factory, job_template_factory, patch, service):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization, webhook_service=service,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
|
||||
cred_type = CredentialType.defaults['{}_token'.format(service)]()
|
||||
cred_type.save()
|
||||
cred = Credential.objects.create(credential_type=cred_type, name='test-cred',
|
||||
inputs={'token': 'secret'})
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
patch(url, {'webhook_credential': cred.pk}, user=admin, expect=200)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
assert jt.webhook_credential == cred
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service,token", [
|
||||
(s, WebhookTemplateMixin.SERVICES[i - 1][0]) for i, (s, _) in enumerate(WebhookTemplateMixin.SERVICES)
|
||||
]
|
||||
)
|
||||
def test_set_wrong_service_webhook_credential(organization_factory, job_template_factory, patch, service, token):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization, webhook_service=service,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
|
||||
cred_type = CredentialType.defaults['{}_token'.format(token)]()
|
||||
cred_type.save()
|
||||
cred = Credential.objects.create(credential_type=cred_type, name='test-cred',
|
||||
inputs={'token': 'secret'})
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
response = patch(url, {'webhook_credential': cred.pk}, user=admin, expect=400)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
assert jt.webhook_credential is None
|
||||
assert response.data == {'webhook_credential': ["Must match the selected webhook service."]}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service", [s for s, _ in WebhookTemplateMixin.SERVICES]
|
||||
)
|
||||
def test_set_webhook_credential_without_service(organization_factory, job_template_factory, patch, service):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert jt.webhook_service == ''
|
||||
assert jt.webhook_key == ''
|
||||
|
||||
cred_type = CredentialType.defaults['{}_token'.format(service)]()
|
||||
cred_type.save()
|
||||
cred = Credential.objects.create(credential_type=cred_type, name='test-cred',
|
||||
inputs={'token': 'secret'})
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
response = patch(url, {'webhook_credential': cred.pk}, user=admin, expect=400)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert jt.webhook_service == ''
|
||||
assert jt.webhook_key == ''
|
||||
assert jt.webhook_credential is None
|
||||
assert response.data == {'webhook_credential': ["Must match the selected webhook service."]}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"service", [s for s, _ in WebhookTemplateMixin.SERVICES]
|
||||
)
|
||||
def test_unset_webhook_service_with_credential(organization_factory, job_template_factory, patch, service):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization, webhook_service=service,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
admin = objs.superusers.admin
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
|
||||
cred_type = CredentialType.defaults['{}_token'.format(service)]()
|
||||
cred_type.save()
|
||||
cred = Credential.objects.create(credential_type=cred_type, name='test-cred',
|
||||
inputs={'token': 'secret'})
|
||||
jt.webhook_credential = cred
|
||||
jt.save()
|
||||
|
||||
url = reverse('api:job_template_detail', kwargs={'pk': jt.pk})
|
||||
response = patch(url, {'webhook_service': ''}, user=admin, expect=400)
|
||||
jt.refresh_from_db()
|
||||
|
||||
assert jt.webhook_service == service
|
||||
assert jt.webhook_key != ''
|
||||
assert jt.webhook_credential == cred
|
||||
assert response.data == {'webhook_credential': ["Must match the selected webhook service."]}
|
||||
@@ -82,6 +82,8 @@ def test_default_cred_types():
|
||||
'cloudforms',
|
||||
'conjur',
|
||||
'gce',
|
||||
'github_token',
|
||||
'gitlab_token',
|
||||
'hashivault_kv',
|
||||
'hashivault_ssh',
|
||||
'insights',
|
||||
|
||||
@@ -29,6 +29,7 @@ def job_template(mocker):
|
||||
mock_jt.pk = 5
|
||||
mock_jt.host_config_key = '9283920492'
|
||||
mock_jt.validation_errors = mock_JT_resource_data
|
||||
mock_jt.webhook_service = ''
|
||||
return mock_jt
|
||||
|
||||
|
||||
@@ -50,6 +51,7 @@ class TestJobTemplateSerializerGetRelated():
|
||||
'schedules',
|
||||
'activity_stream',
|
||||
'launch',
|
||||
'webhook_key',
|
||||
'notification_templates_started',
|
||||
'notification_templates_success',
|
||||
'notification_templates_error',
|
||||
|
||||
@@ -32,6 +32,7 @@ class TestWorkflowJobTemplateSerializerGetRelated():
|
||||
'workflow_jobs',
|
||||
'launch',
|
||||
'workflow_nodes',
|
||||
'webhook_key',
|
||||
])
|
||||
def test_get_related(self, mocker, test_get_related, workflow_job_template, related_resource_name):
|
||||
test_get_related(WorkflowJobTemplateSerializer,
|
||||
|
||||
Reference in New Issue
Block a user