mirror of
https://github.com/ansible/awx.git
synced 2026-07-09 07:18:05 -02:30
Merge branch 'master' into licenses-unstable
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# All Rights Reserved.
|
||||
|
||||
# Python
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
|
||||
@@ -147,7 +148,7 @@ class BaseAccess(object):
|
||||
def check_license(self, add_host=False):
|
||||
reader = TaskSerializer()
|
||||
validation_info = reader.from_file()
|
||||
if 'test' in sys.argv or 'jenkins' in sys.argv:
|
||||
if ('test' in sys.argv or 'jenkins' in sys.argv) and not os.environ.get('SKIP_LICENSE_FIXUP_FOR_TEST', ''):
|
||||
validation_info['free_instances'] = 99999999
|
||||
validation_info['time_remaining'] = 99999999
|
||||
validation_info['grace_period_remaining'] = 99999999
|
||||
|
||||
@@ -882,9 +882,8 @@ class Command(NoArgsCommand):
|
||||
continue
|
||||
mem_group = self.all_group.all_groups[group_name]
|
||||
group = self.inventory.groups.create(name=group_name, variables=json.dumps(mem_group.variables), description='imported')
|
||||
# Access auto one-to-one attribute to create related object.
|
||||
#group.inventory_source
|
||||
InventorySource.objects.create(group=group, inventory=self.inventory, name=('%s (%s)' % (group_name, self.inventory.name)))
|
||||
# Create related inventory source (name will be set by save() method on InventorySource).
|
||||
InventorySource.objects.create(group=group, inventory=self.inventory)
|
||||
self.logger.info('Group "%s" added', group.name)
|
||||
if inv_src_group and group_name in root_group_names:
|
||||
self._batch_add_m2m(inv_src_group.children, group)
|
||||
|
||||
@@ -192,6 +192,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
||||
host = self.host or ''
|
||||
if not host and self.kind == 'vmware':
|
||||
raise ValidationError('Host required for VMware credential.')
|
||||
if not host and self.kind == 'openstack':
|
||||
raise ValidationError('Host required for OpenStack credential.')
|
||||
return host
|
||||
|
||||
def clean_username(self):
|
||||
@@ -203,6 +205,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
||||
'credential.')
|
||||
if not username and self.kind == 'vmware':
|
||||
raise ValidationError('Username required for VMware credential.')
|
||||
if not username and self.kind == 'openstack':
|
||||
raise ValidationError('Username required for OpenStack credential.')
|
||||
return username
|
||||
|
||||
def clean_password(self):
|
||||
@@ -213,6 +217,8 @@ class Credential(PasswordFieldsModel, CommonModelNameNotUnique):
|
||||
raise ValidationError('API key required for Rackspace credential.')
|
||||
if not password and self.kind == 'vmware':
|
||||
raise ValidationError('Password required for VMware credential.')
|
||||
if not password and self.kind == 'openstack':
|
||||
raise ValidationError('Password or API key required for OpenStack credential.')
|
||||
return password
|
||||
|
||||
def clean_project(self):
|
||||
|
||||
@@ -1110,12 +1110,14 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions):
|
||||
self.inventory = self.group.inventory
|
||||
if 'inventory' not in update_fields:
|
||||
update_fields.append('inventory')
|
||||
# Set name automatically.
|
||||
# Set name automatically. Include PK (or placeholder) to make sure the names are always unique.
|
||||
replace_text = '__replace_%s__' % now()
|
||||
old_name_re = re.compile(r'^inventory_source \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*?$')
|
||||
if not self.name or old_name_re.match(self.name):
|
||||
if self.inventory and self.group:
|
||||
self.name = '%s (%s)' % (self.group.name, self.inventory.name)
|
||||
if self.inventory and self.group and self.pk:
|
||||
self.name = '%s (%s - %s)' % (self.group.name, self.inventory.name, self.pk)
|
||||
elif self.inventory and self.group:
|
||||
self.name = '%s (%s - %s)' % (self.group.name, self.inventory.name, replace_text)
|
||||
elif self.inventory and self.pk:
|
||||
self.name = '%s (%s)' % (self.inventory.name, self.pk)
|
||||
elif self.inventory:
|
||||
@@ -1247,6 +1249,19 @@ class InventoryUpdate(UnifiedJob, InventorySourceOptions):
|
||||
def task_impact(self):
|
||||
return 50
|
||||
|
||||
# InventoryUpdate credential required
|
||||
# Custom InventoryUpdate credential not required
|
||||
@property
|
||||
def can_start(self):
|
||||
if not super(InventoryUpdate, self).can_start:
|
||||
return False
|
||||
|
||||
if (self.source != 'custom'
|
||||
and not (self.credential and self.credential.active)):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class CustomInventoryScript(CommonModelNameNotUnique):
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -491,6 +491,17 @@ class Job(UnifiedJob, JobOptions):
|
||||
presets[kw] = getattr(self, kw)
|
||||
return self.job_template.create_unified_job(**presets)
|
||||
|
||||
# Job Credential required
|
||||
@property
|
||||
def can_start(self):
|
||||
if not super(Job, self).can_start:
|
||||
return False
|
||||
|
||||
if not (self.credential and self.credential.active):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
class JobHostSummary(CreatedModifiedModel):
|
||||
'''
|
||||
Per-host statistics for each job.
|
||||
|
||||
@@ -610,11 +610,15 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
||||
"""Return a file-like object containing the standard out of the
|
||||
job's result.
|
||||
"""
|
||||
msg = {
|
||||
'pending': 'Waiting for results...',
|
||||
'missing': 'stdout capture is missing',
|
||||
}
|
||||
if self.result_stdout_text:
|
||||
return StringIO(self.result_stdout_text)
|
||||
else:
|
||||
if not os.path.exists(self.result_stdout_file):
|
||||
return StringIO("stdout capture is missing")
|
||||
return StringIO(msg['missing' if self.finished else 'pending'])
|
||||
|
||||
# There is a potential timing issue here, because another
|
||||
# process may be deleting the stdout file after it is written
|
||||
@@ -631,7 +635,7 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
||||
self.result_stdout_text = type(self).objects.get(id=self.id).result_stdout_text
|
||||
return self.result_stdout_raw_handle(attempt=attempt + 1)
|
||||
else:
|
||||
return StringIO("stdout capture is missing")
|
||||
return StringIO(msg['missing' if self.finished else 'pending'])
|
||||
|
||||
def _escape_ascii(self, content):
|
||||
ansi_escape = re.compile(r'\x1b[^m]*m')
|
||||
|
||||
@@ -17,3 +17,4 @@ from awx.main.tests.redact import * # noqa
|
||||
from awx.main.tests.views import * # noqa
|
||||
from awx.main.tests.commands import * # noqa
|
||||
from awx.main.tests.fact import * # noqa
|
||||
from awx.main.tests.unified_jobs import * # noqa
|
||||
|
||||
@@ -6,6 +6,7 @@ import glob
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import mock
|
||||
|
||||
# Django
|
||||
from django.conf import settings
|
||||
@@ -15,36 +16,37 @@ from django.core.urlresolvers import reverse
|
||||
from crum import impersonate
|
||||
|
||||
# AWX
|
||||
from awx.main.utils import * # noqa
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.tests.base import BaseJobExecutionTest
|
||||
from awx.main.tests.tasks import TEST_SSH_KEY_DATA, TEST_SSH_KEY_DATA_LOCKED, TEST_SSH_KEY_DATA_UNLOCK
|
||||
|
||||
__all__ = ['RunAdHocCommandTest', 'AdHocCommandApiTest']
|
||||
|
||||
|
||||
class BaseAdHocCommandTest(BaseJobExecutionTest):
|
||||
'''
|
||||
Common initialization for testing ad hoc commands.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
super(BaseAdHocCommandTest, self).setUp()
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.super_django_user, 1)[0]
|
||||
self.organization.admins.add(self.normal_django_user)
|
||||
self.inventory = self.organization.inventories.create(name='test-inventory', description='description for test-inventory')
|
||||
self.host = self.inventory.hosts.create(name='host.example.com')
|
||||
self.host2 = self.inventory.hosts.create(name='host2.example.com')
|
||||
self.group = self.inventory.groups.create(name='test-group')
|
||||
self.group2 = self.inventory.groups.create(name='test-group2')
|
||||
self.group.hosts.add(self.host)
|
||||
self.group2.hosts.add(self.host, self.host2)
|
||||
self.inventory2 = self.organization.inventories.create(name='test-inventory2')
|
||||
self.host3 = self.inventory2.hosts.create(name='host3.example.com')
|
||||
self.credential = None
|
||||
settings.INTERNAL_API_URL = self.live_server_url
|
||||
settings.CALLBACK_CONSUMER_PORT = ''
|
||||
with ignore_inventory_computed_fields():
|
||||
super(BaseAdHocCommandTest, self).setUp()
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.super_django_user, 1)[0]
|
||||
self.organization.admins.add(self.normal_django_user)
|
||||
self.inventory = self.organization.inventories.create(name='test-inventory', description='description for test-inventory')
|
||||
self.host = self.inventory.hosts.create(name='host.example.com')
|
||||
self.host2 = self.inventory.hosts.create(name='host2.example.com')
|
||||
self.group = self.inventory.groups.create(name='test-group')
|
||||
self.group2 = self.inventory.groups.create(name='test-group2')
|
||||
self.group.hosts.add(self.host)
|
||||
self.group2.hosts.add(self.host, self.host2)
|
||||
self.inventory2 = self.organization.inventories.create(name='test-inventory2')
|
||||
self.host3 = self.inventory2.hosts.create(name='host3.example.com')
|
||||
self.credential = None
|
||||
settings.INTERNAL_API_URL = self.live_server_url
|
||||
settings.CALLBACK_CONSUMER_PORT = ''
|
||||
|
||||
def create_test_credential(self, **kwargs):
|
||||
self.credential = self.make_credential(**kwargs)
|
||||
@@ -124,7 +126,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.check_job_result(ad_hoc_command, 'failed')
|
||||
self.check_ad_hoc_command_events(ad_hoc_command, 'unreachable')
|
||||
|
||||
def test_cancel_ad_hoc_command(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('canceled', 0))
|
||||
def test_cancel_ad_hoc_command(self, ignore):
|
||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
self.assertFalse(ad_hoc_command.cancel_flag)
|
||||
@@ -145,7 +148,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
# Unable to start ad hoc command again.
|
||||
self.assertFalse(ad_hoc_command.signal_start())
|
||||
|
||||
def test_ad_hoc_command_options(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_ad_hoc_command_options(self, ignore):
|
||||
ad_hoc_command = self.create_test_ad_hoc_command(forks=2, verbosity=2)
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
self.assertFalse(ad_hoc_command.passwords_needed_to_start)
|
||||
@@ -191,7 +195,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.check_ad_hoc_command_events(ad_hoc_command3, 'ok', hosts=[])
|
||||
self.assertEqual(ad_hoc_command3.ad_hoc_command_events.count(), 0)
|
||||
|
||||
def test_ssh_username_and_password(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_ssh_username_and_password(self, ignore):
|
||||
self.create_test_credential(username='sshuser', password='sshpass')
|
||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
@@ -199,10 +204,11 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start())
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.assertTrue('"-u"' in ad_hoc_command.job_args)
|
||||
self.assertTrue('"--ask-pass"' in ad_hoc_command.job_args)
|
||||
self.assertIn('"-u"', ad_hoc_command.job_args)
|
||||
self.assertIn('"--ask-pass"', ad_hoc_command.job_args)
|
||||
|
||||
def test_ssh_ask_password(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_ssh_ask_password(self, ignore):
|
||||
self.create_test_credential(password='ASK')
|
||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
@@ -212,9 +218,10 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start(ssh_password='sshpass'))
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.assertTrue('"--ask-pass"' in ad_hoc_command.job_args)
|
||||
self.assertIn('"--ask-pass"', ad_hoc_command.job_args)
|
||||
|
||||
def test_sudo_username_and_password(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_sudo_username_and_password(self, ignore):
|
||||
self.create_test_credential(become_method="sudo",
|
||||
become_username='sudouser',
|
||||
become_password='sudopass')
|
||||
@@ -223,15 +230,14 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertFalse(ad_hoc_command.passwords_needed_to_start)
|
||||
self.assertTrue(ad_hoc_command.signal_start())
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
# Job may fail if current user doesn't have password-less sudo
|
||||
# privileges, but we're mainly checking the command line arguments.
|
||||
self.check_job_result(ad_hoc_command, ('successful', 'failed'))
|
||||
self.assertTrue('"--become-method"' in ad_hoc_command.job_args)
|
||||
self.assertTrue('"--become-user"' in ad_hoc_command.job_args)
|
||||
self.assertTrue('"--ask-become-pass"' in ad_hoc_command.job_args)
|
||||
self.assertFalse('"--become"' in ad_hoc_command.job_args)
|
||||
self.assertIn('"--become-method"', ad_hoc_command.job_args)
|
||||
self.assertIn('"--become-user"', ad_hoc_command.job_args)
|
||||
self.assertIn('"--ask-become-pass"', ad_hoc_command.job_args)
|
||||
self.assertNotIn('"--become"', ad_hoc_command.job_args)
|
||||
|
||||
def test_sudo_ask_password(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_sudo_ask_password(self, ignore):
|
||||
self.create_test_credential(become_password='ASK')
|
||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
@@ -240,13 +246,13 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertFalse(ad_hoc_command.signal_start())
|
||||
self.assertTrue(ad_hoc_command.signal_start(become_password='sudopass'))
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
# Job may fail, but we're mainly checking the command line arguments.
|
||||
self.check_job_result(ad_hoc_command, ('successful', 'failed'))
|
||||
self.assertTrue('"--ask-become-pass"' in ad_hoc_command.job_args)
|
||||
self.assertFalse('"--become-user"' in ad_hoc_command.job_args)
|
||||
self.assertFalse('"--become"' in ad_hoc_command.job_args)
|
||||
self.assertIn('"--ask-become-pass"', ad_hoc_command.job_args)
|
||||
self.assertNotIn('"--become-user"', ad_hoc_command.job_args)
|
||||
self.assertNotIn('"--become"', ad_hoc_command.job_args)
|
||||
|
||||
def test_unlocked_ssh_key(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('successful', 0))
|
||||
def test_unlocked_ssh_key(self, ignore):
|
||||
self.create_test_credential(ssh_key_data=TEST_SSH_KEY_DATA)
|
||||
ad_hoc_command = self.create_test_ad_hoc_command()
|
||||
self.assertEqual(ad_hoc_command.status, 'new')
|
||||
@@ -254,8 +260,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start())
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.assertFalse('"--private-key=' in ad_hoc_command.job_args)
|
||||
self.assertTrue('ssh-agent' in ad_hoc_command.job_args)
|
||||
self.assertNotIn('"--private-key=', ad_hoc_command.job_args)
|
||||
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
||||
|
||||
def test_locked_ssh_key_with_password(self):
|
||||
self.create_test_credential(ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
|
||||
@@ -266,8 +272,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start())
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.assertTrue('ssh-agent' in ad_hoc_command.job_args)
|
||||
self.assertTrue('Bad passphrase' not in ad_hoc_command.result_stdout)
|
||||
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
||||
self.assertNotIn('Bad passphrase', ad_hoc_command.result_stdout)
|
||||
|
||||
def test_locked_ssh_key_with_bad_password(self):
|
||||
self.create_test_credential(ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
|
||||
@@ -278,8 +284,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start())
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'failed')
|
||||
self.assertTrue('ssh-agent' in ad_hoc_command.job_args)
|
||||
self.assertTrue('Bad passphrase' in ad_hoc_command.result_stdout)
|
||||
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
||||
self.assertIn('Bad passphrase', ad_hoc_command.result_stdout)
|
||||
|
||||
def test_locked_ssh_key_ask_password(self):
|
||||
self.create_test_credential(ssh_key_data=TEST_SSH_KEY_DATA_LOCKED,
|
||||
@@ -303,8 +309,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.assertTrue(ad_hoc_command.signal_start(ssh_key_unlock=TEST_SSH_KEY_DATA_UNLOCK))
|
||||
ad_hoc_command = AdHocCommand.objects.get(pk=ad_hoc_command.pk)
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.assertTrue('ssh-agent' in ad_hoc_command.job_args)
|
||||
self.assertTrue('Bad passphrase' not in ad_hoc_command.result_stdout)
|
||||
self.assertIn('ssh-agent', ad_hoc_command.job_args)
|
||||
self.assertNotIn('Bad passphrase', ad_hoc_command.result_stdout)
|
||||
|
||||
def test_run_with_proot(self):
|
||||
# Only run test if proot is installed
|
||||
@@ -348,7 +354,8 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.check_job_result(ad_hoc_command, 'successful')
|
||||
self.check_ad_hoc_command_events(ad_hoc_command, 'ok')
|
||||
|
||||
def test_run_with_proot_not_installed(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', return_value=('failed', 0))
|
||||
def test_run_with_proot_not_installed(self, ignore):
|
||||
# Enable proot for this test, specify invalid proot cmd.
|
||||
settings.AWX_PROOT_ENABLED = True
|
||||
settings.AWX_PROOT_CMD = 'PR00T'
|
||||
@@ -360,6 +367,9 @@ class RunAdHocCommandTest(BaseAdHocCommandTest):
|
||||
self.check_job_result(ad_hoc_command, 'error', expect_traceback=True)
|
||||
|
||||
|
||||
def run_pexpect_mock(self, *args, **kwargs):
|
||||
return 'successful', 0
|
||||
|
||||
class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
'''
|
||||
Test API list/detail views for ad hoc commands.
|
||||
@@ -385,7 +395,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
del data[k]
|
||||
return self.post(url, data, expect=expect)
|
||||
|
||||
def test_ad_hoc_command_list(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_ad_hoc_command_list(self, ignore):
|
||||
url = reverse('api:ad_hoc_command_list')
|
||||
|
||||
# Retrieve the empty list of ad hoc commands.
|
||||
@@ -557,8 +568,16 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command(become_enabled=True)
|
||||
self.assertEqual(response['become_enabled'], True)
|
||||
|
||||
# Try to run with expired license.
|
||||
self.create_expired_license_file()
|
||||
with self.current_user('admin'):
|
||||
self.run_test_ad_hoc_command(expect=403)
|
||||
with self.current_user('normal'):
|
||||
self.run_test_ad_hoc_command(expect=403)
|
||||
|
||||
def test_ad_hoc_command_detail(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_ad_hoc_command_detail(self, ignore):
|
||||
with self.current_user('admin'):
|
||||
response1 = self.run_test_ad_hoc_command()
|
||||
response2 = self.run_test_ad_hoc_command()
|
||||
@@ -622,7 +641,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.delete(url, expect=204)
|
||||
self.delete(url, expect=404)
|
||||
|
||||
def test_ad_hoc_command_cancel(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_ad_hoc_command_cancel(self, ignore):
|
||||
# Override setting so that ad hoc command isn't actually started.
|
||||
with self.settings(CELERY_UNIT_TEST=False):
|
||||
with self.current_user('admin'):
|
||||
@@ -674,7 +694,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.assertEqual(response['can_cancel'], False)
|
||||
self.post(url, {}, expect=405)
|
||||
|
||||
def test_ad_hoc_command_relaunch(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_ad_hoc_command_relaunch(self, ignore):
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
|
||||
@@ -734,7 +755,16 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.assertEqual(response['passwords_needed_to_start'], [])
|
||||
response = self.post(url, {}, expect=400)
|
||||
|
||||
# Try to relaunch with expired license.
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command(inventory=self.inventory2.pk)
|
||||
self.create_expired_license_file()
|
||||
with self.current_user('admin'):
|
||||
self.post(response['related']['relaunch'], {}, expect=403)
|
||||
|
||||
def test_ad_hoc_command_events_list(self):
|
||||
# TODO: Create test events instead of relying on playbooks execution
|
||||
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
response = self.run_test_ad_hoc_command()
|
||||
@@ -823,6 +853,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.delete(url, expect=401)
|
||||
|
||||
def test_ad_hoc_command_event_detail(self):
|
||||
# TODO: Mock pexpect. Create test events instead of relying on playbooks execution
|
||||
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
|
||||
@@ -877,7 +909,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.patch(url, {}, expect=401)
|
||||
self.delete(url, expect=401)
|
||||
|
||||
def test_ad_hoc_command_activity_stream(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_ad_hoc_command_activity_stream(self, ignore):
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
|
||||
@@ -927,7 +960,8 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.patch(url, {}, expect=401)
|
||||
self.delete(url, expect=401)
|
||||
|
||||
def test_inventory_ad_hoc_commands_list(self):
|
||||
@mock.patch('awx.main.tasks.BaseTask.run_pexpect', side_effect=run_pexpect_mock)
|
||||
def test_inventory_ad_hoc_commands_list(self, ignore):
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
response = self.run_test_ad_hoc_command(inventory=self.inventory2.pk)
|
||||
@@ -1029,7 +1063,16 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
response = self.get(inventory_url, expect=200)
|
||||
self.assertTrue(response['can_run_ad_hoc_commands'])
|
||||
|
||||
# Try to run with expired license.
|
||||
self.create_expired_license_file()
|
||||
with self.current_user('admin'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
with self.current_user('normal'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
|
||||
def test_host_ad_hoc_commands_list(self):
|
||||
# TODO: Figure out why this test needs pexpect
|
||||
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
response = self.run_test_ad_hoc_command(limit=self.host2.name)
|
||||
@@ -1078,7 +1121,16 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.patch(url, {}, expect=401)
|
||||
self.delete(url, expect=401)
|
||||
|
||||
# Try to run with expired license.
|
||||
self.create_expired_license_file()
|
||||
with self.current_user('admin'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
with self.current_user('normal'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
|
||||
def test_group_ad_hoc_commands_list(self):
|
||||
# TODO: Figure out why this test needs pexpect
|
||||
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command() # self.host + self.host2
|
||||
response = self.run_test_ad_hoc_command(limit=self.group.name) # self.host
|
||||
@@ -1132,7 +1184,16 @@ class AdHocCommandApiTest(BaseAdHocCommandTest):
|
||||
self.patch(url, {}, expect=401)
|
||||
self.delete(url, expect=401)
|
||||
|
||||
# Try to run with expired license.
|
||||
self.create_expired_license_file()
|
||||
with self.current_user('admin'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
with self.current_user('normal'):
|
||||
self.run_test_ad_hoc_command(url=url, expect=403)
|
||||
|
||||
def test_host_ad_hoc_command_events_list(self):
|
||||
# TODO: Mock run_pexpect. Create test events instead of relying on playbooks execution
|
||||
|
||||
with self.current_user('admin'):
|
||||
response = self.run_test_ad_hoc_command()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import time
|
||||
from multiprocessing import Process
|
||||
from subprocess import Popen
|
||||
import re
|
||||
import mock
|
||||
|
||||
# PyYAML
|
||||
import yaml
|
||||
@@ -76,8 +77,14 @@ class QueueStartStopTestMixin(QueueTestMixin):
|
||||
super(QueueStartStopTestMixin, self).tearDown()
|
||||
self.terminate_queue()
|
||||
|
||||
class MockCommonlySlowTestMixin(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
from awx.api import generics
|
||||
mock.patch.object(generics, 'get_view_description', return_value=None).start()
|
||||
super(MockCommonlySlowTestMixin, self).__init__(*args, **kwargs)
|
||||
|
||||
ansible_version = get_ansible_version()
|
||||
class BaseTestMixin(QueueTestMixin):
|
||||
class BaseTestMixin(QueueTestMixin, MockCommonlySlowTestMixin):
|
||||
'''
|
||||
Mixin with shared code for use by all test cases.
|
||||
'''
|
||||
@@ -179,6 +186,13 @@ class BaseTestMixin(QueueTestMixin):
|
||||
self._temp_paths.append(license_path)
|
||||
os.environ['AWX_LICENSE_FILE'] = license_path
|
||||
|
||||
def create_expired_license_file(self, instance_count=1000, grace_period=False):
|
||||
license_date = time.time() - 1
|
||||
if not grace_period:
|
||||
license_date -= 2592000
|
||||
self.create_test_license_file(instance_count, license_date)
|
||||
os.environ['SKIP_LICENSE_FIXUP_FOR_TEST'] = '1'
|
||||
|
||||
def assertElapsedLessThan(self, seconds):
|
||||
elapsed = time.time() - self._start_time
|
||||
self.assertTrue(elapsed < seconds, 'elapsed time of %0.3fs is greater than %0.3fs' % (elapsed, seconds))
|
||||
|
||||
@@ -341,7 +341,7 @@ class CleanupJobsTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
shutil.rmtree(self.test_project_path, True)
|
||||
|
||||
def create_test_credential(self, **kwargs):
|
||||
self.credential = self.make_credential(kwargs)
|
||||
self.credential = self.make_credential(**kwargs)
|
||||
return self.credential
|
||||
|
||||
def create_test_project(self, playbook_content):
|
||||
@@ -409,6 +409,7 @@ class CleanupJobsTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
self.assertEqual(ad_hoc_commands_before, ad_hoc_commands_after)
|
||||
|
||||
# Create and run job.
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
|
||||
@@ -20,7 +20,7 @@ from django.utils.timezone import now
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.tests.base import BaseTest, BaseTransactionTest
|
||||
|
||||
__all__ = ['InventoryTest', 'InventoryUpdatesTest']
|
||||
__all__ = ['InventoryTest', 'InventoryUpdatesTest', 'InventoryCredentialTest']
|
||||
|
||||
TEST_SIMPLE_INVENTORY_SCRIPT = "#!/usr/bin/env python\nimport json\nprint json.dumps({'hosts': ['ahost-01', 'ahost-02', 'ahost-03', 'ahost-04']})"
|
||||
TEST_SIMPLE_INVENTORY_SCRIPT_WITHOUT_HASHBANG = "import json\nprint json.dumps({'hosts': ['ahost-01', 'ahost-02', 'ahost-03', 'ahost-04']})"
|
||||
@@ -1762,6 +1762,22 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
self.assertTrue(self.group.children.get(name='images').children.filter(active=True).count())
|
||||
self.assertTrue('instances' in child_names)
|
||||
self.assertTrue(self.group.children.get(name='instances').children.filter(active=True).count())
|
||||
# Sync again with overwrite set to False after renaming a group that
|
||||
# was created by the sync. With overwrite false, the renamed group and
|
||||
# the original group (created again by the sync) will both exist.
|
||||
region_group = self.group.children.get(name='regions').children.all()[0]
|
||||
region_group_original_name = region_group.name
|
||||
region_group.name = region_group.name + '-renamed'
|
||||
region_group.save(update_fields=['name'])
|
||||
cache_path3 = tempfile.mkdtemp(prefix='awx_ec2_')
|
||||
self._temp_paths.append(cache_path3)
|
||||
inventory_source.source_vars = '---\n\ncache_path: %s\n' % cache_path3
|
||||
inventory_source.overwrite = False
|
||||
inventory_source.save()
|
||||
self.check_inventory_source(inventory_source, initial=False, instance_id_group_ok=True)
|
||||
child_names = self.group.children.filter(active=True).values_list('name', flat=True)
|
||||
self.assertTrue(region_group_original_name in self.group.children.get(name='regions').children.values_list('name', flat=True))
|
||||
self.assertTrue(region_group.name in self.group.children.get(name='regions').children.values_list('name', flat=True))
|
||||
return
|
||||
# Print out group/host tree for debugging.
|
||||
print
|
||||
@@ -1978,3 +1994,35 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
project=api_project)
|
||||
inventory_source = self.update_inventory_source(self.group, source='openstack', credential=credential)
|
||||
self.check_inventory_source(inventory_source)
|
||||
|
||||
|
||||
class InventoryCredentialTest(BaseTest):
|
||||
def setUp(self):
|
||||
super(InventoryCredentialTest, self).setUp()
|
||||
#self.start_redis()
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
|
||||
self.url = reverse('api:credential_list')
|
||||
|
||||
def test_openstack_create_ok(self):
|
||||
data = {
|
||||
'kind': 'openstack',
|
||||
'name': 'Best credential ever',
|
||||
'username': 'some_user',
|
||||
'password': 'some_password',
|
||||
'project': 'some_project',
|
||||
'host': 'some_host',
|
||||
}
|
||||
self.post(self.url, data=data, expect=201, auth=self.get_super_credentials())
|
||||
|
||||
def test_openstack_create_fail_required_fields(self):
|
||||
data = {
|
||||
'kind': 'openstack',
|
||||
'name': 'Best credential ever',
|
||||
}
|
||||
response = self.post(self.url, data=data, expect=400, auth=self.get_super_credentials())
|
||||
self.assertIn('username', response)
|
||||
self.assertIn('password', response)
|
||||
self.assertIn('host', response)
|
||||
self.assertIn('project', response)
|
||||
|
||||
@@ -754,6 +754,13 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
|
||||
self.assertEqual(job.hosts.count(), 1)
|
||||
self.assertEqual(job.hosts.all()[0], host)
|
||||
|
||||
# Run the callback job again with extra vars and verify their presence
|
||||
data.update(dict(extra_vars=dict(key="value")))
|
||||
result = self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
jobs_qs = job_template.jobs.filter(launch_type='callback').order_by('-pk')
|
||||
job = jobs_qs[0]
|
||||
self.assertTrue("key" in job.extra_vars)
|
||||
|
||||
# GET as unauthenticated user will prompt for authentication.
|
||||
self.get(url, expect=401, remote_addr=host_ip)
|
||||
|
||||
@@ -797,9 +804,9 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
|
||||
if host_ip:
|
||||
break
|
||||
self.assertTrue(host)
|
||||
self.assertEqual(jobs_qs.count(), 1)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 2)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 3)
|
||||
job = jobs_qs[0]
|
||||
self.assertEqual(job.launch_type, 'callback')
|
||||
self.assertEqual(job.limit, host.name)
|
||||
@@ -822,9 +829,9 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
|
||||
if host_ip:
|
||||
break
|
||||
self.assertTrue(host)
|
||||
self.assertEqual(jobs_qs.count(), 2)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 3)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 4)
|
||||
job = jobs_qs[0]
|
||||
self.assertEqual(job.launch_type, 'callback')
|
||||
self.assertEqual(job.limit, host.name)
|
||||
@@ -836,9 +843,9 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
|
||||
host_qs = host_qs.filter(variables__icontains='ansible_ssh_host')
|
||||
host = host_qs[0]
|
||||
host_ip = host.variables_dict['ansible_ssh_host']
|
||||
self.assertEqual(jobs_qs.count(), 3)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 4)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 5)
|
||||
job = jobs_qs[0]
|
||||
self.assertEqual(job.launch_type, 'callback')
|
||||
self.assertEqual(job.limit, host.name)
|
||||
@@ -868,9 +875,9 @@ class JobTemplateCallbackTest(BaseJobTestMixin, django.test.LiveServerTestCase):
|
||||
host_ip = list(ips)[0]
|
||||
break
|
||||
self.assertTrue(host)
|
||||
self.assertEqual(jobs_qs.count(), 4)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 5)
|
||||
self.post(url, data, expect=202, remote_addr=host_ip)
|
||||
self.assertEqual(jobs_qs.count(), 6)
|
||||
job = jobs_qs[0]
|
||||
self.assertEqual(job.launch_type, 'callback')
|
||||
self.assertEqual(job.limit, ':&'.join([job_template.limit, host.name]))
|
||||
|
||||
@@ -18,6 +18,7 @@ from django.utils.timezone import now
|
||||
from crum import impersonate
|
||||
|
||||
# AWX
|
||||
from awx.main.utils import * # noqa
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.tests.base import BaseJobExecutionTest
|
||||
|
||||
@@ -345,22 +346,23 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
super(RunJobTest, self).setUp()
|
||||
self.test_project_path = None
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.super_django_user, 1)[0]
|
||||
self.inventory = self.organization.inventories.create(name='test-inventory',
|
||||
description='description for test-inventory')
|
||||
self.host = self.inventory.hosts.create(name='host.example.com')
|
||||
self.group = self.inventory.groups.create(name='test-group')
|
||||
self.group2 = self.inventory.groups.create(name='test-group2')
|
||||
self.group.hosts.add(self.host)
|
||||
self.group2.hosts.add(self.host)
|
||||
self.project = None
|
||||
self.credential = None
|
||||
self.cloud_credential = None
|
||||
settings.INTERNAL_API_URL = self.live_server_url
|
||||
with ignore_inventory_computed_fields():
|
||||
super(RunJobTest, self).setUp()
|
||||
self.test_project_path = None
|
||||
self.setup_instances()
|
||||
self.setup_users()
|
||||
self.organization = self.make_organizations(self.super_django_user, 1)[0]
|
||||
self.inventory = self.organization.inventories.create(name='test-inventory',
|
||||
description='description for test-inventory')
|
||||
self.host = self.inventory.hosts.create(name='host.example.com')
|
||||
self.group = self.inventory.groups.create(name='test-group')
|
||||
self.group2 = self.inventory.groups.create(name='test-group2')
|
||||
self.group.hosts.add(self.host)
|
||||
self.group2.hosts.add(self.host)
|
||||
self.project = None
|
||||
self.credential = None
|
||||
self.cloud_credential = None
|
||||
settings.INTERNAL_API_URL = self.live_server_url
|
||||
|
||||
def tearDown(self):
|
||||
super(RunJobTest, self).tearDown()
|
||||
@@ -562,6 +564,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertEqual(qs.count(), 0)
|
||||
|
||||
def test_run_job(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -590,6 +593,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
return job
|
||||
|
||||
def test_check_job(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template, job_type='check')
|
||||
@@ -617,6 +621,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
return job
|
||||
|
||||
def test_run_job_that_fails(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK2)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -644,6 +649,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
return job
|
||||
|
||||
def test_run_job_with_ignore_errors(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_IGNORE_ERRORS_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -766,6 +772,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertEqual(self.host.last_job_host_summary, None)
|
||||
|
||||
def test_check_job_where_task_would_fail(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK2)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template, job_type='check')
|
||||
@@ -799,6 +806,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertTrue(job.cancel()) # No change from calling again.
|
||||
|
||||
def test_cancel_job(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
# Pass save=False just for the sake of test coverage.
|
||||
@@ -824,6 +832,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertFalse(job.signal_start())
|
||||
|
||||
def test_extra_job_options(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_EXTRA_VARS_PLAYBOOK)
|
||||
# Test with extra_vars containing misc whitespace.
|
||||
job_template = self.create_test_job_template(force_handlers=True,
|
||||
@@ -856,6 +865,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.check_job_result(job3, 'successful')
|
||||
|
||||
def test_lots_of_extra_vars(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_EXTRA_VARS_PLAYBOOK)
|
||||
extra_vars = json.dumps(dict(('var_%d' % x, x) for x in xrange(200)))
|
||||
job_template = self.create_test_job_template(extra_vars=extra_vars)
|
||||
@@ -869,6 +879,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertTrue('"-e"' in job.job_args)
|
||||
|
||||
def test_limit_option(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template(limit='bad.example.com')
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -893,6 +904,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertTrue('ssh-agent' in job.job_args)
|
||||
|
||||
def test_tag_and_task_options(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK_WITH_TAGS)
|
||||
job_template = self.create_test_job_template(job_tags='runme',
|
||||
skip_tags='skipme',
|
||||
@@ -972,6 +984,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertFalse('"--become-method"' in job.job_args)
|
||||
|
||||
def test_job_template_become_enabled(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template(become_enabled=True)
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1127,6 +1140,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
ssh_key_data=TEST_SSH_CERT_KEY)
|
||||
playbook = TEST_ENV_PLAYBOOK % {'env_var1': env_var1,
|
||||
'env_var2': env_var2}
|
||||
self.create_test_credential()
|
||||
self.create_test_project(playbook)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1154,6 +1168,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self._test_cloud_credential_environment_variables('vmware')
|
||||
|
||||
def test_run_async_job(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_ASYNC_OK_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1184,6 +1199,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
# FIXME: We are not sure why proot needs to be disabled on this test
|
||||
# Maybe they are simply susceptable to timing and proot adds time
|
||||
settings.AWX_PROOT_ENABLED = False
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_ASYNC_FAIL_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1214,6 +1230,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
# FIXME: We are not sure why proot needs to be disabled on this test
|
||||
# Maybe they are simply susceptable to timing and proot adds time
|
||||
settings.AWX_PROOT_ENABLED = False
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_ASYNC_TIMEOUT_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1242,6 +1259,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertEqual(job.processed_hosts.count(), 1)
|
||||
|
||||
def test_run_async_job_fire_and_forget(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_ASYNC_NOWAIT_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1269,6 +1287,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
self.assertEqual(job.processed_hosts.count(), 1)
|
||||
|
||||
def test_run_job_with_roles(self):
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK_WITH_ROLES, TEST_ROLE_PLAYBOOKS)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
@@ -1299,6 +1318,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
settings.AWX_PROOT_HIDE_PATHS = [os.path.join(settings.BASE_DIR, 'settings')]
|
||||
# Create another project alongside the one we're using to verify it
|
||||
# is hidden.
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
other_project_path = self.project.local_path
|
||||
# Create a temp directory that should not be visible to the playbook.
|
||||
@@ -1334,6 +1354,7 @@ class RunJobTest(BaseJobExecutionTest):
|
||||
# Enable proot for this test, specify invalid proot cmd.
|
||||
settings.AWX_PROOT_ENABLED = True
|
||||
settings.AWX_PROOT_CMD = 'PR00T'
|
||||
self.create_test_credential()
|
||||
self.create_test_project(TEST_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
job = self.create_test_job(job_template=job_template)
|
||||
|
||||
53
awx/main/tests/unified_jobs.py
Normal file
53
awx/main/tests/unified_jobs.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved
|
||||
|
||||
# Python
|
||||
import mock
|
||||
from StringIO import StringIO
|
||||
from django.utils.timezone import now
|
||||
|
||||
# Django
|
||||
from django.test import SimpleTestCase
|
||||
|
||||
# AWX
|
||||
from awx.main.models import * # noqa
|
||||
|
||||
__all__ = ['UnifiedJobsUnitTest',]
|
||||
|
||||
class UnifiedJobsUnitTest(SimpleTestCase):
|
||||
|
||||
# stdout file present
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('codecs.open', return_value='my_file_handler')
|
||||
def test_result_stdout_raw_handle_file__found(self, exists, open):
|
||||
unified_job = UnifiedJob()
|
||||
unified_job.result_stdout_file = 'dummy'
|
||||
|
||||
result = unified_job.result_stdout_raw_handle()
|
||||
|
||||
self.assertEqual(result, 'my_file_handler')
|
||||
|
||||
# stdout file missing, job finished
|
||||
@mock.patch('os.path.exists', return_value=False)
|
||||
def test_result_stdout_raw_handle__missing(self, exists):
|
||||
unified_job = UnifiedJob()
|
||||
unified_job.result_stdout_file = 'dummy'
|
||||
unified_job.finished = now()
|
||||
|
||||
result = unified_job.result_stdout_raw_handle()
|
||||
|
||||
self.assertIsInstance(result, StringIO)
|
||||
self.assertEqual(result.read(), 'stdout capture is missing')
|
||||
|
||||
# stdout file missing, job not finished
|
||||
@mock.patch('os.path.exists', return_value=False)
|
||||
def test_result_stdout_raw_handle__pending(self, exists):
|
||||
unified_job = UnifiedJob()
|
||||
unified_job.result_stdout_file = 'dummy'
|
||||
unified_job.finished = None
|
||||
|
||||
result = unified_job.result_stdout_raw_handle()
|
||||
|
||||
self.assertIsInstance(result, StringIO)
|
||||
self.assertEqual(result.read(), 'Waiting for results...')
|
||||
|
||||
Reference in New Issue
Block a user