from asyncio import run, gather, sleep
from contextlib import asynccontextmanager
from collections import namedtuple
Connection = namedtuple('Connection', 'hostname')
@asynccontextmanager
async def connect_password(hostname, *, fail=False):
try:
print(f'connect to {hostname} with password')
if fail:
raise ValueError('failed')
yield Connection(hostname)
except Exception as e:
print(f'failed to connect to {hostname} (pw)')
raise
else:
print(f'disconnect from {hostname} (pw)')
@asynccontextmanager
async def connect_pubkey(hostname, *, fail=False):
try:
print(f'connect to {hostname} with pubkey')
if fail:
raise ValueError('failed')
yield Connection(hostname)
except Exception as e:
print(f'failed to connect to {hostname} (pk)')
raise
else:
print(f'disconnect from {hostname} (pk)')
@asynccontextmanager
async def connect(hostname, *, fail_with_pk, fail_with_pw):
try:
async with connect_pubkey(hostname, fail=fail_with_pk) as conn:
yield conn
except ValueError as e1:
try:
async with connect_password(hostname, fail=fail_with_pw) as conn:
yield conn
except ValueError as e2:
yield None
# raise ValueError('failed to connect') from e2
async def task(hostname, *commands, **failures):
async with connect(hostname, **failures) as conn:
if conn is not None:
for cmd in commands:
print(f'\trunning {cmd} on {conn}')
await sleep(0)
FailModes = namedtuple('FailureModes', 'fail_with_pk fail_with_pw')
async def main():
devices = {
'rsw2': FailModes(False, False),
'fsw1': FailModes(True, True),
'ssw3': FailModes(False, True),
}
commands = 'ls', 'hostname'
tasks = [task(hn, *commands, **fs._asdict()) for hn, fs in devices.items()]
await gather(*tasks)
run(main())