mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 18:09:57 -03:30
added initial API support for Network credential
This commit is contained in:
parent
25b8faa81a
commit
e8b35533e4
@ -77,6 +77,7 @@ SUMMARIZABLE_FK_FIELDS = {
|
||||
'project': DEFAULT_SUMMARY_FIELDS + ('status',),
|
||||
'credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud'),
|
||||
'cloud_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud'),
|
||||
'network_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'net'),
|
||||
'permission': DEFAULT_SUMMARY_FIELDS,
|
||||
'job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed',),
|
||||
'job_template': DEFAULT_SUMMARY_FIELDS,
|
||||
@ -1551,7 +1552,7 @@ class JobOptionsSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
fields = ('*', 'job_type', 'inventory', 'project', 'playbook',
|
||||
'credential', 'cloud_credential', 'forks', 'limit',
|
||||
'credential', 'cloud_credential', 'network_credential', 'forks', 'limit',
|
||||
'verbosity', 'extra_vars', 'job_tags', 'force_handlers',
|
||||
'skip_tags', 'start_at_task',)
|
||||
|
||||
@ -1567,6 +1568,9 @@ class JobOptionsSerializer(BaseSerializer):
|
||||
if obj.cloud_credential:
|
||||
res['cloud_credential'] = reverse('api:credential_detail',
|
||||
args=(obj.cloud_credential.pk,))
|
||||
if obj.network_credential:
|
||||
res['network_credential'] = reverse('api:credential_detail',
|
||||
args=(obj.network_credential.pk,))
|
||||
return res
|
||||
|
||||
def _summary_field_labels(self, obj):
|
||||
@ -1591,6 +1595,8 @@ class JobOptionsSerializer(BaseSerializer):
|
||||
ret['credential'] = None
|
||||
if 'cloud_credential' in ret and not obj.cloud_credential:
|
||||
ret['cloud_credential'] = None
|
||||
if 'network_credential' in ret and not obj.network_credential:
|
||||
ret['network_credential'] = None
|
||||
return ret
|
||||
|
||||
def validate(self, attrs):
|
||||
@ -1718,6 +1724,8 @@ class JobSerializer(UnifiedJobSerializer, JobOptionsSerializer):
|
||||
data.setdefault('credential', job_template.credential.pk)
|
||||
if job_template.cloud_credential:
|
||||
data.setdefault('cloud_credential', job_template.cloud_credential.pk)
|
||||
if job_template.network_credential:
|
||||
data.setdefault('network_credential', job_template.network_credential.pk)
|
||||
data.setdefault('forks', job_template.forks)
|
||||
data.setdefault('limit', job_template.limit)
|
||||
data.setdefault('verbosity', job_template.verbosity)
|
||||
|
||||
@ -33,6 +33,7 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique, ResourceMixin):
|
||||
|
||||
KIND_CHOICES = [
|
||||
('ssh', _('Machine')),
|
||||
('net', _('Network')),
|
||||
('scm', _('Source Control')),
|
||||
('aws', _('Amazon Web Services')),
|
||||
('rax', _('Rackspace')),
|
||||
|
||||
@ -85,6 +85,14 @@ class JobOptions(BaseModel):
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
network_credential = models.ForeignKey(
|
||||
'Credential',
|
||||
related_name='%(class)ss_as_network_credential+',
|
||||
blank=True,
|
||||
null=True,
|
||||
default=None,
|
||||
on_delete=models.SET_NULL,
|
||||
),
|
||||
forks = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
default=0,
|
||||
@ -141,6 +149,14 @@ class JobOptions(BaseModel):
|
||||
)
|
||||
return cred
|
||||
|
||||
def clean_network_credential(self):
|
||||
cred = self.network_credential
|
||||
if cred and cred.kind != 'net':
|
||||
raise ValidationError(
|
||||
'You must provide a network credential.',
|
||||
)
|
||||
return cred
|
||||
|
||||
def clean_cloud_credential(self):
|
||||
cred = self.cloud_credential
|
||||
if cred and cred.kind not in CLOUD_PROVIDERS + ('aws',):
|
||||
@ -212,7 +228,7 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, ResourceMixin):
|
||||
@classmethod
|
||||
def _get_unified_job_field_names(cls):
|
||||
return ['name', 'description', 'job_type', 'inventory', 'project',
|
||||
'playbook', 'credential', 'cloud_credential', 'forks', 'schedule',
|
||||
'playbook', 'credential', 'cloud_credential', 'network_credential', 'forks', 'schedule',
|
||||
'limit', 'verbosity', 'job_tags', 'extra_vars', 'launch_type',
|
||||
'force_handlers', 'skip_tags', 'start_at_task', 'become_enabled',
|
||||
'labels',]
|
||||
|
||||
@ -372,7 +372,7 @@ class BaseTask(Task):
|
||||
'''
|
||||
Create a temporary files containing the private data.
|
||||
Returns a dictionary with keys from build_private_data
|
||||
(i.e. 'credential', 'cloud_credential') and values the file path.
|
||||
(i.e. 'credential', 'cloud_credential', 'network_credential') and values the file path.
|
||||
'''
|
||||
private_data = self.build_private_data(instance, **kwargs)
|
||||
private_data_files = {}
|
||||
@ -694,8 +694,9 @@ class RunJob(BaseTask):
|
||||
Returns a dict of the form
|
||||
dict['credential'] = <credential_decrypted_ssh_key_data>
|
||||
dict['cloud_credential'] = <cloud_credential_decrypted_ssh_key_data>
|
||||
dict['network_credential'] = <network_credential_decrypted_ssh_key_data>
|
||||
'''
|
||||
job_credentials = ['credential', 'cloud_credential']
|
||||
job_credentials = ['credential', 'cloud_credential', 'network_credential']
|
||||
private_data = {}
|
||||
# If we were sent SSH credentials, decrypt them and send them
|
||||
# back (they will be written to a temporary file).
|
||||
@ -801,6 +802,16 @@ class RunJob(BaseTask):
|
||||
elif cloud_cred and cloud_cred.kind == 'openstack':
|
||||
env['OS_CLIENT_CONFIG_FILE'] = kwargs.get('private_data_files', {}).get('cloud_credential', '')
|
||||
|
||||
network_cred = job.network_credential
|
||||
if network_cred:
|
||||
env['ANSIBLE_NET_USERNAME'] = network_cred.username
|
||||
env['ANSIBLE_NET_PASSWORD'] = decrypt_field(network_cred, 'password')
|
||||
|
||||
authorize = network_cred.become_method == 'sudo'
|
||||
env['ANSIBLE_NET_AUTHORIZE'] = unicode(int(authorize))
|
||||
if authorize:
|
||||
env['ANSIBLE_NET_AUTHORIZE_PASSWORD'] = decrypt_field(network_cred, 'become_password')
|
||||
|
||||
# Set environment variables related to scan jobs
|
||||
if job.job_type == PERM_INVENTORY_SCAN:
|
||||
env['ANSIBLE_LIBRARY'] = self.get_path_to('..', 'plugins', 'library')
|
||||
|
||||
29
awx/main/tests/unit/test_network_credential.py
Normal file
29
awx/main/tests/unit/test_network_credential.py
Normal file
@ -0,0 +1,29 @@
|
||||
from awx.main.models.credential import Credential
|
||||
from awx.main.models.jobs import Job
|
||||
from awx.main.models.inventory import Inventory
|
||||
from awx.main.tasks import RunJob
|
||||
|
||||
ssh_key_data = """-----BEGIN PRIVATE KEY-----\nstuff==\n-----END PRIVATE KEY-----"""
|
||||
|
||||
def test_net_cred_parse(mocker):
|
||||
opts = {
|
||||
'username':'test',
|
||||
'password':'test',
|
||||
'ssh_key_data': ssh_key_data,
|
||||
'become_method': 'sudo',
|
||||
'become_password': 'passwd',
|
||||
}
|
||||
|
||||
with mocker.patch('django.db.ConnectionRouter.db_for_write'):
|
||||
job = Job(id=1)
|
||||
job.inventory = mocker.MagicMock(spec=Inventory, id=2)
|
||||
job.network_credential = Credential(**opts)
|
||||
|
||||
run_job = RunJob()
|
||||
run_job.should_use_proot = False
|
||||
|
||||
env = run_job.build_env(job, private_data_dir='/tmp')
|
||||
assert env['ANSIBLE_NET_USERNAME'] == opts['username']
|
||||
assert env['ANSIBLE_NET_PASSWORD'] == opts['password']
|
||||
assert env['ANSIBLE_NET_AUTHORIZE'] == '1'
|
||||
assert env['ANSIBLE_NET_AUTHORIZE_PASSWORD'] == opts['become_password']
|
||||
Loading…
x
Reference in New Issue
Block a user