mirror of
https://github.com/ansible/awx.git
synced 2026-01-23 15:38:06 -03:30
remove the deprecated extra_credentials endpoints
This commit is contained in:
parent
72de660ea1
commit
18607107a7
@ -2756,16 +2756,11 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
||||
if obj.organization_id:
|
||||
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id})
|
||||
if isinstance(obj, UnifiedJobTemplate):
|
||||
res['extra_credentials'] = self.reverse(
|
||||
'api:job_template_extra_credentials_list',
|
||||
kwargs={'pk': obj.pk}
|
||||
)
|
||||
res['credentials'] = self.reverse(
|
||||
'api:job_template_credentials_list',
|
||||
kwargs={'pk': obj.pk}
|
||||
)
|
||||
elif isinstance(obj, UnifiedJob):
|
||||
res['extra_credentials'] = self.reverse('api:job_extra_credentials_list', kwargs={'pk': obj.pk})
|
||||
res['credentials'] = self.reverse('api:job_credentials_list', kwargs={'pk': obj.pk})
|
||||
|
||||
return res
|
||||
@ -2934,7 +2929,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
||||
summary_fields = super(JobTemplateSerializer, self).get_summary_fields(obj)
|
||||
all_creds = []
|
||||
# Organize credential data into multitude of deprecated fields
|
||||
extra_creds = []
|
||||
if obj.pk:
|
||||
for cred in obj.credentials.all():
|
||||
summarized_cred = {
|
||||
@ -2945,10 +2939,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
||||
'cloud': cred.credential_type.kind == 'cloud'
|
||||
}
|
||||
all_creds.append(summarized_cred)
|
||||
if cred.credential_type.kind in ('cloud', 'net'):
|
||||
extra_creds.append(summarized_cred)
|
||||
if self.is_detail_view:
|
||||
summary_fields['extra_credentials'] = extra_creds
|
||||
summary_fields['credentials'] = all_creds
|
||||
return summary_fields
|
||||
|
||||
@ -3023,7 +3013,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
summary_fields = super(JobSerializer, self).get_summary_fields(obj)
|
||||
all_creds = []
|
||||
# Organize credential data into multitude of deprecated fields
|
||||
extra_creds = []
|
||||
if obj.pk:
|
||||
for cred in obj.credentials.all():
|
||||
summarized_cred = {
|
||||
@ -3034,10 +3023,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
'cloud': cred.credential_type.kind == 'cloud'
|
||||
}
|
||||
all_creds.append(summarized_cred)
|
||||
if cred.credential_type.kind in ('cloud', 'net'):
|
||||
extra_creds.append(summarized_cred)
|
||||
if self.is_detail_view:
|
||||
summary_fields['extra_credentials'] = extra_creds
|
||||
summary_fields['credentials'] = all_creds
|
||||
return summary_fields
|
||||
|
||||
|
||||
@ -23,9 +23,7 @@ from awx.api.views import (
|
||||
UnifiedJobList,
|
||||
HostAnsibleFactsDetail,
|
||||
JobCredentialsList,
|
||||
JobExtraCredentialsList,
|
||||
JobTemplateCredentialsList,
|
||||
JobTemplateExtraCredentialsList,
|
||||
SchedulePreview,
|
||||
ScheduleZoneInfo,
|
||||
OAuth2ApplicationList,
|
||||
@ -83,9 +81,7 @@ v2_urls = [
|
||||
url(r'^credential_types/', include(credential_type_urls)),
|
||||
url(r'^credential_input_sources/', include(credential_input_source_urls)),
|
||||
url(r'^hosts/(?P<pk>[0-9]+)/ansible_facts/$', HostAnsibleFactsDetail.as_view(), name='host_ansible_facts_detail'),
|
||||
url(r'^jobs/(?P<pk>[0-9]+)/extra_credentials/$', JobExtraCredentialsList.as_view(), name='job_extra_credentials_list'),
|
||||
url(r'^jobs/(?P<pk>[0-9]+)/credentials/$', JobCredentialsList.as_view(), name='job_credentials_list'),
|
||||
url(r'^job_templates/(?P<pk>[0-9]+)/extra_credentials/$', JobTemplateExtraCredentialsList.as_view(), name='job_template_extra_credentials_list'),
|
||||
url(r'^job_templates/(?P<pk>[0-9]+)/credentials/$', JobTemplateCredentialsList.as_view(), name='job_template_credentials_list'),
|
||||
url(r'^schedules/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
|
||||
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
|
||||
|
||||
@ -12,7 +12,7 @@ import socket
|
||||
import sys
|
||||
import time
|
||||
from base64 import b64encode
|
||||
from collections import OrderedDict, Iterable
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
# Django
|
||||
@ -2344,51 +2344,6 @@ class JobTemplateLaunch(RetrieveAPIView):
|
||||
if 'inventory' not in modern_data and id_fd in modern_data:
|
||||
modern_data['inventory'] = modern_data[id_fd]
|
||||
|
||||
# Automatically convert legacy launch credential arguments into a list of `.credentials`
|
||||
if 'credentials' in modern_data and 'extra_credentials' in modern_data:
|
||||
raise ParseError({"error": _(
|
||||
"'credentials' cannot be used in combination with 'extra_credentials'."
|
||||
)})
|
||||
|
||||
if 'extra_credentials' in modern_data:
|
||||
# make a list of the current credentials
|
||||
existing_credentials = obj.credentials.all()
|
||||
template_credentials = list(existing_credentials) # save copy of existing
|
||||
new_credentials = []
|
||||
if 'extra_credentials' in modern_data:
|
||||
existing_credentials = [
|
||||
cred for cred in existing_credentials
|
||||
if cred.credential_type.kind not in ('cloud', 'net')
|
||||
]
|
||||
prompted_value = modern_data.pop('extra_credentials')
|
||||
|
||||
# validate type, since these are not covered by a serializer
|
||||
if not isinstance(prompted_value, Iterable):
|
||||
msg = _(
|
||||
"Incorrect type. Expected a list received {}."
|
||||
).format(prompted_value.__class__.__name__)
|
||||
raise ParseError({'extra_credentials': [msg], 'credentials': [msg]})
|
||||
|
||||
# add the deprecated credential specified in the request
|
||||
if not isinstance(prompted_value, Iterable) or isinstance(prompted_value, str):
|
||||
prompted_value = [prompted_value]
|
||||
|
||||
# If user gave extra_credentials, special case to use exactly
|
||||
# the given list without merging with JT credentials
|
||||
if prompted_value:
|
||||
obj._deprecated_credential_launch = True # signal to not merge credentials
|
||||
new_credentials.extend(prompted_value)
|
||||
|
||||
# combine the list of "new" and the filtered list of "old"
|
||||
new_credentials.extend([cred.pk for cred in existing_credentials])
|
||||
if new_credentials:
|
||||
# If provided list doesn't contain the pre-existing credentials
|
||||
# defined on the template, add them back here
|
||||
for cred_obj in template_credentials:
|
||||
if cred_obj.pk not in new_credentials:
|
||||
new_credentials.append(cred_obj.pk)
|
||||
modern_data['credentials'] = new_credentials
|
||||
|
||||
# credential passwords were historically provided as top-level attributes
|
||||
if 'credential_passwords' not in modern_data:
|
||||
modern_data['credential_passwords'] = data.copy()
|
||||
@ -2711,22 +2666,6 @@ class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView):
|
||||
return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created)
|
||||
|
||||
|
||||
class JobTemplateExtraCredentialsList(JobTemplateCredentialsList):
|
||||
|
||||
deprecated = True
|
||||
|
||||
def get_queryset(self):
|
||||
sublist_qs = super(JobTemplateExtraCredentialsList, self).get_queryset()
|
||||
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
|
||||
return sublist_qs
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
valid = super(JobTemplateExtraCredentialsList, self).is_valid_relation(parent, sub, created)
|
||||
if sub.credential_type.kind not in ('cloud', 'net'):
|
||||
return {'error': _('Extra credentials must be network or cloud.')}
|
||||
return valid
|
||||
|
||||
|
||||
class JobTemplateLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView):
|
||||
|
||||
model = models.Label
|
||||
@ -3543,16 +3482,6 @@ class JobCredentialsList(SubListAPIView):
|
||||
relationship = 'credentials'
|
||||
|
||||
|
||||
class JobExtraCredentialsList(JobCredentialsList):
|
||||
|
||||
deprecated = True
|
||||
|
||||
def get_queryset(self):
|
||||
sublist_qs = super(JobExtraCredentialsList, self).get_queryset()
|
||||
sublist_qs = sublist_qs.filter(credential_type__kind__in=['cloud', 'net'])
|
||||
return sublist_qs
|
||||
|
||||
|
||||
class JobLabelList(SubListAPIView):
|
||||
|
||||
model = models.Label
|
||||
|
||||
@ -439,13 +439,9 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
||||
field = self._meta.get_field(field_name)
|
||||
if isinstance(field, models.ManyToManyField):
|
||||
old_value = set(old_value.all())
|
||||
if getattr(self, '_deprecated_credential_launch', False):
|
||||
# TODO: remove this code branch when support for `extra_credentials` goes away
|
||||
new_value = set(kwargs[field_name])
|
||||
else:
|
||||
new_value = set(kwargs[field_name]) - old_value
|
||||
if not new_value:
|
||||
continue
|
||||
new_value = set(kwargs[field_name]) - old_value
|
||||
if not new_value:
|
||||
continue
|
||||
|
||||
if new_value == old_value:
|
||||
# no-op case: Fields the same as template's value
|
||||
|
||||
@ -413,9 +413,8 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique, Notificatio
|
||||
if 'extra_vars' in validated_kwargs:
|
||||
unified_job.handle_extra_data(validated_kwargs['extra_vars'])
|
||||
|
||||
if not getattr(self, '_deprecated_credential_launch', False):
|
||||
# Create record of provided prompts for relaunch and rescheduling
|
||||
unified_job.create_config_from_prompts(kwargs, parent=self)
|
||||
# Create record of provided prompts for relaunch and rescheduling
|
||||
unified_job.create_config_from_prompts(kwargs, parent=self)
|
||||
|
||||
# manually issue the create activity stream entry _after_ M2M relations
|
||||
# have been associated to the UJ
|
||||
|
||||
@ -105,9 +105,6 @@ class TestSwaggerGeneration():
|
||||
'get', 'put', 'patch', 'delete'
|
||||
]
|
||||
|
||||
# Test deprecated paths
|
||||
assert paths['/api/v2/jobs/{id}/extra_credentials/']['get']['deprecated'] is True
|
||||
|
||||
@pytest.mark.parametrize('path', [
|
||||
'/api/',
|
||||
'/api/v2/',
|
||||
|
||||
@ -24,41 +24,6 @@ def job_template(job_template, project, inventory):
|
||||
return job_template
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credentials_filtering(get, job_template, admin,
|
||||
machine_credential, vault_credential, credential):
|
||||
job_template.credentials.add(machine_credential)
|
||||
job_template.credentials.add(vault_credential)
|
||||
job_template.credentials.add(credential)
|
||||
url = reverse(
|
||||
'api:job_template_extra_credentials_list',
|
||||
kwargs={'pk': job_template.pk}
|
||||
)
|
||||
resp = get(url, admin, expect=200)
|
||||
assert resp.data['count'] == 1
|
||||
assert resp.data['results'][0]['id'] == credential.pk
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credentials_requires_cloud_or_net(get, post, job_template, admin,
|
||||
machine_credential, vault_credential, credential,
|
||||
net_credential):
|
||||
url = reverse(
|
||||
'api:job_template_extra_credentials_list',
|
||||
kwargs={'pk': job_template.pk}
|
||||
)
|
||||
|
||||
for cred in (machine_credential, vault_credential):
|
||||
resp = post(url, {'associate': True, 'id': cred.pk}, admin, expect=400)
|
||||
assert 'Extra credentials must be network or cloud.' in smart_str(resp.content)
|
||||
|
||||
post(url, {'associate': True, 'id': credential.pk}, admin, expect=204)
|
||||
assert get(url, admin).data['count'] == 1
|
||||
|
||||
post(url, {'associate': True, 'id': net_credential.pk}, admin, expect=204)
|
||||
assert get(url, admin).data['count'] == 2
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_prevent_multiple_machine_creds(get, post, job_template, admin, machine_credential):
|
||||
url = reverse(
|
||||
@ -115,52 +80,6 @@ def test_prevent_multiple_machine_creds_at_launch(get, post, job_template, admin
|
||||
assert 'Cannot assign multiple Machine credentials.' in smart_str(resp.content)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credentials_unique_by_kind(get, post, job_template, admin,
|
||||
credentialtype_aws):
|
||||
url = reverse(
|
||||
'api:job_template_extra_credentials_list',
|
||||
kwargs={'pk': job_template.pk}
|
||||
)
|
||||
|
||||
def _new_cred(name):
|
||||
return {
|
||||
'name': name,
|
||||
'credential_type': credentialtype_aws.pk,
|
||||
'inputs': {
|
||||
'username': 'bob',
|
||||
'password': 'secret',
|
||||
}
|
||||
}
|
||||
|
||||
post(url, _new_cred('First Cred'), admin, expect=201)
|
||||
assert get(url, admin).data['count'] == 1
|
||||
|
||||
resp = post(url, _new_cred('Second Cred'), admin, expect=400)
|
||||
assert 'Cannot assign multiple Amazon Web Services credentials.' in smart_str(resp.content)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credentials_at_launch(get, post, job_template, admin, credential):
|
||||
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
|
||||
pk = post(url, {'extra_credentials': [credential.pk]}, admin, expect=201).data['job']
|
||||
summary_fields = get(reverse('api:job_detail', kwargs={'pk': pk}), admin).data['summary_fields']
|
||||
|
||||
assert len(summary_fields['credentials']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_modify_extra_credentials_at_launch(get, post, job_template, admin,
|
||||
machine_credential, vault_credential, credential):
|
||||
job_template.credentials.add(machine_credential)
|
||||
job_template.credentials.add(vault_credential)
|
||||
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
|
||||
pk = post(url, {'extra_credentials': [credential.pk]}, admin, expect=201).data['job']
|
||||
|
||||
summary_fields = get(reverse('api:job_detail', kwargs={'pk': pk}), admin).data['summary_fields']
|
||||
assert len(summary_fields['credentials']) == 3
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_ssh_password_prompted_at_launch(get, post, job_template, admin, machine_credential):
|
||||
job_template.credentials.add(machine_credential)
|
||||
@ -229,25 +148,6 @@ def test_vault_credential_with_password_at_launch(get, post, job_template, admin
|
||||
signal_start.assert_called_with(vault_password='testing123')
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_creds_prompted_at_launch(get, post, job_template, admin, net_credential):
|
||||
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
|
||||
resp = post(url, {'extra_credentials': [net_credential.pk]}, admin, expect=201)
|
||||
|
||||
summary_fields = get(
|
||||
reverse('api:job_detail', kwargs={'pk': resp.data['job']}),
|
||||
admin
|
||||
).data['summary_fields']
|
||||
assert len(summary_fields['credentials']) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_invalid_mixed_credentials_specification(get, post, job_template, admin, net_credential):
|
||||
url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk})
|
||||
post(url=url, data={'credentials': [net_credential.pk], 'extra_credentials': [net_credential.pk]},
|
||||
user=admin, expect=400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_deprecated_credential_activity_stream(patch, admin_user, machine_credential, job_template):
|
||||
job_template.credentials.add(machine_credential)
|
||||
|
||||
@ -22,20 +22,6 @@ from awx.main.models import (
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credentials(get, organization_factory, job_template_factory, credential):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
jt.credentials.add(credential)
|
||||
jt.save()
|
||||
job = jt.create_unified_job()
|
||||
|
||||
url = reverse('api:job_extra_credentials_list', kwargs={'pk': job.pk})
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_job_relaunch_permission_denied_response(
|
||||
post, get, inventory, project, credential, net_credential, machine_credential):
|
||||
@ -50,7 +36,7 @@ def test_job_relaunch_permission_denied_response(
|
||||
r = get(job.get_absolute_url(), jt_user, expect=200)
|
||||
assert r.data['summary_fields']['user_capabilities']['start']
|
||||
|
||||
# Job has prompted extra_credential, launch denied w/ message
|
||||
# Job has prompted credential, launch denied w/ message
|
||||
job.launch_config.credentials.add(net_credential)
|
||||
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)
|
||||
assert 'launched with prompted fields you do not have access to' in r.data['detail']
|
||||
@ -70,7 +56,7 @@ def test_job_relaunch_prompts_not_accepted_response(
|
||||
r = get(job.get_absolute_url(), jt_user, expect=200)
|
||||
assert r.data['summary_fields']['user_capabilities']['start']
|
||||
|
||||
# Job has prompted extra_credential, launch denied w/ message
|
||||
# Job has prompted credential, launch denied w/ message
|
||||
job.launch_config.credentials.add(net_credential)
|
||||
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)
|
||||
|
||||
|
||||
@ -304,7 +304,7 @@ def test_job_launch_with_default_creds(machine_credential, vault_credential, dep
|
||||
@pytest.mark.django_db
|
||||
def test_job_launch_JT_enforces_unique_credentials_kinds(machine_credential, credentialtype_aws, deploy_jobtemplate):
|
||||
"""
|
||||
JT launching should require that extra_credentials have distinct CredentialTypes
|
||||
JT launching should require that credentials have distinct CredentialTypes
|
||||
"""
|
||||
creds = []
|
||||
for i in range(2):
|
||||
|
||||
@ -45,27 +45,6 @@ def test_create(post, project, machine_credential, inventory, alice, grant_proje
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credential_creation(get, post, organization_factory, job_template_factory, credentialtype_aws):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
|
||||
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
|
||||
response = post(url, {
|
||||
'name': 'My Cred',
|
||||
'credential_type': credentialtype_aws.pk,
|
||||
'inputs': {
|
||||
'username': 'bob',
|
||||
'password': 'secret',
|
||||
}
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 201
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('kind', ['scm', 'insights'])
|
||||
def test_invalid_credential_kind_xfail(get, post, organization_factory, job_template_factory, kind):
|
||||
@ -87,42 +66,6 @@ def test_invalid_credential_kind_xfail(get, post, organization_factory, job_temp
|
||||
assert 'Cannot assign a Credential of kind `{}`.'.format(kind) in response.data.values()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_extra_credential_unique_type_xfail(get, post, organization_factory, job_template_factory, credentialtype_aws):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
|
||||
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
|
||||
response = post(url, {
|
||||
'name': 'My Cred',
|
||||
'credential_type': credentialtype_aws.pk,
|
||||
'inputs': {
|
||||
'username': 'bob',
|
||||
'password': 'secret',
|
||||
}
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 201
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 1
|
||||
|
||||
# this request should fail because you can't assign the same type (aws)
|
||||
# twice
|
||||
response = post(url, {
|
||||
'name': 'My Cred',
|
||||
'credential_type': credentialtype_aws.pk,
|
||||
'inputs': {
|
||||
'username': 'joe',
|
||||
'password': 'another-secret',
|
||||
}
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 400
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, inventory, settings):
|
||||
project.use_role.members.add(alice)
|
||||
@ -143,60 +86,6 @@ def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, invento
|
||||
assert 'Maximum number of forks (10) exceeded' in str(response.data)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_attach_extra_credential(get, post, organization_factory, job_template_factory, credential):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
|
||||
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
|
||||
response = post(url, {
|
||||
'associate': True,
|
||||
'id': credential.id,
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 204
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_detach_extra_credential(get, post, organization_factory, job_template_factory, credential):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
jt.credentials.add(credential)
|
||||
jt.save()
|
||||
|
||||
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
|
||||
response = post(url, {
|
||||
'disassociate': True,
|
||||
'id': credential.id,
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 204
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_attach_extra_credential_wrong_kind_xfail(get, post, organization_factory, job_template_factory, machine_credential):
|
||||
"""Extra credentials only allow net + cloud credentials"""
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
|
||||
url = reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk})
|
||||
response = post(url, {
|
||||
'associate': True,
|
||||
'id': machine_credential.id,
|
||||
}, objs.superusers.admin)
|
||||
assert response.status_code == 400
|
||||
|
||||
response = get(url, user=objs.superusers.admin)
|
||||
assert response.data.get('count') == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize(
|
||||
"grant_project, grant_inventory, expect", [
|
||||
@ -368,57 +257,6 @@ def test_launch_with_pending_deletion_inventory_workflow(get, post, organization
|
||||
assert resp.data['inventory'] == ['The inventory associated with this Workflow is being deleted.']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_launch_with_extra_credentials(get, post, organization_factory,
|
||||
job_template_factory, machine_credential,
|
||||
credential, net_credential):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
jt.ask_credential_on_launch = True
|
||||
jt.save()
|
||||
|
||||
resp = post(
|
||||
reverse('api:job_template_launch', kwargs={'pk': jt.pk}),
|
||||
dict(
|
||||
credentials=[machine_credential.pk, credential.pk, net_credential.pk]
|
||||
),
|
||||
objs.superusers.admin, expect=201
|
||||
)
|
||||
job_pk = resp.data.get('id')
|
||||
|
||||
resp = get(reverse('api:job_extra_credentials_list', kwargs={'pk': job_pk}), objs.superusers.admin)
|
||||
assert resp.data.get('count') == 2
|
||||
|
||||
resp = get(reverse('api:job_template_extra_credentials_list', kwargs={'pk': jt.pk}), objs.superusers.admin)
|
||||
assert resp.data.get('count') == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_launch_with_extra_credentials_not_allowed(get, post, organization_factory,
|
||||
job_template_factory, machine_credential,
|
||||
credential, net_credential):
|
||||
objs = organization_factory("org", superusers=['admin'])
|
||||
jt = job_template_factory("jt", organization=objs.organization,
|
||||
inventory='test_inv', project='test_proj').job_template
|
||||
jt.credentials.add(machine_credential)
|
||||
jt.ask_credential_on_launch = False
|
||||
jt.save()
|
||||
|
||||
resp = post(
|
||||
reverse('api:job_template_launch', kwargs={'pk': jt.pk}),
|
||||
dict(
|
||||
credentials=[machine_credential.pk, credential.pk, net_credential.pk]
|
||||
),
|
||||
objs.superusers.admin
|
||||
)
|
||||
assert 'credentials' in resp.data['ignored_fields'].keys()
|
||||
job_pk = resp.data.get('id')
|
||||
|
||||
resp = get(reverse('api:job_extra_credentials_list', kwargs={'pk': job_pk}), objs.superusers.admin)
|
||||
assert resp.data.get('count') == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_jt_without_project(inventory):
|
||||
data = dict(name="Test", job_type="run",
|
||||
|
||||
@ -128,7 +128,7 @@ def test_job_template_access_admin(role_names, jt_linked, rando):
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_job_template_extra_credentials_prompts_access(
|
||||
def test_job_template_credentials_prompts_access(
|
||||
rando, post, inventory, project, machine_credential, vault_credential):
|
||||
jt = JobTemplate.objects.create(
|
||||
name = 'test-jt',
|
||||
@ -149,14 +149,14 @@ def test_job_template_extra_credentials_prompts_access(
|
||||
@pytest.mark.django_db
|
||||
class TestJobTemplateCredentials:
|
||||
|
||||
def test_job_template_cannot_add_extra_credentials(self, job_template, credential, rando):
|
||||
def test_job_template_cannot_add_credentials(self, job_template, credential, rando):
|
||||
job_template.admin_role.members.add(rando)
|
||||
credential.read_role.members.add(rando)
|
||||
# without permission to credential, user can not attach it
|
||||
assert not JobTemplateAccess(rando).can_attach(
|
||||
job_template, credential, 'credentials', {})
|
||||
|
||||
def test_job_template_can_add_extra_credentials(self, job_template, credential, rando):
|
||||
def test_job_template_can_add_credentials(self, job_template, credential, rando):
|
||||
job_template.admin_role.members.add(rando)
|
||||
credential.use_role.members.add(rando)
|
||||
# user has permission to apply credential
|
||||
|
||||
@ -123,9 +123,9 @@ export default
|
||||
if(!Empty(scope.selected_credentials.machine)) {
|
||||
job_launch_data.credential_id = scope.selected_credentials.machine.id;
|
||||
}
|
||||
job_launch_data.extra_credentials = [];
|
||||
job_launch_data.credentials = [];
|
||||
scope.selected_credentials.extra.forEach((extraCredential) => {
|
||||
job_launch_data.extra_credentials.push(extraCredential.id);
|
||||
job_launch_data.credentials.push(extraCredential.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
"labels": "/api/v2/job_templates/7/labels/",
|
||||
"inventory": "/api/v2/inventories/1/",
|
||||
"project": "/api/v2/projects/6/",
|
||||
"extra_credentials": "/api/v2/job_templates/7/extra_credentials/",
|
||||
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||
"last_job": "/api/v2/jobs/12/",
|
||||
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||
@ -143,7 +142,6 @@
|
||||
"type": "job"
|
||||
}
|
||||
],
|
||||
"extra_credentials": [],
|
||||
"credentials": [
|
||||
{
|
||||
"id": 1, "kind": "ssh" , "name": "Credential 1"
|
||||
@ -195,4 +193,4 @@
|
||||
"job_slice_count": 1,
|
||||
"webhook_service": "github",
|
||||
"webhook_credential": 8
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
"labels": "/api/v2/jobs/2/labels/",
|
||||
"inventory": "/api/v2/inventories/1/",
|
||||
"project": "/api/v2/projects/6/",
|
||||
"extra_credentials": "/api/v2/jobs/2/extra_credentials/",
|
||||
"credentials": "/api/v2/jobs/2/credentials/",
|
||||
"unified_job_template": "/api/v2/job_templates/7/",
|
||||
"stdout": "/api/v2/jobs/2/stdout/",
|
||||
@ -80,7 +79,6 @@
|
||||
"count": 0,
|
||||
"results": []
|
||||
},
|
||||
"extra_credentials": [],
|
||||
"credentials": [
|
||||
{
|
||||
"id": 1,
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
"labels": "/api/v2/job_templates/7/labels/",
|
||||
"inventory": "/api/v2/inventories/1/",
|
||||
"project": "/api/v2/projects/6/",
|
||||
"extra_credentials": "/api/v2/job_templates/7/extra_credentials/",
|
||||
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||
"last_job": "/api/v2/jobs/12/",
|
||||
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||
@ -118,7 +117,6 @@
|
||||
"finished": "2019-10-01T14:34:35.142483Z",
|
||||
"type": "job"
|
||||
}],
|
||||
"extra_credentials": [],
|
||||
"credentials": [{
|
||||
"id": 1,
|
||||
"kind": "ssh",
|
||||
|
||||
@ -362,9 +362,7 @@ class Credentials(page.PageList, Credential):
|
||||
|
||||
|
||||
page.register_page([resources.credentials,
|
||||
resources.related_credentials,
|
||||
resources.job_extra_credentials,
|
||||
resources.job_template_extra_credentials],
|
||||
resources.related_credentials],
|
||||
Credentials)
|
||||
|
||||
|
||||
|
||||
@ -189,16 +189,6 @@ class JobTemplate(
|
||||
dict(id=kwargs['vault_credential']))
|
||||
return ret
|
||||
|
||||
def add_extra_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.extra_credentials.post(
|
||||
dict(id=credential.id, associate=True))
|
||||
|
||||
def remove_extra_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.extra_credentials.post(
|
||||
dict(id=credential.id, disassociate=True))
|
||||
|
||||
def add_credential(self, credential):
|
||||
with suppress(exc.NoContent):
|
||||
self.related.credentials.post(
|
||||
|
||||
@ -88,7 +88,6 @@ class Resources(object):
|
||||
_job_event = r'job_events/\d+/'
|
||||
_job_event_children = r'job_events/\d+/children/'
|
||||
_job_events = 'job_events/'
|
||||
_job_extra_credentials = _job + 'extra_credentials/'
|
||||
_job_host_summaries = r'jobs/\d+/job_host_summaries/'
|
||||
_job_host_summary = r'job_host_summaries/\d+/'
|
||||
_job_job_event = r'jobs/\d+/job_events/\d+/'
|
||||
@ -105,7 +104,6 @@ class Resources(object):
|
||||
_job_template_access_list = r'job_templates/\d+/access_list/'
|
||||
_job_template_callback = r'job_templates/\d+/callback/'
|
||||
_job_template_copy = r'job_templates/\d+/copy/'
|
||||
_job_template_extra_credentials = _job_template + 'extra_credentials/'
|
||||
_job_template_jobs = r'job_templates/\d+/jobs/'
|
||||
_job_template_labels = r'job_templates/\d+/labels/'
|
||||
_job_template_launch = r'job_templates/\d+/launch/'
|
||||
|
||||
@ -37,7 +37,7 @@ Important Changes
|
||||
two OpenStack credentials.
|
||||
|
||||
* In the same manner as "promptable SSH credentials", when
|
||||
``ask_credential_on_launch = true``, ``JobTemplate.extra_credentials`` can be
|
||||
``ask_credential_on_launch = true``, ``JobTemplate.credentials`` can be
|
||||
specified in the launch payload.
|
||||
|
||||
* Custom inventory sources can now utilize a ``Credential``; you
|
||||
@ -221,9 +221,9 @@ API resources in `/api/v2/` now have two credential related fields:
|
||||
...
|
||||
}
|
||||
|
||||
...and a new endpoint for fetching all "extra" credentials:
|
||||
...and a new endpoint for fetching all credentials:
|
||||
|
||||
HTTP GET /api/v2/job_templates/N/extra_credentials/
|
||||
HTTP GET /api/v2/job_templates/N/credentials/
|
||||
|
||||
{
|
||||
'count': N,
|
||||
@ -239,21 +239,21 @@ Similar to other list attachment/detachment API views, cloud and network
|
||||
credentials can be created and attached via an `HTTP POST` at this new
|
||||
endpoint:
|
||||
|
||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
||||
HTTP POST /api/v2/job_templates/N/credentials/
|
||||
|
||||
{
|
||||
'id': <cloud_credential_primary_key>,
|
||||
'associate': True,
|
||||
}
|
||||
|
||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
||||
HTTP POST /api/v2/job_templates/N/credentials/
|
||||
|
||||
{
|
||||
'id': <network_credential_primary_key>,
|
||||
'disassociate': True,
|
||||
}
|
||||
|
||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
||||
HTTP POST /api/v2/job_templates/N/credentials/
|
||||
|
||||
{
|
||||
'name': 'My Credential',
|
||||
|
||||
@ -283,7 +283,3 @@ of what happened.
|
||||
- Job template has machine & cloud credentials, set to prompt for credential on launch
|
||||
- Schedule for job template provides no credentials
|
||||
- Spawned job still uses all job template credentials
|
||||
|
||||
**Credentials Deprecated Behavior**
|
||||
- Manual launch providing `"extra_credentials": []` should launch with no job credentials
|
||||
- Such jobs cannot have schedules created from them
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user