I am trying to read a key present in multiple hiera files and merge the values.
My hiera file contains:
hierarchy:
- name: "Per-env secrets"
paths:
- "puppet/hiera/dict-1.yaml"
- "puppet/hiera/dict-2.yaml"
and My puppet script contains:
lookup(dictionaries,Hash).each |String $keyDico, Hash $valueDico| {
notify{"The value of dictionary is: ${keyDico}": }
The key 'dictionaries' is present in both dict-1.yaml and dict-2.yaml. However, It always reads and prints the Key from the first matched hiera file.
I tried changing 'Hash' in lookup function's argument to 'Unique' or 'Deep'. But it didn't work.
Getting error:
Error: Evaluation Error: Resource type not found: Deep and Error: Evaluation Error: Resource type not found: Unique
Is there any way to achieve this?
Thanks in advance.
If you look at the docs for specifying merge behaviours (ref), you can see that you need to specify the optional third argument to lookup, and you are getting that error because "unique" is being interpreted as the data type.
Try either:
lookup(dictionaries, Hash, 'unique')
or
lookup(dictionaries, Hash, {'strategy' => 'unique'})
according to whichever you find more readable.
Related
I am trying to understand what exactly the function "lookup" does in terraform code? does it find maps or lists? just confused how to use this lookup correctly.
The lookup documentation has the following to say about it:
lookup retrieves the value of a single element from a map, given its key. If the given key does not exist, the given default value is returned instead.
The normal way to look up a value from a map by key is to use the index syntax, like example["foo"], but that operation will return an error if there is no element with the key foo in the map example.
lookup is therefore similar to the index syntax except for the additional behavior of choosing a fallback value to use instead of an error if the key doesn't exist. lookup(example, "foo", "default") is the same as example["foo"] except that it will produce "default" rather than an error if there is no element with the key "foo".
More recent Terraform versions also have the try function which can serve as a perhaps easier to understand alternative to lookup, because it still uses the normal index syntax as part of the expression: try(example["foo"], "default") is similar to lookup(example, "foo", "default"), and will produce the same result as long as example is a map of strings.
How can I achieve something like this in Hiera?
service::enabled: true
plugin:
sensu:
ensure: (if service::enabled: 'present' else 'absent')
I know I can do this with puppet but would like to avoid that.
If you really, really (see below why you don't want to do this) want to have conditional logic in your data, then you could use my tahu::ppyaml() hiera backend which allows you to have puppet logic embedded in the yaml data, or write your own specific backend function. The tahu module requires Puppet 6. For versions of puppet before Hiera 5 you need to write a hiera 3 backend to achieve something similar. With Hiera 5 a backend function is very simple and can even be written in the puppet language.
You can find the tahu::ppayaml function here:
https://github.com/hlindberg/tahu/blob/master/lib/puppet/functions/tahu/ppyaml_key.rb
Your data would then look like this:
service::enabled: true
plugin:
sensu:
ensure: "if $service::enabled { 'present'} else {'absent'}"
Since the ppyaml backend treats every string as puppet language you need to quote all literal strings in the data file read by ppyaml; for example "'foo'" or '"foo"'.
You can however break out the key with a conditional into a separate file and use and alias in your main data file. Like this:
service::enabled: true
plugin:
sensu:
ensure: '%{alias("sensu::ensure")}'
And then, either using the tahu::ppyaml to bind only dynamic keys:
sensu::ensure: if $service::enabled { 'present'} else {'absent'}"
and adding that to your hiera.yaml referencing tahu::ppyaml as a backend.
It would work the same way if you write your own backend.
If any of this is recommended is a different question as it is questionable to have conditional logic in the data that depends on a variable being set or not in a manifest as you will get one value if you do the lookup before the inclusion of sensu and a different value after - and you are probably looking up the hash for the very purpose of declaring sensu.
Unfortunately, Hiera doesn't have expressions that can do anything as sophisticated as conditional logic.
There are some aliasing and lookup functions, so you may be able to pass the value service::enabled through unmodified, but that is it. The functions in Hiera are documented at https://puppet.com/docs/puppet/latest/hiera_merging.html.
I'm adding an If Condition to my ADFv2 Pipeline based on the output of an activity. I'm simply checking if a file is downloaded and if so I want to load the table with the downloaded file.
My Expression looks like this:
#{equals(activity('RunFunction').output.files[1].Downloaded,true)}
And I'm getting the following warning:
Expression of type 'String' does not match the field 'expression'
How do I update my code to remove this warning?
Why you have to add { } in your expression? Please remove it,#equals(A,B) is correct format.
#equals(activity('Azure Function1').output.files[1].Downloaded,true)
I'm trying to open the files whose name contains a pattern - which is the key value stored in a dictionary (key values in the dictionary are the patterns I'm trying to match in the file name).
I'm currently using glob.blob to match the pattern in the file name. The name of my dictionary is "xd". So, I want to implement something like this:
for key in xd :
for name in glob.glob(*key*):
file = open ('name','w')
I'm getting invalid syntax error here
I want to be able to open all the files which have the 'key' in their name and perform text addition in those files. Could someone please tell me if there is a way of doing this?
glob.glob() expects a str parameter, so you'll need to make a string out of the wildcards with key included. I'd also suggest opening files using with so you don't forget to close the file descriptor.
for key in xd:
for name in glob.glob(f"*{key}*"):
with open(name, 'w')
...
I'm trying to use the keys expression in Terraform to grab a list of keys (from a map variable) and assign it to a local variable. Here is the code snippet:
locals {
project_name_list = keys(${var.project_map})
}
However, I'm getting the following error:
Unknown token: 29:22 IDENT keys
Am I missing something here. Nowhere can I find an example of this expression. As bad as it is, even the official documentation does not help -https://www.terraform.io/docs/configuration/functions/keys.html
HashiCorp has really done a bad job of elaborating the nuances of Terraform for beginners on their website.
Terraform functions need to be wrapped in expression syntax to show that it's not a literal value: "${}"
So try this: project_name_list = "${keys(var.project_map)}"
The example in the documentation is written as though being run from the terraform command line, which already assumes the command is a HCL expression and doesn't require that syntax.
UPDATE
I said above that the expression syntax is to show that it's not a literal value. It's probably more accurate to speak of it as expression syntax vs. configuration syntax. Configuration syntax is the first level of interpolation, which forms the basic structure of your terraform file with resource blocks, data blocks, etc. The second interpolation level is expression syntax which is used to generate values used by your configuration.
Thinking of it in these terms makes better sense of the error message, Unknown token, because terraform is attempting to read it as a configuration key word.
I had compared it to a literal value because it's in the same position as where a literal value would be.