Thanks so much for the epic response 😊 So far Fabric 2 seems more sensible in a 
lot of ways, and since my old codebase was so integrated into a former 
employer’s infrastructure, I’m going to keep trying to operate in the new world.

I’ll work through the workaround for now. When is 2.3 likely to drop?



From: bitprop...@gmail.com <bitprop...@gmail.com> On Behalf Of Jeff Forcier
Sent: Monday, July 23, 2018 9:56 PM
To: Christian MacNevin <cmacne...@nvidia.com>
Cc: fab-user@nongnu.org
Subject: Re: [Fab-user] New to fabric 2. Using groups with Connection?

Hi Christian,

First, do note you can always fall back to Fabric 1 for a while if Fabric 2 
isn't yet up to snuff for your particular use case. We're still feeling out 
some of the APIs in terms of ease of use. Unfortunately, Group is one of those 
- it's real basic right now.

I just looked and there's no great way to set global connect_kwargs in such an 
object, without creating your own Connections to hand to its alternate 
constructor 'from_connections()':

```
hosts = ['switch1', 'switch2', 'switch3']
connections = [Connection(host=host, user='user', connect_kwargs={'password': 
'pw'}) for host in hosts]
switch_group = group.SerialGroup.from_connections(connections)

@task
def inventory(c):
  switch_group.run('show chassis hardware')
```

That's not the end of the world, but it's not ideal, so I just made 
https://github.com/fabric/fabric/issues/1831 and then (since I was thinking 
about it and it was very easy for once) implemented it. It'll be out in the 
next feature release!

The rest of your issues are more high level, so here's a bit of a wall of text 
(sorry!):

Version 2 is much less implicit/magic than v1 – all objects need to fit 
together in obvious, Pythonic ways (such as being handed to one another in 
constructors or method calls). For example, context managers don't change any 
object besides the one that they yield, so trying to do things to switch_group 
inside a context manager about some other Connection object won't do anything. 
(This is as opposed to e.g. 'with settings()' in v1, which I assume you were 
thinking of; it, like the rest of that API, is all about magically twiddling 
data behind the scenes.)

Connections can't be created without some 'host' argument, which I think is 
triggering your TypeError. This ought to be in its __init__ docs, FWIW :) See 
the code example above; you either need to make your Group from 
explicitly-created Connections, where a host arg is being given, or (after the 
next release) you can tell the Group's constructor about connect_kwargs.

Depending on your use case, there's a CLI flag that may replace your getpass 
code: 
http://docs.fabfile.org/en/2.2/cli.html#cmdoption-prompt-for-login-password

Which brings us to that context argument in the task signature: that's how 
`fab` explicitly transmits CLI and config info to your tasks, including the 
connection password. However, this introduces some ordering problems with your 
code - you need to pass that context's config into your Group or Connections.

Should be easily solved by moving away from module-level code exec (which is 
honestly an antipattern anyways). Based on my above snippet:

```
hosts = ['switch1', 'switch2', 'switch3']

def make_group(c):
  connections = [
    Connection(host=host, user='user', config=c.config)
    for host in hosts
  ]
  return group.SerialGroup.from_connections(connections)

@task
def inventory(c):
  switch_group = make_group(c)
  switch_group.run('show chassis hardware')
```

Or, after 2.3 comes out, you could arguably nix make_group() again, though 
hopefully you can see the various opportunities for refactoring, given that 
everything is explicit:

```
hosts = ['switch1', 'switch2', 'switch3']

@task
def inventory(c):
  switch_group = SerialGroup(*hosts, config=c.config)
  switch_group.run('show chassis hardware')
```

Finally: if you're thinking "ok, but it'd be so nice to just plop my switch 
hostnames and the fact that I want password prompting all the time, into a 
config file and call it done": that sort of thing is definitely in the 
pipeline! As I said up top, we're still hashing out a lot of the 'convenience' 
angles here, even though the core APIs are mostly in good shape.

Hope that all helps,
Jeff


On Mon, Jul 23, 2018 at 3:45 PM, Christian MacNevin 
<cmacne...@nvidia.com<mailto:cmacne...@nvidia.com>> wrote:
Hi all,
I’m new to Fabric 2, though in the past I’d used 1 a lot. I can find docs on 
using SerialGroup, but only with run directly. I’m using interactive mode 
authentication, so it seems like I need to gather a password (that’s fine, I’m 
doing it via getpass) and also pass kwargs into Connection.  I have a large 
list of hosts, and also was planning to use @task decorators.

What I have right now is a muddle between the two which obviously won’t work, 
but I can’t figure out how to glue the three
concepts of having a defined group, a task which can be specified from the cli, 
and an interactive user/pass sequence together.


import getpass
from fabric import Connection, group
from invoke import task

switch_group = group.SerialGroup(switch1', 'switch2', 'switch3')

pw = getpass.getpass("Password for netuser?")

@task
def inventory(c):    <-- This is purely here because tasks will error out if a 
kwarg ‘Context(..?)’ isn’t specified
    with Connection(user = 'user', connect_kwargs = {'password' : pw }) as c:
        switch_group.run('show chassis hardware')

It’s failing out with ’TypeError: __init__() takes at least 2 arguments (3 
given)’



_______________________________________________
Fab-user mailing list
Fab-user@nongnu.org<mailto:Fab-user@nongnu.org>
https://lists.nongnu.org/mailman/listinfo/fab-user



--
Jeff Forcier
Unix sysadmin; Python engineer
http://bitprophet.org
_______________________________________________
Fab-user mailing list
Fab-user@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fab-user

Reply via email to