mirror of
https://github.com/ansible/awx.git
synced 2026-03-13 15:09:32 -02:30
AC-132 More updates after testing various SCM username/password/key options.
This commit is contained in:
@@ -7,6 +7,7 @@ import distutils.version
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
@@ -64,8 +65,10 @@ class BaseTask(Task):
|
||||
Create a temporary file containing the SSH private key.
|
||||
'''
|
||||
ssh_key_data = ''
|
||||
if hasattr(instance, 'scm_key_data'):
|
||||
ssh_key_data = decrypt_field(instance, 'scm_key_data')
|
||||
if hasattr(instance, 'project'):
|
||||
project = instance.project
|
||||
if hasattr(project, 'scm_key_data'):
|
||||
ssh_key_data = decrypt_field(project, 'scm_key_data')
|
||||
elif hasattr(instance, 'credential'):
|
||||
credential = instance.credential
|
||||
if hasattr(credential, 'ssh_key_data'):
|
||||
@@ -82,9 +85,13 @@ class BaseTask(Task):
|
||||
|
||||
def build_passwords(self, instance, **kwargs):
|
||||
'''
|
||||
Build a dictionary of passwords responding to prompts.
|
||||
Build a dictionary of passwords for responding to prompts.
|
||||
'''
|
||||
return {}
|
||||
return {
|
||||
'yes': 'yes',
|
||||
'no': 'no',
|
||||
'': '',
|
||||
}
|
||||
|
||||
def build_env(self, instance, **kwargs):
|
||||
'''
|
||||
@@ -222,7 +229,7 @@ class RunJob(BaseTask):
|
||||
'''
|
||||
Build a dictionary of passwords for SSH private key, SSH user and sudo.
|
||||
'''
|
||||
passwords = {}
|
||||
passwords = super(RunJob, self).build_passwords(job, **kwargs)
|
||||
creds = job.credential
|
||||
if creds:
|
||||
for field in ('ssh_key_unlock', 'ssh_password', 'sudo_password'):
|
||||
@@ -339,13 +346,15 @@ class RunProjectUpdate(BaseTask):
|
||||
|
||||
name = 'run_project_update'
|
||||
model = ProjectUpdate
|
||||
idle_timeout = 30
|
||||
#idle_timeout = 30
|
||||
|
||||
def build_passwords(self, project_update, **kwargs):
|
||||
'''
|
||||
Build a dictionary of passwords for SSH private key.
|
||||
Build a dictionary of passwords for SSH private key unlock and SCM
|
||||
username/password.
|
||||
'''
|
||||
passwords = {}
|
||||
passwords = super(RunProjectUpdate, self).build_passwords(project_update,
|
||||
**kwargs)
|
||||
project = project_update.project
|
||||
value = decrypt_field(project, 'scm_key_unlock')
|
||||
if value not in ('', 'ASK'):
|
||||
@@ -360,6 +369,7 @@ class RunProjectUpdate(BaseTask):
|
||||
'''
|
||||
env = super(RunProjectUpdate, self).build_env(project_update, **kwargs)
|
||||
env['ANSIBLE_ASK_SUDO_PASS'] = str(False)
|
||||
env['DISPLAY'] = '' # Prevent stupid password popup when running tests.
|
||||
return env
|
||||
|
||||
def update_url_auth(self, url, username=None, password=None):
|
||||
@@ -384,24 +394,32 @@ class RunProjectUpdate(BaseTask):
|
||||
# Since we specify -vvv and tasks use async polling, we should get some
|
||||
# output regularly...
|
||||
args.append('-%s' % ('v' * 3))
|
||||
extra_vars = {}
|
||||
project = project_update.project
|
||||
scm_url = project.scm_url
|
||||
if project.scm_username and project.scm_password not in ('ASK', ''):
|
||||
scm_url = self.update_url_auth(scm_url, project.scm_username,
|
||||
decrypt_field(project, 'scm_password'))
|
||||
if project.scm_type == 'svn':
|
||||
extra_vars['scm_username'] = project.scm_username
|
||||
extra_vars['scm_password'] = decrypt_field(project, 'scm_password')
|
||||
else:
|
||||
scm_url = self.update_url_auth(scm_url, project.scm_username,
|
||||
decrypt_field(project, 'scm_password'))
|
||||
elif project.scm_username:
|
||||
scm_url = self.update_url_auth(scm_url, project.scm_username)
|
||||
if project.scm_type == 'svn':
|
||||
extra_vars['scm_username'] = project.scm_username
|
||||
else:
|
||||
scm_url = self.update_url_auth(scm_url, project.scm_username)
|
||||
# FIXME: Need to hide password in saved job_args and result_stdout!
|
||||
scm_branch = project.scm_branch or {'hg': 'tip'}.get(project.scm_type, 'HEAD')
|
||||
scm_delete_on_update = project.scm_delete_on_update or project.scm_delete_on_next_update
|
||||
extra_vars = {
|
||||
extra_vars.update({
|
||||
'project_path': project.get_project_path(check_if_exists=False),
|
||||
'scm_type': project.scm_type,
|
||||
'scm_url': scm_url,
|
||||
'scm_branch': scm_branch,
|
||||
'scm_clean': project.scm_clean,
|
||||
'scm_delete_on_update': scm_delete_on_update,
|
||||
}
|
||||
})
|
||||
args.extend(['-e', json.dumps(extra_vars)])
|
||||
args.append('project_update.yml')
|
||||
|
||||
@@ -418,9 +436,8 @@ class RunProjectUpdate(BaseTask):
|
||||
def get_password_prompts(self):
|
||||
d = super(RunProjectUpdate, self).get_password_prompts()
|
||||
d.update({
|
||||
r'Username for.*:': 'scm_username',
|
||||
r'Password for.*:': 'scm_password',
|
||||
r'Are you sure you want to continue connecting (yes/no)\?': 'yes', # FIXME: Should we really do this?
|
||||
# FIXME: Configure whether we should auto accept host keys?
|
||||
r'Are you sure you want to continue connecting \(yes/no\)\?': 'yes',
|
||||
})
|
||||
return d
|
||||
|
||||
@@ -441,3 +458,4 @@ class RunProjectUpdate(BaseTask):
|
||||
Hook for actions after project_update has completed.
|
||||
'''
|
||||
# Start any jobs waiting on this update to finish.
|
||||
|
||||
|
||||
@@ -721,6 +721,36 @@ class ProjectUpdatesTest(BaseTransactionTest):
|
||||
project.save()
|
||||
self.check_project_update(project)
|
||||
self.assertFalse(os.path.exists(untracked_path))
|
||||
# Change username/password for private projects and verify the update
|
||||
# fails (but doesn't cause the task to hang).
|
||||
if project.scm_username and project.scm_password not in ('', 'ASK'):
|
||||
scm_username = project.scm_username
|
||||
# Clear username only.
|
||||
project = Project.objects.get(pk=project.pk)
|
||||
project.scm_username = ''
|
||||
project.save()
|
||||
self.check_project_update(project, should_fail=True)
|
||||
# Try invalid username.
|
||||
project = Project.objects.get(pk=project.pk)
|
||||
project.scm_username = 'notavalidusername'
|
||||
project.save()
|
||||
self.check_project_update(project, should_fail=True)
|
||||
# Clear username and password.
|
||||
project = Project.objects.get(pk=project.pk)
|
||||
project.scm_username = ''
|
||||
project.scm_password = ''
|
||||
project.save()
|
||||
self.check_project_update(project, should_fail=True)
|
||||
# Set username, but no password.
|
||||
project = Project.objects.get(pk=project.pk)
|
||||
project.scm_username = scm_username
|
||||
project.save()
|
||||
self.check_project_update(project, should_fail=True)
|
||||
# Set username, with invalid password.
|
||||
project = Project.objects.get(pk=project.pk)
|
||||
project.scm_password = 'notavalidpassword'
|
||||
project.save()
|
||||
self.check_project_update(project, should_fail=True)
|
||||
|
||||
def test_public_git_project_over_https(self):
|
||||
scm_url = getattr(settings, 'TEST_GIT_PUBLIC_HTTPS',
|
||||
@@ -871,3 +901,4 @@ class ProjectUpdatesTest(BaseTransactionTest):
|
||||
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)
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# scm_branch: HEAD
|
||||
# scm_clean: true/false
|
||||
# scm_delete_on_update: true/false
|
||||
# scm_username: username (only for svn)
|
||||
# scm_password: password (only for svn)
|
||||
|
||||
- hosts: all
|
||||
connection: local
|
||||
@@ -27,4 +29,9 @@
|
||||
|
||||
- name: update project using svn
|
||||
subversion: dest={{project_path}} repo={{scm_url}} revision={{scm_branch}} force={{scm_clean}}
|
||||
when: scm_type == 'svn'
|
||||
when: scm_type == 'svn' and not scm_username|default('')
|
||||
|
||||
- name: update project using svn with auth
|
||||
subversion: dest={{project_path}} repo={{scm_url}} revision={{scm_branch}} force={{scm_clean}} username={{scm_username}} password={{scm_password}}
|
||||
when: scm_type == 'svn' and scm_username|default('')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user