Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

role variables defined in vars aren't unique #2796

Closed
knightlabs opened this issue Apr 27, 2013 · 9 comments
Closed

role variables defined in vars aren't unique #2796

knightlabs opened this issue Apr 27, 2013 · 9 comments

Comments

@knightlabs
Copy link

Create two roles, for instance "nginx" and "tomcat"; define variable files in each role with a 'version' variable, set to match expected versions of nginx and tomcat; create a playbook which associates both 'nginx' and 'tomcat' roles to a set of hosts.

Depending on order of execution, it appears that ansible overwrites the tomcat:version property with the nginx:version property, and then attempts to install tomcat-{{nginx:version}} which fails.

Either documentation should be updated to reflect the idea that roles maintain variables in a global namespace, or roles should be updated to auto-namespace vars files inside them, such that similarly named vars can co-exist between roles.

@mpdehaan
Copy link
Contributor

Roles were never meant to namespace variables, they are an automation around multiple vars_files includes.

@knightlabs
Copy link
Author

Sure, I guess my initial confusion was around separating roles out; in this case, there's no real benefit from a variable perspective to having an "nginx" role with $version=1.4.0 broken out from a "tomcat" role with $version=7.0.29 as opposed to having a single common role with variables like nginx_version=1.4.0 and tomcat_version=7.0.29; if vars were automatically associated with the appropriate role, then roles would be much more effective being shared between projects, between organizations, etc. Hence my point that from a documentation standpoint, re-affirming that might be useful so that it encourages people to independently namespace their variables (me_nginx__version vs you_tomcat__version) to avoid side effects.

@mpdehaan
Copy link
Contributor

Yes, you can't name the variable 'version' in each.

I don't document everyone's possible confusions as that keeps the docs
super dense.

We do talk about how it is a macro for vars_files, and that doesn't say
anything about namespacing.

On Sat, Apr 27, 2013 at 2:00 PM, John Knight notifications@github.comwrote:

Sure, I guess my initial confusion was around separating roles out; in
this case, there's no real benefit to having an "nginx" role with
$version=1.4.0 broken out from a "tomcat" role with $version=7.0.29 as
opposed to having a single common role with variables like
nginx_version=1.4.0 and tomcat_version=7.0.29; if vars were automatically
associated with the appropriate role, then roles would be much more
effective being shared between projects, between organizations, etc. Hence
my point that from a documentation standpoint, re-affirming that might be
useful so that it encourages people to independently namespace their
variables (me_nginx__version vs you_tomcat__version) to avoid side effects.


Reply to this email directly or view it on GitHubhttps://github.com//issues/2796#issuecomment-17120396
.

@ghost
Copy link

ghost commented Jun 14, 2013

Just got bitten badly by this. like @knightlabs I find this unintuitive, though I understand that
it is in fact just sugar.

The use case I was attempting is to reuse a task include for different roles,
parameterized by the contents of the vars/main.yml file for the role. Which doesn't
work, since the last role's vars win over.
Lost some time tracking down mysterious errors.

Ended up having an intermediate include file, called from main with a vars key,
not pretty but works.

roleFoo/tasks/main.yml

- include secondary.yml
  vars:
    foo: bar

roleFoo/tasks/secondary.yml

- some things dependent on variables , and...
- include parameterized_task.yml

@knightlabs
Copy link
Author

y-p – i ended up working around this for multiple roles by simply namespacing the variables as rolename__var in each vars/main.yml

It was a little chaotic to start with, but it actually makes the entire system more readable when I know I'm using service1__version v. service2__path

@ghost
Copy link

ghost commented Jun 15, 2013

That does look more readable, but doesn't solve my problem unless that namespacing
has some ansible magic to support it that I'm unaware of.

I wanted to use task includes to reduce code duplication across roles, that means
calling the same code using different values for the same variables.
You can't use the vars/ dir for that as discussed above, and OTOH include files aren't plays
so you can't just plunk a vars: key in there and go, so I had to introduce a nested include
in order to attach a vars: to that.

