group_vars best practices

Is it considered bad practice to have variables in group_vars defined as such:

ntp:
  server: server.foo.com
  setting: foo

myapp:
   database: bar
   option: baz

instead of :

ntp_server: server.foo.com
ntp_setting: foo

myapp_database: bar
myapp_option: baz

It seems the first option is cleaner, but I don't believe you could
override variables in your hosts file. Instead, you'd create a
inventory/host_vars/myhost file to override?

Thanks,

James

There’s no problem doing it either way, but you’re right in that the first requires configuring host variable merging in ansible.cfg (which is not the standard option).

As a result, people shouldn’t really write roles for sharing that rely on that in many cases.

I'm trying to visualize a case where hash merging would be bad:

Let's you had this in your group_vars/all

foo:
  bar: baz
  zib: zab

but at some point you wanted to override that completely with:

foo:
  bar: biz

If you had merging on, that would yield:

foo:
  bar: biz
  zib: zab

Without merging, it would yield:

foo:
  bar:biz

Is that why merging is off by default?

- James

Yep!

-- Michael

group_vars/all:
tomcat_jvm_settings:

  • debug=on
  • GCfunckymode=True
  • dump_heap=true

group_vars/prod:
tomcat_jvm_settings:

  • XmxMax: 234324
  • XmxMin: 12342

with merge off, i can use same settings for dev/qa/staging and differnt ones for prod, if i had merge ON, i would have to always override the settings in prod:

  • debug=off
  • GCfunkymode=False
  • dump_heap=true

but I think a better example is with user access:

all:
sudoers:

  • devs
  • managers
  • it
  • releng

staging:
sudoers:

  • managers
  • releng
  • it

prod:
sudoers:
-it
-releng

Thanks for the example. Would it be crazy/possible to implement
optional merging dependent on the hash's name? Seems like for some
vars you could possibly want it, in others, not. So things that are
in nature restrictive like sudo would be merged, and others wouldn't.

something like:

hash_behaviour = replace # by default we replace all vars except
those in merge_hashes
merge_hashes = foo, baz, bar

- James

I wonder if merging could be handled explicitly with a jinja filter,
say, something like:

    mysql: prod_mysql | merge(default_mysql)

That way the merging would be explicit and encapsulated in the playbook.

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

​I agree it would be a good feature if merging dicts or not could be​ set
more granullary.

About your example, I think this is already possible with Jinja2, something
like

{{ default_mysql.update(prod_mysql) }}

But allowing merges or not per variable, instead of inventory wide as per
ansible.cfg is more difficult. Code wise, the merging happens​ (or not)
when loading the inventory, before a host is contacted for the first time,
and before the playbook starts to run, so this example can't be implemented
(at least without a major update to ansible.)

I think going that path would add a lot of unnecessary complexity, e.g. the
following ugly example :slight_smile:

GROUP: all
mysql:
  _meta_merge: True
  server: some_default_value1
  port: some_default_value2

GROUP: production
mysql:
  _meta_merge: True
  port: some_default_value3

GROUP: production
mysql:
  _meta_merge: True
  port: some_default_value4

Serge

I'd rather not introduce something like that as adds something rather
abstract to think about which would not be immediately clear when
auditing the playbook.

-- Michael

Something like this sounds like a good compromise!

-- Michael

this is easy to implement using yaml tags/directives, but would look a bit diff:

mysql: !!merge
port: some_default_value4

Brian,

That's interesting -- so if "!!merge" was specified somewhere down the
line that var would get merged versus replaced? I like it!

- James

I don’t like it at all.

We shouldn’t be inserting lesser known YAML syntax into things, especially if we have to define a new “directive”.

This would be moving Ansible down the wrong direction.

Kahlil,

Is this how you'd expect your solution to work?

I'm thinking in your case you'd have a

group_vars/all:

default_mysql:
  setting1: foo
  setting2: bar
  setting3: baz

group_vars/prod_mysql
  setting2: bip

and maybe you had a role called mysql that internally used "mysql" as
the variable hash?

- James

Er maybe?

Checkout my quick implementation at https://github.com/tartansandal/ansible.git

If I run the following against it

Ergh, hit send too fast.

The branch you want to look at is called 'merge-filter'.

Apologies if this makes no sense because:

1. I've had a few beers,
2. I'm writing this on a tram,
3. My python skills are limited.

K

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

Hi guys,

If we’re talking about implementation of new features, this should go to ansible-devel list

Thanks!