mirror of
https://github.com/ansible/awx.git
synced 2026-05-14 21:07:39 -02:30
Merge pull request #6885 from ryanpetrello/remove-extra-credentials
remove the deprecated extra_credentials endpoints Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -2756,16 +2756,11 @@ class JobOptionsSerializer(LabelsListMixin, BaseSerializer):
|
|||||||
if obj.organization_id:
|
if obj.organization_id:
|
||||||
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id})
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization_id})
|
||||||
if isinstance(obj, UnifiedJobTemplate):
|
if isinstance(obj, UnifiedJobTemplate):
|
||||||
res['extra_credentials'] = self.reverse(
|
|
||||||
'api:job_template_extra_credentials_list',
|
|
||||||
kwargs={'pk': obj.pk}
|
|
||||||
)
|
|
||||||
res['credentials'] = self.reverse(
|
res['credentials'] = self.reverse(
|
||||||
'api:job_template_credentials_list',
|
'api:job_template_credentials_list',
|
||||||
kwargs={'pk': obj.pk}
|
kwargs={'pk': obj.pk}
|
||||||
)
|
)
|
||||||
elif isinstance(obj, UnifiedJob):
|
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})
|
res['credentials'] = self.reverse('api:job_credentials_list', kwargs={'pk': obj.pk})
|
||||||
|
|
||||||
return res
|
return res
|
||||||
@@ -2934,7 +2929,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
|||||||
summary_fields = super(JobTemplateSerializer, self).get_summary_fields(obj)
|
summary_fields = super(JobTemplateSerializer, self).get_summary_fields(obj)
|
||||||
all_creds = []
|
all_creds = []
|
||||||
# Organize credential data into multitude of deprecated fields
|
# Organize credential data into multitude of deprecated fields
|
||||||
extra_creds = []
|
|
||||||
if obj.pk:
|
if obj.pk:
|
||||||
for cred in obj.credentials.all():
|
for cred in obj.credentials.all():
|
||||||
summarized_cred = {
|
summarized_cred = {
|
||||||
@@ -2945,10 +2939,6 @@ class JobTemplateSerializer(JobTemplateMixin, UnifiedJobTemplateSerializer, JobO
|
|||||||
'cloud': cred.credential_type.kind == 'cloud'
|
'cloud': cred.credential_type.kind == 'cloud'
|
||||||
}
|
}
|
||||||
all_creds.append(summarized_cred)
|
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
|
summary_fields['credentials'] = all_creds
|
||||||
return summary_fields
|
return summary_fields
|
||||||
|
|
||||||
@@ -3023,7 +3013,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
|||||||
summary_fields = super(JobSerializer, self).get_summary_fields(obj)
|
summary_fields = super(JobSerializer, self).get_summary_fields(obj)
|
||||||
all_creds = []
|
all_creds = []
|
||||||
# Organize credential data into multitude of deprecated fields
|
# Organize credential data into multitude of deprecated fields
|
||||||
extra_creds = []
|
|
||||||
if obj.pk:
|
if obj.pk:
|
||||||
for cred in obj.credentials.all():
|
for cred in obj.credentials.all():
|
||||||
summarized_cred = {
|
summarized_cred = {
|
||||||
@@ -3034,10 +3023,6 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
|||||||
'cloud': cred.credential_type.kind == 'cloud'
|
'cloud': cred.credential_type.kind == 'cloud'
|
||||||
}
|
}
|
||||||
all_creds.append(summarized_cred)
|
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
|
summary_fields['credentials'] = all_creds
|
||||||
return summary_fields
|
return summary_fields
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ from awx.api.views import (
|
|||||||
UnifiedJobList,
|
UnifiedJobList,
|
||||||
HostAnsibleFactsDetail,
|
HostAnsibleFactsDetail,
|
||||||
JobCredentialsList,
|
JobCredentialsList,
|
||||||
JobExtraCredentialsList,
|
|
||||||
JobTemplateCredentialsList,
|
JobTemplateCredentialsList,
|
||||||
JobTemplateExtraCredentialsList,
|
|
||||||
SchedulePreview,
|
SchedulePreview,
|
||||||
ScheduleZoneInfo,
|
ScheduleZoneInfo,
|
||||||
OAuth2ApplicationList,
|
OAuth2ApplicationList,
|
||||||
@@ -83,9 +81,7 @@ v2_urls = [
|
|||||||
url(r'^credential_types/', include(credential_type_urls)),
|
url(r'^credential_types/', include(credential_type_urls)),
|
||||||
url(r'^credential_input_sources/', include(credential_input_source_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'^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'^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'^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/preview/$', SchedulePreview.as_view(), name='schedule_rrule'),
|
||||||
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
|
url(r'^schedules/zoneinfo/$', ScheduleZoneInfo.as_view(), name='schedule_zoneinfo'),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import socket
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
from collections import OrderedDict, Iterable
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
@@ -2344,51 +2344,6 @@ class JobTemplateLaunch(RetrieveAPIView):
|
|||||||
if 'inventory' not in modern_data and id_fd in modern_data:
|
if 'inventory' not in modern_data and id_fd in modern_data:
|
||||||
modern_data['inventory'] = modern_data[id_fd]
|
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
|
# credential passwords were historically provided as top-level attributes
|
||||||
if 'credential_passwords' not in modern_data:
|
if 'credential_passwords' not in modern_data:
|
||||||
modern_data['credential_passwords'] = data.copy()
|
modern_data['credential_passwords'] = data.copy()
|
||||||
@@ -2711,22 +2666,6 @@ class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView):
|
|||||||
return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created)
|
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):
|
class JobTemplateLabelList(DeleteLastUnattachLabelMixin, SubListCreateAttachDetachAPIView):
|
||||||
|
|
||||||
model = models.Label
|
model = models.Label
|
||||||
@@ -3543,16 +3482,6 @@ class JobCredentialsList(SubListAPIView):
|
|||||||
relationship = 'credentials'
|
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):
|
class JobLabelList(SubListAPIView):
|
||||||
|
|
||||||
model = models.Label
|
model = models.Label
|
||||||
|
|||||||
@@ -439,13 +439,9 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
|
|||||||
field = self._meta.get_field(field_name)
|
field = self._meta.get_field(field_name)
|
||||||
if isinstance(field, models.ManyToManyField):
|
if isinstance(field, models.ManyToManyField):
|
||||||
old_value = set(old_value.all())
|
old_value = set(old_value.all())
|
||||||
if getattr(self, '_deprecated_credential_launch', False):
|
new_value = set(kwargs[field_name]) - old_value
|
||||||
# TODO: remove this code branch when support for `extra_credentials` goes away
|
if not new_value:
|
||||||
new_value = set(kwargs[field_name])
|
continue
|
||||||
else:
|
|
||||||
new_value = set(kwargs[field_name]) - old_value
|
|
||||||
if not new_value:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if new_value == old_value:
|
if new_value == old_value:
|
||||||
# no-op case: Fields the same as template's 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:
|
if 'extra_vars' in validated_kwargs:
|
||||||
unified_job.handle_extra_data(validated_kwargs['extra_vars'])
|
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
|
||||||
# Create record of provided prompts for relaunch and rescheduling
|
unified_job.create_config_from_prompts(kwargs, parent=self)
|
||||||
unified_job.create_config_from_prompts(kwargs, parent=self)
|
|
||||||
|
|
||||||
# manually issue the create activity stream entry _after_ M2M relations
|
# manually issue the create activity stream entry _after_ M2M relations
|
||||||
# have been associated to the UJ
|
# have been associated to the UJ
|
||||||
|
|||||||
@@ -105,9 +105,6 @@ class TestSwaggerGeneration():
|
|||||||
'get', 'put', 'patch', 'delete'
|
'get', 'put', 'patch', 'delete'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Test deprecated paths
|
|
||||||
assert paths['/api/v2/jobs/{id}/extra_credentials/']['get']['deprecated'] is True
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('path', [
|
@pytest.mark.parametrize('path', [
|
||||||
'/api/',
|
'/api/',
|
||||||
'/api/v2/',
|
'/api/v2/',
|
||||||
|
|||||||
@@ -24,41 +24,6 @@ def job_template(job_template, project, inventory):
|
|||||||
return job_template
|
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
|
@pytest.mark.django_db
|
||||||
def test_prevent_multiple_machine_creds(get, post, job_template, admin, machine_credential):
|
def test_prevent_multiple_machine_creds(get, post, job_template, admin, machine_credential):
|
||||||
url = reverse(
|
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)
|
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
|
@pytest.mark.django_db
|
||||||
def test_ssh_password_prompted_at_launch(get, post, job_template, admin, machine_credential):
|
def test_ssh_password_prompted_at_launch(get, post, job_template, admin, machine_credential):
|
||||||
job_template.credentials.add(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')
|
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
|
@pytest.mark.django_db
|
||||||
def test_deprecated_credential_activity_stream(patch, admin_user, machine_credential, job_template):
|
def test_deprecated_credential_activity_stream(patch, admin_user, machine_credential, job_template):
|
||||||
job_template.credentials.add(machine_credential)
|
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
|
@pytest.mark.django_db
|
||||||
def test_job_relaunch_permission_denied_response(
|
def test_job_relaunch_permission_denied_response(
|
||||||
post, get, inventory, project, credential, net_credential, machine_credential):
|
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)
|
r = get(job.get_absolute_url(), jt_user, expect=200)
|
||||||
assert r.data['summary_fields']['user_capabilities']['start']
|
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)
|
job.launch_config.credentials.add(net_credential)
|
||||||
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)
|
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']
|
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)
|
r = get(job.get_absolute_url(), jt_user, expect=200)
|
||||||
assert r.data['summary_fields']['user_capabilities']['start']
|
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)
|
job.launch_config.credentials.add(net_credential)
|
||||||
r = post(reverse('api:job_relaunch', kwargs={'pk':job.pk}), {}, jt_user, expect=403)
|
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
|
@pytest.mark.django_db
|
||||||
def test_job_launch_JT_enforces_unique_credentials_kinds(machine_credential, credentialtype_aws, deploy_jobtemplate):
|
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 = []
|
creds = []
|
||||||
for i in range(2):
|
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.django_db
|
||||||
@pytest.mark.parametrize('kind', ['scm', 'insights'])
|
@pytest.mark.parametrize('kind', ['scm', 'insights'])
|
||||||
def test_invalid_credential_kind_xfail(get, post, organization_factory, job_template_factory, kind):
|
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()
|
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
|
@pytest.mark.django_db
|
||||||
def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, inventory, settings):
|
def test_create_with_forks_exceeding_maximum_xfail(alice, post, project, inventory, settings):
|
||||||
project.use_role.members.add(alice)
|
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)
|
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.django_db
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"grant_project, grant_inventory, expect", [
|
"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.']
|
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
|
@pytest.mark.django_db
|
||||||
def test_jt_without_project(inventory):
|
def test_jt_without_project(inventory):
|
||||||
data = dict(name="Test", job_type="run",
|
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
|
@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):
|
rando, post, inventory, project, machine_credential, vault_credential):
|
||||||
jt = JobTemplate.objects.create(
|
jt = JobTemplate.objects.create(
|
||||||
name = 'test-jt',
|
name = 'test-jt',
|
||||||
@@ -149,14 +149,14 @@ def test_job_template_extra_credentials_prompts_access(
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
class TestJobTemplateCredentials:
|
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)
|
job_template.admin_role.members.add(rando)
|
||||||
credential.read_role.members.add(rando)
|
credential.read_role.members.add(rando)
|
||||||
# without permission to credential, user can not attach it
|
# without permission to credential, user can not attach it
|
||||||
assert not JobTemplateAccess(rando).can_attach(
|
assert not JobTemplateAccess(rando).can_attach(
|
||||||
job_template, credential, 'credentials', {})
|
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)
|
job_template.admin_role.members.add(rando)
|
||||||
credential.use_role.members.add(rando)
|
credential.use_role.members.add(rando)
|
||||||
# user has permission to apply credential
|
# user has permission to apply credential
|
||||||
|
|||||||
@@ -123,9 +123,9 @@ export default
|
|||||||
if(!Empty(scope.selected_credentials.machine)) {
|
if(!Empty(scope.selected_credentials.machine)) {
|
||||||
job_launch_data.credential_id = scope.selected_credentials.machine.id;
|
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) => {
|
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/",
|
"labels": "/api/v2/job_templates/7/labels/",
|
||||||
"inventory": "/api/v2/inventories/1/",
|
"inventory": "/api/v2/inventories/1/",
|
||||||
"project": "/api/v2/projects/6/",
|
"project": "/api/v2/projects/6/",
|
||||||
"extra_credentials": "/api/v2/job_templates/7/extra_credentials/",
|
|
||||||
"credentials": "/api/v2/job_templates/7/credentials/",
|
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||||
"last_job": "/api/v2/jobs/12/",
|
"last_job": "/api/v2/jobs/12/",
|
||||||
"jobs": "/api/v2/job_templates/7/jobs/",
|
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||||
@@ -143,7 +142,6 @@
|
|||||||
"type": "job"
|
"type": "job"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"extra_credentials": [],
|
|
||||||
"credentials": [
|
"credentials": [
|
||||||
{
|
{
|
||||||
"id": 1, "kind": "ssh" , "name": "Credential 1"
|
"id": 1, "kind": "ssh" , "name": "Credential 1"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
"labels": "/api/v2/jobs/2/labels/",
|
"labels": "/api/v2/jobs/2/labels/",
|
||||||
"inventory": "/api/v2/inventories/1/",
|
"inventory": "/api/v2/inventories/1/",
|
||||||
"project": "/api/v2/projects/6/",
|
"project": "/api/v2/projects/6/",
|
||||||
"extra_credentials": "/api/v2/jobs/2/extra_credentials/",
|
|
||||||
"credentials": "/api/v2/jobs/2/credentials/",
|
"credentials": "/api/v2/jobs/2/credentials/",
|
||||||
"unified_job_template": "/api/v2/job_templates/7/",
|
"unified_job_template": "/api/v2/job_templates/7/",
|
||||||
"stdout": "/api/v2/jobs/2/stdout/",
|
"stdout": "/api/v2/jobs/2/stdout/",
|
||||||
@@ -80,7 +79,6 @@
|
|||||||
"count": 0,
|
"count": 0,
|
||||||
"results": []
|
"results": []
|
||||||
},
|
},
|
||||||
"extra_credentials": [],
|
|
||||||
"credentials": [
|
"credentials": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"labels": "/api/v2/job_templates/7/labels/",
|
"labels": "/api/v2/job_templates/7/labels/",
|
||||||
"inventory": "/api/v2/inventories/1/",
|
"inventory": "/api/v2/inventories/1/",
|
||||||
"project": "/api/v2/projects/6/",
|
"project": "/api/v2/projects/6/",
|
||||||
"extra_credentials": "/api/v2/job_templates/7/extra_credentials/",
|
|
||||||
"credentials": "/api/v2/job_templates/7/credentials/",
|
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||||
"last_job": "/api/v2/jobs/12/",
|
"last_job": "/api/v2/jobs/12/",
|
||||||
"jobs": "/api/v2/job_templates/7/jobs/",
|
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||||
@@ -118,7 +117,6 @@
|
|||||||
"finished": "2019-10-01T14:34:35.142483Z",
|
"finished": "2019-10-01T14:34:35.142483Z",
|
||||||
"type": "job"
|
"type": "job"
|
||||||
}],
|
}],
|
||||||
"extra_credentials": [],
|
|
||||||
"credentials": [{
|
"credentials": [{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"kind": "ssh",
|
"kind": "ssh",
|
||||||
|
|||||||
@@ -362,9 +362,7 @@ class Credentials(page.PageList, Credential):
|
|||||||
|
|
||||||
|
|
||||||
page.register_page([resources.credentials,
|
page.register_page([resources.credentials,
|
||||||
resources.related_credentials,
|
resources.related_credentials],
|
||||||
resources.job_extra_credentials,
|
|
||||||
resources.job_template_extra_credentials],
|
|
||||||
Credentials)
|
Credentials)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -189,16 +189,6 @@ class JobTemplate(
|
|||||||
dict(id=kwargs['vault_credential']))
|
dict(id=kwargs['vault_credential']))
|
||||||
return ret
|
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):
|
def add_credential(self, credential):
|
||||||
with suppress(exc.NoContent):
|
with suppress(exc.NoContent):
|
||||||
self.related.credentials.post(
|
self.related.credentials.post(
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ class Resources(object):
|
|||||||
_job_event = r'job_events/\d+/'
|
_job_event = r'job_events/\d+/'
|
||||||
_job_event_children = r'job_events/\d+/children/'
|
_job_event_children = r'job_events/\d+/children/'
|
||||||
_job_events = 'job_events/'
|
_job_events = 'job_events/'
|
||||||
_job_extra_credentials = _job + 'extra_credentials/'
|
|
||||||
_job_host_summaries = r'jobs/\d+/job_host_summaries/'
|
_job_host_summaries = r'jobs/\d+/job_host_summaries/'
|
||||||
_job_host_summary = r'job_host_summaries/\d+/'
|
_job_host_summary = r'job_host_summaries/\d+/'
|
||||||
_job_job_event = r'jobs/\d+/job_events/\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_access_list = r'job_templates/\d+/access_list/'
|
||||||
_job_template_callback = r'job_templates/\d+/callback/'
|
_job_template_callback = r'job_templates/\d+/callback/'
|
||||||
_job_template_copy = r'job_templates/\d+/copy/'
|
_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_jobs = r'job_templates/\d+/jobs/'
|
||||||
_job_template_labels = r'job_templates/\d+/labels/'
|
_job_template_labels = r'job_templates/\d+/labels/'
|
||||||
_job_template_launch = r'job_templates/\d+/launch/'
|
_job_template_launch = r'job_templates/\d+/launch/'
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Important Changes
|
|||||||
two OpenStack credentials.
|
two OpenStack credentials.
|
||||||
|
|
||||||
* In the same manner as "promptable SSH credentials", when
|
* 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.
|
specified in the launch payload.
|
||||||
|
|
||||||
* Custom inventory sources can now utilize a ``Credential``; you
|
* 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,
|
'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
|
credentials can be created and attached via an `HTTP POST` at this new
|
||||||
endpoint:
|
endpoint:
|
||||||
|
|
||||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
HTTP POST /api/v2/job_templates/N/credentials/
|
||||||
|
|
||||||
{
|
{
|
||||||
'id': <cloud_credential_primary_key>,
|
'id': <cloud_credential_primary_key>,
|
||||||
'associate': True,
|
'associate': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
HTTP POST /api/v2/job_templates/N/credentials/
|
||||||
|
|
||||||
{
|
{
|
||||||
'id': <network_credential_primary_key>,
|
'id': <network_credential_primary_key>,
|
||||||
'disassociate': True,
|
'disassociate': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTP POST /api/v2/job_templates/N/extra_credentials/
|
HTTP POST /api/v2/job_templates/N/credentials/
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'My Credential',
|
'name': 'My Credential',
|
||||||
|
|||||||
@@ -283,7 +283,3 @@ of what happened.
|
|||||||
- Job template has machine & cloud credentials, set to prompt for credential on launch
|
- Job template has machine & cloud credentials, set to prompt for credential on launch
|
||||||
- Schedule for job template provides no credentials
|
- Schedule for job template provides no credentials
|
||||||
- Spawned job still uses all job template 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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user