Merge "Ansible launcher: delay node assignment under load"
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index 07b777a..be9570c 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -399,11 +399,12 @@
approval matching all specified requirements.
*username*
- If present, an approval from this username is required.
+ If present, an approval from this username is required. It is
+ treated as a regular expression.
*email*
If present, an approval with this email address is required. It
- is treated as a regular expression as above.
+ is treated as a regular expression.
*email-filter* (deprecated)
A deprecated alternate spelling of *email*. Only one of *email* or
diff --git a/tests/fixtures/layout-requirement-username.yaml b/tests/fixtures/layout-requirement-username.yaml
index 7a549f0..f9e6477 100644
--- a/tests/fixtures/layout-requirement-username.yaml
+++ b/tests/fixtures/layout-requirement-username.yaml
@@ -3,7 +3,7 @@
manager: IndependentPipelineManager
require:
approval:
- - username: jenkins
+ - username: ^(jenkins|zuul)$
trigger:
gerrit:
- event: comment-added
diff --git a/zuul/launcher/ansiblelaunchserver.py b/zuul/launcher/ansiblelaunchserver.py
index 1457665..2b76e0d 100644
--- a/zuul/launcher/ansiblelaunchserver.py
+++ b/zuul/launcher/ansiblelaunchserver.py
@@ -515,6 +515,8 @@
self.termination_queue = termination_queue
self.keep_jobdir = keep_jobdir
self.running_job_lock = threading.Lock()
+ self.pending_registration = False
+ self.registration_lock = threading.Lock()
self._get_job_lock = threading.Lock()
self._got_job = False
self._job_complete_event = threading.Event()
@@ -638,6 +640,8 @@
self._got_job = False
def _runGearman(self):
+ if self.pending_registration:
+ self.register()
with self._get_job_lock:
try:
job = self.worker.getJob()
@@ -671,13 +675,23 @@
return ret
def register(self):
- if self._running_job:
+ if not self.registration_lock.acquire(False):
+ self.log.debug("Registration already in progress")
return
- new_functions = set()
- for job in self.jobs.values():
- new_functions |= self.generateFunctionNames(job)
- self.worker.sendMassDo(new_functions)
- self.registered_functions = new_functions
+ try:
+ if self._running_job:
+ self.pending_registration = True
+ self.log.debug("Ignoring registration due to running job")
+ return
+ self.log.debug("Updating registration")
+ self.pending_registration = False
+ new_functions = set()
+ for job in self.jobs.values():
+ new_functions |= self.generateFunctionNames(job)
+ self.worker.sendMassDo(new_functions)
+ self.registered_functions = new_functions
+ finally:
+ self.registration_lock.release()
def abortRunningJob(self):
self._aborted_job = True
@@ -1157,7 +1171,7 @@
config.write('private_key_file = %s\n' % self.private_key_file)
config.write('retry_files_enabled = False\n')
config.write('log_path = %s\n' % os.path.join(
- jobdir.logs, 'ansible.log'))
+ jobdir.logs, 'ansible.txt'))
config.write('gathering = explicit\n')
callback_path = zuul.ansible.plugins.callback_plugins.__file__
@@ -1177,13 +1191,22 @@
self.abortRunningProc(proc)
def runAnsiblePlaybook(self, jobdir, timeout):
+ # Set LOGNAME env variable so Ansible log_path log reports
+ # the correct user.
+ env_copy = os.environ.copy()
+ env_copy['LOGNAME'] = 'zuul'
+
+ cmd = ['ansible-playbook', jobdir.playbook,
+ '-e', 'timeout=%s' % timeout, '-v']
+ self.log.debug("Ansible command: %s" % (cmd,))
+
self.ansible_job_proc = subprocess.Popen(
- ['ansible-playbook', jobdir.playbook,
- '-e', 'timeout=%s' % timeout, '-v'],
+ cmd,
cwd=jobdir.ansible_root,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
preexec_fn=os.setsid,
+ env=env_copy,
)
ret = None
watchdog = Watchdog(timeout + ANSIBLE_WATCHDOG_GRACE,
@@ -1207,13 +1230,22 @@
return ret == 0
def runAnsiblePostPlaybook(self, jobdir, success):
+ # Set LOGNAME env variable so Ansible log_path log reports
+ # the correct user.
+ env_copy = os.environ.copy()
+ env_copy['LOGNAME'] = 'zuul'
+
+ cmd = ['ansible-playbook', jobdir.post_playbook,
+ '-e', 'success=%s' % success, '-v']
+ self.log.debug("Ansible post command: %s" % (cmd,))
+
self.ansible_post_proc = subprocess.Popen(
- ['ansible-playbook', jobdir.post_playbook,
- '-e', 'success=%s' % success, '-v'],
+ cmd,
cwd=jobdir.ansible_root,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
preexec_fn=os.setsid,
+ env=env_copy,
)
ret = None
watchdog = Watchdog(ANSIBLE_DEFAULT_POST_TIMEOUT,
diff --git a/zuul/model.py b/zuul/model.py
index ca8f098..46b0b98 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -1079,7 +1079,7 @@
for a in approvals:
for k, v in a.items():
if k == 'username':
- pass
+ a['username'] = re.compile(v)
elif k in ['email', 'email-filter']:
a['email'] = re.compile(v)
elif k == 'newer-than':
@@ -1098,7 +1098,7 @@
by = approval.get('by', {})
for k, v in rapproval.items():
if k == 'username':
- if (by.get('username', '') != v):
+ if (not v.search(by.get('username', ''))):
return False
elif k == 'email':
if (not v.search(by.get('email', ''))):
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index f08612d..a30b735 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -1105,10 +1105,11 @@
return
if build.end_time and build.start_time and build.result:
duration = build.end_time - build.start_time
- try:
- self.time_database.update(build.job.name, duration, build.result)
- except Exception:
- self.log.exception("Exception recording build time:")
+ try:
+ self.time_database.update(
+ build.job.name, duration, build.result)
+ except Exception:
+ self.log.exception("Exception recording build time:")
pipeline.manager.onBuildCompleted(event.build)
def _doMergeCompletedEvent(self, event):