Use a single lock for all fact gathering and use the host as the index, not the `host.name`.
@@ -19,7 +19,7 @@ from socket import (
import click
import six
-from gevent.lock import Semaphore
+from gevent.lock import BoundedSemaphore
from paramiko import SSHException
from pyinfra import logger
@@ -29,6 +29,7 @@ from .util import get_arg_value, log_host_command_error, make_hash, underscore
# Index of snake_case facts -> CamelCase classes
FACTS = {}
+FACT_LOCK = BoundedSemaphore()
def is_fact(name):
@@ -107,20 +108,17 @@ def get_facts(state, name, args=None):
# Locks are used to maintain order.
fact_hash = make_hash((name, args, sudo, sudo_user, su_user, ignore_errors))
- # Lock!
- state.fact_locks.setdefault(fact_hash, Semaphore()).acquire()
-
# Already got this fact? Unlock and return 'em
if state.facts.get(fact_hash):
- state.fact_locks[fact_hash].release()
return state.facts[fact_hash]
+ with FACT_LOCK:
# Execute the command for each state inventory in a greenlet
greenlets = {}
for host in state.inventory:
- if host in state.ready_host_names:
- continue
+ # if host in state.ready_hosts:
+ # continue
# Work out the command
command = fact.command
@@ -131,7 +129,7 @@ def get_facts(state, name, args=None):
command = command(*host_args)
- greenlets[host.name] = state.fact_pool.spawn(
+ greenlets[host] = state.fact_pool.spawn(
host.run_shell_command, state, command,
sudo=sudo, sudo_user=sudo_user, su_user=su_user,
print_output=state.print_fact_output,
@@ -141,7 +139,7 @@ def get_facts(state, name, args=None):
failed_hosts = set()
# Collect the facts and any failures
- for hostname, greenlet in six.iteritems(greenlets):
+ for host, greenlet in six.iteritems(greenlets):
status = False
stdout = []
@@ -152,7 +150,7 @@ def get_facts(state, name, args=None):
kwargs = {}
if not ignore_errors:
- kwargs['callback'] = lambda: failed_hosts.add(hostname)
+ kwargs['callback'] = lambda: failed_hosts.add(host)
log_host_command_error(
host,
@@ -166,7 +164,7 @@ def get_facts(state, name, args=None):
if status and stdout:
data = fact.process(stdout)
- hostname_facts[hostname] = data
+ hostname_facts[host] = data
log_name = click.style(name, bold=True)
@@ -187,12 +185,10 @@ def get_facts(state, name, args=None):
# Assign the facts
state.facts[fact_hash] = hostname_facts
- # Release the lock, return the data
- state.fact_locks[fact_hash].release()
return state.facts[fact_hash]
-def get_fact(state, hostname, name):
+def get_fact(state, host, name):
'''
Wrapper around ``get_facts`` returning facts for one host or a function
that does.
@@ -203,7 +199,7 @@ def get_fact(state, hostname, name):
def wrapper(*args):
fact_data = get_facts(state, name, args=args)
- return fact_data.get(hostname)
+ return fact_data.get(host)
return wrapper
# Expecting the fact as a return value
@@ -211,4 +207,4 @@ def get_fact(state, hostname, name):
# Get the fact
fact_data = get_facts(state, name)
- return fact_data.get(hostname)
+ return fact_data.get(host)
