Is there a way to create a logic condition in packer provisioner? - json

I am trying to add a condition so my volume_size: can get two different values depending on what is passed in "-var role="
I've tried something like this :
"volume_size": [{
"Fn::If" : [
".ami_id_bar",
{"foo" : "50"},
{"foo" : "20"}
]
}],
.ami_id_bar is a :
"environment_vars": [
"ami_id_bar={{user `role`}}"
],
that gets it from command line when executing packer
This is the error I get :
error(s) decoding:
'launch_block_device_mappings[0].volume_size' expected type 'int64', got unconvertible type '[]interface {}'
Is it impossible or what am I doing wrong ?
Thank you in advance!

No you can't. Packers templates are logicless. The standard way of achieving the what you want is to use -var-file where each vars file represents a role, e.g.
packer build -var-file=role-A.json template.json
In more complex cases we recommend that you preprocess your template and other files and wrap packer in some build script like make.

Related

How to fill/change particular unknown strings of some sections of a well formated JSON file from bash keeping the format intact?

How to fill/change particular unknown strings of some sections of a well formated .json file from bash keeping the format intact ?
Details:
Part of settings.json :
"profiles":
{
"defaults":
{
// Put settings here that you want to apply to all profiles.
},
"theme": "dark",
"list":
[
{
// Make changes here to the powershell.exe profile.
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false,
"acrylicOpacity": 0.9,
"colorScheme" : "Material",
"cursorColor" : "#FFFFFD",
"useAcrylic" : true
},
{
// Make changes here to the cmd.exe profile.
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "Command Prompt",
"commandline": "cmd.exe",
"hidden": false,
"acrylicOpacity": 0.2,
"colorScheme" : "Frost",
"cursorColor" : "#000000",
"useAcrylic": true,
},
"schemes": [
{
"name" : "Frost",
"background" : "#ffffff",
"black" : "#3C5712",
"blue" : "#17b2ff",
"brightBlack" : "#749B36",
"brightBlue" : "#27B2F6",
"brightCyan" : "#13A8C0",
"brightGreen" : "#89AF50",
"brightPurple" : "#F2A20A",
"brightRed" : "#F49B36",
"brightWhite" : "#741274",
"brightYellow" : "#991070",
"cyan" : "#3C96A6",
"foreground" : "#000000",
"green" : "#6AAE08",
"purple" : "#991070",
"red" : "#8D0C0C",
"white" : "#6E386E",
"yellow" : "#991070"
},
another file pickcolor.txt:
#FFFAFA
#FFFAFA
#EEE9E9
#FFC1C1
#EEB4B4
#CDC9C9
#F08080
#FF6A6A
#CD9B9B
#EE6363
#BC8F8F
#FF4040
#FF3030
#EE3B3B
#CD5C5C
#CD5555
#EE2C2C
#8B8989
#CD3333
#FF0000
#FF0000
#8B6969
#CD2626
#EE0000
#B22222
#A52A2A
#CD0000
#8B3A3A
#8B2323
Want to create a bash which changes value of fields like "background", "cursorColor" to any random value from pickcolor.txt
Requirements/problems I am facing:
Fields appearing many times gets different values from each other
Value of fields changes from time to time, so simple find and replace do not work
Fields changes there line number every time new contents are added, so line number for fields do not remain same.
Format of .json file should not change
Please note : I do not want anyone to write the complete code ; just hinting/pointing out ways will be sufficient. And thanks in advance !!
I believe what you need is something like this
fields=(background cursorColor)
colors=("#FFFAFA" "#CDC9C9" "#EE3B3B")
size=${#colors[#]}
for f in "${fields[#]}"; do
for line in $(grep -n "\"$f\"" myfile.json | cut -f1 -d:); do
index=$(($RANDOM % $size))
color="${colors[$index]}"
sed -i $line's|\("'"$f"'"\s*:\s*"\).\+"|\1'"$color"'"|' myfile.json
done
done
There is some magic in this solution:
We choose random index from array of colors
For each of fields which should be replaced we create it's own unique sed expression, which
First part (\("'"$f"'"\s*:\s*"\)#.\+" finds anything matching pattern "<field name>"<spaces>:<spaces>"<any color>"
Captures anything until 3rd double quote into group
In second group (\1'"${colors[$index]}"'") replaces matched part with itself, but inserts randomly picked color from array into second double quote group
Weird things with lots of quotes are made to interpolate field name and color into single quotes
NB: this is tested with GNU sed. May need a bit different syntax for BSD

Not sure why I'm getting an error of "Value of property VPCSecurityGroups must be of type List of String"

I'm not sure why I'm getting the error that reads "Value of property VPCSecurityGroups must be of type List of String"
I've tried creating a db instance in cloud formation. The name of the security group is: wordpressDBSecurityGroup. I've tried passing the value to the db instance in the following ways:
I tried using FN::GetAtt
"VPCSecurityGroups" : {
"Fn::GetAtt":
[
"wordpressDBSecurityGroup",
"GroupId"]
}
I also tried hard coding the name into the attribute:
"VPCSecurityGroups": "wordpressDBSecurityGroup"
I also tried using the 'Ref' functionality:
"VPCSecurityGroups" : {"Ref": "wordpressDBSecurityGroup"}
Can anyone tell me why I'm getting this error? How should I be doing it?
I forgot to add the brackets to the ref functionality. This fixed the issue.
"VPCSecurityGroups" : [{"Ref": "wordpressDBSecurityGroup"}]

Python: create json query

I'm trying to get python to create a json formatted like :
[
{
"machine_working": true
},
{
"MachineName": "TBL165-169",
"MachineType": "Rig Test"
}
]
However, i can seam to do it, this is the code i have currently but its giving me error
this_is_a_dict_too=[]
this_is_a_dict_too = dict(State="on",dict(MachineType="machinetype1",MachineName="MachineType2"))
File "c:\printjson.py", line 40
this_is_a_dict_too = dict(Statedsf="test",dict(MachineType="Rig Test",MachineName="TBL165-169")) SyntaxError: non-keyword arg after
keyword arg
this_is_a_dict_too = [dict(machine_working=True),dict(MachineType="machinetype1",MachineName="MachineType2")]
print(this_is_a_dict_too)
You are trying to make dictionary in dictionary, the error message say that you try to add element without name (corresponding key)
dict(a='b', b=dict(state='on'))
will work, but
dict(a='b', dict(state='on'))
won't.
The thing that you presented is list, so you can use
list((dict(a='b'), dict(b='a')))
Note that example above use two dictionaries packed into tuple.
or
[ dict(a='b'), dict(b='a') ]

Using logical operators in json path file

Is there a functionality to use logical operators in JSON path file used in copy command.
For example, I have a JSON which can contain a key which can either be
Desc
Or
Description
So in the JSON it would be something like -
{
"Desc": "Hello",
"City" : "City1",
"Age": "21"
}
{
"Description" : "World",
"City" : "City2",
"Age": "25"
}
I'm using copy command to pull the data from the JSON above into my table in redshift. The table has a column named "description_data". This would store values of either "Desc" or "Description". So I want my path file to identify using an "OR" condition.
This is the path file that I'm currently using -
{
"jsonpaths": [
"$['Desc']",
"$['City']",
"$['Age']"
]
}
Which is working fine.
What I'm trying to do is the below (this is where I'm unsure if there is any syntax or functionality to achieve the objective)
{
"jsonpaths": [
"$['Desc']" or "$['Description']",
"$['City']",
"$['Age']"
]
}
No, Redshift doesn't support this.
You can issue two copy commands, one with Desc, and another with Description, to load the data into two temporary tables. After that, you can merge the two into your final table.

MongoDB: how to select an empty-key subdocument?

Ahoy! I'm having a very funny issue with MongoDB and, possibly more in general, with JSON. Basically, I accidentally created some MongoDB documents whose subdocuments contain an empty key, e.g. (I stripped ObjectIDs to make the code look nicer):
{
"_id" : ObjectId("..."),
"stats" :
{
"violations" : 0,
"cost" : 170,
},
"parameters" :
{
"" : "../instances/comp/comp20.ectt",
"repetition" : 29,
"time" : 600000
},
"batch" : ObjectId("..."),
"system" : "Linux 3.5.0-27-generic",
"host" : "host3",
"date_started" : ISODate("2013-05-14T16:46:46.788Z"),
"date_stopped" : ISODate("2013-05-14T16:56:48.483Z"),
"copy" : false
}
Of course the problem is line:
"" : "../instances/comp/comp20.ectt"
since I cannot get back the value of the field. If I query using:
db.experiments.find({"batch": ObjectId("...")}, { "parameters.": 1 })
what I get is the full content of the parameters subdocument. My guess is that . is probably ignored if followed by an empty selector. From the JSON specification (15.12.*) it looks like empty keys are allowed. Do you have any ideas about how to solve that?
Is that a known behavior? Is there a use for that?
Update I tried to $rename the field, but that won't work, for the same reasons. Keys that end with . are not allowed.
Update filed issue on MongoDB issue tracker.
Thanks,
Tommaso
I have this same problem. You can select your sub-documents with something like this:
db.foo.find({"parameters.":{$exists:true}})
The dot at the end of "parameters" tells Mongo to look for an empty key in that sub-document. This works for me with Mongo 2.4.x.
Empty keys are not well supported by Mongo, I don't think they are officially supported, but you can insert data with them. So you shouldn't be using them and should find the place in your system where these keys are inserted and eliminate it.
I just checked the code and this does not currently seem possible for the reasons you mention. Since it is allowed to create documents with zero length field names I would consider this a bug. You can report it here : https://jira.mongodb.org
By the way, ironically you can query on it :
> db.c.save({a:{"":1}})
> db.c.save({a:{"":2}})
> db.c.find({"a.":1})
{ "_id" : ObjectId("519349da6bd8a34a4985520a"), "a" : { "" : 1 } }