ansible / proposals

Repository for sharing and tracking progress on enhancement proposals for Ansible.
Creative Commons Zero v1.0 Universal
93 stars 19 forks source link

Proposal: Allow user different host variables when deploying to the same host #137

Closed horseinthesky closed 4 years ago

horseinthesky commented 5 years ago

Proposal:

Author: Kirill Pletnev pwnedbyspawn@gmail.com

Date: 2018-08-04

Motivation

Now it is impossible to use different host variables for the same host if this host is in different groups.

A similar issue was discussed here

Problems

Inventory example:

  children:
    group1:
      hosts:
        host1:
          hostname: cloud-myt-1vpnrr1
        host2:
          hostname: cloud-myt-1vpnrr2
    group2:
      hosts:
        host1:
          hostname: cloud-myt-1fvrr1

With the inventory example above we have this:

ansible -m debug -a 'var=hostvars[inventory_hostname].hostname' -i hosts.yml group1
host2 | SUCCESS => {
    "changed": false,
    "hostvars[inventory_hostname].hostname": "cloud-myt-1vpnrr2"
}
host1 | SUCCESS => {
    "changed": false,
    "hostvars[inventory_hostname].hostname": "cloud-myt-1fvrr1"
}

If I want to run some play on one host with different host vars (hostname) I'm now able to do it now. The latest definition always wins.

ansible -m debug -a 'var=hostvars[inventory_hostname].hostname' -i hosts.yml group2     
host1 | SUCCESS => {
    "changed": false,
    "hostvars[inventory_hostname].hostname": "cloud-myt-1fvrr1"
}

Solution proposal

We should be able to define variables for the same host in different groups independently of each other.

So we should do it like this:

agaffney commented 5 years ago

This isn't really a place for feature requests. A proposal should generally have an actual solution to the problem as part of the proposal.

It's difficult to tell exactly what you are proposing due to the formatting, but if I understand correctly, this would be a large change in the way that hosts/groups/vars are handled in a play and would likely break a lot of existing workflows.

horseinthesky commented 5 years ago

I've fixed formatting and updated solution proposal. As far as I can tell this should not break any existing workflows.

dagwieers commented 5 years ago

@horseinthesky The behaviour you see is on purpose. Group variables are assigned to hosts regardless of whether the group is targeted from a play or on the command line. So if your host is in multiple groups, it will inherit all the group vars (and other vars with a specific variable precedence rule).

This makes it possible to have your Windows hosts in a group named "windows", and regardless to whether you target it individually, or as (any) group it will understand the windows-related variables from the group it belongs to.

(The issue you reference above actually has a few users explaining the current behaviour)

If you have a single host, and you want to target it with different sets of variables, the easiest way is to make 2 entries in your inventory for that same host, and both entries use the same ansible_host, but with different group-membership or different host variables.

However if that single host has multiple services, or different variables per group, you could either opt to have complex dictionaries (and merge dictionaries) or namespace variables per group. Personally I don't think using groups here for this purpose makes sense, you probably want to use a complex data-structure and use a selector to get the information you require.

But if you would share your use-case, we might understand what you are doing and maybe there's an even more elegant solution for that. However this is not the right forum for that.

horseinthesky commented 5 years ago

I have several sites with two servers each where I want to deploy VMs. Server one always has two VMs, server two just one.

My inventory file with just one site is above. Playbook look like this:

- hosts: group1
  become: yes

  tasks:
  - name: Deploy vRR
    tags: deploy
    import_role:
      name: kvm
    vars:
      operation: deploy

  - name: Undeploy vRR
    tags: undeploy
    import_role:
      name: kvm
    vars:
      operation: undeploy

- hosts: group2
  become: yes

  tasks:
  - name: Deploy vRR
    tags: deploy
    import_role:
      name: kvm
    vars:
      operation: deploy

  - name: Undeploy vRR
    tags: undeploy
    import_role:
      name: kvm
    vars:
      operation: undeploy

kvm role uses virt module to deploy VMs.

Group vars: group1:

role: vpnrr
console:
  host: 0.0.0.0
  port: 3517
  protocol: telnet

group2

role: fvrr
console:
  host: 0.0.0.0
  port: 3518
  protocol: telnet

What I was going to archive is the first task deploys VM on all servers in group1 with vars for group1. Th second task does the same to group2. But in real life host vars sticks to hosts regardless of group.

bcoca commented 5 years ago

@horseinthesky or you can just define the host/group_vars adjacent to the specific plays, inventory adjacent always get loaded, but 'play adjacent' only get loaded when that play is used.

horseinthesky commented 5 years ago

I decided to do it like this: I have two invenroty files:

all:
  children:
    vpnrr_hosts:
      hosts:
        host1:
          hostname: cloud-myt-1vpnrr1
        host2:
          hostname: cloud-myt-1vpnrr2

and

all:
  children:
    fvrr_hosts:
      hosts:
        host1:
          hostname: cloud-myt-1vpnrr1

And launch the same playbook with different inventory files but it shouldn't be that way I think.

Changing the behavior shouldn't break existing scenarios but can make work with Ansible more logical and handy.

bcoca commented 5 years ago

i find it more logical that a host is always member of the groups defined vs only being a member of groups you target

horseinthesky commented 5 years ago

I agree but we can do nothing with adhered host variables than.

bcoca commented 5 years ago

you can do plenty, just not exactly this case

bcoca commented 4 years ago

closing as per above, also vars plugins allow for users to change reading behaviour.