yaml syntax error when defining variables using WHEN - yaml

I defined these in defaults/main.yml:
- mode : production
- consul_server_address :192.168.1.5
when : mode == "production"
- consul_server_address :192.168.2.5
when : mode == "staging"
but I got:
The offending line appears to be:
- consul_server_address : 192.168.1.5
when : mode == "production"
^ here
When I add a space after colons on consul_server_address, the error changes to:
ERROR! The default/main.yml file for role 'dnsmasq' must contain a dictionary of
variables
I spent some time on yaml syntax but I think this idea is wrong and I should do using another ansible-playbook solution.

You start your YAML with:
- mode : production
- denotes a sequence item, so this line defines that the root element of your YAML document is a sequence. Another sequence item follows:
- consul_server_address : 192.168.1.5
But now, there is a line which is not a sequence item:
when : mode == "production"
This is invalid because we are at indentation level 0, which contains the root element, which is a sequence, which may only contain sequence items. But when : … is a mapping key and therefor illegal here.
What you probably want to do is this:
- mode : production
- consul_server_address : 192.168.1.5
when : mode == "production"
- consul_server_address : 192.168.2.5
when : mode == "staging"
By properly indenting the when lines, they are keys of the mapping contained in the sequence item.

Someone on Ansible's IRC channel suggested me to use groupvars/hostvars for this purpose.
I edited my hosts inventory file and did something like this:
[nginx-staging]
IP_ADDRESS OR FQDN
[nginx-staging:vars]
...
consul_server_address=192.168.2.5
[nginx-production]
IP_ADDRESS OR FQDN
[nginx-production:vars]
...
consul_server_address=192.168.1.5
and it worked for me with a simpler and more straight forward solution.

Related

The %procid% sometimes blank in rsyslog template

I'm trying to configure rsyslog to output in RFC5424 format. This means that the PROCID must be output in the syslog header. If there's no header, it should output a single dash (-) in its place. However, some of the events output have it just blank, and some have an actual value.
This is rsyslogd 5.8.10 running on Amazon Linux.
Here are the config lines:
$template CustomFormat,"<%PRI%>1 %timegenerated:1:23:date-rfc3339%-00:00 %HOSTNAME% %app-name% b%procid%b %msgid% %STRUCTURED-DATA%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
$ActionFileDefaultTemplate CustomFormat
Note that I put a "b" on each side of %procid% to make it more visible (this part is not RFC5424-compliant). Here are two lines of sample output.
<87>1 2019-06-19T20:03:01.929-00:00 ip-10-90-0-15 crond b29408b - - pam_unix(crond:account): expired password for user root (password aged)
<85>1 2019-06-19T20:17:18.150-00:00 ip-10-90-0-15 sudo bb - - ssm-user : TTY=pts/0 ; PWD=/ ; USER=root ; COMMAND=/bin/vi /etc/rsyslog.conf
The first line is correct, but the second example should have "b-b" instead of "bb". What should I do to make the blank %procid% show up as a dash? It works fine for the %msgid% and %STRUCTURED-DATA%.
Is there a better way to get RFC5424 output? (I have to use -00:00 instead of Z.)
There may be a better way, but one thing you can try is to use a Rainer script variable in the template instead of the property, and set this variable to "-" if the procid is empty. For example,
$template CustomFormat,"<%PRI%>1 ... b%$.myprocid%b ..."
$ActionFileDefaultTemplate CustomFormat
if ($procid == "") then {
set $.myprocid = "-";
} else {
set $.myprocid = $procid;
}
*.* ./outputfile
Just make sure the if statement is before any action statements. Note, you cannot change the procid property itself with set.

Puppet 6 and module puppetlabs/accounts does not create user account in Hiera YAML format

