The current AnyConnectionProvisioner still needs a Connection type + args + kwargs for initialization, meaning a pre-existing Connection cannot be universally reused. Sure, you can copy over ssh options to a new ManagedSSHConnection, but it won't be the same.
This means a pattern like
with TestingFarmProvisioner(...) as tf:
tf.provision()
remote = tf.get_remote()
with AnyConnectionProvisioner(remote) as p:
# create multiple "copies" of the 'tf' remote/connection here
p.provision(10)
...
is not currently possible.
This kind of makes sense - for a Provisioner to enforce max_remotes and be able to clean after itself using a Context Manager, the Remote needs to be created by it, so it can call release_hook() via its .release() to remove itself from the Provisioner's list of remotes.
But the original use case of "gimme a system via one Provisioner, then use its .cmd() for X virtual Connections to execute many commands in parallel" is still there.
Enter: AnyRemoteProvisioner - you give it a class Remote instance via a function factory and it literally hands those over via a Provisioner style API. No auto-cleanup, no max_remotes, you are responsible for that.
With it, this becomes possible:
with TestingFarmProvisioner(...) as tf:
tf.provision()
remote = tf.get_remote()
# make .release() a no-op, we have only one real connection
real_release = remote.release
remote.release = lambda: pass
try:
with AnyRemoteProvisioner(lambda: remote) as p:
p.provision(10) # no-op
fake_remote = p.get_remote() # literally returns the 'remote' object above
fake_remote.release() # no-op
...
finally:
remote.release = real_release # let TFProvisioner clean up
The current AnyConnectionProvisioner still needs a Connection type + args + kwargs for initialization, meaning a pre-existing Connection cannot be universally reused. Sure, you can copy over ssh
optionsto a new ManagedSSHConnection, but it won't be the same.This means a pattern like
is not currently possible.
This kind of makes sense - for a Provisioner to enforce
max_remotesand be able to clean after itself using a Context Manager, the Remote needs to be created by it, so it can callrelease_hook()via its.release()to remove itself from the Provisioner's list of remotes.But the original use case of "gimme a system via one Provisioner, then use its .cmd() for X virtual Connections to execute many commands in parallel" is still there.
Enter: AnyRemoteProvisioner - you give it a class Remote instance via a function factory and it literally hands those over via a Provisioner style API. No auto-cleanup, no
max_remotes, you are responsible for that.With it, this becomes possible: