Using set_fact in conjunction with delegate_to

Here is the use case:

  1. Run playbook against localhost

  2. Playbook creates nodes on some virt type (OpenStack, libvirt, whatever)

  3. Add some additional metadata via add_host for those nodes

  4. In order for the metadata to survive to an included playbook (that gathers facts), set_fact must be used.

  5. Since the playbook is running against localhost, set_fact just operates on localhost. It would be desirable to do something like the following:

  • name: Add facts

set_fact: “some_var={{ hostvars[item].some_var }}”
delegate_to: {{ item }}
with_items: groups.mygroup

Doing this from memory, so if the syntax isn’t 100%, my apologies.

Currently, I have to put another play in between, that does not gather facts, and uses mygroup as the hosts list.

Brad

delegate_to means “run this command on this remote system” so it doesn’t really make sense here.

What is sounds like what you want more of is the ability for the set_fact module to take a hostname in which to set the fact to.

I’d like to step back though, and ask where this ‘some_var’ is being used.

If in a template, you can just include these lookups in the template, and it would be pretty straightforward, which also keeps your template more simplified.

I’d like to understand the end use case, as we step back away from Ansible concepts, and it will help me better suggest a way to model things.

delegate_to means “run this command on this remote system” so it doesn’t really make sense here.

What is sounds like what you want more of is the ability for the set_fact module to take a hostname in which to set the fact to.

Agreed on delegate_to vs set for a particular host.

I’d like to step back though, and ask where this ‘some_var’ is being used.

If in a template, you can just include these lookups in the template, and it would be pretty straightforward, which also keeps your template more simplified.

It is in a template, however some_var could come from a number of different sources. It could come from nova_compute, or virt, or even quantum_floating_ip… Basically assembling metadata about the host to be used in a later playbook. So, regardless of the source, I’d like a “known name” off the host inventory.

Since I am “building an inventory” during an ansible run, the initial part of the playbook is being run against localhost. Then, through an included playbook, it kicks of the rest of my process, then operating on the created nodes.

Part of what complicates this is that I’m creating the nodes in a loop, using a complex var to drive it. Then, I need to get additional info from the results of the node creation.

I’d like to understand the end use case, as we step back away from Ansible concepts, and it will help me better suggest a way to model things.

Overall, setting arbitrary facts on a specific node would be useful in my scenario.

The underlying issue here is one of people trying more than something was designed for. I’m not saying it’s bad, or that it shouldn’t be used as such, but it was never imagined as such.

set_fact isn’t meant to delegate to anything, it was meant for simple one liners, where you want to store things like “this value is x times 10”

It just creates a variable for the current inventory host.

As such, if you use “set_fact” the delegation parameters should be ignored, but really nothing should be specified.

Ultimately I’m all for making new semantics work (or better, making unintended semantics raise errors), though I think this will be better resolved after we complete some (currently ongoing) attempts to refactor and cleanup Runner code that will make this easier.

Right now the with_items logic is growing a bit dense, and it’s hard to make a few additional changes.

So, while I don’t really want to say that’s the answer, the technical answer here to “my arms hurt when I do this”, is “don’t do that”, at least for now :slight_smile:

(Unless something small and clever can take care of it, of course)

I only meant the ‘me too’ with regards to the use case. I hadn’t tried delegating set_fact (which i assume is what you were suggesting not doing, as opposed to not using ec2_facts for now). I just wondered if there was a better way to call ec2_facts after creating an instance and access them in a deployment role (in this case I need to use the private ec2 fqdn of a web server instance when setting some mysql permissions on a db instance).

The delegation discussion did make we wonder…could I just call ec2_facts right after instance creation but delegate the call to the instance itself instead of localhost? I think it would work within the role unless the facts were mistakenly set for localhost, but I don’t know if the facts would bubble back up to the parent play; may try it Monday.

Alternatively (I can’t remember…but…) if the ec2.py inventory returns facts that include the same ones ec2_facts provides, it might be easier to end the parent play after starting the instances and then recall ansible-playbook with a deployment playbook using dynamic inventory.

In truth my underlying issue is that with multiple public and private IPs and hostnames per ec2 instance, I don’t know how to guarantee what I’ll get out of the built-in ansible facts for names and IPs. Even with ec2_facts, if I ever have an instance with more than one public or private interface (though I’ve never needed to) I think I’ll be in the same boat there.

Lastly, my continued thanks to you and your team for Ansible. Been working with it more lately and the more I learn the easier and better it is. :slight_smile:

Thanks,
Mark

“if there was a better way to call ec2_facts after creating an instance and access them in a deployment role”

Use group_by as shown in the ec2 examples, then:

  • hosts: new_hosts
    tasks:
  • ec2_facts