When I run puppet agent --test I have no errors output but the user did not create.
My puppet hira.yaml configuration is:
---
version: 5
datadir: "/etc/puppetlabs/code/environments"
data_hash: yaml_data
hierarchy:
- name: "Per-node data (yaml version)"
path: "%{::environment}/nodes/%{::trusted.certname}.yaml"
- name: "Common YAML hierarchy levels"
paths:
- "defaults/common.yaml"
- "defaults/users.yaml"
users.yaml is:
accounts::user:
joed:
locked: false
comment: System Operator
uid: '1700'
gid: '1700'
groups:
- admin
- sudonopw
sshkeys:
- ssh-rsa ...Hw== sysop+moduledevkey#puppetlabs.com
I use this module
Nothing in Hiera data itself causes anything to be applied to target nodes. Some kind of declaration is required in a manifest somewhere or in the output of an external node classifier script. Moreover, the puppetlabs/accounts module provides only defined types, not classes. You can store defined-type data in Hiera and read it back, but automated parameter binding via Hiera applies only to classes, not defined types.
In short, then, no user is created (and no error is reported) because no relevant resources are declared into the target node's catalog. You haven't given Puppet anything to do.
If you want to apply the stored user data presented to your nodes, you would want something along these lines:
$user_data = lookup('accounts::user', Hash[String,Hash], 'hash', {})
$user_data.each |$user,$props| {
accounts::user { $user: * => $props }
}
That would go into the node block matched to your target node, or, better, into a class that is declared by that node block or an equivalent. It's fairly complicated for so few lines, but in brief:
the lookup function looks up key 'accounts::user' in your Hiera data
performing a hash merge of results appearing at different levels of the hierarchy
expecting the result to be a hash with string keys and hash values
and defaulting to an empty hash if no results are found;
the mappings in the result hash are iterated, and for each one, an instance of the accounts::user defined type is declared
using the (outer) hash key as the user name,
and the value associated with that key as a mapping from parameter names to parameter values.
There are a few problems here.
You are missing a line in your hiera.yaml namely the defaults key. It should be:
---
version: 5
defaults: ## add this line
datadir: "/etc/puppetlabs/code/environments"
data_hash: yaml_data
hierarchy:
- name: "Per-node data (yaml version)"
path: "%{::environment}/nodes/%{::trusted.certname}.yaml"
- name: "Common YAML hierarchy levels"
paths:
- "defaults/common.yaml"
- "defaults/users.yaml"
I detected that using the puppet-syntax gem (included if you use PDK, which is recommended):
▶ bundle exec rake validate
Syntax OK
---> syntax:manifests
---> syntax:templates
---> syntax:hiera:yaml
ERROR: Failed to parse hiera.yaml: (hiera.yaml): mapping values are not allowed in this context at line 3 column 10
Also, in addition to what John mentioned, the simplest class to read in your data would be this:
class test (Hash[String,Hash] $users) {
create_resources(accounts::user, $users)
}
Or if you want to avoid using create_resources*:
class test (Hash[String,Hash] $users) {
$users.each |$user,$props| {
accounts::user { $user: * => $props }
}
}
Note that I have relied on the Automatic Parameter Lookup feature for that. See the link below.
Then, in your Hiera data, you would have a key named test::users to correspond (class name "test", key name "users"):
---
test::users: ## Note that this line changed.
joed:
locked: false
comment: System Operator
uid: '1700'
gid: '1700'
groups:
- admin
- sudonopw
sshkeys:
- ssh-rsa ...Hw== sysop+moduledevkey#puppetlabs.com
Use of automatic parameter lookup is generally the more idiomatic way of writing Puppet code compared to calling the lookup function explicitly.
For more info:
PDK
Automatic Parameter Lookup
create_resources
(*Note that create_resources is "controversial". Many in the Puppet community prefer not to use it.)

Rancher error when setting a boolean field with an environment variable

I have a rancher-compose.yml file where I set the upgrade_strategy.start_first field using an environment variable like this:
upgrade_strategy:
start_first: ${START_FIRST}
batch_size: 1
When running using the rancher-compose CLI, I get the following error:
ERRO[0000] Failed to open project origami-svcproxy: yaml: unmarshal errors:
line 28: cannot unmarshal !!str `false` into bool
When running in debug I see the following yaml:
upgrade_strategy:
batch_size: 1
start_first: "false" # <-- notice the surrounding quotes, missing from the rest of the variable replacements
How can I set this field dynamically?
I had the same problem and used a different strategy to fix the issue. First step is to convert docker-compose.yml to a template, docker-compose.yml.tpl. Second, use template logic to fetch the value of the boolean variable.
upgrade_strategy:
start_first: {{ .Values.START_FIRST }}
batch_size: 1
Reference: https://github.com/rancher/rancher-catalog/blob/v1.6-development/infra-templates/ipsec/9/docker-compose.yml.tpl#L21