Also, It's difficult to share an include file among roles due to the directory structure,
I had to put symlinks to a top-level util/ directory in each roles/foo/tasks/.

@gedwards
Copy link

I believe this is a major problem because of the increasing probability of variable name collisions and debugging difficulties over time (I got bitten by this one too).

Lack of var isolation means that adding a new role (from yourself in the future, or some other team, or from some 3rd party) requires making sure there are not variable name clashes, which is a pain.

Please, please make it possible to have role vars that do not affect other role vars.

P.S. thank you so much for making Ansible!

@ghost ghost mentioned this issue Jun 20, 2013
@trinitronx
Copy link

Speaking as someone who has come from Chef and now learning to use Ansible (joined a team that was using it so I must adapt), I'm immediately seeing the importance of the convention to namespace variables. I'm caught off guard by some things:

  • There seems to be no well-followed namespace convention for Ansible community roles
  • Very few roles appear to have default settings (Chef cookbooks generally have sane default settings... Convention over Configuration)
  • Roles in Chef are more like the concept of Inventory Host Groups plus role-specific attributes (i.e.: Role as in "Q: What role is this server I'm describing? A: It's a database node", vs. Role as in "Q: What role is this piece of configuration management code? A: It's a database "role" describing the configuration for a database node"
  • Playbooks are not the community distributable unit of config management code... Roles are (Intuitively I expected playbooks to be similar to cookbooks just because of the words used.)
  • Playbooks seem more akin to the concept of a Wrapper Cookbook or Role Cookbook
  • Hashes aren't merged (The argument against this seems to be in favor of 'simplicity', however I'd argue that hash merge behavior is simple if it's done consistently and predictably. It also has the helpful result of simplifying the easy scoping of attributes/variables into namespaced Hashes)

In Chef cookbooks, you would define your default node attributes in my_cookbook/attributes/default.rb using a namespaced Hash. For example:

default['my_cookbook']['bar'] = 'something default'
default['my_cookbook']['foo'] = { 'things' => [ 'thing1', 'thing2', 'thing3' ] }
default['my_cookbook']['install_prefix'] = '/usr/local/'

These settings would usually be sane defaults for whatever package or thing the my_cookbook installs. A common example is the install_prefix above. Since install_prefix is a pretty generic name, and might be used by other cookbooks, it's a very good idea to namespace it under the my_cookbook key of the Hash. This makes configuration data for other components we install easy to access globally also, simply by using the namespaced hash key. Global access might be helpful in trying to aid service discovery or discovery of other config settings for integrating subsystems of a larger set of installable components. Local Ruby variables (different than the global node object which contains attributes) inside recipes are scoped to the recipe, so no need to worry there about leakage.

I'm very happy to find that in Ansible, there seems to be a concept of default settings which can be set inside a role under defaults/main.yml. However, the precedence or merge behavior of these variables is a bit unclear also. (Perhaps Hash merging and variable overrides both need to be considered in a discussion of the precedence order and behavior of Ansible?)

In Ansible, it seems that the variable scoping rules and namespace conventions are pretty unclear to me at the moment. This is probably just due to insufficient effort in exploring how it works, but my initial intuition is that it feels somewhat loose and not as safe to choose any old variable name in a role or playbook. I feel like I should explore variable scoping a bit more to see if I'm correct.

I don't mean to post this to say that this is the only way, or the right way, but speaking as a Chef user who is now also using Ansible... it's something I noticed that I found sadly missing since I was used to using it so extensively in Chef. I just thought I'd throw the idea out there and see what sort of consensus the Ansible community has about this.

@iteratelance
Copy link

I run a software development company and we use Ansible to create vagrant images and magage AWS resources and I've been happy with it for the most part, but as our projects grow in complexity I'd have to agree that namespacing varialbes would make the playbooks much more manageable and easier to extend.

Perhaps I'm misusing Ansible, as we're using it for configuration and a company wide package manager so I'd love to have roles as follows:

- {role: ruby, version: 2.2.2}
- {role: php, version: 7}

Where version is namespaced to the role.

@ansible ansible locked and limited conversation to collaborators Apr 24, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants