AC-626 Removed support for prompting for password and ssh_key_unlock for scm/cloud credentials.

This commit is contained in:
Chris Church
2013-11-16 17:59:51 -05:00
parent f254f8bc92
commit 621cbb9f66
9 changed files with 48 additions and 144 deletions

View File

@@ -143,8 +143,6 @@ class JobTemplate(CommonModel):
needed.append('ssh_password')
else:
needed.append(pw)
if self.project.scm_update_on_launch:
needed.extend(self.project.scm_passwords_needed)
return bool(self.credential and not len(needed))
class Job(CommonTask):
@@ -262,8 +260,6 @@ class Job(CommonTask):
needed.append('ssh_password')
else:
needed.append(pw)
if self.project.scm_update_on_launch:
needed.extend(self.project.scm_passwords_needed)
return needed
def _get_task_class(self):

View File

@@ -200,7 +200,8 @@ class Credential(CommonModelNameNotUnique):
default='',
max_length=1024,
verbose_name=_('Password'),
help_text=_('Password for this credential.'),
help_text=_('Password for this credential (or "ASK" to prompt the '
'user for machine credentials).'),
)
ssh_key_data = models.TextField(
blank=True,
@@ -214,7 +215,7 @@ class Credential(CommonModelNameNotUnique):
default='',
verbose_name=_('SSH key unlock'),
help_text=_('Passphrase to unlock SSH private key if encrypted (or '
'"ASK" to prompt the user).'),
'"ASK" to prompt the user for machine credentials).'),
)
sudo_username = models.CharField(
max_length=1024,
@@ -231,16 +232,16 @@ class Credential(CommonModelNameNotUnique):
@property
def needs_password(self):
return not self.ssh_key_data and self.password == 'ASK'
return self.kind == 'ssh' and self.password == 'ASK'
@property
def needs_ssh_key_unlock(self):
return 'ENCRYPTED' in decrypt_field(self, 'ssh_key_data') and \
(not self.ssh_key_unlock or self.ssh_key_unlock == 'ASK')
return self.kind == 'ssh' and self.ssh_key_unlock == 'ASK' and \
'ENCRYPTED' in decrypt_field(self, 'ssh_key_data')
@property
def needs_sudo_password(self):
return self.sudo_password == 'ASK'
return self.kind == 'ssh' and self.sudo_password == 'ASK'
@property
def passwords_needed(self):
@@ -321,7 +322,8 @@ class Credential(CommonModelNameNotUnique):
# If update_fields has been specified, add our field names to it,
# if hit hasn't been specified, then we're just doing a normal save.
for field in self.PASSWORD_FIELDS:
encrypted = encrypt_field(self, field, bool(field != 'ssh_key_data'))
ask = bool(self.kind == 'ssh' and field != 'ssh_key_data')
encrypted = encrypt_field(self, field, ask)
setattr(self, field, encrypted)
if field not in update_fields:
update_fields.append(field)

View File

@@ -186,27 +186,10 @@ class Project(CommonModel):
update_fields.append('local_path')
if update_fields:
self.save(update_fields=update_fields)
# If we just created a new project with SCM and it doesn't require any
# passwords to update, start the initial update.
if new_instance and self.scm_type and not self.scm_passwords_needed:
# If we just created a new project with SCM, start the initial update.
if new_instance and self.scm_type:
self.update()
@property
def needs_scm_password(self):
return self.credential and self.credential.needs_password
@property
def needs_scm_key_unlock(self):
return self.credential and self.credential.needs_ssh_key_unlock
@property
def scm_passwords_needed(self):
needed = []
for field in ('scm_password', 'scm_key_unlock'):
if getattr(self, 'needs_%s' % field):
needed.append(field)
return needed
def set_status_and_last_updated(self, save=True):
# Determine current status.
if self.scm_type:
@@ -256,12 +239,8 @@ class Project(CommonModel):
def update(self, **kwargs):
if self.can_update:
needed = self.scm_passwords_needed
opts = dict([(field, kwargs.get(field, '')) for field in needed])
if not all(opts.values()):
return
project_update = self.project_updates.create()
project_update.start(**opts)
project_update.start()
return project_update
def get_absolute_url(self):
@@ -332,9 +311,6 @@ class ProjectUpdate(CommonTask):
from awx.main.tasks import RunProjectUpdate
return RunProjectUpdate
def _get_passwords_needed_to_start(self):
return self.project.scm_passwords_needed
def _update_parent_instance(self):
parent_instance = self._get_parent_instance()
if parent_instance:

View File

@@ -440,9 +440,7 @@ class RunJob(BaseTask):
try:
project_update = pu_qs[0]
except IndexError:
kw = dict([(k,v) for k,v in kwargs.items()
if k.startswith('scm_')])
project_update = project.update(**kw)
project_update = project.update()
if not project_update:
msg = 'Unable to update project before launch.'
job = self.update_model(pk, status='error',
@@ -460,10 +458,7 @@ class RunJob(BaseTask):
try:
inventory_update = iu_qs.filter(inventory_source=inventory_source)[0]
except IndexError:
# FIXME: Doesn't support multiple sources!!!
kw = dict([(k,v) for k,v in kwargs.items()
if k.startswith('source_')])
inventory_update = inventory_source.update(**kw)
inventory_update = inventory_source.update()
if not inventory_update:
msgs.append('Unable to update inventory source %d before launch' % inventory_source.pk)
continue
@@ -528,12 +523,12 @@ class RunProjectUpdate(BaseTask):
**kwargs)
project = project_update.project
if project.credential:
value = kwargs.get('scm_key_unlock', decrypt_field(project.credential, 'ssh_key_unlock'))
value = decrypt_field(project.credential, 'ssh_key_unlock')
if value not in ('', 'ASK'):
passwords['scm_key_unlock'] = value
passwords['scm_username'] = project.credential.username
passwords['scm_password'] = kwargs.get('scm_password',
decrypt_field(project.credential, 'password'))
passwords['scm_password'] = decrypt_field(project.credential,
'password')
return passwords
def build_env(self, project_update, **kwargs):

View File

@@ -918,7 +918,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
scm_password = kwargs.get('scm_password',
decrypt_field(project.credential,
'password'))
if scm_password not in ('', 'ASK'):
if scm_password:
self.assertFalse(scm_password in pu.job_args, pu.job_args)
self.assertFalse(scm_password in json.dumps(pu.job_env),
json.dumps(pu.job_env))
@@ -932,7 +932,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
scm_key_unlock = kwargs.get('scm_key_unlock',
decrypt_field(project.credential,
'ssh_key_unlock'))
if scm_key_unlock not in ('', 'ASK'):
if scm_key_unlock:
self.assertFalse(scm_key_unlock in pu.job_args, pu.job_args)
self.assertFalse(scm_key_unlock in json.dumps(pu.job_env),
json.dumps(pu.job_env))
@@ -968,7 +968,7 @@ class ProjectUpdatesTest(BaseTransactionTest):
project_path = project.get_project_path(check_if_exists=False)
# If project could be auto-updated on creation, the project dir should
# already exist, otherwise run an initial checkout.
if project.scm_type and not project.scm_passwords_needed:
if project.scm_type:
self.assertTrue(project.last_update)
self.check_project_update(project,
project_udpate=project.last_update)
@@ -1035,7 +1035,8 @@ class ProjectUpdatesTest(BaseTransactionTest):
# Change username/password for private projects and verify the update
# fails (but doesn't cause the task to hang).
scm_url_parts = urlparse.urlsplit(project.scm_url)
if 0 and project.scm_username and project.scm_password not in ('', 'ASK'):
# FIXME: Implement these tests again with new credentials!
if 0 and project.scm_username and project.scm_password:
scm_username = project.scm_username
should_still_fail = not (getpass.getuser() == scm_username and
scm_url_parts.hostname == 'localhost' and
@@ -1344,59 +1345,6 @@ class ProjectUpdatesTest(BaseTransactionTest):
)
self.check_project_scm(project)
def test_prompt_for_scm_password_on_update(self):
scm_url = getattr(settings, 'TEST_GIT_PUBLIC_HTTPS',
'https://github.com/ansible/ansible.github.com.git')
if not all([scm_url]):
self.skipTest('no public git repo defined for https!')
project = self.create_project(
name='my public git project over https',
scm_type='git',
scm_url=scm_url,
scm_username='nobody',
scm_password='ASK',
)
url = reverse('api:project_update_view', args=(project.pk,))
with self.current_user(self.super_django_user):
response = self.get(url, expect=200)
self.assertTrue(response['can_update'])
self.assertTrue('scm_password' in response['passwords_needed_to_update'])
with self.current_user(self.super_django_user):
response = self.post(url, {}, expect=400)
self.assertTrue('scm_password' in response['passwords_needed_to_update'])
with self.current_user(self.super_django_user):
response = self.post(url, {'scm_password': 'blah1234'}, expect=202)
project_update = project.project_updates.order_by('-pk')[0]
self.check_project_update(project, should_fail=False,
scm_password='blah1234',
project_update=project_update)
def test_prompt_for_scm_key_unlock_on_update(self):
scm_url = 'git@github.com:ansible/ansible.github.com.git'
project = self.create_project(
name='my public git project over ssh',
scm_type='git',
scm_url=scm_url,
scm_key_data=TEST_SSH_KEY_DATA_LOCKED,
scm_key_unlock='ASK',
)
url = reverse('api:project_update_view', args=(project.pk,))
with self.current_user(self.super_django_user):
response = self.get(url, expect=200)
self.assertTrue(response['can_update'])
self.assertTrue('scm_key_unlock' in response['passwords_needed_to_update'])
with self.current_user(self.super_django_user):
response = self.post(url, {}, expect=400)
self.assertTrue('scm_key_unlock' in response['passwords_needed_to_update'])
with self.current_user(self.super_django_user):
response = self.post(url, {'scm_key_unlock': TEST_SSH_KEY_DATA_UNLOCK}, expect=202)
project_update = project.project_updates.order_by('-pk')[0]
self.check_project_update(project, should_fail=None,
scm_key_unlock=TEST_SSH_KEY_DATA_UNLOCK,
project_update=project_update)
# Verify that we responded to ssh-agent prompt.
self.assertTrue('Identity added' in project_update.result_stdout)
def create_test_job_template(self, **kwargs):
opts = {
'name': 'test-job-template %s' % str(now()),
@@ -1491,33 +1439,34 @@ class ProjectUpdatesTest(BaseTransactionTest):
scm_type='git',
scm_url=scm_url,
scm_username=scm_username,
scm_password='ASK',
scm_password=scm_password,
scm_update_on_launch=True,
)
self.check_project_update(self.project, scm_password=scm_password)
self.assertEqual(self.project.project_updates.count(), 1)
self.check_project_update(self.project)
self.assertEqual(self.project.project_updates.count(), 2)
job_template = self.create_test_job_template()
job = self.create_test_job(job_template=job_template)
self.assertEqual(job.status, 'new')
self.assertTrue(job.passwords_needed_to_start)
self.assertTrue('scm_password' in job.passwords_needed_to_start)
self.assertTrue(job.start(**{'scm_password': scm_password}))
self.assertFalse(job.passwords_needed_to_start)
self.assertTrue(job.start())
self.assertEqual(job.status, 'pending')
job = Job.objects.get(pk=job.pk)
self.assertTrue(job.status in ('successful', 'failed'),
job.result_stdout + job.result_traceback)
self.assertEqual(self.project.project_updates.count(), 2)
# Try again but with a bad password - the job should flag an error
# because the project update failed.
self.assertEqual(self.project.project_updates.count(), 3)
# Try again but set a bad project password - the job should flag an
# error because the project update failed.
cred = self.project.credential
cred.password = 'bad scm password'
cred.save()
job = self.create_test_job(job_template=job_template)
self.assertEqual(job.status, 'new')
self.assertTrue(job.passwords_needed_to_start)
self.assertTrue('scm_password' in job.passwords_needed_to_start)
self.assertTrue(job.start(**{'scm_password': 'lasdkfjlsdkfj'}))
self.assertFalse(job.passwords_needed_to_start)
self.assertTrue(job.start())
self.assertEqual(job.status, 'pending')
job = Job.objects.get(pk=job.pk)
# FIXME: Not quite sure why the project update still returns successful
# in this case?
#self.assertEqual(job.status, 'error',
# '\n'.join([job.result_stdout, job.result_traceback]))
self.assertEqual(self.project.project_updates.count(), 3)
self.assertEqual(self.project.project_updates.count(), 4)