How to concatenate several strings and variables in Yaml? - yaml

I need to do something like this:
domain: &domain example.com
ip: &ip 1.2.3.4
Address4: v=spf1 include:*domain ip4:*ip -all
I tried this but didn't work, it says there's a syntax error:
Address4: 'v=spf1 include:'*domain' ip4:'*ip' -all'
The implementation (I'm using these files in Ansible) seems to support concatenation, for example this works fine:
Address2: http://*domain # actually this doesn't work, I don't remember the exact example
Any ideas?

I don't exactly get why you're trying to concatinate in YAML, since Ansible uses jinja2 as a templating engine:
Defining variables in a vars file for Ansible (in YAML):
domain: example.com
ip: 1.2.3.4
Referencing variables (still in YAML):
Address4: v=spf1 include:{{ domain }} ip4:{{ ip }} -all
When you use the Address4 variable in the template module (I assume), it works the same way.

Related

Can I define the hostname (or other variable) on the vagrant command line?

I want to do something like this:
vagrant up --hostname="hello.world"
However there's no --hostname.
The reason I want this is so that the provisioner (Ansible) can use it to modify the provisioning depending on the hostname.
I could also use vagrant up hello.world (in which case Ansible could use it as inventory_hostname), but in that case I'd need to create an entry for hello.world in the Vagrantfile, which I don't want, since all possible hosts use the same Vagrantfile configuration. (An alternative could be to somehow specify in the Vagrantfile "use this configuration regardless of vm-name", but I don't know how to do that either.)
If none of this works, I could use an environment variable, but I don't know how to process that in Vagrantfile either.
You can call vagrant like:
HOSTNAME=myhostname vagrant up
In your Vagrantfile, store the environment variable:
$hostname = #{ENV['HOSTNAME']}"
And then call your ansible playbook passing extra_vars:
ansible.extra_vars = {
hostname: "#{$hostname}"
}
Alternatively, if these hostnames are predefined in groups in your playbook you can use limit:
ansible.limit = "#{$hostname}"

Fail to use yaml reference in ansible inventory plugin

I would like to use this config with an inventory plugin
# test_inventory_xxx.yml
plugin: cloudscale # or openstack or ...
inventory_hostname: &inventory_hostname_value uuid
compose:
setting_of_inventory_hostname: *inventory_hostname_value
I get no error, but the value is not set. And it is valid yaml. (At least my checker nor myself see an error.
So I decided to simplify it by using the constructed plugin, which is standard:
# inventory_constructed.yaml
plugin: constructed
# add variables to existing inventory
keyed_groups:
- key: from_inventory
prefix: inventory
parent_group: &common_parent_group test_group_1
compose:
var_from_constructed: 1233456789
also_from_constr: "'also'" # must be in quotes 2x!
some_from_constr: &ref1 1234567777
ref_from_constr: *ref1 # this works fine
ref_to_test: *common_parent_group # <--- this line returns an error
strict: yes
Now I get the error: Could not set ref_to_test for host my_host: 'test_group_1' is undefined
But it passes when I uncomment the marked line. (the ref &common_parent_group is still defined, but not used with *common_parent_group.) Why is test_group_1 undefined in one case, but not in the other?
How to reproduce: ansible -i some_of/your_inventory -i inventory_constructed.yaml -m debug -a var=vars
What do I do wrong? Or what else is the problem?
(I tought it is an missing feature, so original info in https://github.com/ansible/ansible/issues/69043)
It seems like parent_group takes a literal string while ref_to_test takes a Jinja2 expression (because it's under compose). It should fail the same way if you write
ref_to_test: test_group_1
because test_group_1 simply isn't a Jinja2 variable. You'll have to write
ref_to_test: "'test_group_1'"
just like above so Jinja2 sees 'test_group_1' which is a literal string. This also means you can't use an alias because parent_group does not evaluate its content with Jinja2 and therefore shouldn't include quotes in its content.

How to read Heroku's nested process.env vars / object in nconf?

I'm trying to deploy Ghost 1.2.0 to Heroku. With previous versions of Ghost (<= 0.11.x), they used a config.js file where you could just do:
database: {
client: 'postgres',
connection: {
host: process.env.POSTGRES_HOST,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DATABASE,
port: process.env.POSTGRES_PORT
},
debug: false
}, …
But in this version they're using nconf that replaces this config.js for environment dependent JSON files like config.production.json.
JSON files unlike JS objects can't have vars as values. I could hardcode my credentials to the JSON file, but I don't want to do that because:
Looks like a bad practise to me, and
Heroku rotates credentials periodically and updates applications where this database is attached. (Quoted from Heroku)
After some digging into nconf README and issues I understood that it would be possible to imitate this expected database object just with:
nconf.env({
separator: '__' // Two dashes
});
and defining vars as:
heroku config:set DATABASE__CLIENT=postgres
heroku config:set DATABASE__CONNECTION__HOST=<value>
...
but, no matter what, I get undefined when I later call:
nconf.get('database');
nconf.get('DATABASE'); // In case it was case-sensitive...
Instead, if I call:
nconf.get('DATABASE__CLIENT'); // postgres
it works. I could try (and I will) to modify Ghost scripts to read all variables this way, but as long as it expects a database object it'll be so cool to get it working the right way.
So, has anybody figured out how to correctly recreate an object with Heroku's env vars?
I've finally found the solution.
Unless you want to modify nconf.env(settings) like:
nconf.env({
separator: '__', // Two dashes
lowerCase: true
});
This will make it possible to pass lowerCase: true to env() so that if an environment variable is called SOMETHING or SOMEthing, it will also be gettable using something [Source]
I recommend to use already lowercase env vars.
So,
heroku config:set database__client=postgres
will be readable using:
nconf.get('database:client');
Looks like nconf has a different character separator to define nested variables called separator and another one to read them called logicalSeparator (its default value is :)

Extract server IP from the group in the inventory file

I have the following inventory file:
[group_01]
g01_h01 ansible_ssh_host='10.1.0.1'
g01_h01 ansible_ssh_host='10.1.0.2'
[group_02]
g02_h01 ansible_ssh_host='10.2.0.1'
g02_h01 ansible_ssh_host='10.2.0.2'
[group_03:children]
group_01
group_02
[group_03:vars]
fst_group2={{groups['group_02'][0]}}
snd_group1={{groups['group_01'][1]}}
I would like that in my playbook variables had the following values:
fst_group2=10.2.0.1
snd_group1=10.1.0.2
Instead I get:
fst_group2=g02_h01
snd_group1=g01_h02
Any ideas, a workaround?
Very strange task indeed... Anyway,
groups variable – is a list of hosts, which are g01_h01, g01_h02, etc.
To achieve what you expect, you may use this:
[group_03:vars]
fst_group2={{hostvars[groups['group_02'][0]]['ansible_ssh_host']}}
snd_group1={{hostvars[groups['group_01'][1]]['ansible_ssh_host']}}
And keep in mind that ansible_ssh_host is deprecated in favor of ansible_host.

Ansible: Extracting IP address from a CIDR( 192.168.21.x/24)

I have a variable name something like this defined in json format.
"zxc_address" : "192.168.21.x/24"
and i need to extract the IP address part(192.168.21.x) using ansible(yaml code)
what is the simple solution for that? can it be done using ansible filters. if yes then how?
Thanks,
VM
If you are using Ansible >=1.9 it is possible to use a filter for this:
{{ '192.0.2.1/24' | ipaddr('address') }}
Have a look at the documentation.
This should work:
{{ zxc_address.split("/")[0] }}

Resources