0

I need to sort the hosts from a roledef so they can run those tasks in a certain order.

I'm implementing a PostgreSQL BDR (http://2ndquadrant.com/en-us/resources/bdr/) deployer. In order to succeed, you need to create a BDR group in a host and only then join the BDR group in all other hosts.

The user need to choose which would be the first host from the list.

----EDITED----

I try to set env.hosts dynamically but it's not working.

env.roledefs = {
  'array1':    [],
}

env.hostsdefs = {
  'array1': [
    {'host': 'data-03', 'server': 'root@data-03'},
    {'host': 'data-01', 'server': 'root@data-01'},
  ],
}

@serial
def sort_and_echo(default_host):
    sort_host(default_host)
    echoing()

@serial
def sort_host(default_host):
    hostnames = env.hostsdefs[env.roles[0]]
    new_hosts = []
    for host in (hostnames):
        if (host['host'] != default_host):
            new_hosts.append(host['server'])
        else:
            new_hosts = [host['server']] + new_hosts
    env.hosts = new_hosts


@serial
def echoing():
    print env.hosts
    print('current host: %s' % (env.host_string))

This way, if I try:

fab -R array1 sort_and_echo:default_host=data-03
['root@data-03', 'root@data-01']
current host: None

Done.

It will not run echoing for each server in the list.

But if I try one sort and then echoing in the same command:

fab -R array1 sort_host:default_host=data-03 echoing

It will provide the expected output:

[root@data-03] Executing task 'echoing'
['root@data-03', 'root@data-01']
current host: root@data-03
[root@data-01] Executing task 'echoing'
['root@data-03', 'root@data-01']
current host: root@data-01

Done.

How can I change the hosts list in runtime?

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
otaviofcs
  • 785
  • 2
  • 6
  • 16
  • I dont know enough about bdr but if you need node-02 to be first why not just change the order in the `env.roledefs` -- maybe im misunderstanding you. Can you provide the "solution" you have so i can make head and tails of it. Thanks. – Javier Buzzi Feb 12 '16 at 15:47
  • Javier, thank you. My current solution is to force a server for every task. But is not working as expected. Right now I'm comparing env output of both tests I explain above in order to find the trigger – otaviofcs Feb 12 '16 at 16:03
  • Ok. Can you provide a better explanation of what you need. Forget postgres, just explain what you need fabric to do -- or better yet, what you want it to do (usually different). A little sudo code sometimes goes a long way. – Javier Buzzi Feb 12 '16 at 16:05
  • @Javier, sorry, I though I edited before. Does it seem clearer? – otaviofcs Feb 12 '16 at 16:40

2 Answers2

1

After a while I solve my problem. It was easier than expected. No hacks needed.

Passing the hosts parameter would make the host to be added at the begging of the array. As the standard behaviour of fabric is to throw out deduplication (check Host list deduplication in http://docs.fabfile.org/en/1.10/usage/execution.html#combining-host-lists), it solves the problem.

If you don't pass the parameter, it will use the first one of the array

env.roledefs = {
'array1': {'hosts': ['root@data-01', 'root@data-03'], }
}

So when I try:

fab -R array1 -H data-03 echoing

It will run in the correct order:

[root@data-03] Executing task 'echoing'
['root@data-03']
current host: root@data-03
[root@data-01] Executing task 'echoing'
['root@data-03']
current host: root@data-01

Done.
otaviofcs
  • 785
  • 2
  • 6
  • 16
0

If i understand you correctly, you can do something like this:

@task
def environment(*args):
    env.hosts = args

@task
def dev(*args):
    hosts = list(args)
    hosts.append('dev.host1')
    hosts.append('dev.host2')
    environment(*hosts)

@task
@serial # <--- PS. you dont really need this
def echoing():
    print env.hosts
    print('current host: %s' % (env.host_string))

you can now call it like this:

fab environment:node1.host.com,node2.host.com echoing

or:

# which is a "predetermined" list
fab dev echoing
# or add stuff to dev
fab dev:qa.node.host.com echoing
# ^^ this will just append the qa host to your existing list
Javier Buzzi
  • 6,296
  • 36
  • 50
  • first of all, thanks for your time. As I wrote, if I try the tasks in sequence it works: fab -R array1 sort_host:default_host=data-03 echoing. – otaviofcs Feb 12 '16 at 18:39
  • first of all, thanks for your time. As I wrote, if I try the tasks in sequence it works: fab -R array1 sort_host:default_host=data-03 echoing. But I do want do encapsulate in one task. I think, I'll try to test a different approach denying when the server is not valid – otaviofcs Feb 12 '16 at 18:45
  • @otaviofcs If you're set on using `roledefs` and `hostsdefs` im afraid you're going to have to hack it the way you're doing it now. Unless you want to go and hack fabric internals. But this is not a bad solution, you disregard the `hostsdefs` and `roledefs` and move it down to the task level. Do whatever magic you want to the hosts; assign it to `env.hosts` and call whatever secondary task you have. -- your needs are known only to you, i can only try and help ;) – Javier Buzzi Feb 12 '16 at 19:00
  • thanks for your time again. This is not a trivial question because it's not the way fabric works. I understand. – otaviofcs Feb 12 '16 at 19:12