Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
('2nd Order loop 1', True),
('Order loop 2', True),
('2nd Order loop 2', True),
('Final limited operation', ('somehost',)),
]
hosts = ['somehost', 'anotherhost', 'someotherhost']
shuffle(hosts)
result = run_cli(
','.join(hosts),
path.join('tests', 'test_deploy', 'deploy.py'),
)
assert result.exit_code == 0
state = pseudo_state
op_order = state.get_op_order()
self.assertEqual(
len(correct_op_name_and_host_names), len(op_order),
'Incorrect number of operations detected',
)
for i, (correct_op_name, correct_host_names) in enumerate(
correct_op_name_and_host_names,
):
op_hash = op_order[i]
op_meta = state.op_meta[op_hash]
self.assertEqual(list(op_meta['names'])[0], correct_op_name)
for host in state.inventory:
def setUp(self):
pseudo_state.reset()
def test_op_line_numbers(self):
inventory = make_inventory()
state = State(inventory, Config())
connect_all(state)
# Add op to both hosts
add_op(state, server.shell, 'echo "hi"')
# Add op to just the second host - using the pseudo modules such that
# it replicates a deploy file.
pseudo_state.set(state)
pseudo_host.set(inventory['anotherhost'])
first_pseudo_hash = server.user('anotherhost_user').hash
first_pseudo_call_line = getframeinfo(currentframe()).lineno - 1
# Add op to just the first host - using the pseudo modules such that
# it replicates a deploy file.
pseudo_state.set(state)
pseudo_host.set(inventory['somehost'])
second_pseudo_hash = server.user('somehost_user').hash
second_pseudo_call_line = getframeinfo(currentframe()).lineno - 1
pseudo_state.reset()
pseudo_host.reset()
# Ensure there are two ops
op_order = state.get_op_order()
# Add op to just the second host - using the pseudo modules such that
# it replicates a deploy file.
pseudo_state.set(state)
pseudo_host.set(inventory['anotherhost'])
first_pseudo_hash = server.user('anotherhost_user').hash
first_pseudo_call_line = getframeinfo(currentframe()).lineno - 1
# Add op to just the first host - using the pseudo modules such that
# it replicates a deploy file.
pseudo_state.set(state)
pseudo_host.set(inventory['somehost'])
second_pseudo_hash = server.user('somehost_user').hash
second_pseudo_call_line = getframeinfo(currentframe()).lineno - 1
pseudo_state.reset()
pseudo_host.reset()
# Ensure there are two ops
op_order = state.get_op_order()
self.assertEqual(len(op_order), 3)
# And that the two ops above were called in the expected order
self.assertEqual(op_order[1], first_pseudo_hash)
self.assertEqual(op_order[2], second_pseudo_hash)
# And that they have the expected line numbers
self.assertEqual(
state.op_line_numbers_to_hash.get((0, first_pseudo_call_line)),
first_pseudo_hash,
)
self.assertEqual(
elif len(operations[0].split('.')) == 2:
command = 'op'
operations = get_operation_and_args(operations)
else:
raise CliError('''Invalid operations: {0}
Operation usage:
pyinfra INVENTORY deploy_web.py [deploy_db.py]...
pyinfra INVENTORY server.user pyinfra home=/home/pyinfra
pyinfra INVENTORY exec -- echo "hello world"
pyinfra INVENTORY fact os [users]...'''.format(operations))
# Create an empty/unitialised state object
state = State()
pseudo_state.set(state)
# Setup printing on the new state
print_output = verbosity > 0
print_fact_output = verbosity > 1
state.print_output = print_output # -v
state.print_fact_info = print_output # -v
state.print_fact_output = print_fact_output # -vv
print('--> Loading config...')
# Load up any config.py from the filesystem
config = load_config(deploy_dir)
# Load any hooks/config from the deploy file
if command == 'deploy':
deploy_dir = inventory_path
# Set a fake state/host/inventory
pseudo_state.set(FakeState())
pseudo_host.set(FakeHost())
pseudo_inventory.set(FakeInventory())
# Load up any config.py from the filesystem
config = load_config(deploy_dir)
# Load any hooks/config from the deploy file
load_deploy_config(arguments['deploy'], config)
# Unset fake state/host/inventory
pseudo_host.reset()
pseudo_state.reset()
pseudo_inventory.reset()
# Arg based config overrides
if arguments['sudo']:
config.SUDO = True
if arguments['sudo_user']:
config.SUDO_USER = arguments['sudo_user']
if arguments['su_user']:
config.SU_USER = arguments['su_user']
if arguments['parallel']:
config.PARALLEL = arguments['parallel']
if arguments['fail_percent'] is not None:
config.FAIL_PERCENT = arguments['fail_percent']
hosts (string, list): group name or list of hosts to limit this include to
when (bool): indicate whether to trigger operations in this include
'''
if not pyinfra.is_cli:
raise PyinfraError('local.include is only available in CLI mode.')
if not when:
return
if hosts is not False:
hosts = ensure_host_list(hosts, inventory=pseudo_state.inventory)
if pseudo_host not in hosts:
return
if pseudo_state.deploy_dir:
filename = path.join(pseudo_state.deploy_dir, filename)
frameinfo = get_caller_frameinfo()
logger.debug('Including local file: {0}'.format(filename))
try:
# Fixes a circular import because `pyinfra.local` is really a CLI
# only thing (so should be `pyinfra_cli.local`). It is kept here
# to maintain backwards compatability and the nicer public import
# (ideally users never need to import from `pyinfra_cli`).
from pyinfra_cli.config import extract_file_config
from pyinfra_cli.util import exec_file
# Load any config defined in the file and setup like a @deploy
def exec_file(filename, return_locals=False, is_deploy_code=False):
'''
Execute a Python file and optionally return it's attributes as a dict.
'''
if filename not in PYTHON_CODES:
with open(filename, 'r') as f:
code = f.read()
code = compile(code, filename, 'exec')
PYTHON_CODES[filename] = code
# Create some base attributes for our "module"
data = {
'__file__': filename,
'state': pseudo_state,
}
# Execute the code with locals/globals going into the dict above
exec(PYTHON_CODES[filename], data)
return data
message = getattr(e, 'message', e.args[0])
raise CliError(message)
raise
except Exception as e:
# Attach the tracback to the exception before returning as state (Py2
# does not have `Exception.__traceback__`).
_, _, traceback = sys.exc_info()
e._traceback = traceback
# Re-raise any unexpected exceptions as UnexpectedError
raise UnexpectedError(e)
finally:
if pseudo_state.isset() and pseudo_state.initialised:
# Triggers any executor disconnect requirements
disconnect_all(pseudo_state)
def decorated_func(*args, **kwargs):
# If we're in CLI mode, there's no state/host passed down, we need to
# use the global "pseudo" modules.
if len(args) < 2 or not (
isinstance(args[0], (State, PseudoModule))
and isinstance(args[1], (Host, PseudoModule))
):
state = pseudo_state._module
host = pseudo_host._module
if state.in_deploy:
raise PyinfraError((
'Nested deploy called without state/host: {0}'
).format(func))
# Otherwise (API mode) we just trim off the commands
else:
args_copy = list(args)
state, host = args[0], args[1]
args = args_copy[2:]
# In API mode we have the kwarg - if a nested deploy we actually
# want the frame of the caller (ie inside the deploy package).
frameinfo = kwargs.pop('frameinfo', get_caller_frameinfo())