puppet resource with duplicate attributes fails instead of overwriting - puppet

If I have puppet resources with duplicate attributes, why does it fail instead of overwriting?
file { '/tmp/the_inlinetemplate.txt' :
content => inline_template("What do you get if multiply 6 by 9 ? <%= 6 * 7 %> . \n")
content => inline_template("My address <%= ipaddress %> \n")
}

You just cannot define the same parameter twice. From documentation:
A resource declaration is an expression that describes the desired state for a resource and tells Puppet to add it to the catalog
In your example it is impossible to decide which file content is desired:
"What do you get if multiply 6 by 9 ? <%= 6 * 7 %> . \n"
or
"My address <%= ipaddress %> \n"

I thought about several different answers, but the bottom line is simply that that's how Puppet chooses to deal with the uncertainty in what you are asking it to do. Rather than adopting an arbitrary rule to deal with the situation (why should it choose the last-appearing property binding instead of the first, or a random one?) it insists that you be clear and unambiguous up front.
This provides a degree of protection against performing unintended actions. Although the content of file /tmp/the_inlinetemplate.txt in particular probably doesn't matter in the grand scheme of things, Puppet applies the same principle to all resource declarations, many of which are rather more consequential.

Related

Adding an extra dependency in new Rules to existing Rules

I am writing a Shakefile with the aim of making it extensible with new Rules. Its interface is a function mainFor :: Rules () -> IO (), the idea being that client projects would only need to define main = mainFor myCustomRules to get the whole thing working. mainFor customRules is defined as a bunch of Shake Rules followed by a call to customRules.
This works as long as the custom rules passed to mainFor are for new targets.
However, some of my stock (non-custom) rules are basically of the form "run this big opaque proprietary external script with this input and hope for the best"; and there can be extra files used by the external script depending on its input. For example, imagine I have a rule of the following form:
"_build/output.bin" %> out -> do
need ["_build/script.scr", "_build/src/generated.src"]
runExternalScript
For a particular client project, maybe the generated source code contains references to another file _build/src/extrainput.src. So in the custom rules passed to mainFor, not only do I need extra rules for this file, but the existing rule should also be modified to mark that it needs this input:
main = mainFor $ do
"_build/src/extrainput.src" %> \out -> do
generateExtraSrc
"_buld/output.bin" %> \out -> do
need ["_build/src/extrainput.src"]
but this, unsurprisingly, fails because both the stock rule in mainFor and the second custom rule passed in the customRules argument are for the same target. Note that I do not want to fully override the stock rule, only extend it to add the extra dependency.
There is currently no way to do this using Shake. The possibilities are:
Add it to Shake. Whether that's the right thing depends on how common this requirement is - and my guess is relatively rare - but that needs validating. The fact you want the dependencies run before the rule is more concerning - it's somehow less compositional than just providing multiple actions that together produce a result.
Do it on the outside. My straw man would be to write the "extras" as some kind of FilePath -> Action () function, then define your own %> that also applied that function to the output. It would only work with pre-selected extension points, but if you redefine %> at the top of the file it can hit all your instances.
If you really want to hide it more, use shakeExtra to store the state in some way.

Freemarker: How to check for ?api-able type (v 2.3.26)