How to append values in ansible variable using conditional statements

I am passing a set of values to the ansible play book. Using the value I try to create a string.
For example, I pass arguments: first_nm, last_nm and nick_nm to my playbook via --extra-vars. And inside my role/:
<task-name>/
vars/main.yml
I tried to do the following:
full_name: {{first_nm}} {{last_nm}}{{'-'+nick_nm if nick_nm is defined else ''}}
My Problem:
Since nick_nm is optional, when its empty or not defined if get the full name as for example : david john- with a - appended to the value.
So how can I avoid this append. Is there a better way to do the same?
You should also check if string is not empty. In your setup you only checking if the variable exists, and since it does the condition evaluates to True and gives you - + nick_nm
You can do it like this:
---
- hosts: localhost
gather_facts: no
connection: local
vars:
- first_nm: John
- last_nm: Smith
- nick_nm:
tasks:
- set_fact: full_name="{{first_nm}} {{last_nm}}{% if nick_nm is defined and nick_nm %}-{{nick_nm}}{%endif%}"
- debug: var=full_name

Create XML based on puppet templates with correct custom values?

In a database config setup I have 20 something XML files with the database connection information.
They have all exactly the same content except the connection information that is different. I have to use these XML files for five different environments, so instead of updating them manually I was hoping there was a good way to update their content with puppet, as I use this to set up the rest of the environment:
<config-property-setting name="DatabaseName"></config-property-setting>
<config-property-setting name="Password"></config-property-setting>
<config-property-setting name="UserName"></config-property-setting>
<config-property-setting name="ServerName"></config-property-setting>
<config-property-setting name="DriverType"></config-property-setting>
<config-property-setting name="MaxStatements"></config-property-setting>
<config-property-setting name="NetworkProtocol"></config-property-setting>
<config-property-setting name="PortNumber"></config-property-setting>
<config-property-setting name="LoginTimeout"></config-property-setting>
These are the values needed to be changed for each XML file.
Is there a good way to have a config file where the values for these files are entered and then, through templates, are pushed out as the correct configured and named XML files?
The most elegant way to do that in pure puppet is probably by using Hiera and an Erb template.
First of all, make sure that your hiera.yaml contains a hierarchy appropriate for your use case. For example, if the distinct environments are in distinct domains (but it might be more common to use the environment variable) :
:hierarchy:
- "%{module_name}/%{::fqdn}"
- "%{module_name}/%{::domain}"
- "%{module_name}/global"
- "global"
Then you can store the various configuration values just as #mudasobwa suggested, for example in hieradata/xmlmodule/domain1.internal :
:properties:
:DatabaseName : 'name'
:Password : 'pwd'
:UserName : 'user'
:ServerName : 'server'
:DriverType : 'mysql'
:MaxStatements : 30
:NetworkProtocol : 'udp'
:PortNumber : 1234
:LoginTimeout : 60
Then it's as simple as :
$properties = hiera('properties')
file { '/where/the/xml/fileS/goes.xml':
content => template('template.xml.erb');
}
And you get the values you need in the properties hash :
<config-property-setting name="DatabaseName">
<%=properties['DatabaseName']%>
</config-property-setting>
<config-property-setting name="Password">
<%=properties['Password']%>
</config-property-setting>
...
I would use pure ruby for that. First of all, create YAML config file:
:properties:
:DatabaseName : 'name'
:Password : 'pwd'
:UserName : 'user'
:ServerName : 'server'
:DriverType : 'mysql'
:MaxStatements : 30
:NetworkProtocol : 'udp'
:PortNumber : 1234
:LoginTimeout : 60
Then use this ruby code to produce what you need:
require 'yaml'
cfg = YAML.load_file 'cfg.yml'
xml = cfg[:properties].map { |k, v|
"<config-property-setting name='#{k}'>#{v}</config-property-setting>"
}.join("\n")
And, finally, inject these values into xml config templates (there must be a placeholder within xml configs to denote the place for proper values, e. g. if you want to insert them right after the root node <root>):
xml_config_files.each { |file|
File.write(file, File.read(f).gsub /<root>/m, "<root>\n#{xml}\n")
}
Hope it helps.

Resources