0

I'm currently trying to automate a deployment process, involving 3 different machines :

  • userA@hostA, pwdA
  • userB@hostB, pwdB
  • userC@hostC, pwdC

Here's the scenario I would like to execute, using Python's Fabric library (to which I'm new) :

def deploy():
    execute(taskA, hosts=[hostA])
    execute(taskB, hosts=[hostB])
    execute(taskC, hosts=[hostC])

I've tried to set the variable env.passwords like this:

env.passwords = {'userA@hostA:22':pwdA, 'userB@hostB:22':pwdB, 'userC@hostC:22':pwdC}

But it makes the SSH connection hanging.

My current workaround is to modify the variables env.user and env.password before each call to execute (I could also do that at the beginning of taskA, taskB and taskC). I really do not find that very elegant, and totally outside of Fabric's spirit.

If someone has ran into such situation, found him/herself with a hanging SSH connection while trying to use the env.passwords dict, I'm all yours ! And of course, if anyone already managed to make a more elegant multi-host-password handling, I would be glad to hear about any hint.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Ismaïl Mourtada
  • 452
  • 5
  • 11

2 Answers2

0

It might be better to keep your ssh details in ~/.ssh/config and have Fabric use that. See

jq170727
  • 13,159
  • 3
  • 46
  • 56
  • Hello, @jq170727, thanks for your answer and sorry for my late reply ! I confirm that your answer works well, when we handle security via a public-key/private-key pair ! However, in my context, I have to stick to the unsecure way, and have no control over that for the moment. Yet I found a workaround for my problem, which I will describe in the answer above – Ismaïl Mourtada Oct 07 '17 at 18:45
0

As said in my comment above, using the use_ssh_config variable works well. But in case you SSH with a password, Fabric currently doesn't handle per-host/per-user/per-password connection (which is normal, since using SSH passwords is considered as insecure)

That's why I dug into Fabric's source code, and added that new "feature". Here is my repository if you want to have a look. Basically, I used the env.roledefs variable, which lists roles as dictionary entries. And each role has a list of hosts, a user, and a password. Now, if you want to execute a task in one or more hosts (which have different usernames and passwords), there are two ways to do it:

  • Annotating the task with the decorator @complete_roles('role1', 'role2')
  • Using the function execute(task, complete_roles=['role1', 'role2'])

Just be sure to have 'role1' and 'role2' as keys in env.roledefs

If you want to have more info about my contribution, just check the two latest commits. I know, my code is not the cleanest...

Ismaïl Mourtada
  • 452
  • 5
  • 11