In Freemarker, I have a Map<Map<...>> in the model.
Due to FM glitch, querying for 2nd level Map needs ?api. However, that escapes the normal value existence checks and complicates things.
This is what I have:
<#if sortedStatsMap[rowTag.name]?? && sortedStatsMap[rowTag.name]?is_hash>
${mapToJson(sortedStatsMap[rowTag.name]?api.get(boxTag.name))!}
</#if>
This ends up with:
APINotSupportedTemplateException: The value doesn't support ?api. See requirements in the FreeMarker Manual.
(FTL type: sequence+extended_hash+string (wrapper: f.c.DefaultToExpression$EmptyStringAndSequence),
TemplateModel class: f.c.DefaultToExpression$EmptyStringAndSequence,
ObjectWapper: freemarker.template.DefaultObjectWrapper#1074040321(2.3.26, useAdaptersForContainers=true, forceLegacyNonListCollections=true, iterableSupport=trueexposureLevel=1, exposeFields=false, treatDefaultMethodsAsBeanMembers=true, sharedClassIntrospCache=#1896185155, ...))
The blamed expression:
==> sortedStatsMap[rowTag.name]! [in template "reports/templates/techReport-boxes.ftl" at line 152, column 84]
If I try
sortedStatsMap[rowTag.name]!?is_hash
then this also fails because if missing, it gives me empty_string_and_sequence and ?is_hash can't be applied, reportedly. (Says that in an error.)
What's the proper logic to check whether I can use ?api.get(key)? Or the right way to use ! to handle missing values or a missing key?
You can check if a value supports ?api with ?has_api. Though maybe you don't need that; the example and the problems related to it should be clarified (see my comments).

Modify a line in a scope with Ansible

I need to modify a line in a file. Only problem, the line appears multiple times, but in different scopes. Like in this example from wso2 configuration manual :
<KeyStore>
<Location>${carbon.home}/resources/security/wso2carbon.jks</Location>
<Type>JKS</Type>
<Password>wso2carbon</Password>
<KeyAlias>wso2carbon</KeyAlias>
<KeyPassword>wso2carbon</KeyPassword>
</KeyStore>
<TrustStore>
<!-- trust-store file location -->
<Location>${carbon.home}/repository/resources/security/client-truststore.jks</Location>
<!-- trust-store type (JKS/PKCS12 etc.) -->
<Type>JKS</Type>
<!-- trust-store password -->
<Password>wso2carbon</Password>
</TrustStore>
I would need for example to modify the <Password> entry with one value in the <Keystore> scope, and with a second different value in the <TrustStore> scope in order to have different passwords. Can the lineinfile module do that ? Or is there any other way ?
PS.
Using a template is not the solution I am looking for, as I would like to use this to modify preexisting servers and not lose any local modification.
You can't do this with lineinfile, because it handles every line of the file separately – so there's no context from other lines possible.
Regex in lineinfile is not multiline.
You can use replace – it uses multiline regex.
For example:
- replace:
backup: yes
dest: config.xml
regexp: '(<{{ item.scope }}>[\S\s]*<Password>)(?!{{ item.password }}<).*(</Password>[\S\s]*</{{ item.scope }}>)'
replace: '\1{{ item.password }}\2'
with_items:
- scope: KeyStore
password: foo
- scope: TrustStore
password: bar
Keep in mind that this solution is not bulletproof – scope names and password shouldn't have any XML special characters or regular expression sequences. Also I can't say for sure how it handles nested XML blocks with the same scope name.
But for general cases it should be fine.
There's even a try to be idempotent – it will not match a block if the password is the same.
Ansible lineinfile regex parameter can match multiple lines. There is no problem in that beside that the regex would be long and hard to understand and maintain.
As you are trying to manipulate XML ansible-xml module might be a good option to solve this problem.

label x assigned to a block which is not a set

trying out upgrading antlr4, I have 2 lines in the grammar that produce the error message:
label tok assigned to a block which is not a set
Specifically for a grammar line that looks like this:
contextRadius: tok=('radius' 'change-authorize-nas-ip') (IP4_ADDRESS|IP6_ADDRESS) 'encrypted' 'key' ID 'port' INT_TOK 'event-timestamp-window' INT_TOK 'no-reverse-path-forward-check'
;
What does this imply, exactly - to be a "block which is not set" and is there a general solution?
The improper label is the following:
tok=('radius' 'change-authorize-nas-ip')
In this case, ANTLR doesn't know whether to assign the token 'radius' or the token 'change-authorize-nas-ip' to the label tok. Starting with ANTLR 4, rather than generate code with unclear semantics an error is produced. You'll want to either remove the label tok or move it to the intended item. In other words, use one of the following three forms.
('radius' 'change-authorize-nas-ip')
(tok='radius' 'change-authorize-nas-ip')
('radius' tok='change-authorize-nas-ip')
The reason labels are allowed on blocks in grammars is to support items like the following. This block is a set, meaning the contents can be collapsed to matching exactly one token from a fixed set of allowed tokens. The particular item matched by the set is then assigned to x.
x=('a' | 'b')

Prefix namespace in RDF

I have this RDF statement (turtle format):
#prefix cd: <http://mai.com/contactwrapper/0.1#> .
<http://mai.com/contactwrapper/0.1#malzaa#m.com>
cd:Belongs_To "1"^^xmls:string ;
cd:Email_Address "malzaa#m.com"^^xmls:string ;
cd:Email_Type "WORK"^^xmls:string .
As you can see, the prefix worked with the properties (Belongs_To, Email_Address, and Email_Type) but didn't work with the name of the resource (malzaa#m.com). Because "http://mai.com/contactwrapper/0.1#" should be replaced by cd.
Could anyone please explain whats wrong with that ??
Thank you
The abbreviated form is often called a QName (which stands for "qualified name"). The reason cd:malazaam#m.com does not work as a QName are the # and the . char in the part behind the :. Turtle syntax does not allow these characters in a QName, which is why the full URI is used instead.
See the Turtle grammar for an overview of what characters are allowed in a QName.
As an aside: your Turtle fragment does not declare the xmls: namespace either (which you use for your literal datatypes), so it will fail to parse.
As Jeen says "#" is not allowed in a prefixed name in Turtle, despite prefixed name being broader than QNames.
In RDF 1.1, the Turtle language is being formally standardized. "#" is not legal in the local part of prefixed names, but "\#" is.
The latest grammar is: http://www.w3.org/TR/turtle/#sec-grammar-grammar
There are many parers that accept the traditional Turtle. Jena writers are conservative - they output legal RDF in a way to maximise the chances of being readable by another parser. Writing in full <..> form or using a prefixed name does not change the URI being written, only it's surface appearance.

Resources